1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "dfx_kernel_stack.h" 17 18#include <dlfcn.h> 19#include <fcntl.h> 20#include <regex> 21#include <string_ex.h> 22#include <sys/ioctl.h> 23#include <unistd.h> 24 25#include "dfx_log.h" 26 27#define LOGGER_GET_STACK _IO(0xAB, 9) 28namespace OHOS { 29namespace HiviewDFX { 30namespace { 31// keep sync with defines in kernel/hicollie 32const char* const BBOX_PATH = "/dev/bbox"; 33const int BUFF_STACK_SIZE = 20 * 1024; 34const uint32_t MAGIC_NUM = 0x9517; 35typedef struct HstackVal { 36 uint32_t magic {0}; 37 pid_t pid {0}; 38 char hstackLogBuff[BUFF_STACK_SIZE] {0}; 39} HstackVal; 40} 41int DfxGetKernelStack(int32_t pid, std::string& kernelStack) 42{ 43 auto kstackBuf = std::make_shared<HstackVal>(); 44 if (kstackBuf == nullptr) { 45 DFXLOGW("Failed create HstackVal, errno:%{public}d", errno); 46 return -1; 47 } 48 kstackBuf->pid = pid; 49 kstackBuf->magic = MAGIC_NUM; 50 int fd = open(BBOX_PATH, O_WRONLY | O_CLOEXEC); 51 if (fd < 0) { 52 DFXLOGW("Failed to open bbox, errno:%{public}d", errno); 53 return -1; 54 } 55 56 int ret = ioctl(fd, LOGGER_GET_STACK, kstackBuf.get()); 57 if (ret != 0) { 58 DFXLOGW("Failed to get pid(%{public}d) kernel stack, errno:%{public}d", pid, errno); 59 } else { 60 kernelStack = std::string(kstackBuf->hstackLogBuff); 61 } 62 close(fd); 63 return ret; 64} 65 66bool FormatThreadKernelStack(const std::string& kernelStack, DfxThreadStack& threadStack) 67{ 68#ifdef __aarch64__ 69 std::regex headerPattern(R"(name=(.{1,20}), tid=(\d{1,10}), ([\w\=\.]{1,256}, ){3}pid=(\d{1,10}))"); 70 std::smatch result; 71 if (!regex_search(kernelStack, result, headerPattern)) { 72 DFXLOGI("search thread name failed"); 73 return false; 74 } 75 threadStack.threadName = result[1].str(); 76 int base {10}; 77 threadStack.tid = strtol(result[2].str().c_str(), nullptr, base); // 2 : second of searched element 78 auto pos = kernelStack.rfind("pid=" + result[result.size() - 1].str()); 79 if (pos == std::string::npos) { 80 return false; 81 } 82 size_t index = 0; 83 std::regex framePattern(R"(\[(\w{16})\]\<[\w\?+/]{1,1024}\> \(([\w\-./]{1,1024})\))"); 84 for (std::sregex_iterator it = std::sregex_iterator(kernelStack.begin() + pos, kernelStack.end(), framePattern); 85 it != std::sregex_iterator(); ++it) { 86 if ((*it)[2].str().rfind(".elf") != std::string::npos) { // 2 : second of searched element is map name 87 continue; 88 } 89 DfxFrame frame; 90 frame.index = index++; 91 base = 16; // 16 : Hexadecimal 92 frame.relPc = strtoull((*it)[1].str().c_str(), nullptr, base); 93 frame.mapName = (*it)[2].str(); // 2 : second of searched element is map name 94 threadStack.frames.emplace_back(frame); 95 } 96 return true; 97#else 98 return false; 99#endif 100} 101 102bool FormatProcessKernelStack(const std::string& kernelStack, std::vector<DfxThreadStack>& processStack) 103{ 104#ifdef __aarch64__ 105 std::vector<std::string> threadKernelStackVec; 106 OHOS::SplitStr(kernelStack, "Thread info:", threadKernelStackVec); 107 if (threadKernelStackVec.size() == 1) { 108 return false; 109 } 110 for (const std::string& threadKernelStack : threadKernelStackVec) { 111 DfxThreadStack threadStack; 112 if (FormatThreadKernelStack(threadKernelStack, threadStack)) { 113 processStack.emplace_back(threadStack); 114 } 115 } 116 return true; 117#else 118 return false; 119#endif 120} 121} 122}