1800b99b8Sopenharmony_ci/*
2800b99b8Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3800b99b8Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4800b99b8Sopenharmony_ci * you may not use this file except in compliance with the License.
5800b99b8Sopenharmony_ci * You may obtain a copy of the License at
6800b99b8Sopenharmony_ci *
7800b99b8Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8800b99b8Sopenharmony_ci *
9800b99b8Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10800b99b8Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11800b99b8Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12800b99b8Sopenharmony_ci * See the License for the specific language governing permissions and
13800b99b8Sopenharmony_ci * limitations under the License.
14800b99b8Sopenharmony_ci */
15800b99b8Sopenharmony_ci
16800b99b8Sopenharmony_ci#include "dfx_kernel_stack.h"
17800b99b8Sopenharmony_ci
18800b99b8Sopenharmony_ci#include <dlfcn.h>
19800b99b8Sopenharmony_ci#include <fcntl.h>
20800b99b8Sopenharmony_ci#include <regex>
21800b99b8Sopenharmony_ci#include <string_ex.h>
22800b99b8Sopenharmony_ci#include <sys/ioctl.h>
23800b99b8Sopenharmony_ci#include <unistd.h>
24800b99b8Sopenharmony_ci
25800b99b8Sopenharmony_ci#include "dfx_log.h"
26800b99b8Sopenharmony_ci
27800b99b8Sopenharmony_ci#define LOGGER_GET_STACK    _IO(0xAB, 9)
28800b99b8Sopenharmony_cinamespace OHOS {
29800b99b8Sopenharmony_cinamespace HiviewDFX {
30800b99b8Sopenharmony_cinamespace {
31800b99b8Sopenharmony_ci// keep sync with defines in kernel/hicollie
32800b99b8Sopenharmony_ciconst char* const BBOX_PATH = "/dev/bbox";
33800b99b8Sopenharmony_ciconst int BUFF_STACK_SIZE = 20 * 1024;
34800b99b8Sopenharmony_ciconst uint32_t MAGIC_NUM = 0x9517;
35800b99b8Sopenharmony_citypedef struct HstackVal {
36800b99b8Sopenharmony_ci    uint32_t magic {0};
37800b99b8Sopenharmony_ci    pid_t pid {0};
38800b99b8Sopenharmony_ci    char hstackLogBuff[BUFF_STACK_SIZE] {0};
39800b99b8Sopenharmony_ci} HstackVal;
40800b99b8Sopenharmony_ci}
41800b99b8Sopenharmony_ciint DfxGetKernelStack(int32_t pid, std::string& kernelStack)
42800b99b8Sopenharmony_ci{
43800b99b8Sopenharmony_ci    auto kstackBuf = std::make_shared<HstackVal>();
44800b99b8Sopenharmony_ci    if (kstackBuf == nullptr) {
45800b99b8Sopenharmony_ci        DFXLOGW("Failed create HstackVal, errno:%{public}d", errno);
46800b99b8Sopenharmony_ci        return -1;
47800b99b8Sopenharmony_ci    }
48800b99b8Sopenharmony_ci    kstackBuf->pid = pid;
49800b99b8Sopenharmony_ci    kstackBuf->magic = MAGIC_NUM;
50800b99b8Sopenharmony_ci    int fd = open(BBOX_PATH, O_WRONLY | O_CLOEXEC);
51800b99b8Sopenharmony_ci    if (fd < 0) {
52800b99b8Sopenharmony_ci        DFXLOGW("Failed to open bbox, errno:%{public}d", errno);
53800b99b8Sopenharmony_ci        return -1;
54800b99b8Sopenharmony_ci    }
55800b99b8Sopenharmony_ci
56800b99b8Sopenharmony_ci    int ret = ioctl(fd, LOGGER_GET_STACK, kstackBuf.get());
57800b99b8Sopenharmony_ci    if (ret != 0) {
58800b99b8Sopenharmony_ci        DFXLOGW("Failed to get pid(%{public}d) kernel stack, errno:%{public}d", pid, errno);
59800b99b8Sopenharmony_ci    } else {
60800b99b8Sopenharmony_ci        kernelStack = std::string(kstackBuf->hstackLogBuff);
61800b99b8Sopenharmony_ci    }
62800b99b8Sopenharmony_ci    close(fd);
63800b99b8Sopenharmony_ci    return ret;
64800b99b8Sopenharmony_ci}
65800b99b8Sopenharmony_ci
66800b99b8Sopenharmony_cibool FormatThreadKernelStack(const std::string& kernelStack, DfxThreadStack& threadStack)
67800b99b8Sopenharmony_ci{
68800b99b8Sopenharmony_ci#ifdef __aarch64__
69800b99b8Sopenharmony_ci    std::regex headerPattern(R"(name=(.{1,20}), tid=(\d{1,10}), ([\w\=\.]{1,256}, ){3}pid=(\d{1,10}))");
70800b99b8Sopenharmony_ci    std::smatch result;
71800b99b8Sopenharmony_ci    if (!regex_search(kernelStack, result, headerPattern)) {
72800b99b8Sopenharmony_ci        DFXLOGI("search thread name failed");
73800b99b8Sopenharmony_ci        return false;
74800b99b8Sopenharmony_ci    }
75800b99b8Sopenharmony_ci    threadStack.threadName = result[1].str();
76800b99b8Sopenharmony_ci    int base {10};
77800b99b8Sopenharmony_ci    threadStack.tid = strtol(result[2].str().c_str(), nullptr, base); // 2 : second of searched element
78800b99b8Sopenharmony_ci    auto pos = kernelStack.rfind("pid=" + result[result.size() - 1].str());
79800b99b8Sopenharmony_ci    if (pos == std::string::npos) {
80800b99b8Sopenharmony_ci        return false;
81800b99b8Sopenharmony_ci    }
82800b99b8Sopenharmony_ci    size_t index = 0;
83800b99b8Sopenharmony_ci    std::regex framePattern(R"(\[(\w{16})\]\<[\w\?+/]{1,1024}\> \(([\w\-./]{1,1024})\))");
84800b99b8Sopenharmony_ci    for (std::sregex_iterator it = std::sregex_iterator(kernelStack.begin() + pos, kernelStack.end(), framePattern);
85800b99b8Sopenharmony_ci        it != std::sregex_iterator(); ++it) {
86800b99b8Sopenharmony_ci        if ((*it)[2].str().rfind(".elf") != std::string::npos) { // 2 : second of searched element is map name
87800b99b8Sopenharmony_ci            continue;
88800b99b8Sopenharmony_ci        }
89800b99b8Sopenharmony_ci        DfxFrame frame;
90800b99b8Sopenharmony_ci        frame.index = index++;
91800b99b8Sopenharmony_ci        base = 16; // 16 : Hexadecimal
92800b99b8Sopenharmony_ci        frame.relPc = strtoull((*it)[1].str().c_str(), nullptr, base);
93800b99b8Sopenharmony_ci        frame.mapName = (*it)[2].str(); // 2 : second of searched element is map name
94800b99b8Sopenharmony_ci        threadStack.frames.emplace_back(frame);
95800b99b8Sopenharmony_ci    }
96800b99b8Sopenharmony_ci    return true;
97800b99b8Sopenharmony_ci#else
98800b99b8Sopenharmony_ci    return false;
99800b99b8Sopenharmony_ci#endif
100800b99b8Sopenharmony_ci}
101800b99b8Sopenharmony_ci
102800b99b8Sopenharmony_cibool FormatProcessKernelStack(const std::string& kernelStack, std::vector<DfxThreadStack>& processStack)
103800b99b8Sopenharmony_ci{
104800b99b8Sopenharmony_ci#ifdef __aarch64__
105800b99b8Sopenharmony_ci    std::vector<std::string> threadKernelStackVec;
106800b99b8Sopenharmony_ci    OHOS::SplitStr(kernelStack, "Thread info:", threadKernelStackVec);
107800b99b8Sopenharmony_ci    if (threadKernelStackVec.size() == 1) {
108800b99b8Sopenharmony_ci        return false;
109800b99b8Sopenharmony_ci    }
110800b99b8Sopenharmony_ci    for (const std::string& threadKernelStack : threadKernelStackVec) {
111800b99b8Sopenharmony_ci        DfxThreadStack threadStack;
112800b99b8Sopenharmony_ci        if (FormatThreadKernelStack(threadKernelStack, threadStack)) {
113800b99b8Sopenharmony_ci            processStack.emplace_back(threadStack);
114800b99b8Sopenharmony_ci        }
115800b99b8Sopenharmony_ci    }
116800b99b8Sopenharmony_ci    return true;
117800b99b8Sopenharmony_ci#else
118800b99b8Sopenharmony_ci    return false;
119800b99b8Sopenharmony_ci#endif
120800b99b8Sopenharmony_ci}
121800b99b8Sopenharmony_ci}
122800b99b8Sopenharmony_ci}