From 88815604d7203388896e0a6cebe52e9583271f2a Mon Sep 17 00:00:00 2001 From: oh_ci Date: Sat, 1 Mar 2025 03:39:47 +0000 Subject: [PATCH] =?UTF-8?q?=E5=9B=9E=E9=80=80=20'Pull=20Request=20!1702=20?= =?UTF-8?q?:=20=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96&=E4=BC=98=E5=8C=96dump?= =?UTF-8?q?catch=E5=BC=82=E6=AD=A5=E8=8E=B7=E5=8F=96=E5=86=85=E6=A0=B8?= =?UTF-8?q?=E6=A0=88=E9=80=BB=E8=BE=91'?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README_zh.md | 2 +- common/cutil/dfx_cutil.c | 66 ++- common/cutil/dfx_cutil.h | 2 + common/cutil/musl_cutil.h | 145 +++++++ common/dfxlog/dfx_log.h | 3 +- common/dfxutil/BUILD.gn | 8 +- common/dfxutil/dfx_util.cpp | 65 +-- common/dfxutil/dfx_util.h | 5 +- common/dfxutil/elapsed_time.h | 6 +- .../dfxutil/{stack_utils.cpp => stack_util.h} | 155 ++++--- common/dfxutil/stack_utils.h | 53 --- .../localhandler/dfx_signal_local_handler.cpp | 16 +- interfaces/common/dfx_define.h | 14 +- interfaces/common/dfx_dump_res.h | 53 ++- interfaces/common/dfx_errors.h | 32 +- interfaces/common/dfx_exception.h | 76 ++-- interfaces/common/dfx_param.h | 37 +- .../innerkits/async_stack/async_stack.cpp | 1 + .../innerkits/async_stack/fp_unwinder.cpp | 25 +- .../innerkits/async_stack/fp_unwinder.h | 2 +- .../async_stack/include/unique_stack_table.h | 6 +- .../crash_exception/crash_exception.cpp | 12 + interfaces/innerkits/dump_catcher/BUILD.gn | 1 - .../dump_catcher/dfx_dump_catcher.cpp | 378 ++++++++-------- .../dump_catcher/dfx_dump_catcher_errno.cpp | 62 ++- .../dump_catcher/include/dfx_dump_catcher.h | 54 ++- .../{ => include}/dfx_dump_catcher_errno.h | 3 +- .../kernel_stack_async_collector.cpp | 178 -------- .../dump_catcher/libdfx_dumpcatcher.map | 5 +- .../formatter/dfx_json_formatter.cpp | 8 +- .../formatter/include/dfx_json_formatter.h | 2 +- interfaces/innerkits/procinfo/procinfo.cpp | 6 +- interfaces/innerkits/signal_handler/BUILD.gn | 2 +- .../signal_handler/dfx_dumprequest.c | 39 +- .../signal_handler/dfx_signal_handler.c | 31 +- .../innerkits/signal_handler/encaps.json | 7 +- .../signal_handler/include/dfx_dumprequest.h | 2 + interfaces/innerkits/unwinder/BUILD.gn | 124 +++--- interfaces/innerkits/unwinder/arch_util.cpp | 88 ++++ .../exidx_entry_parser.cpp => arm_exidx.cpp} | 118 ++--- .../arm_exidx_instructions.txt | 0 .../{src/memory => }/dfx_accessors.cpp | 3 + .../unwinder/{src/ark => }/dfx_ark.cpp | 0 .../unwinder/{src/utils => }/dfx_config.cpp | 0 .../unwinder/{src/elf => }/dfx_elf.cpp | 402 +++++++++++++++--- .../unwinder/{src/elf => }/dfx_elf_parser.cpp | 146 ++----- .../{src/utils => }/dfx_frame_formatter.cpp | 0 .../unwinder/{src/ark => }/dfx_hap.cpp | 3 +- .../{src/utils => }/dfx_instr_statistic.cpp | 0 .../{src/utils => }/dfx_instructions.cpp | 0 .../unwinder/{src/maps => }/dfx_map.cpp | 26 +- .../unwinder/{src/maps => }/dfx_maps.cpp | 2 +- .../unwinder/{src/memory => }/dfx_memory.cpp | 86 ++-- .../unwinder/{src/elf => }/dfx_mmap.cpp | 12 +- .../unwinder/{src/utils => }/dfx_ptrace.cpp | 0 .../unwinder/{src/registers => }/dfx_regs.cpp | 18 +- .../{src/registers => }/dfx_regs_arm.cpp | 1 + .../{src/registers => }/dfx_regs_arm64.cpp | 40 +- .../registers => }/dfx_regs_loongarch64.cpp | 45 +- .../{src/registers => }/dfx_regs_riscv64.cpp | 37 +- .../{src/registers => }/dfx_regs_x86_64.cpp | 1 + .../innerkits/unwinder}/dfx_signal.cpp | 1 + .../unwinder/{src/elf => }/dfx_symbols.cpp | 4 +- .../innerkits/unwinder/dfx_xz_utils.cpp | 75 ++++ .../unwind_entry_parser => }/dwarf_cfa.txt | 0 .../dwarf_cfa_instructions.cpp | 0 .../unwind_entry_parser => }/dwarf_op.cpp | 0 ...arf_entry_parser.cpp => dwarf_section.cpp} | 59 ++- .../{src/registers => }/getcontext_x86_64.S | 0 ...ind_entry_parser_factory.h => arch_util.h} | 32 +- .../{exidx_entry_parser.h => arm_exidx.h} | 31 +- .../innerkits/unwinder/include/dfx_elf.h | 36 +- .../unwinder/include/dfx_elf_define.h | 8 +- .../unwinder/include/dfx_elf_parser.h | 30 +- .../innerkits/unwinder/include/dfx_map.h | 3 + .../innerkits/unwinder/include/dfx_memory.h | 6 +- .../innerkits/unwinder/include/dfx_mmap.h | 6 +- .../innerkits/unwinder/include}/dfx_signal.h | 0 ...{elf_factory_selector.h => dfx_xz_utils.h} | 23 +- .../{dwarf_entry_parser.h => dwarf_section.h} | 114 ++--- .../innerkits/unwinder/include/elf_factory.h | 79 ---- .../innerkits/unwinder/include/fp_unwinder.h | 6 +- .../unwinder/include/unwind_context.h | 37 +- .../unwinder/include/unwind_entry_parser.h | 41 -- .../include/unwind_loc.h} | 72 ++-- .../innerkits/unwinder/include/unwinder.h | 2 +- interfaces/innerkits/unwinder/libunwinder.map | 11 +- .../unwinder/src/elf/elf_factory.cpp | 269 ------------ .../{src/unwind_local => }/thread_context.cpp | 5 +- interfaces/innerkits/unwinder/unwinder.cpp | 105 +++-- .../{src/utils => }/unwinder_config.cpp | 0 test/benchmarktest/unwind/BUILD.gn | 3 +- test/benchmarktest/unwinder/BUILD.gn | 5 +- .../faultloggerdunwinder_fuzzer/BUILD.gn | 4 + .../faultloggerdunwinder_fuzzer.cpp | 17 + test/systemtest/faultloggerd_system_test.cpp | 2 +- test/unittest/common/param_test.cpp | 2 +- test/unittest/dump_catcher/BUILD.gn | 5 - .../dump_catcher/dumpcatcher_command_test.cpp | 29 +- .../dumpcatcher_interfaces_test.cpp | 30 -- .../kernelstack_async_collector_test.cpp | 223 ---------- test/unittest/unwind/BUILD.gn | 53 +-- test/unittest/unwind/arch_util_test.cpp | 112 +++++ test/unittest/unwind/arm_exidx_test.cpp | 357 ++++++++-------- test/unittest/unwind/dwarf_test.cpp | 41 +- test/unittest/unwind/elf_factory_test.cpp | 325 -------------- test/unittest/unwind/elf_imitate.cpp | 10 +- test/unittest/unwind/elf_test.cpp | 112 ++--- test/unittest/unwind/include/elf_imitate.h | 4 +- test/unittest/unwind/memory_test.cpp | 94 +++- test/unittest/unwind/symbols_test.cpp | 12 +- .../unwind/unwind_entry_parser_test.cpp | 186 -------- test/unittest/unwind/unwinder_test.cpp | 5 +- .../unittest/unwind/xz_util_test.cpp | 65 ++- .../process_dump/dfx_unwind_async_thread.cpp | 3 +- tools/process_dump/faultlogger_client_msg.h | 6 - tools/process_dump/process_dumper.cpp | 14 +- 117 files changed, 2524 insertions(+), 2964 deletions(-) create mode 100644 common/cutil/musl_cutil.h rename common/dfxutil/{stack_utils.cpp => stack_util.h} (34%) delete mode 100644 common/dfxutil/stack_utils.h rename interfaces/innerkits/dump_catcher/{ => include}/dfx_dump_catcher_errno.h (93%) delete mode 100644 interfaces/innerkits/dump_catcher/kernel_stack_async_collector.cpp create mode 100644 interfaces/innerkits/unwinder/arch_util.cpp rename interfaces/innerkits/unwinder/{src/unwind_entry_parser/exidx_entry_parser.cpp => arm_exidx.cpp} (84%) rename interfaces/innerkits/unwinder/{src/unwind_entry_parser => }/arm_exidx_instructions.txt (100%) rename interfaces/innerkits/unwinder/{src/memory => }/dfx_accessors.cpp (99%) rename interfaces/innerkits/unwinder/{src/ark => }/dfx_ark.cpp (100%) rename interfaces/innerkits/unwinder/{src/utils => }/dfx_config.cpp (100%) rename interfaces/innerkits/unwinder/{src/elf => }/dfx_elf.cpp (58%) rename interfaces/innerkits/unwinder/{src/elf => }/dfx_elf_parser.cpp (75%) rename interfaces/innerkits/unwinder/{src/utils => }/dfx_frame_formatter.cpp (100%) rename interfaces/innerkits/unwinder/{src/ark => }/dfx_hap.cpp (97%) rename interfaces/innerkits/unwinder/{src/utils => }/dfx_instr_statistic.cpp (100%) rename interfaces/innerkits/unwinder/{src/utils => }/dfx_instructions.cpp (100%) rename interfaces/innerkits/unwinder/{src/maps => }/dfx_map.cpp (93%) rename interfaces/innerkits/unwinder/{src/maps => }/dfx_maps.cpp (99%) rename interfaces/innerkits/unwinder/{src/memory => }/dfx_memory.cpp (86%) rename interfaces/innerkits/unwinder/{src/elf => }/dfx_mmap.cpp (90%) rename interfaces/innerkits/unwinder/{src/utils => }/dfx_ptrace.cpp (100%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs.cpp (94%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs_arm.cpp (99%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs_arm64.cpp (61%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs_loongarch64.cpp (60%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs_riscv64.cpp (60%) rename interfaces/innerkits/unwinder/{src/registers => }/dfx_regs_x86_64.cpp (99%) rename {common/dfxutil => interfaces/innerkits/unwinder}/dfx_signal.cpp (99%) rename interfaces/innerkits/unwinder/{src/elf => }/dfx_symbols.cpp (98%) create mode 100644 interfaces/innerkits/unwinder/dfx_xz_utils.cpp rename interfaces/innerkits/unwinder/{src/unwind_entry_parser => }/dwarf_cfa.txt (100%) rename interfaces/innerkits/unwinder/{src/unwind_entry_parser => }/dwarf_cfa_instructions.cpp (100%) rename interfaces/innerkits/unwinder/{src/unwind_entry_parser => }/dwarf_op.cpp (100%) rename interfaces/innerkits/unwinder/{src/unwind_entry_parser/dwarf_entry_parser.cpp => dwarf_section.cpp} (84%) rename interfaces/innerkits/unwinder/{src/registers => }/getcontext_x86_64.S (100%) rename interfaces/innerkits/unwinder/include/{unwind_entry_parser_factory.h => arch_util.h} (49%) rename interfaces/innerkits/unwinder/include/{exidx_entry_parser.h => arm_exidx.h} (77%) rename {common/dfxutil => interfaces/innerkits/unwinder/include}/dfx_signal.h (100%) rename interfaces/innerkits/unwinder/include/{elf_factory_selector.h => dfx_xz_utils.h} (65%) rename interfaces/innerkits/unwinder/include/{dwarf_entry_parser.h => dwarf_section.h} (68%) delete mode 100644 interfaces/innerkits/unwinder/include/elf_factory.h delete mode 100644 interfaces/innerkits/unwinder/include/unwind_entry_parser.h rename interfaces/innerkits/{dump_catcher/kernel_stack_async_collector.h => unwinder/include/unwind_loc.h} (31%) delete mode 100644 interfaces/innerkits/unwinder/src/elf/elf_factory.cpp rename interfaces/innerkits/unwinder/{src/unwind_local => }/thread_context.cpp (98%) rename interfaces/innerkits/unwinder/{src/utils => }/unwinder_config.cpp (100%) delete mode 100644 test/unittest/dump_catcher/kernelstack_async_collector_test.cpp create mode 100644 test/unittest/unwind/arch_util_test.cpp delete mode 100644 test/unittest/unwind/elf_factory_test.cpp delete mode 100644 test/unittest/unwind/unwind_entry_parser_test.cpp rename interfaces/innerkits/unwinder/src/elf/elf_factory_selector.cpp => test/unittest/unwind/xz_util_test.cpp (33%) diff --git a/README_zh.md b/README_zh.md index d3922d7e0..40ad7479e 100644 --- a/README_zh.md +++ b/README_zh.md @@ -92,7 +92,7 @@ DumpCatcher是提供给第三方模块使用的抓取调用栈基础库,其中 接口定义: * 默认(支持混合栈):`bool DumpCatch(int pid, int tid, std::string& msg);` * 支持输出到指定文件:`bool DumpCatchFd(int pid, int tid, std::string& msg, int fd);` -* 支持批量抓栈:`bool DumpCatchMultiPid(const std::vector &pids, std::string& msg);` +* 支持批量抓栈:`bool DumpCatchMultiPid(const std::vector pidV, std::string& msg);` 接口参数说明: * 接口返回值: diff --git a/common/cutil/dfx_cutil.c b/common/cutil/dfx_cutil.c index 558fb08ee..f89fd75b9 100644 --- a/common/cutil/dfx_cutil.c +++ b/common/cutil/dfx_cutil.c @@ -15,42 +15,56 @@ #include "dfx_cutil.h" -#include #include #include #include #include #include #include -#ifndef DFX_SIGNAL_LIBC #include -#endif #include #include #include "dfx_define.h" +static const char PID_STR_NAME[] = "Pid:"; + static bool ReadStringFromFile(const char* path, char* dst, size_t dstSz) { if ((dst == NULL) || (path == NULL) || (dstSz == 0)) { return false; } - int fd = OHOS_TEMP_FAILURE_RETRY(open(path, O_RDONLY)); + char name[NAME_BUF_LEN]; + char nameFilter[NAME_BUF_LEN]; + (void)memset_s(name, sizeof(name), '\0', sizeof(name)); + (void)memset_s(nameFilter, sizeof(nameFilter), '\0', sizeof(nameFilter)); + + int fd = -1; + fd = OHOS_TEMP_FAILURE_RETRY(open(path, O_RDONLY)); if (fd < 0) { return false; } - char name[NAME_BUF_LEN] = {0}; ssize_t nRead = OHOS_TEMP_FAILURE_RETRY(read(fd, name, NAME_BUF_LEN - 1)); if (nRead <= 0) { syscall(SYS_close, fd); return false; } - size_t i = 0; - for (; i < dstSz - 1 && name[i] != '\n' && name[i] != '\0'; i++) { - dst[i] = name[i]; + char* p = name; + int i = 0; + while (*p != '\0') { + if ((*p == '\n') || (i == NAME_BUF_LEN)) { + break; + } + nameFilter[i] = *p; + p++, i++; + } + nameFilter[NAME_BUF_LEN - 1] = '\0'; + + if (memcpy_s(dst, dstSz, nameFilter, strlen(nameFilter) + 1) != 0) { + syscall(SYS_close, fd); + return false; } - dst[i] = '\0'; syscall(SYS_close, fd); return true; @@ -64,11 +78,7 @@ bool GetThreadName(char* buffer, size_t bufferSz) bool GetThreadNameByTid(int32_t tid, char* buffer, size_t bufferSz) { char threadNamePath[NAME_BUF_LEN] = { 0 }; -#ifdef DFX_SIGNAL_LIBC - if (snprintf(threadNamePath, sizeof(threadNamePath), "/proc/%d/comm", tid) <= 0) { -#else if (snprintf_s(threadNamePath, sizeof(threadNamePath), sizeof(threadNamePath) - 1, "/proc/%d/comm", tid) <= 0) { -#endif return false; } return ReadStringFromFile(threadNamePath, buffer, bufferSz); @@ -81,7 +91,35 @@ bool GetProcessName(char* buffer, size_t bufferSz) pid_t GetRealPid(void) { - return syscall(SYS_getpid); + pid_t pid = syscall(SYS_getpid); + int fd = OHOS_TEMP_FAILURE_RETRY(open(PROC_SELF_STATUS_PATH, O_RDONLY)); + if (fd < 0) { + return pid; + } + + char buf[LINE_BUF_SIZE]; + int i = 0; + char b; + while (1) { + ssize_t nRead = OHOS_TEMP_FAILURE_RETRY(read(fd, &b, sizeof(char))); + if (nRead <= 0 || b == '\0') { + break; + } + + if (b == '\n' || i == LINE_BUF_SIZE) { + if (strncmp(buf, PID_STR_NAME, strlen(PID_STR_NAME)) == 0) { + (void)sscanf_s(buf, "%*[^0-9]%d", &pid); + break; + } + i = 0; + (void)memset_s(buf, sizeof(buf), '\0', sizeof(buf)); + continue; + } + buf[i] = b; + i++; + } + syscall(SYS_close, fd); + return pid; } uint64_t GetTimeMilliseconds(void) diff --git a/common/cutil/dfx_cutil.h b/common/cutil/dfx_cutil.h index 61dcb4fdf..730a05d09 100644 --- a/common/cutil/dfx_cutil.h +++ b/common/cutil/dfx_cutil.h @@ -16,6 +16,8 @@ #define DFX_COMMON_CUTIL_H #include +#include +#include #include #include #include "dfx_define.h" diff --git a/common/cutil/musl_cutil.h b/common/cutil/musl_cutil.h new file mode 100644 index 000000000..1cc9d07f2 --- /dev/null +++ b/common/cutil/musl_cutil.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2022-2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DFX_MUSL_CUTIL_H +#define DFX_MUSL_CUTIL_H + +#include +#include +#include +#include +#include +#include +#include "dfx_define.h" +#include "musl_log.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ENABLE_MUSL_CUTIL +static const char PID_STR_NAME[] = "Pid:"; + +static bool ReadStringFromFile(const char* path, char* dst, size_t dstSz) +{ + char name[NAME_BUF_LEN]; + char nameFilter[NAME_BUF_LEN]; + memset(name, 0, sizeof(name)); + memset(nameFilter, 0, sizeof(nameFilter)); + + int fd = -1; + fd = OHOS_TEMP_FAILURE_RETRY(open(path, O_RDONLY)); + if (fd < 0) { + return false; + } + + int nRead = OHOS_TEMP_FAILURE_RETRY(read(fd, name, NAME_BUF_LEN -1)); + if (nRead == -1) { + close(fd); + return false; + } + + char* p = name; + int i = 0; + while (*p != '\0') { + if ((*p == '\n') || (i == NAME_BUF_LEN)) { + break; + } + nameFilter[i] = *p; + p++, i++; + } + nameFilter[NAME_BUF_LEN - 1] = '\0'; + + size_t cpyLen = strlen(nameFilter) + 1; + if (cpyLen > dstSz) { + cpyLen = dstSz; + } + memcpy(dst, nameFilter, cpyLen); + close(fd); + return true; +} + +bool GetThreadName(char* buffer, size_t bufferSz) +{ + return ReadStringFromFile(PROC_SELF_COMM_PATH, buffer, bufferSz); +} + +bool GetThreadNameByTid(int32_t tid, char* buffer, size_t bufferSz) +{ + char threadNamePath[NAME_BUF_LEN] = { 0 }; + if (snprintf(threadNamePath, sizeof(threadNamePath), "/proc/%d/comm", tid) <= 0) { + return false; + } + return ReadStringFromFile(threadNamePath, buffer, bufferSz); +} + +bool GetProcessName(char* buffer, size_t bufferSz) +{ + return ReadStringFromFile(PROC_SELF_CMDLINE_PATH, buffer, bufferSz); +} + +pid_t GetRealPid(void) +{ + pid_t pid = syscall(SYS_getpid); + int fd = OHOS_TEMP_FAILURE_RETRY(open(PROC_SELF_STATUS_PATH, O_RDONLY)); + if (fd < 0) { + DFXLOGE("GetRealPid:: open failed! pid:(%{public}ld), errno:(%{public}d).", pid, errno); + return pid; + } + + char buf[LINE_BUF_SIZE] = {0}; + int i = 0; + char b; + ssize_t nRead = 0; + while (1) { + nRead = OHOS_TEMP_FAILURE_RETRY(read(fd, &b, sizeof(char))); + if (nRead <= 0 || b == '\0') { + DFXLOGE("GetRealPid:: read failed! pid:(%{public}ld), errno:(%{public}d), " \ + "nRead(%{public}zd), readchar(%{public}02X).", + pid, errno, nRead, b); + break; + } + + if (b == '\n' || i == LINE_BUF_SIZE) { + if (strncmp(buf, PID_STR_NAME, strlen(PID_STR_NAME)) != 0) { + i = 0; + (void)memset(buf, '\0', sizeof(buf)); + continue; + } + if (sscanf(buf, "%*[^0-9]%d", &pid) < 0) { + DFXLOGE("GetRealPid:: sscanf failed! pid:(%{public}ld), errno:(%{public}d), buf(%{public}s).", + pid, errno, buf); + } + break; + } + buf[i] = b; + i++; + } + close(fd); + return pid; +} + +uint64_t GetTimeMilliseconds(void) +{ + struct timespec ts; + (void)clock_gettime(CLOCK_REALTIME, &ts); + return ((uint64_t)ts.tv_sec * NUMBER_ONE_THOUSAND) + // 1000 : second to millisecond convert ratio + (((uint64_t)ts.tv_nsec) / NUMBER_ONE_MILLION); // 1000000 : nanosecond to millisecond convert ratio +} + +#endif +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/common/dfxlog/dfx_log.h b/common/dfxlog/dfx_log.h index 3fea0fa2f..af58c5d88 100644 --- a/common/dfxlog/dfx_log.h +++ b/common/dfxlog/dfx_log.h @@ -32,6 +32,7 @@ extern "C" { #ifndef DFX_NO_PRINT_LOG #ifdef DFX_LOG_HILOG_BASE +// replace the old interface, and delete the old interface after the replacement is complete #ifdef DFX_LOG_UNWIND #define DFXLOGD(fmt, ...) HILOG_BASE_DEBUG(LOG_CORE, fmt, ##__VA_ARGS__) #else @@ -57,7 +58,7 @@ extern "C" { #endif #else - +// replace the old interface, and delete the old interface after the replacement is complete #define DFXLOGD(fmt, ...) HILOG_DEBUG(LOG_CORE, fmt, ##__VA_ARGS__) #define DFXLOGI(fmt, ...) HILOG_INFO(LOG_CORE, fmt, ##__VA_ARGS__) #define DFXLOGW(fmt, ...) HILOG_WARN(LOG_CORE, fmt, ##__VA_ARGS__) diff --git a/common/dfxutil/BUILD.gn b/common/dfxutil/BUILD.gn index 3918989f5..74700a793 100644 --- a/common/dfxutil/BUILD.gn +++ b/common/dfxutil/BUILD.gn @@ -13,11 +13,7 @@ import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") -dfx_util_sources = [ - "dfx_signal.cpp", - "dfx_util.cpp", - "stack_utils.cpp", -] +dfx_util_sources = [ "dfx_util.cpp" ] if (defined(ohos_lite)) { static_library("dfx_util") { @@ -81,7 +77,7 @@ if (defined(ohos_lite)) { } ohos_static_library("dfx_util_host") { - sources = [ "dfx_util.cpp" ] + sources = dfx_util_sources public_configs = [ ":dfx_util_config" ] defines = [ "DFX_NO_PRINT_LOG" ] if (is_ohos) { diff --git a/common/dfxutil/dfx_util.cpp b/common/dfxutil/dfx_util.cpp index 137a50922..7349a029d 100644 --- a/common/dfxutil/dfx_util.cpp +++ b/common/dfxutil/dfx_util.cpp @@ -35,9 +35,7 @@ #include #endif #include -#if is_ohos && !is_mingw -#include -#endif + #include "dfx_log.h" #ifdef LOG_DOMAIN @@ -126,7 +124,7 @@ std::string GetCurrentTimeStr(uint64_t current) if (ret <= 0) { return "invalid timestamp\n"; } - return millBuf; + return std::string(millBuf, strlen(millBuf)); } bool ReadDirFiles(const std::string& path, std::vector& files) @@ -145,16 +143,16 @@ bool ReadDirFiles(const std::string& path, std::vector& files) files.emplace_back(std::string(ent->d_name)); } (void)closedir(dir); - return !files.empty(); + return (files.size() > 0); } bool VerifyFilePath(const std::string& filePath, const std::vector& validPaths) { - if (validPaths.empty()) { + if (validPaths.size() == 0) { return true; } - for (const auto &validPath : validPaths) { + for (auto validPath : validPaths) { if (filePath.find(validPath) == 0) { return true; } @@ -175,16 +173,16 @@ void ParseSiValue(siginfo_t& si, uint64_t& endTime, int& tid) } #endif -off_t GetFileSize(int fd) +off_t GetFileSize(const int& fd) { - if (fd < 0) { - return 0; - } - struct stat fileStat; - if (fstat(fd, &fileStat) == 0) { - return fileStat.st_size; + off_t fileSize = 0; + if (fd >= 0) { + struct stat fileStat; + if (fstat(fd, &fileStat) == 0) { + fileSize = fileStat.st_size; + } } - return 0; + return fileSize; } bool ReadFdToString(int fd, std::string& content) @@ -195,9 +193,9 @@ bool ReadFdToString(int fd, std::string& content) content.reserve(sb.st_size); } - char buf[BUFSIZ] = {0}; + char buf[BUFSIZ] __attribute__((__uninitialized__)); ssize_t n; - while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, buf, sizeof(buf)))) > 0) { + while ((n = OHOS_TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)))) > 0) { content.append(buf, n); } return (n == 0); @@ -227,39 +225,6 @@ uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask) #endif return outAddr; } - -#if is_ohos && !is_mingw -size_t ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size) -{ - std::vector remoteIovs; - struct iovec dataIov = { - .iov_base = data, - .iov_len = size, - }; - uint64_t currentAddr = addr; - while (size > 0) { - if (currentAddr >= UINTPTR_MAX) { - break; - } - uintptr_t misalign = currentAddr & static_cast(getpagesize() - 1); - size_t iovLen = std::min(getpagesize() - misalign, size); - struct iovec remoteIov = { - .iov_base = reinterpret_cast(currentAddr), - .iov_len = iovLen, - }; - if (__builtin_add_overflow(currentAddr, iovLen, ¤tAddr)) { - break; - } - remoteIovs.emplace_back(remoteIov); - size -= iovLen; - } - if (remoteIovs.empty()) { - return 0; - } - ssize_t readCount = process_vm_readv(pid, &dataIov, 1, &remoteIovs[0], remoteIovs.size(), 0); - return readCount <= 0 ? 0 : static_cast(readCount); -} -#endif } // namespace HiviewDFX } // namespace OHOS diff --git a/common/dfxutil/dfx_util.h b/common/dfxutil/dfx_util.h index 09fa54a5d..cc466b052 100644 --- a/common/dfxutil/dfx_util.h +++ b/common/dfxutil/dfx_util.h @@ -37,13 +37,10 @@ AT_SYMBOL_HIDDEN bool ReadDirFiles(const std::string& path, std::vector& validPaths); AT_SYMBOL_HIDDEN void ParseSiValue(siginfo_t& si, uint64_t& endTime, int& tid); #endif -AT_SYMBOL_HIDDEN off_t GetFileSize(int fd); +AT_SYMBOL_HIDDEN off_t GetFileSize(const int& fd); AT_SYMBOL_HIDDEN bool ReadFdToString(int fd, std::string& content); AT_SYMBOL_HIDDEN void CloseFd(int& fd); AT_SYMBOL_HIDDEN uintptr_t StripPac(uintptr_t inAddr, uintptr_t pacMask); -#if is_ohos && !is_mingw -AT_SYMBOL_HIDDEN size_t ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size); -#endif } // nameapace HiviewDFX } // nameapace OHOS diff --git a/common/dfxutil/elapsed_time.h b/common/dfxutil/elapsed_time.h index c0b0da161..6b683582d 100644 --- a/common/dfxutil/elapsed_time.h +++ b/common/dfxutil/elapsed_time.h @@ -25,7 +25,7 @@ public: ElapsedTime() { begin_ = std::chrono::high_resolution_clock::now(); - } + }; ElapsedTime(std::string printContent, time_t limitCostMilliseconds) : limitCostMilliseconds_(limitCostMilliseconds), printContent_(std::move(printContent)) @@ -46,13 +46,13 @@ public: void Reset() { begin_ = std::chrono::high_resolution_clock::now(); - } + }; template time_t Elapsed() const { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin_).count(); - } + }; private: std::chrono::time_point begin_; diff --git a/common/dfxutil/stack_utils.cpp b/common/dfxutil/stack_util.h similarity index 34% rename from common/dfxutil/stack_utils.cpp rename to common/dfxutil/stack_util.h index 1020e3b26..a3fde0e25 100644 --- a/common/dfxutil/stack_utils.cpp +++ b/common/dfxutil/stack_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,57 +12,96 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#ifndef STACK_UTIL_H +#define STACK_UTIL_H + #include #include #include -#include +#include #include -#include #include "dfx_define.h" -#include "stack_utils.h" namespace OHOS { namespace HiviewDFX { -StackUtils::StackUtils() -{ - ParseSelfMaps(); -} +namespace { +static uintptr_t g_stackMapStart = 0; +static uintptr_t g_stackMapEnd = 0; +static uintptr_t g_arkMapStart = 0; +static uintptr_t g_arkMapEnd = 0; -StackUtils& StackUtils::Instance() +static bool ParseSelfMaps() { - static StackUtils inst; - return inst; + FILE *fp = fopen(PROC_SELF_MAPS_PATH, "r"); + if (fp == NULL) { + return false; + } + bool ret = false; + char mapInfo[256] = {0}; // 256: map info size + int pos = 0; + uint64_t begin = 0; + uint64_t end = 0; + uint64_t offset = 0; + char perms[5] = {0}; // 5:rwxp + while (fgets(mapInfo, sizeof(mapInfo), fp) != NULL) { + if (strstr(mapInfo, "[stack]") != NULL) { + if (sscanf_s(mapInfo, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %*x:%*x %*d%n", &begin, &end, + &perms, sizeof(perms), &offset, &pos) != 4) { // 4:scan size + continue; + } + g_stackMapStart = static_cast(begin); + g_stackMapEnd = static_cast(end); + ret = true; + } + + if (strstr(mapInfo, "stub.an") != NULL) { + if (sscanf_s(mapInfo, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %*x:%*x %*d%n", &begin, &end, + &perms, sizeof(perms), &offset, &pos) != 4) { // 4:scan size + continue; + } + if (strcmp(perms, "r-xp") != 0) { + continue; + } + + g_arkMapStart = static_cast(begin); + g_arkMapEnd = static_cast(end); + ret = true; + } + } + (void)fclose(fp); + return ret; +}; } -bool StackUtils::GetMainStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) const +AT_UNUSED inline bool GetArkStackRange(uintptr_t& start, uintptr_t& end) { - if (!mainStack_.IsValid()) { - return false; + if (g_arkMapStart == 0 || g_arkMapEnd == 0) { + ParseSelfMaps(); } - stackBottom = mainStack_.start; - stackTop = mainStack_.end; - return true; + start = g_arkMapStart; + end = g_arkMapEnd; + return (g_arkMapStart != 0 && g_arkMapEnd != 0); } -bool StackUtils::GetArkStackRange(uintptr_t& start, uintptr_t& end) const +AT_UNUSED inline bool GetMainStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) { - if (!arkCode_.IsValid()) { - return false; + if (g_stackMapStart == 0 || g_stackMapEnd == 0) { + ParseSelfMaps(); } - start = arkCode_.start; - end = arkCode_.end; - return true; + stackBottom = g_stackMapStart; + stackTop = g_stackMapEnd; + return (g_stackMapStart != 0 && g_stackMapEnd != 0); } -bool StackUtils::GetSelfStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) +AT_UNUSED static bool GetSelfStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) { + bool ret = false; pthread_attr_t tattr; - if (pthread_getattr_np(pthread_self(), &tattr) != 0) { - return false; - } void *base = nullptr; size_t size = 0; - bool ret = false; + if (pthread_getattr_np(pthread_self(), &tattr) != 0) { + return ret; + } if (pthread_attr_getstack(&tattr, &base, &size) == 0) { stackBottom = reinterpret_cast(base); stackTop = reinterpret_cast(base) + size; @@ -72,61 +111,19 @@ bool StackUtils::GetSelfStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) return ret; } -bool StackUtils::GetSigAltStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) +AT_UNUSED static bool GetSigAltStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) { + bool ret = false; stack_t altStack; - if (sigaltstack(nullptr, &altStack) == -1) { - return false; - } - if ((static_cast(altStack.ss_flags) & SS_ONSTACK) != 0) { - stackBottom = reinterpret_cast(altStack.ss_sp); - stackTop = reinterpret_cast(altStack.ss_sp) + altStack.ss_size; - return true; - } - return false; -} - -void StackUtils::ParseSelfMaps() -{ - std::unique_ptr fp(fopen(PROC_SELF_MAPS_PATH, "r"), [](FILE* fp) { - if (fp != nullptr) { - fclose(fp); - } - }); - if (fp == nullptr) { - return; - } - auto parser = [] (const char *mapInfo, bool checkExec, MapRange &range) { - uint64_t begin = 0; - uint64_t end = 0; - uint64_t offset = 0; - char perms[5] = {0}; // 5:rwxp - int pos = 0; - if (sscanf_s(mapInfo, "%" SCNxPTR "-%" SCNxPTR " %4s %" SCNxPTR " %*x:%*x %*d%n", &begin, &end, - &perms, sizeof(perms), &offset, &pos) != 4) { // 4:scan size - return; - } - if (checkExec && strcmp(perms, "r-xp") != 0) { - return; - } - range.start = begin; - range.end = end; - }; - - char mapInfo[256] = {0}; // 256: map info size - while (fgets(mapInfo, sizeof(mapInfo), fp.get()) != nullptr) { - if (mainStack_.IsValid() && arkCode_.IsValid()) { - return; - } - if (!mainStack_.IsValid() && (strstr(mapInfo, "[stack]") != nullptr)) { - parser(mapInfo, false, mainStack_); - continue; - } - - if (!arkCode_.IsValid() && strstr(mapInfo, "stub.an") != nullptr) { - parser(mapInfo, true, arkCode_); + if (sigaltstack(nullptr, &altStack) != -1) { + if ((static_cast(altStack.ss_flags) & SS_ONSTACK) != 0) { + stackBottom = reinterpret_cast(altStack.ss_sp); + stackTop = reinterpret_cast(altStack.ss_sp) + altStack.ss_size; + ret = true; } } + return ret; } } // namespace HiviewDFX } // namespace OHOS +#endif diff --git a/common/dfxutil/stack_utils.h b/common/dfxutil/stack_utils.h deleted file mode 100644 index 2dd746508..000000000 --- a/common/dfxutil/stack_utils.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2024-2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef STACK_UTILS_H -#define STACK_UTILS_H - -#include -#include -#include -#include - -namespace OHOS { -namespace HiviewDFX { - -class StackUtils { -public: - static StackUtils& Instance(); - - StackUtils(const StackUtils&) = delete; - StackUtils& operator=(const StackUtils&) = delete; - - bool GetMainStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) const; - bool GetArkStackRange(uintptr_t& start, uintptr_t& end) const; - static bool GetSelfStackRange(uintptr_t& stackBottom, uintptr_t& stackTop); - static bool GetSigAltStackRange(uintptr_t& stackBottom, uintptr_t& stackTop); -private: - struct MapRange { - bool IsValid() const - { - return start != 0 && start < end; - } - uintptr_t start{0}; - uintptr_t end{0}; - }; - StackUtils(); - void ParseSelfMaps(); - MapRange mainStack_; - MapRange arkCode_; -}; -} // namespace HiviewDFX -} // namespace OHOS -#endif diff --git a/frameworks/localhandler/dfx_signal_local_handler.cpp b/frameworks/localhandler/dfx_signal_local_handler.cpp index 29b0c9164..5ae386d62 100644 --- a/frameworks/localhandler/dfx_signal_local_handler.cpp +++ b/frameworks/localhandler/dfx_signal_local_handler.cpp @@ -43,21 +43,18 @@ #define LOG_TAG "DfxSignalLocalHandler" #endif +#define LOCAL_HANDLER_STACK_SIZE (128 * 1024) // 128K constexpr uint32_t FAULTLOGGERD_UID = 1202; static CrashFdFunc g_crashFdFn = nullptr; -#if !defined(__aarch64__) && !defined(__loongarch_lp64) -constexpr uint32_t LOCAL_HANDLER_STACK_SIZE = 128 * 1024; // 128K static void *g_reservedChildStack = nullptr; -#endif static struct ProcessDumpRequest g_request; static pthread_mutex_t g_signalHandlerMutex = PTHREAD_MUTEX_INITIALIZER; -static constexpr int CATCHER_STACK_SIGNALS[] = { +static int g_platformSignals[] = { SIGABRT, SIGBUS, SIGILL, SIGSEGV, }; -#if !defined(__aarch64__) && !defined(__loongarch_lp64) static void ReserveChildThreadSignalStack(void) { // reserve stack for fork @@ -70,7 +67,6 @@ static void ReserveChildThreadSignalStack(void) g_reservedChildStack = static_cast(static_cast(g_reservedChildStack) + LOCAL_HANDLER_STACK_SIZE - 1); } -#endif AT_UNUSED static void FutexWait(volatile void* ftx, int value) { @@ -119,7 +115,7 @@ void DFX_SignalLocalHandler(int sig, siginfo_t *si, void *context) if (ret < 0) { DFXLOGE("memcpy_s context fail, ret=%{public}d", ret); } -#if defined(__aarch64__) || defined(__loongarch_lp64) +#if defined(__aarch64__) || defined(__loongarch_lp64) DoCrashHandler(NULL); #else int pseudothreadTid = -1; @@ -147,9 +143,7 @@ void DFX_GetCrashFdFunc(CrashFdFunc fn) void DFX_InstallLocalSignalHandler(void) { -#if !defined(__aarch64__) && !defined(__loongarch_lp64) ReserveChildThreadSignalStack(); -#endif sigset_t set; sigemptyset(&set); @@ -159,8 +153,10 @@ void DFX_InstallLocalSignalHandler(void) action.sa_sigaction = DFX_SignalLocalHandler; action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK; - for (auto sig : CATCHER_STACK_SIGNALS) { + for (size_t i = 0; i < sizeof(g_platformSignals) / sizeof(g_platformSignals[0]); i++) { + int32_t sig = g_platformSignals[i]; remove_all_special_handler(sig); + sigaddset(&set, sig); if (sigaction(sig, &action, nullptr) != 0) { DFXLOGE("Failed to register signal(%{public}d)", sig); diff --git a/interfaces/common/dfx_define.h b/interfaces/common/dfx_define.h index 0bd1746d2..7fe022a61 100644 --- a/interfaces/common/dfx_define.h +++ b/interfaces/common/dfx_define.h @@ -86,13 +86,13 @@ static const char* const PROC_SELF_EXE_PATH = "/proc/self/exe"; #define FALLTHROUGH_INTENDED [[clang::fallthrough]] // NOLINT #endif -#define OHOS_TEMP_FAILURE_RETRY(exp) \ - ({ \ - long int _rc; \ - do { \ - _rc = (long int)(exp); \ - } while ((_rc == -1) && (errno == EINTR)); \ - _rc; \ +#define OHOS_TEMP_FAILURE_RETRY(exp) \ + ({ \ + long int _rc; \ + do { \ + _rc = (long int)(exp); \ + } while ((_rc == -1) && (errno == EINTR)); \ + _rc; \ }) #if defined(__LP64__) diff --git a/interfaces/common/dfx_dump_res.h b/interfaces/common/dfx_dump_res.h index 44c826597..9d3128734 100644 --- a/interfaces/common/dfx_dump_res.h +++ b/interfaces/common/dfx_dump_res.h @@ -60,40 +60,35 @@ enum DumpErrorCode : int32_t { class DfxDumpRes { public: - inline static std::string ToString(int32_t res) + inline static std::string ToString(const int32_t& res) { - return std::to_string(res) + " ( " + GetResStr(res) + " )"; + std::string ss = std::to_string(res) + " ( " + GetResStr(res) + " )"; + return ss; } private: - struct DumpErrInfo { - int32_t errCode; - const char *info; - }; - static const char* GetResStr(int32_t res) + inline static const char* GetResStr(const int32_t& res) { - const DumpErrInfo errInfos[] = { - { DUMP_ESUCCESS, "no error" }, - { DUMP_EREADREQUEST, "read dump request error" }, - { DUMP_EATTACH, "ptrace attach thread failed" }, - { DUMP_EGETFD, "get fd error" }, - { DUMP_ENOMEM, "out of memory" }, - { DUMP_EBADREG, "bad register number" }, - { DUMP_EREADONLYREG, "attempt to write read-only register" }, - { DUMP_ESTOPUNWIND, "stop unwinding" }, - { DUMP_EINVALIDIP, "invalid IP" }, - { DUMP_EBADFRAME, "bad frame" }, - { DUMP_EINVAL, "unsupported operation or bad value" }, - { DUMP_EBADVERSION, "unwind info has unsupported version" }, - { DUMP_ENOINFO, "no unwind info found" }, - { DUMP_ENOMAP, "mapinfo is not exist" }, - { DUMP_EREADPID, "fail to read real pid" }, - }; - - auto iter = std::find_if(std::begin(errInfos), std::end(errInfos), [res](const DumpErrInfo &ele) { - return ele.errCode == res; - }); - return iter != std::end(errInfos) ? iter->info : "invalid error code"; + const char *cp; + switch (res) { + case DUMP_ESUCCESS: cp = "no error"; break; + case DUMP_EREADREQUEST: cp = "read dump request error"; break; + case DUMP_EATTACH: cp = "ptrace attach thread failed"; break; + case DUMP_EGETFD: cp = "get fd error"; break; + case DUMP_ENOMEM: cp = "out of memory"; break; + case DUMP_EBADREG: cp = "bad register number"; break; + case DUMP_EREADONLYREG: cp = "attempt to write read-only register"; break; + case DUMP_ESTOPUNWIND: cp = "stop unwinding"; break; + case DUMP_EINVALIDIP: cp = "invalid IP"; break; + case DUMP_EBADFRAME: cp = "bad frame"; break; + case DUMP_EINVAL: cp = "unsupported operation or bad value"; break; + case DUMP_EBADVERSION: cp = "unwind info has unsupported version"; break; + case DUMP_ENOINFO: cp = "no unwind info found"; break; + case DUMP_ENOMAP: cp = "mapinfo is not exist"; break; + case DUMP_EREADPID: cp = "fail to read real pid"; break; + default: cp = "invalid error code"; break; + } + return cp; } }; } // namespace HiviewDFX diff --git a/interfaces/common/dfx_errors.h b/interfaces/common/dfx_errors.h index fc98da86b..758f33042 100644 --- a/interfaces/common/dfx_errors.h +++ b/interfaces/common/dfx_errors.h @@ -88,29 +88,37 @@ enum UnwindErrorCode : uint16_t { /** * @brief Unwind error data */ -class UnwindErrorData { -public: - uint16_t GetCode() { return code_; } - uint64_t GetAddr() { return addr_; } +struct UnwindErrorData { + inline const uint16_t& GetCode() { return code_; } + inline const uint64_t& GetAddr() { return addr_; } - void SetAddrAndCode(uintptr_t addr, uint16_t code) + template + inline void SetAddrAndCode([[maybe_unused]] T1 addr, [[maybe_unused]] T2 code) { - addr_ = addr; - code_ = code; +#ifdef DFX_UNWIND_ERROR + addr_ = static_cast(addr); + code_ = static_cast(code); +#endif } - void SetCode(uint16_t code) + template + inline void SetCode([[maybe_unused]] T code) { - code_ = code; +#ifdef DFX_UNWIND_ERROR + code_ = static_cast(code); +#endif } - void SetAddr(uintptr_t addr) + template + inline void SetAddr([[maybe_unused]] T addr) { - addr_ = addr; +#ifdef DFX_UNWIND_ERROR + addr_ = static_cast(addr); +#endif } private: uint16_t code_ = 0; - uintptr_t addr_ = 0; + uint64_t addr_ = 0; }; } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/common/dfx_exception.h b/interfaces/common/dfx_exception.h index dc19c9b04..c77b9b324 100644 --- a/interfaces/common/dfx_exception.h +++ b/interfaces/common/dfx_exception.h @@ -64,52 +64,44 @@ enum CrashExceptionCode : int32_t { CRASH_UNKNOWN = 500, /* Unknown reason */ }; -struct ErrCodeToMsg { +struct ErrCodeToStr { /** Crash exception stage code */ int32_t errCode; - /** Crash exception msg string */ - const char* msg; + /** Crash exception string */ + const char* str; }; -static inline const char* GetCrashDescription(int32_t errCode) -{ - const struct ErrCodeToMsg crashExceptions[] = { - { CRASH_SIGNAL_EMASKED, "Signal has been masked." }, - { CRASH_SIGNAL_EFORK, "Failed to fork child process." }, - { CRASH_SIGNAL_ECLONE, "Failed to clone thread of recycle dump process." }, - { CRASH_SIGNAL_ESETSTATE, "Failed to set dump state." }, - { CRASH_SIGNAL_EINHERITCAP, "Failed to inherit capabilities." }, - { CRASH_SIGNAL_EEXECL, "Failed to execl processdump." }, - { CRASH_SIGNAL_EWAITEXIT, "Failed to wait vm process exit." }, - { CRASH_SIGNAL_EREADPIPE, "Failed to read pipe due to timeout."}, - { CRASH_SIGNAL_ECREATEPIPE, "Failed to init create pipe."}, - { CRASH_SIGNAL_EDUMPREQUEST, "Failed to find symbol to dump request."}, - { CRASH_SIGNAL_EWAITPIDTIMEOUT, "Signal handler waitpid timeout"}, - { CRASH_DUMP_EREADREQ, "Failed to read dump request." }, - { CRASH_DUMP_EPARENTPID, "Failed to check parent pid." }, - { CRASH_DUMP_EATTACH, "Failed to attach target process." }, - { CRASH_DUMP_EWRITEFD, "Failed to request writen fd." }, - { CRASH_DUMP_EKILLED, "Tagert process has been killed." }, - { CRASH_DUMP_EREADPID, "Failed to read real pid."}, - { CRASH_UNWIND_ECONTEXT, "Unwind context illegal." }, - { CRASH_UNWIND_EFRAME, "Failed to step ark js frame." }, - { CRASH_UNWIND_ESTACK, "Stack corruption." }, - { CRASH_LOG_ESTACKLOS, "Crash thread stack not found." }, - { CRASH_LOG_ECHILDSTACK, "Child thread stack not found." }, - { CRASH_LOG_EREGLOS, "Registers not found." }, - { CRASH_LOG_EMEMLOS, "Memory not found." }, - { CRASH_LOG_ESTACKMEMLOS, "Fault stack not found." }, - { CRASH_LOG_EMAPLOS, "Maps not found." }, - { CRASH_LOG_EHILOGLOS, "Hilog not found." }, - { CRASH_LOG_ESUMMARYLOS, "Fault Summary not found." }, - }; - for (uint8_t i = 0; i < sizeof(crashExceptions) / sizeof(crashExceptions[0]); i++) { - if (errCode == crashExceptions[i].errCode) { - return crashExceptions[i].msg; - } - } - return "Unknown reason."; -} +static struct ErrCodeToStr g_crashExceptionMap[] = { + {CRASH_SIGNAL_EMASKED, "Signal has been masked." }, + {CRASH_SIGNAL_EFORK, "Failed to fork child process." }, + {CRASH_SIGNAL_ECLONE, "Failed to clone thread of recycle dump process." }, + {CRASH_SIGNAL_ESETSTATE, "Failed to set dump state." }, + {CRASH_SIGNAL_EINHERITCAP, "Failed to inherit capabilities." }, + {CRASH_SIGNAL_EEXECL, "Failed to execl processdump." }, + {CRASH_SIGNAL_EWAITEXIT, "Failed to wait vm process exit." }, + {CRASH_SIGNAL_EREADPIPE, "Failed to read pipe due to timeout."}, + {CRASH_SIGNAL_ECREATEPIPE, "Failed to init create pipe."}, + {CRASH_SIGNAL_EDUMPREQUEST, "Failed to find symbol to dump request."}, + {CRASH_SIGNAL_EWAITPIDTIMEOUT, "Signal handler waitpid timeout"}, + {CRASH_DUMP_EREADREQ, "Failed to read dump request." }, + {CRASH_DUMP_EPARENTPID, "Failed to check parent pid." }, + {CRASH_DUMP_EATTACH, "Failed to attach target process." }, + {CRASH_DUMP_EWRITEFD, "Failed to request writen fd." }, + {CRASH_DUMP_EKILLED, "Tagert process has been killed." }, + {CRASH_DUMP_EREADPID, "Failed to read real pid."}, + {CRASH_UNWIND_ECONTEXT, "Unwind context illegal." }, + {CRASH_UNWIND_EFRAME, "Failed to step ark js frame." }, + {CRASH_UNWIND_ESTACK, "Stack corruption." }, + {CRASH_LOG_ESTACKLOS, "Crash thread stack not found." }, + {CRASH_LOG_ECHILDSTACK, "Child thread stack not found." }, + {CRASH_LOG_EREGLOS, "Registers not found." }, + {CRASH_LOG_EMEMLOS, "Memory not found." }, + {CRASH_LOG_ESTACKMEMLOS, "Fault stack not found." }, + {CRASH_LOG_EMAPLOS, "Maps not found." }, + {CRASH_LOG_EHILOGLOS, "Hilog not found." }, + {CRASH_LOG_ESUMMARYLOS, "Fault Summary not found."}, + {CRASH_UNKNOWN, "Unknown reason." }, +}; /** * @brief Process crash dump exception description diff --git a/interfaces/common/dfx_param.h b/interfaces/common/dfx_param.h index f8b13e4c8..52c55c0c0 100644 --- a/interfaces/common/dfx_param.h +++ b/interfaces/common/dfx_param.h @@ -17,26 +17,43 @@ #include #if defined(ENABLE_PARAMETER) +#include #include "parameter.h" #include "parameters.h" #endif namespace OHOS { namespace HiviewDFX { +namespace { +[[maybe_unused]] constexpr char MIXSTACK_ENABLED_KEY[] = "faultloggerd.priv.mixstack.enabled"; +} -class DfxParam { -public: - static bool IsEnableMixstack() - { #if defined(ENABLE_PARAMETER) - static bool isEnable = [] { - return OHOS::system::GetParameter("faultloggerd.priv.mixstack.enabled", "true") == "true"; - }(); - return isEnable; +#define GEN_ENABLE_PARAM_FUNC(FuncName, EnableKey, DefValue, ExpValue) \ + __attribute__((noinline)) static bool FuncName() \ + { \ + static bool ret = true; \ + static std::once_flag flag; \ + std::call_once(flag, [&] { \ + if (OHOS::system::GetParameter(EnableKey, DefValue) == ExpValue) { \ + ret = true; \ + } else { \ + ret = false; \ + } \ + }); \ + return ret; \ + } #else - return false; -#endif +#define GEN_ENABLE_PARAM_FUNC(FuncName, EnableKey, DefValue, ExpValue) \ + __attribute__((noinline)) static bool FuncName() \ + { \ + return false; \ } +#endif + +class DfxParam { +public: + GEN_ENABLE_PARAM_FUNC(EnableMixstack, MIXSTACK_ENABLED_KEY, "true", "true"); }; } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/async_stack/async_stack.cpp b/interfaces/innerkits/async_stack/async_stack.cpp index ed795562f..819d21d1a 100644 --- a/interfaces/innerkits/async_stack/async_stack.cpp +++ b/interfaces/innerkits/async_stack/async_stack.cpp @@ -17,6 +17,7 @@ #include #include +#include "dfx_param.h" #include "unique_stack_table.h" #include "fp_unwinder.h" diff --git a/interfaces/innerkits/async_stack/fp_unwinder.cpp b/interfaces/innerkits/async_stack/fp_unwinder.cpp index e77f1fe92..76ffce302 100644 --- a/interfaces/innerkits/async_stack/fp_unwinder.cpp +++ b/interfaces/innerkits/async_stack/fp_unwinder.cpp @@ -25,11 +25,11 @@ #include #include "dfx_log.h" #include "dfx_util.h" -#include "stack_utils.h" +#include "stack_util.h" namespace OHOS { namespace HiviewDFX { - +static int32_t g_validPipe[PIPE_NUM_SZ] = {-1, -1}; constexpr uintptr_t MAX_UNWIND_ADDR_RANGE = 16 * 1024; int32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) { @@ -42,11 +42,11 @@ int32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) uintptr_t stackTop = 0; uint32_t realSz = 0; if (getpid() == gettid()) { - StackUtils::Instance().GetMainStackRange(stackBottom, stackTop); + GetMainStackRange(stackBottom, stackTop); } else { - StackUtils::GetSelfStackRange(stackBottom, stackTop); + GetSelfStackRange(stackBottom, stackTop); if (!(stackPtr >= stackBottom && stackPtr < stackTop)) { - StackUtils::GetSigAltStackRange(stackBottom, stackTop); + GetSigAltStackRange(stackBottom, stackTop); if (stackPtr < stackBottom || stackPtr >= stackTop) { return realSz; } @@ -72,8 +72,7 @@ int32_t FpUnwinder::Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) int32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum) { - int32_t validPipe[PIPE_NUM_SZ] = {-1, -1}; - if (pipe2(validPipe, O_CLOEXEC | O_NONBLOCK) != 0) { + if (pipe2(g_validPipe, O_CLOEXEC | O_NONBLOCK) != 0) { DFXLOGE("Failed to init pipe, errno(%{public}d)", errno); return 0; } @@ -83,7 +82,7 @@ int32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrame int32_t realSz = 0; while ((index < sz - 1) && (fp - firstFp < MAX_UNWIND_ADDR_RANGE)) { uintptr_t addr = fp + sizeof(uintptr_t); - if (!ReadUintptrSafe(validPipe[PIPE_WRITE], addr, pcs[++index])) { + if (!ReadUintptrSafe(addr, pcs[++index])) { break; } if ((++index) >= skipFrameNum) { @@ -91,21 +90,21 @@ int32_t FpUnwinder::UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrame realSz = index - skipFrameNum + 1; } uintptr_t prevFp = fp; - if (!ReadUintptrSafe(validPipe[PIPE_WRITE], prevFp, fp)) { + if (!ReadUintptrSafe(prevFp, fp)) { break; } if (fp <= prevFp) { break; } } - close(validPipe[PIPE_WRITE]); - close(validPipe[PIPE_READ]); + close(g_validPipe[PIPE_WRITE]); + close(g_validPipe[PIPE_READ]); return realSz; } -NO_SANITIZE bool FpUnwinder::ReadUintptrSafe(int pipeWrite, uintptr_t addr, uintptr_t& value) +NO_SANITIZE bool FpUnwinder::ReadUintptrSafe(uintptr_t addr, uintptr_t& value) { - if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, pipeWrite, addr, sizeof(uintptr_t))) == -1) { + if (OHOS_TEMP_FAILURE_RETRY(syscall(SYS_write, g_validPipe[PIPE_WRITE], addr, sizeof(uintptr_t))) == -1) { DFXLOGE("Failed to write addr to pipe, it is a invalid addr"); return false; } diff --git a/interfaces/innerkits/async_stack/fp_unwinder.h b/interfaces/innerkits/async_stack/fp_unwinder.h index cb425a2bc..c881ef17b 100644 --- a/interfaces/innerkits/async_stack/fp_unwinder.h +++ b/interfaces/innerkits/async_stack/fp_unwinder.h @@ -37,7 +37,7 @@ public: static int32_t Unwind(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum); private: static int32_t UnwindFallback(uintptr_t* pcs, int32_t sz, int32_t skipFrameNum); - static bool ReadUintptrSafe(int pipeWrite, uintptr_t addr, uintptr_t& value); + static bool ReadUintptrSafe(uintptr_t addr, uintptr_t& value); }; } } // namespace OHOS diff --git a/interfaces/innerkits/async_stack/include/unique_stack_table.h b/interfaces/innerkits/async_stack/include/unique_stack_table.h index 04b8a3396..725b65fa3 100644 --- a/interfaces/innerkits/async_stack/include/unique_stack_table.h +++ b/interfaces/innerkits/async_stack/include/unique_stack_table.h @@ -79,7 +79,9 @@ public: bool Init(); static UniqueStackTable* Instance(); - UniqueStackTable() = default; + UniqueStackTable() + { + } explicit UniqueStackTable(pid_t pid) : pid_(pid) { @@ -90,7 +92,7 @@ public: } UniqueStackTable(void* buf, uint32_t size, bool releaseBuffer = true) - : tableBufMMap_(buf), tableSize_(size), releaseBuffer_(releaseBuffer) + :tableBufMMap_(buf), tableSize_(size), releaseBuffer_(releaseBuffer) { totalNodes_ = ((tableSize_ / sizeof(Node)) >> 1) << 1; } diff --git a/interfaces/innerkits/crash_exception/crash_exception.cpp b/interfaces/innerkits/crash_exception/crash_exception.cpp index 5c2aacc5a..415a4c549 100644 --- a/interfaces/innerkits/crash_exception/crash_exception.cpp +++ b/interfaces/innerkits/crash_exception/crash_exception.cpp @@ -50,6 +50,18 @@ void SetCrashProcInfo(std::string& name, int32_t pid, int32_t uid) g_crashProcessUid = uid; } +static const char* GetCrashDescription(const int32_t errCode) +{ + size_t i; + + for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) { + if (errCode == g_crashExceptionMap[i].errCode) { + return g_crashExceptionMap[i].str; + } + } + return g_crashExceptionMap[i - 1].str; /* the end of map is "unknown reason" */ +} + void ReportCrashException(const char* pName, int32_t pid, int32_t uid, int32_t errCode) { if (pName == nullptr || strnlen(pName, NAME_BUF_LEN) == NAME_BUF_LEN) { diff --git a/interfaces/innerkits/dump_catcher/BUILD.gn b/interfaces/innerkits/dump_catcher/BUILD.gn index fc68d5c39..4d44ed7a3 100644 --- a/interfaces/innerkits/dump_catcher/BUILD.gn +++ b/interfaces/innerkits/dump_catcher/BUILD.gn @@ -16,7 +16,6 @@ import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") dumpcatcher_sources = [ "dfx_dump_catcher.cpp", "dfx_dump_catcher_errno.cpp", - "kernel_stack_async_collector.cpp", ] if (defined(ohos_lite)) { diff --git a/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp b/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp index 209fec9e4..95d7f2589 100644 --- a/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp +++ b/interfaces/innerkits/dump_catcher/dfx_dump_catcher.cpp @@ -17,32 +17,29 @@ #include #include -#include -#include +#include #include #include #include #include -#include -#include #include #include +#include +#include #include "backtrace_local.h" -#include "kernel_stack_async_collector.h" #include "dfx_define.h" -#include "dfx_dump_catcher_errno.h" #include "dfx_dump_res.h" +#include "dfx_kernel_stack.h" #include "dfx_log.h" -#include "dfx_socket_request.h" #include "dfx_trace_dlsym.h" #include "dfx_util.h" #include "elapsed_time.h" #include "faultloggerd_client.h" +#include "dfx_socket_request.h" #include "file_ex.h" #include "procinfo.h" -#include "string_printf.h" namespace OHOS { namespace HiviewDFX { @@ -57,6 +54,13 @@ namespace { #define LOG_TAG "DfxDumpCatcher" #endif static const int DUMP_CATCHE_WORK_TIME_S = 60; +static const std::string DFXDUMPCATCHER_TAG = "DfxDumpCatcher"; +static std::string g_kernelStackInfo; +static std::atomic_bool g_asyncThreadRunning; +static int32_t g_kernelStackRet = -1; // -1 : incomplete kernel stack dump +static pid_t g_kernelStackPid = 0; +static std::condition_variable g_cv; +static std::mutex g_kernelStackMutex; static constexpr int WAIT_GET_KERNEL_STACK_TIMEOUT = 1000; // 1000 : time out 1000 ms static constexpr uint32_t HIVIEW_UID = 1201; static constexpr uint32_t FOUNDATION_UID = 5523; @@ -93,79 +97,14 @@ static bool IsLinuxKernel() return isLinux; } -class DfxDumpCatcher::Impl { -public: - bool DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson); - bool DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums); - bool DumpCatchMultiPid(const std::vector &pids, std::string& msg); - int DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson); - std::pair DumpCatchWithTimeout(int pid, std::string& msg, int timeout, int tid, bool isJson); -private: - bool DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums); - bool DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums); - bool DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums); - bool DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums); - int32_t DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson = false, - int timeout = DUMPCATCHER_REMOTE_TIMEOUT); - int32_t DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson = false, - int timeout = DUMPCATCHER_REMOTE_TIMEOUT); - int DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd)[2], - bool isJson = false, int32_t timeout = DUMPCATCHER_REMOTE_TIMEOUT); - bool HandlePollError(const uint64_t endTime, int& remainTime, std::string& resMsg, int& ret); - bool HandlePollTimeout(const int timeout, int& remainTime, std::string& resMsg, int& ret); - bool HandlePollEvents(std::pair& bufState, std::pair& resState, - const struct pollfd (&readFds)[2], bool& bPipeConnect, bool& res); - std::pair DumpRemotePoll(const int timeout, std::pair& bufState, - std::pair& resState); - int DoDumpRemotePoll(int timeout, std::string& msg, const int (&pipeReadFd)[2], bool isJson = false); - bool DoReadBuf(int fd, std::string& msg); - bool DoReadRes(int fd, bool& ret, std::string& msg); - void DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg); - void DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg); - std::pair DealWithDumpCatchRet(int pid, int32_t& ret, std::string& msg); - void ReportDumpCatcherStats(int32_t pid, uint64_t requestTime, int32_t ret, void* retAddr); - - static int32_t KernelRet2DumpcatchRet(int32_t ret); - static const int DUMPCATCHER_REMOTE_P90_TIMEOUT = 1000; - static const int DUMPCATCHER_REMOTE_TIMEOUT = 10000; - - std::mutex mutex_; - int32_t pid_ = -1; - bool notifyCollect_ = false; - KernelStackAsyncCollector stackKit_; - KernelStackAsyncCollector::KernelResult stack_; -}; - -DfxDumpCatcher::DfxDumpCatcher() : impl_(std::make_shared()) -{} - -bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson) -{ - return impl_->DumpCatch(pid, tid, msg, maxFrameNums, isJson); -} - -bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums) -{ - return impl_->DumpCatchFd(pid, tid, msg, fd, maxFrameNums); -} - -bool DfxDumpCatcher::DumpCatchMultiPid(const std::vector &pids, std::string& msg) +static void InitKernelStackInfo() { - return impl_->DumpCatchMultiPid(pids, msg); + g_kernelStackInfo.clear(); + g_kernelStackRet = -1; + g_kernelStackPid = 0; } -int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson) -{ - return impl_->DumpCatchProcess(pid, msg, maxFrameNums, isJson); -} - -std::pair DfxDumpCatcher::DumpCatchWithTimeout(int pid, std::string& msg, - int timeout, int tid, bool isJson) -{ - return impl_->DumpCatchWithTimeout(pid, msg, timeout, tid, isJson); -} - -bool DfxDumpCatcher::Impl::DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums) +bool DfxDumpCatcher::DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums) { bool ret = false; @@ -174,30 +113,30 @@ bool DfxDumpCatcher::Impl::DoDumpCurrTid(const size_t skipFrameNum, std::string& int currTid = gettid(); msg.append("Failed to dump curr thread:" + std::to_string(currTid) + ".\n"); } - DFXLOGD("DoDumpCurrTid :: return %{public}d.", ret); + DFXLOGD("%{public}s :: DoDumpCurrTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); return ret; } -bool DfxDumpCatcher::Impl::DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums) +bool DfxDumpCatcher::DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums) { bool ret = false; if (tid <= 0) { - DFXLOGE("DoDumpLocalTid :: return false as param error."); + DFXLOGE("%{public}s :: DoDumpLocalTid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str()); return ret; } ret = GetBacktraceStringByTid(msg, tid, 0, false, maxFrameNums); if (!ret) { msg.append("Failed to dump thread:" + std::to_string(tid) + ".\n"); } - DFXLOGD("DoDumpLocalTid :: return %{public}d.", ret); + DFXLOGD("%{public}s :: DoDumpLocalTid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); return ret; } -bool DfxDumpCatcher::Impl::DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums) +bool DfxDumpCatcher::DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums) { bool ret = false; if (pid <= 0) { - DFXLOGE("DoDumpLocalPid :: return false as param error."); + DFXLOGE("%{public}s :: DoDumpLocalPid :: return false as param error.", DFXDUMPCATCHER_TAG.c_str()); return ret; } size_t skipFramNum = 5; // 5: skip 5 frame @@ -218,16 +157,16 @@ bool DfxDumpCatcher::Impl::DoDumpLocalPid(int pid, std::string& msg, size_t maxF }; std::vector tids; ret = GetTidsByPidWithFunc(getpid(), tids, func); - DFXLOGD("DoDumpLocalPid :: return %{public}d.", ret); + DFXLOGD("%{public}s :: DoDumpLocalPid :: return %{public}d.", DFXDUMPCATCHER_TAG.c_str(), ret); return ret; } -int32_t DfxDumpCatcher::Impl::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout) +int32_t DfxDumpCatcher::DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson, int timeout) { return DoDumpCatchRemote(pid, tid, msg, isJson, timeout); } -bool DfxDumpCatcher::Impl::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums) +bool DfxDumpCatcher::DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums) { bool ret = false; if (tid == gettid()) { @@ -243,11 +182,11 @@ bool DfxDumpCatcher::Impl::DoDumpLocalLocked(int pid, int tid, std::string& msg, } } - DFXLOGD("DoDumpLocal :: ret(%{public}d).", ret); + DFXLOGD("%{public}s :: DoDumpLocal :: ret(%{public}d).", DFXDUMPCATCHER_TAG.c_str(), ret); return ret; } -void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, +static void ReportDumpCatcherStats(int32_t pid, uint64_t requestTime, int32_t ret, void* retAddr) { std::vector buf(sizeof(struct FaultLoggerdStatsRequest), 0); @@ -257,7 +196,7 @@ void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, stat->requestTime = requestTime; stat->dumpCatcherFinishTime = GetTimeMilliSeconds(); stat->result = (ret == DUMPCATCH_ESUCCESS) ? DUMP_RES_WITH_USERSTACK : DUMP_RES_WITH_KERNELSTACK; - if ((ret != DUMPCATCH_ESUCCESS) && stack_.second.empty()) { + if ((ret != DUMPCATCH_ESUCCESS) && g_kernelStackInfo.empty()) { stat->result = DUMP_RES_NO_KERNELSTACK; } size_t copyLen; @@ -265,7 +204,7 @@ void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, ReadProcessName(pid, processName); copyLen = std::min(sizeof(stat->targetProcess) - 1, processName.size()); if (memcpy_s(stat->targetProcess, sizeof(stat->targetProcess) - 1, processName.c_str(), copyLen) != 0) { - DFXLOGE("Failed to copy target process"); + DFXLOGE("%{public}s::Failed to copy target process", DFXDUMPCATCHER_TAG.c_str()); return; } @@ -273,7 +212,7 @@ void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, std::string summary = DfxDumpCatchError::ToString(ret); copyLen = std::min(sizeof(stat->summary) - 1, summary.size()); if (memcpy_s(stat->summary, sizeof(stat->summary) - 1, summary.c_str(), copyLen) != 0) { - DFXLOGE("Failed to copy dumpcatcher summary"); + DFXLOGE("%{public}s::Failed to copy dumpcatcher summary", DFXDUMPCATCHER_TAG.c_str()); return; } } @@ -282,7 +221,7 @@ void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, if (dladdr(retAddr, &info) != 0) { copyLen = std::min(sizeof(stat->callerElf) - 1, strlen(info.dli_fname)); if (memcpy_s(stat->callerElf, sizeof(stat->callerElf) - 1, info.dli_fname, copyLen) != 0) { - DFXLOGE("Failed to copy caller elf info"); + DFXLOGE("%{public}s::Failed to copy caller elf info", DFXDUMPCATCHER_TAG.c_str()); return; } stat->offset = reinterpret_cast(retAddr) - reinterpret_cast(info.dli_fbase); @@ -293,7 +232,7 @@ void DfxDumpCatcher::Impl::ReportDumpCatcherStats(int32_t pid, copyLen = std::min(sizeof(stat->callerProcess) - 1, cmdline.size()); if (memcpy_s(stat->callerProcess, sizeof(stat->callerProcess) - 1, cmdline.c_str(), copyLen) != 0) { - DFXLOGE("Failed to copy caller cmdline"); + DFXLOGE("%{public}s::Failed to copy caller cmdline", DFXDUMPCATCHER_TAG.c_str()); return; } } @@ -385,25 +324,17 @@ static void AnalyzeTimeoutReason(int pid, int32_t& ret) ret = DUMPCATCH_TIMEOUT_DUMP_SLOW; } -void DfxDumpCatcher::Impl::DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg) +void DfxDumpCatcher::DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg) { if (pollRet == DUMP_POLL_OK) { ret = DUMPCATCH_ESUCCESS; return; } - // get result - if (notifyCollect_) { - stack_ = stackKit_.GetCollectedStackResult(); - } else { - stack_ = stackKit_.GetProcessStackWithTimeout(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + if (g_kernelStackPid != pid) { + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); } - - std::string halfProcStatus; - std::string halfProcWchan; - ReadProcessStatus(halfProcStatus, pid); - ReadProcessWchan(halfProcWchan, pid, false, true); - msg.append(std::move(halfProcStatus)); - msg.append(std::move(halfProcWchan)); + msg.append(halfProcStatus_); + msg.append(halfProcWchan_); switch (pollRet) { case DUMP_POLL_FD: ret = DUMPCATCH_EFD; @@ -431,11 +362,11 @@ void DfxDumpCatcher::Impl::DealWithPollRet(int pollRet, int pid, int32_t& ret, s } } -void DfxDumpCatcher::Impl::DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg) +void DfxDumpCatcher::DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg) { uint32_t uid = getuid(); if (sdkdumpRet == ResponseCode::SDK_DUMP_REPEAT) { - stack_ = stackKit_.GetProcessStackWithTimeout(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); msg.append("Result: pid(" + std::to_string(pid) + ") process is dumping.\n"); ret = DUMPCATCH_IS_DUMPING; } else if (sdkdumpRet == ResponseCode::REQUEST_REJECT) { @@ -449,21 +380,21 @@ void DfxDumpCatcher::Impl::DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret = DUMPCATCH_HAS_CRASHED; } else if (sdkdumpRet == ResponseCode::CONNECT_FAILED) { if (uid == HIVIEW_UID || uid == FOUNDATION_UID) { - stack_ = stackKit_.GetProcessStackWithTimeout(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); } msg.append("Result: pid(" + std::to_string(pid) + ") process fail to conntect faultloggerd.\n"); ret = DUMPCATCH_ECONNECT; } else if (sdkdumpRet == ResponseCode::SEND_DATA_FAILED) { if (uid == HIVIEW_UID || uid == FOUNDATION_UID) { - stack_ = stackKit_.GetProcessStackWithTimeout(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); } msg.append("Result: pid(" + std::to_string(pid) + ") process fail to write to faultloggerd.\n"); ret = DUMPCATCH_EWRITE; } - DFXLOGW("%{public}s :: %{public}s", __func__, msg.c_str()); + DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); } -std::pair DfxDumpCatcher::Impl::DealWithDumpCatchRet(int pid, int32_t& ret, std::string& msg) +static std::pair DealWithDumpCatchRet(int pid, int32_t& ret, std::string& msg) { int result = ret == 0 ? 0 : -1; std::string reason; @@ -471,13 +402,17 @@ std::pair DfxDumpCatcher::Impl::DealWithDumpCatchRet(int pid, reason = "Reason:" + DfxDumpCatchError::ToString(ret) + "\n"; } else { reason = "Reason:\nnormal stack:" + DfxDumpCatchError::ToString(ret) + "\n"; - if (stack_.first != KernelStackAsyncCollector::STACK_SUCCESS) { - ret = KernelRet2DumpcatchRet(stack_.first); - reason += "kernel stack:" + DfxDumpCatchError::ToString(ret) + "\n"; - } else if (!stack_.second.empty()) { - msg.append(stack_.second); + } + if (result != 0) { + if (pid == g_kernelStackPid && !g_asyncThreadRunning) { + msg.append(g_kernelStackInfo); result = 1; - } else { + InitKernelStackInfo(); + } else if (g_kernelStackRet != -1) { + ret = g_kernelStackRet; + reason += "kernel stack:" + DfxDumpCatchError::ToString(ret) + "\n"; + g_kernelStackRet = -1; + } else if (g_kernelStackRet == -1) { reason += "kernel stack:" + DfxDumpCatchError::ToString(DUMPCATCH_KERNELSTACK_NONEED) + "\n"; } } @@ -492,7 +427,7 @@ std::pair DfxDumpCatcher::Impl::DealWithDumpCatchRet(int pid, return std::make_pair(result, reason); } -std::pair DfxDumpCatcher::Impl::DumpCatchWithTimeout(int pid, std::string& msg, int timeout, +std::pair DfxDumpCatcher::DumpCatchWithTimeout(int pid, std::string& msg, int timeout, int tid, bool isJson) { DfxEnableTraceDlsym(true); @@ -541,24 +476,25 @@ std::pair DfxDumpCatcher::Impl::DumpCatchWithTimeout(int pid, return result; } -int DfxDumpCatcher::Impl::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson) +int DfxDumpCatcher::DumpCatchProcess(int pid, std::string& msg, size_t maxFrameNums, bool isJson) { if (DumpCatch(pid, 0, msg, maxFrameNums, isJson)) { return 0; } - // kernel stack - if (stack_.first == KernelStackAsyncCollector::STACK_SUCCESS && !stack_.second.empty()) { - msg.append(std::move(stack_.second)); + if (pid == g_kernelStackPid && !g_asyncThreadRunning) { + msg.append(g_kernelStackInfo); + InitKernelStackInfo(); return 1; } + g_kernelStackRet = -1; return -1; } -bool DfxDumpCatcher::Impl::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson) +bool DfxDumpCatcher::DumpCatch(int pid, int tid, std::string& msg, size_t maxFrameNums, bool isJson) { bool ret = false; if (pid <= 0 || tid < 0) { - DFXLOGE("dump_catch :: param error."); + DFXLOGE("%{public}s :: dump_catch :: param error.", DFXDUMPCATCHER_TAG.c_str()); return ret; } if (!IsLinuxKernel()) { @@ -572,8 +508,6 @@ bool DfxDumpCatcher::Impl::DumpCatch(int pid, int tid, std::string& msg, size_t DfxEnableTraceDlsym(true); ElapsedTime counter; std::unique_lock lck(mutex_); - stack_ = {}; - notifyCollect_ = false; int currentPid = getpid(); uint64_t requestTime = GetTimeMilliSeconds(); DFXLOGI("Receive DumpCatch request for cPid:(%{public}d), pid(%{public}d), " \ @@ -582,13 +516,13 @@ bool DfxDumpCatcher::Impl::DumpCatch(int pid, int tid, std::string& msg, size_t ret = DoDumpLocalLocked(pid, tid, msg, maxFrameNums); } else { if (maxFrameNums != DEFAULT_MAX_FRAME_NUM) { - DFXLOGI("dump_catch :: maxFrameNums does not support setting " \ - "when pid is not equal to caller pid"); + DFXLOGI("%{public}s :: dump_catch :: maxFrameNums does not support setting " \ + "when pid is not equal to caller pid", DFXDUMPCATCHER_TAG.c_str()); } int timeout = (tid == 0 ? 3 : 10) * 1000; // when tid not zero, timeout is 10s int32_t res = DoDumpRemoteLocked(pid, tid, msg, isJson, timeout); - if (res != DUMPCATCH_ESUCCESS && stack_.first != KernelStackAsyncCollector::STACK_SUCCESS) { - res = KernelRet2DumpcatchRet(stack_.first); + if (res != DUMPCATCH_ESUCCESS && g_kernelStackRet != DUMPCATCH_ESUCCESS && g_kernelStackRet != -1) { + res = g_kernelStackRet; } void* retAddr = __builtin_return_address(0); ReportDumpCatcherStats(pid, requestTime, res, retAddr); @@ -602,23 +536,23 @@ bool DfxDumpCatcher::Impl::DumpCatch(int pid, int tid, std::string& msg, size_t return ret; } -bool DfxDumpCatcher::Impl::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums) +bool DfxDumpCatcher::DumpCatchFd(int pid, int tid, std::string& msg, int fd, size_t maxFrameNums) { bool ret = false; - ret = DumpCatch(pid, tid, msg, maxFrameNums, false); + ret = DumpCatch(pid, tid, msg, maxFrameNums); if (fd > 0) { ret = OHOS_TEMP_FAILURE_RETRY(write(fd, msg.c_str(), msg.length())); } return ret; } -int32_t DfxDumpCatcher::Impl::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout) +int32_t DfxDumpCatcher::DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson, int timeout) { DFX_TRACE_SCOPED_DLSYM("DoDumpCatchRemote"); int32_t ret = DUMPCATCH_UNKNOWN; if (pid <= 0 || tid < 0 || timeout <= WAIT_GET_KERNEL_STACK_TIMEOUT) { msg.append("Result: pid(" + std::to_string(pid) + ") param error.\n"); - DFXLOGW("%{public}s :: %{public}s", __func__, msg.c_str()); + DFXLOGW("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); return DUMPCATCH_EPARAM; } pid_ = pid; @@ -633,52 +567,129 @@ int32_t DfxDumpCatcher::Impl::DoDumpCatchRemote(int pid, int tid, std::string& m timeout -= static_cast(GetAbsTimeMilliSeconds() - sdkDumpStartTime); int pollRet = DoDumpRemotePid(pid, msg, pipeReadFd, isJson, timeout); DealWithPollRet(pollRet, pid, ret, msg); - DFXLOGI("%{public}s :: pid(%{public}d) ret: %{public}d", __func__, pid, ret); + DFXLOGI("%{public}s :: %{public}s :: pid(%{public}d) ret: %{public}d", DFXDUMPCATCHER_TAG.c_str(), + __func__, pid, ret); return ret; } -int DfxDumpCatcher::Impl::DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd)[2], bool isJson, int32_t timeout) +int DfxDumpCatcher::DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd)[2], bool isJson, int32_t timeout) { DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePid"); if (timeout <= 0) { DFXLOGW("timeout less than 0, try to get kernel stack and return directly!"); - stack_ = stackKit_.GetProcessStackWithTimeout(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); + AsyncGetAllTidKernelStack(pid, WAIT_GET_KERNEL_STACK_TIMEOUT); RequestDelPipeFd(pid); CloseFd(pipeReadFd[PIPE_BUF_INDEX]); CloseFd(pipeReadFd[PIPE_RES_INDEX]); return DUMP_POLL_TIMEOUT; } else if (timeout < 1000) { // 1000 : one thousand milliseconds DFXLOGW("timeout less than 1 seconds, get kernel stack directly!"); - notifyCollect_ = stackKit_.NotifyStartCollect(pid); + AsyncGetAllTidKernelStack(pid); } int ret = DoDumpRemotePoll(timeout, msg, pipeReadFd, isJson); // request close fds in faultloggerd RequestDelPipeFd(pid); CloseFd(pipeReadFd[PIPE_BUF_INDEX]); CloseFd(pipeReadFd[PIPE_RES_INDEX]); - DFXLOGI("%{public}s :: pid(%{public}d) poll ret: %{public}d", __func__, pid, ret); + DFXLOGI("%{public}s :: %{public}s :: pid(%{public}d) poll ret: %{public}d", + DFXDUMPCATCHER_TAG.c_str(), __func__, pid, ret); return ret; } -int32_t DfxDumpCatcher::Impl::KernelRet2DumpcatchRet(int32_t ret) +static int32_t KernelRet2DumpcatchRet(int32_t ret) { switch (ret) { - case KernelStackAsyncCollector::STACK_ECREATE: - return DUMPCATCH_KERNELSTACK_ECREATE; - case KernelStackAsyncCollector::STACK_EOPEN: - return DUMPCATCH_KERNELSTACK_EOPEN; - case KernelStackAsyncCollector::STACK_EIOCTL: - return DUMPCATCH_KERNELSTACK_EIOCTL; - case KernelStackAsyncCollector::STACK_TIMEOUT: - return DUMPCATCH_KERNELSTACK_TIMEOUT; - case KernelStackAsyncCollector::STACK_OVER_LIMIT: - return DUMPCATCH_KERNELSTACK_OVER_LIMITL; + case KERNELSTACK_ECREATE: + return DUMPCATCH_KERNELSTACK_ECREATE; + case KERNELSTACK_EOPEN: + return DUMPCATCH_KERNELSTACK_EOPEN; + case KERNELSTACK_EIOCTL: + return DUMPCATCH_KERNELSTACK_EIOCTL; default: return DUMPCATCH_UNKNOWN; } } -bool DfxDumpCatcher::Impl::HandlePollError(const uint64_t endTime, int& remainTime, std::string& resMsg, int& ret) +void DfxDumpCatcher::CollectKernelStack(pid_t pid, int waitMilliSeconds) +{ + ElapsedTime timer; + std::string kernelStackInfo; + int32_t kernelRet = 0; + auto finishCollect = [waitMilliSeconds]() { + if (waitMilliSeconds > 0) { + std::unique_lock lock(g_kernelStackMutex); + g_asyncThreadRunning = false; + lock.unlock(); + g_cv.notify_all(); + } else { + g_asyncThreadRunning = false; + } + }; + std::string statusPath = StringPrintf("/proc/%d/status", pid); + if (access(statusPath.c_str(), F_OK) != 0) { + DFXLOGW("No process(%{public}d) status file exist!", pid); + finishCollect(); + return; + } + + std::function func = [&](int tid) { + if (tid <= 0) { + return false; + } + std::string tidKernelStackInfo; + int32_t ret = DfxGetKernelStack(tid, tidKernelStackInfo); + if (ret == 0) { + kernelStackInfo.append(tidKernelStackInfo); + } else if (kernelRet == 0) { + kernelRet = ret; + } + return true; + }; + std::vector tids; + MAYBE_UNUSED bool ret = GetTidsByPidWithFunc(pid, tids, func); + if (kernelStackInfo.empty()) { + DFXLOGE("Process(%{public}d) collect kernel stack fail!", pid); + g_kernelStackRet = KernelRet2DumpcatchRet(kernelRet); + finishCollect(); + return; + } + g_kernelStackPid = pid; + g_kernelStackInfo = kernelStackInfo; + g_kernelStackRet = 0; + finishCollect(); + DFXLOGI("finish collect all tid info for pid(%{public}d) time(%{public}" PRId64 ")ms", pid, + timer.Elapsed()); +} + +void DfxDumpCatcher::AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds) +{ + ReadProcessStatus(halfProcStatus_, pid); + if (IsLinuxKernel()) { + ReadProcessWchan(halfProcWchan_, pid, false, true); + } + if (g_asyncThreadRunning) { + DFXLOGI("pid(%{public}d) get kernel stack thread is running, not get pid(%{public}d)", g_kernelStackPid, pid); + return; + } + g_asyncThreadRunning = true; + InitKernelStackInfo(); + auto func = [pid, waitMilliSeconds] { + CollectKernelStack(pid, waitMilliSeconds); + }; + if (waitMilliSeconds > 0) { + std::unique_lock lock(g_kernelStackMutex); + std::thread kernelStackTask(func); + kernelStackTask.detach(); + g_cv.wait_for(lock, std::chrono::milliseconds(WAIT_GET_KERNEL_STACK_TIMEOUT), + [] {return !g_asyncThreadRunning;}); + } else { + std::thread kernelStackTask(func); + kernelStackTask.detach(); + } +} + +bool DfxDumpCatcher::HandlePollError(const uint64_t endTime, int& remainTime, + bool& collectAllTidStack, std::string& resMsg, int& ret) { if (errno == EINTR) { uint64_t now = GetAbsTimeMilliSeconds(); @@ -687,8 +698,9 @@ bool DfxDumpCatcher::Impl::HandlePollError(const uint64_t endTime, int& remainTi resMsg.append("Result: poll timeout.\n"); return false; } - if (!notifyCollect_ && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { - notifyCollect_ = stackKit_.NotifyStartCollect(pid_); + if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { + AsyncGetAllTidKernelStack(pid_); + collectAllTidStack = true; } remainTime = static_cast(endTime - now); return true; @@ -698,11 +710,13 @@ bool DfxDumpCatcher::Impl::HandlePollError(const uint64_t endTime, int& remainTi return false; } -bool DfxDumpCatcher::Impl::HandlePollTimeout(const int timeout, int& remainTime, std::string& resMsg, int& ret) +bool DfxDumpCatcher::HandlePollTimeout(const int timeout, int& remainTime, + bool& collectAllTidStack, std::string& resMsg, int& ret) { - if (!notifyCollect_ && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { - notifyCollect_ = stackKit_.NotifyStartCollect(pid_); + if (!collectAllTidStack && (remainTime == DUMPCATCHER_REMOTE_P90_TIMEOUT)) { + AsyncGetAllTidKernelStack(pid_); remainTime = timeout - DUMPCATCHER_REMOTE_P90_TIMEOUT; + collectAllTidStack = true; return true; } ret = DUMP_POLL_TIMEOUT; @@ -710,8 +724,8 @@ bool DfxDumpCatcher::Impl::HandlePollTimeout(const int timeout, int& remainTime, return false; } -bool DfxDumpCatcher::Impl::HandlePollEvents(std::pair& bufState, - std::pair& resState, const struct pollfd (&readFds)[2], bool& bPipeConnect, bool& res) +bool DfxDumpCatcher::HandlePollEvents(std::pair& bufState, std::pair& resState, + const struct pollfd (&readFds)[2], bool& bPipeConnect, bool& res) { bool bufRet = true; bool resRet = false; @@ -740,13 +754,14 @@ bool DfxDumpCatcher::Impl::HandlePollEvents(std::pair& bufStat } if ((eventRet == false) || (bufRet == false) || (resRet == true)) { - DFXLOGI("eventRet:%{public}d bufRet:%{public}d resRet:%{public}d", eventRet, bufRet, resRet); + DFXLOGI("%{public}s :: %{public}s :: eventRet(%{public}d) bufRet: %{public}d resRet: %{public}d", + DFXDUMPCATCHER_TAG.c_str(), __func__, eventRet, bufRet, resRet); return false; } return true; } -std::pair DfxDumpCatcher::Impl::DumpRemotePoll(const int timeout, +std::pair DfxDumpCatcher::DumpRemotePoll(const int timeout, std::pair& bufState, std::pair& resState) { int ret = DUMP_POLL_INIT; @@ -760,16 +775,17 @@ std::pair DfxDumpCatcher::Impl::DumpRemotePoll(const int timeout, int fdsSize = sizeof(readFds) / sizeof(readFds[0]); bool bPipeConnect = false; int remainTime = DUMPCATCHER_REMOTE_P90_TIMEOUT < timeout ? DUMPCATCHER_REMOTE_P90_TIMEOUT : timeout; + bool collectAllTidStack = false; uint64_t startTime = GetAbsTimeMilliSeconds(); uint64_t endTime = startTime + static_cast(timeout); bool isContinue = true; do { int pollRet = poll(readFds, fdsSize, remainTime); if (pollRet < 0) { - isContinue = HandlePollError(endTime, remainTime, resState.second, ret); + isContinue = HandlePollError(endTime, remainTime, collectAllTidStack, resState.second, ret); continue; } else if (pollRet == 0) { - isContinue = HandlePollTimeout(timeout, remainTime, resState.second, ret); + isContinue = HandlePollTimeout(timeout, remainTime, collectAllTidStack, resState.second, ret); continue; } if (!HandlePollEvents(bufState, resState, readFds, bPipeConnect, res)) { @@ -787,7 +803,7 @@ std::pair DfxDumpCatcher::Impl::DumpRemotePoll(const int timeout, return std::make_pair(res, ret); } -int DfxDumpCatcher::Impl::DoDumpRemotePoll(int timeout, std::string& msg, const int (&pipeReadFd)[2], bool isJson) +int DfxDumpCatcher::DoDumpRemotePoll(int timeout, std::string& msg, const int (&pipeReadFd)[2], bool isJson) { DFX_TRACE_SCOPED_DLSYM("DoDumpRemotePoll"); if (pipeReadFd[PIPE_BUF_INDEX] < 0 || pipeReadFd[PIPE_RES_INDEX] < 0) { @@ -801,22 +817,22 @@ int DfxDumpCatcher::Impl::DoDumpRemotePoll(int timeout, std::string& msg, const std::pair resState = std::make_pair(pipeReadFd[PIPE_RES_INDEX], ""); std::pair result = DumpRemotePoll(timeout, bufState, resState); - DFXLOGI("%{public}s :: %{public}s", __func__, resState.second.c_str()); + DFXLOGI("%{public}s :: %{public}s :: %{public}s", DFXDUMPCATCHER_TAG.c_str(), __func__, resState.second.c_str()); msg = isJson && result.first ? bufState.second : (resState.second + bufState.second); return result.first ? DUMP_POLL_OK : result.second; } -bool DfxDumpCatcher::Impl::DoReadBuf(int fd, std::string& msg) +bool DfxDumpCatcher::DoReadBuf(int fd, std::string& msg) { bool ret = false; char *buffer = new char[MAX_PIPE_SIZE]; do { ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, buffer, MAX_PIPE_SIZE)); if (nread <= 0) { - DFXLOGW("%{public}s :: read error", __func__); + DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__); break; } - DFXLOGD("%{public}s :: nread: %{public}zu", __func__, nread); + DFXLOGD("%{public}s :: %{public}s :: nread: %{public}zu", DFXDUMPCATCHER_TAG.c_str(), __func__, nread); ret = true; msg.append(buffer); } while (false); @@ -824,12 +840,12 @@ bool DfxDumpCatcher::Impl::DoReadBuf(int fd, std::string& msg) return ret; } -bool DfxDumpCatcher::Impl::DoReadRes(int fd, bool& ret, std::string& msg) +bool DfxDumpCatcher::DoReadRes(int fd, bool& ret, std::string& msg) { int32_t res = DumpErrorCode::DUMP_ESUCCESS; ssize_t nread = OHOS_TEMP_FAILURE_RETRY(read(fd, &res, sizeof(res))); if (nread <= 0 || nread != sizeof(res)) { - DFXLOGW("%{public}s :: read error", __func__); + DFXLOGW("%{public}s :: %{public}s :: read error", DFXDUMPCATCHER_TAG.c_str(), __func__); return false; } if (res == DumpErrorCode::DUMP_ESUCCESS) { @@ -839,28 +855,31 @@ bool DfxDumpCatcher::Impl::DoReadRes(int fd, bool& ret, std::string& msg) return true; } -bool DfxDumpCatcher::Impl::DumpCatchMultiPid(const std::vector &pids, std::string& msg) +bool DfxDumpCatcher::DumpCatchMultiPid(const std::vector pidV, std::string& msg) { bool ret = false; - int pidSize = (int)pids.size(); + int pidSize = (int)pidV.size(); if (pidSize <= 0) { - DFXLOGE("%{public}s :: param error, pidSize(%{public}d).", __func__, pidSize); + DFXLOGE("%{public}s :: %{public}s :: param error, pidSize(%{public}d).", + DFXDUMPCATCHER_TAG.c_str(), __func__, pidSize); return ret; } std::unique_lock lck(mutex_); int currentPid = getpid(); int currentTid = gettid(); - DFXLOGD("%{public}s :: cPid(%{public}d), cTid(%{public}d), pidSize(%{public}d).", + DFXLOGD("%{public}s :: %{public}s :: cPid(%{public}d), cTid(%{public}d), pidSize(%{public}d).", + DFXDUMPCATCHER_TAG.c_str(), \ __func__, currentPid, currentTid, pidSize); time_t startTime = time(nullptr); if (startTime > 0) { - DFXLOGD("%{public}s :: startTime(%{public}" PRId64 ").", __func__, startTime); + DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 ").", + DFXDUMPCATCHER_TAG.c_str(), __func__, startTime); } for (int i = 0; i < pidSize; i++) { - int pid = pids[i]; + int pid = pidV[i]; std::string pidStr; bool ret = DoDumpRemoteLocked(pid, 0, pidStr) == DUMPCATCH_ESUCCESS; if (ret) { @@ -871,7 +890,8 @@ bool DfxDumpCatcher::Impl::DumpCatchMultiPid(const std::vector &pids, std:: time_t currentTime = time(nullptr); if (currentTime > 0) { - DFXLOGD("%{public}s :: startTime(%{public}" PRId64 "), currentTime(%{public}" PRId64 ").", + DFXLOGD("%{public}s :: %{public}s :: startTime(%{public}" PRId64 "), currentTime(%{public}" PRId64 ").", + DFXDUMPCATCHER_TAG.c_str(), \ __func__, startTime, currentTime); if (currentTime > startTime + DUMP_CATCHE_WORK_TIME_S) { break; @@ -879,7 +899,7 @@ bool DfxDumpCatcher::Impl::DumpCatchMultiPid(const std::vector &pids, std:: } } - DFXLOGD("%{public}s :: msg(%{public}s).", __func__, msg.c_str()); + DFXLOGD("%{public}s :: %{public}s :: msg(%{public}s).", DFXDUMPCATCHER_TAG.c_str(), __func__, msg.c_str()); if (msg.find("Tid:") != std::string::npos) { ret = true; } diff --git a/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp b/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp index 6b066d7f5..4c5cb65bd 100644 --- a/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp +++ b/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.cpp @@ -14,46 +14,42 @@ */ #include "dfx_dump_catcher_errno.h" -#include + namespace OHOS { namespace HiviewDFX { -struct DumpCatchErrInfo { - int32_t code; - const char *info; -}; -const DumpCatchErrInfo ERROR_CODE_MAPS[] = { - { DUMPCATCH_ESUCCESS, "success" }, - { DUMPCATCH_EPARAM, "param error" }, - { DUMPCATCH_NO_PROCESS, "process has exited" }, - { DUMPCATCH_IS_DUMPING, "process is dumping" }, - { DUMPCATCH_EPERMISSION, "check permission error" }, - { DUMPCATCH_HAS_CRASHED, "process has been crashed" }, - { DUMPCATCH_ECONNECT, "failed to connect to faultloggerd" }, - { DUMPCATCH_EWRITE, "failed to write data to faultloggerd" }, - { DUMPCATCH_EFD, "buf or res fd error" }, - { DUMPCATCH_EPOLL, "poll error" }, - { DUMPCATCH_DUMP_EPTRACE, "failed to ptrace thread" }, - { DUMPCATCH_DUMP_EUNWIND, "failed to unwind" }, - { DUMPCATCH_DUMP_EMAP, "failed to find map" }, - { DUMPCATCH_TIMEOUT_SIGNAL_BLOCK, "signal has been block by target process" }, - { DUMPCATCH_TIMEOUT_KERNEL_FROZEN, "target process has been frozen in kernel" }, - { DUMPCATCH_TIMEOUT_PROCESS_KILLED, "target process has been killed during dumping" }, - { DUMPCATCH_TIMEOUT_DUMP_SLOW, "failed to fully dump due to timeout" }, - { DUMPCATCH_KERNELSTACK_ECREATE, "kernelstack fail due to create hstackval fail" }, - { DUMPCATCH_KERNELSTACK_EOPEN, "kernelstack fail due to open bbox fail" }, - { DUMPCATCH_KERNELSTACK_EIOCTL, "kernelstack fail due to ioctl fail" }, - { DUMPCATCH_KERNELSTACK_TIMEOUT, "kernelstack fail due to wait timeout" }, - { DUMPCATCH_KERNELSTACK_OVER_LIMITL, "kernelstack fail due to over limit" }, - { DUMPCATCH_KERNELSTACK_NONEED, "no need to dump kernelstack" }, - { DUMPCATCH_UNKNOWN, "unknown reason" } +const std::map ERROR_CODE_MAP = { + { DUMPCATCH_ESUCCESS, std::string("success") }, + { DUMPCATCH_EPARAM, std::string("param error") }, + { DUMPCATCH_NO_PROCESS, std::string("process has exited") }, + { DUMPCATCH_IS_DUMPING, std::string("process is dumping") }, + { DUMPCATCH_EPERMISSION, std::string("check permission error") }, + { DUMPCATCH_HAS_CRASHED, std::string("process has been crashed") }, + { DUMPCATCH_ECONNECT, std::string("failed to connect to faultloggerd") }, + { DUMPCATCH_EWRITE, std::string("failed to write data to faultloggerd") }, + { DUMPCATCH_EFD, std::string("buf or res fd error") }, + { DUMPCATCH_EPOLL, std::string("poll error") }, + { DUMPCATCH_DUMP_EPTRACE, std::string("failed to ptrace thread") }, + { DUMPCATCH_DUMP_EUNWIND, std::string("failed to unwind") }, + { DUMPCATCH_DUMP_EMAP, std::string("failed to find map") }, + { DUMPCATCH_TIMEOUT_SIGNAL_BLOCK, std::string("signal has been block by target process") }, + { DUMPCATCH_TIMEOUT_KERNEL_FROZEN, std::string("target process has been frozen in kernel") }, + { DUMPCATCH_TIMEOUT_PROCESS_KILLED, std::string("target process has been killed during dumping") }, + { DUMPCATCH_TIMEOUT_DUMP_SLOW, std::string("failed to fully dump due to timeout") }, + { DUMPCATCH_KERNELSTACK_ECREATE, std::string("kernelstack fail due to create hstackval fail") }, + { DUMPCATCH_KERNELSTACK_EOPEN, std::string("kernelstack fail due to open bbox fail") }, + { DUMPCATCH_KERNELSTACK_EIOCTL, std::string("kernelstack fail due to ioctl fail") }, + { DUMPCATCH_KERNELSTACK_NONEED, std::string("no need to dump kernelstack") }, + { DUMPCATCH_UNKNOWN, std::string("unknown reason") } }; std::string DfxDumpCatchError::ToString(const int32_t res) { - auto iter = std::find_if(std::begin(ERROR_CODE_MAPS), std::end(ERROR_CODE_MAPS), - [res](const DumpCatchErrInfo &errInfo) { return errInfo.code == res; }); - return iter != std::end(ERROR_CODE_MAPS) ? iter->info : "invalid error code"; + auto it = ERROR_CODE_MAP.find(res); + if (it != ERROR_CODE_MAP.end()) { + return it->second; + } + return std::string("invalid error code"); } } // namespace HiviewDFX } // namespace OHOS \ No newline at end of file diff --git a/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h index 3577dda45..98fab1f3f 100644 --- a/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h +++ b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher.h @@ -17,23 +17,21 @@ #define DFX_DUMPCATCH_H #include +#include +#include #include #include +#include #include -#include -// some module head files not self-included. #include -#include +#include + +#include "dfx_dump_catcher_errno.h" + namespace OHOS { namespace HiviewDFX { class DfxDumpCatcher { public: - static constexpr size_t DEFAULT_MAX_FRAME_NUM = 256; - - DfxDumpCatcher(); - DfxDumpCatcher(const DfxDumpCatcher&) = delete; - DfxDumpCatcher& operator=(const DfxDumpCatcher&) = delete; - /** * @brief Dump native stack by specify pid and tid * @@ -67,7 +65,7 @@ public: * @param msg message of native stack * @return if succeed return true, otherwise return false */ - bool DumpCatchMultiPid(const std::vector &pids, std::string& msg); + bool DumpCatchMultiPid(const std::vector pidV, std::string& msg); /** * @brief Dump stack of process * @@ -95,8 +93,40 @@ public: std::pair DumpCatchWithTimeout(int pid, std::string& msg, int timeout = 3000, int tid = 0, bool isJson = false); private: - class Impl; - std::shared_ptr impl_; + static constexpr size_t DEFAULT_MAX_FRAME_NUM = 256; + bool DoDumpCurrTid(const size_t skipFrameNum, std::string& msg, size_t maxFrameNums); + bool DoDumpLocalTid(const int tid, std::string& msg, size_t maxFrameNums); + bool DoDumpLocalPid(int pid, std::string& msg, size_t maxFrameNums); + bool DoDumpLocalLocked(int pid, int tid, std::string& msg, size_t maxFrameNums); + int32_t DoDumpRemoteLocked(int pid, int tid, std::string& msg, bool isJson = false, + int timeout = DUMPCATCHER_REMOTE_TIMEOUT); + int32_t DoDumpCatchRemote(int pid, int tid, std::string& msg, bool isJson = false, + int timeout = DUMPCATCHER_REMOTE_TIMEOUT); + int DoDumpRemotePid(int pid, std::string& msg, int (&pipeReadFd)[2], + bool isJson = false, int32_t timeout = DUMPCATCHER_REMOTE_TIMEOUT); + bool HandlePollError(const uint64_t endTime, int& remainTime, + bool& collectAllTidStack, std::string& resMsg, int& ret); + bool HandlePollTimeout(const int timeout, int& remainTime, + bool& collectAllTidStack, std::string& resMsg, int& ret); + bool HandlePollEvents(std::pair& bufState, std::pair& resState, + const struct pollfd (&readFds)[2], bool& bPipeConnect, bool& res); + std::pair DumpRemotePoll(const int timeout, std::pair& bufState, + std::pair& resState); + int DoDumpRemotePoll(int timeout, std::string& msg, const int (&pipeReadFd)[2], bool isJson = false); + bool DoReadBuf(int fd, std::string& msg); + bool DoReadRes(int fd, bool& ret, std::string& msg); + static void CollectKernelStack(pid_t pid, int waitMilliSeconds = 0); + void AsyncGetAllTidKernelStack(pid_t pid, int waitMilliSeconds = 0); + void DealWithPollRet(int pollRet, int pid, int32_t& ret, std::string& msg); + void DealWithSdkDumpRet(int sdkdumpRet, int pid, int32_t& ret, std::string& msg); + +private: + static const int DUMPCATCHER_REMOTE_P90_TIMEOUT = 1000; + static const int DUMPCATCHER_REMOTE_TIMEOUT = 10000; + std::mutex mutex_; + int32_t pid_ = -1; + std::string halfProcStatus_ = ""; + std::string halfProcWchan_ = ""; }; } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.h b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h similarity index 93% rename from interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.h rename to interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h index 969b6014f..3260a8459 100644 --- a/interfaces/innerkits/dump_catcher/dfx_dump_catcher_errno.h +++ b/interfaces/innerkits/dump_catcher/include/dfx_dump_catcher_errno.h @@ -18,6 +18,7 @@ #include #include +#include namespace OHOS { namespace HiviewDFX { @@ -53,8 +54,6 @@ enum DumpCatchErrorCode : int32_t { DUMPCATCH_KERNELSTACK_ECREATE = 401, /* kernelstack fail due to create hstackval fail */ DUMPCATCH_KERNELSTACK_EOPEN, /* kernelstack fail due to open bbox fail */ DUMPCATCH_KERNELSTACK_EIOCTL, /* kernelstack fail due to ioctl fail */ - DUMPCATCH_KERNELSTACK_TIMEOUT, /* kernelstack fail due to wait timeout */ - DUMPCATCH_KERNELSTACK_OVER_LIMITL, /* kernelstack fail due to over limit */ DUMPCATCH_KERNELSTACK_NONEED, /* no need to dump kernelstack */ }; diff --git a/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.cpp b/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.cpp deleted file mode 100644 index 6d015d8e7..000000000 --- a/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "kernel_stack_async_collector.h" -#include -#include -#include -#include -#include - -#include "dfx_kernel_stack.h" -#include "dfx_log.h" -#include "elapsed_time.h" -#include "procinfo.h" - -#ifdef LOG_DOMAIN -#undef LOG_DOMAIN -#define LOG_DOMAIN 0xD002D11 -#endif - -#ifdef LOG_TAG -#undef LOG_TAG -#define LOG_TAG "AsyncKernelStack" -#endif - -namespace OHOS { -namespace HiviewDFX { - -std::atomic KernelStackAsyncCollector::asyncCount_{0}; -struct KerrCodeToErrCode { - KernelStackErrorCode kErrCode; - KernelStackAsyncCollector::ErrorCode errCode; -}; -const struct KerrCodeToErrCode ERR_CODE_CONVERT_TABLE[] = { - { KERNELSTACK_ESUCCESS, KernelStackAsyncCollector::STACK_SUCCESS }, - { KERNELSTACK_ECREATE, KernelStackAsyncCollector::STACK_ECREATE }, - { KERNELSTACK_EOPEN, KernelStackAsyncCollector::STACK_EOPEN }, - { KERNELSTACK_EIOCTL, KernelStackAsyncCollector::STACK_EIOCTL }, -}; - -KernelStackAsyncCollector::KernelResult KernelStackAsyncCollector::GetProcessStackWithTimeout(int pid, - uint32_t timeoutMs) const -{ - if (asyncCount_ > maxAsyncTaskNum_) { - DFXLOGE("GetProcessStackWithTimeout fail, overlimit pid:%{public}d count:%{public}d", - pid, static_cast(asyncCount_)); - return {STACK_OVER_LIMIT, ""}; - } - std::promise result; - auto f = result.get_future(); - // kernel may take much time - std::thread {CollectKernelStackTask, pid, std::move(result)}.detach(); - auto st = f.wait_for(std::chrono::milliseconds(timeoutMs)); - if (st == std::future_status::timeout) { - DFXLOGE("GetStackWithTimeout task timeout pid:%{public}d", pid); - return {STACK_TIMEOUT, ""}; - } else if (st == std::future_status::deferred) { - DFXLOGE("GetStackWithTimeout task deferred pid:%{public}d", pid); - return {STACK_DEFERRED, ""}; - } - return f.get(); -} - -bool KernelStackAsyncCollector::NotifyStartCollect(int pid) -{ - if (asyncCount_ > maxAsyncTaskNum_) { - DFXLOGE("NotifyStartCollect fail, overlimit pid:%{public}d count:%{public}d", - pid, static_cast(asyncCount_)); - return false; - } - std::promise result; - stackFuture_ = result.get_future(); - // kernel may take much time - std::thread {CollectKernelStackTask, pid, std::move(result)}.detach(); - return true; -} - -KernelStackAsyncCollector::KernelResult KernelStackAsyncCollector::GetCollectedStackResult() -{ - if (!stackFuture_.valid()) { - DFXLOGE("GetCollectStackResult fail, overlimit count:%{public}d", static_cast(asyncCount_)); - return {STACK_OVER_LIMIT, ""}; - } - auto st = stackFuture_.wait_for(std::chrono::milliseconds(0)); - if (st == std::future_status::timeout) { - DFXLOGE("GetCollectStackResult task timeout"); - return {STACK_TIMEOUT, ""}; - } else if (st == std::future_status::deferred) { - DFXLOGE("GetCollectStackResult task deferred"); - return {STACK_DEFERRED, ""}; - } - return stackFuture_.get(); -} - -class AutoCounter { -public: - explicit AutoCounter(std::atomic &count) : count_(count) - { - count_++; - } - AutoCounter(const AutoCounter&) = delete; - AutoCounter& operator=(const AutoCounter&) = delete; - - ~AutoCounter() - { - count_--; - } -private: - std::atomic &count_; -}; - -void KernelStackAsyncCollector::CollectKernelStackTask(int pid, std::promise result) -{ - AutoCounter autoCounter(asyncCount_); - ElapsedTime timer; - if (!CheckProcessValid(pid)) { - DFXLOGW("No process(%{public}d) status file exist!", pid); - result.set_value({STACK_NO_PROCESS, ""}); - return; - } - std::string kernelStackInfo; - int kernelRet = 0; - std::function stackTask = [&kernelStackInfo, &kernelRet](int tid) { - if (tid <= 0) { - return false; - } - std::string tidKernelStackInfo; - int32_t ret = DfxGetKernelStack(tid, tidKernelStackInfo); - if (ret == 0) { - kernelStackInfo.append(tidKernelStackInfo); - } else if (kernelRet == 0) { - kernelRet = ret; - } - return true; - }; - std::vector tids; - (void)GetTidsByPidWithFunc(pid, tids, stackTask); - if (kernelStackInfo.empty()) { - DFXLOGE("Process(%{public}d) collect kernel stack fail!", pid); - result.set_value({ToErrCode(kernelRet), ""}); - return; - } - result.set_value({STACK_SUCCESS, std::move(kernelStackInfo)}); - - DFXLOGI("finish collect all tid info for pid(%{public}d) time(%{public}" PRId64 ")ms", pid, - timer.Elapsed()); -} - -bool KernelStackAsyncCollector::CheckProcessValid(int pid) -{ - std::string statusPath = std::string {"/proc/"} + std::to_string(pid) + "/status"; - if (access(statusPath.c_str(), F_OK) != 0) { - DFXLOGW("No process(%{public}d) status file exist!", pid); - return false; - } - return true; -} - -KernelStackAsyncCollector::ErrorCode KernelStackAsyncCollector::ToErrCode(int kernelErr) -{ - auto iter = std::find_if(std::begin(ERR_CODE_CONVERT_TABLE), std::end(ERR_CODE_CONVERT_TABLE), - [kernelErr] (const KerrCodeToErrCode &kerrCodeToErrCode) { return kerrCodeToErrCode.kErrCode == kernelErr; }); - return iter != std::end(ERR_CODE_CONVERT_TABLE) ? iter->errCode : STACK_UNKNOWN; -} -} // namespace HiviewDFX -} // namespace OHOS diff --git a/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map b/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map index 18b3a75e8..9c49c9ad0 100644 --- a/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map +++ b/interfaces/innerkits/dump_catcher/libdfx_dumpcatcher.map @@ -1,8 +1,9 @@ { global: extern "C++" { - OHOS::HiviewDFX::DfxDumpCatcher::DfxDumpCatcher*; - OHOS::HiviewDFX::DfxDumpCatcher::DumpCatch*; + OHOS::HiviewDFX::DfxDumpCatcher::Dump*; + OHOS::HiviewDFX::DfxDumpCatcher::Do*; + OHOS::HiviewDFX::DfxDumpCatchError::ToString*; }; local: *; diff --git a/interfaces/innerkits/formatter/dfx_json_formatter.cpp b/interfaces/innerkits/formatter/dfx_json_formatter.cpp index ac349891b..f54b0ec73 100644 --- a/interfaces/innerkits/formatter/dfx_json_formatter.cpp +++ b/interfaces/innerkits/formatter/dfx_json_formatter.cpp @@ -35,7 +35,7 @@ static bool FormatJsFrame(const Json::Value& frames, const uint32_t& frameIdx, s if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, idxFmt, frameIdx) <= 0) { return false; } - outStr = std::string(buf); + outStr = std::string(buf, strlen(buf)); std::string symbol = frames[frameIdx]["symbol"].asString(); if (!symbol.empty()) { outStr.append(" " + symbol); @@ -66,7 +66,7 @@ static bool FormatNativeFrame(const Json::Value& frames, const uint32_t& frameId file.empty() ? "Unknown" : file.c_str()) <= 0) { return false; } - outStr = std::string(buf); + outStr = std::string(buf, strlen(buf)); if (!symbol.empty()) { outStr.append("(" + symbol + "+" + offset + ")"); } @@ -77,7 +77,7 @@ static bool FormatNativeFrame(const Json::Value& frames, const uint32_t& frameId } } -bool DfxJsonFormatter::FormatJsonStack(const std::string& jsonStack, std::string& outStackStr) +bool DfxJsonFormatter::FormatJsonStack(std::string jsonStack, std::string& outStackStr) { Json::Reader reader; Json::Value threads; @@ -157,7 +157,7 @@ static bool FormatKernelStackJson(std::vector processStack, std: if (snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, format, frame.relPc) <= 0) { continue; } - frameJson["pc"] = std::string(buf); + frameJson["pc"] = std::string(buf, strlen(buf)); frameJson["symbol"] = ""; frameJson["offset"] = 0; frameJson["file"] = frame.mapName.empty() ? "Unknown" : frame.mapName; diff --git a/interfaces/innerkits/formatter/include/dfx_json_formatter.h b/interfaces/innerkits/formatter/include/dfx_json_formatter.h index 0c5b5f8ce..965ecb646 100644 --- a/interfaces/innerkits/formatter/include/dfx_json_formatter.h +++ b/interfaces/innerkits/formatter/include/dfx_json_formatter.h @@ -33,7 +33,7 @@ public: * @param outStackStr output the stack string * @return bool */ - static bool FormatJsonStack(const std::string& jsonStack, std::string& outStackStr); + static bool FormatJsonStack(std::string jsonStack, std::string& outStackStr); /** * @brief Format kernel stack diff --git a/interfaces/innerkits/procinfo/procinfo.cpp b/interfaces/innerkits/procinfo/procinfo.cpp index c2fd46a4d..499f40a8b 100644 --- a/interfaces/innerkits/procinfo/procinfo.cpp +++ b/interfaces/innerkits/procinfo/procinfo.cpp @@ -32,9 +32,9 @@ namespace OHOS { namespace HiviewDFX { namespace { -const char * const PID_STR_NAME = "Pid:"; -const char * const PPID_STR_NAME = "PPid:"; -const char * const NSPID_STR_NAME = "NSpid:"; +const char PID_STR_NAME[] = "Pid:"; +const char PPID_STR_NAME[] = "PPid:"; +const char NSPID_STR_NAME[] = "NSpid:"; const int ARGS_COUNT_ONE = 1; const int ARGS_COUNT_TWO = 2; const int STATUS_LINE_SIZE = 1024; diff --git a/interfaces/innerkits/signal_handler/BUILD.gn b/interfaces/innerkits/signal_handler/BUILD.gn index 408db3a0f..cd287677e 100644 --- a/interfaces/innerkits/signal_handler/BUILD.gn +++ b/interfaces/innerkits/signal_handler/BUILD.gn @@ -33,7 +33,6 @@ template("lib_dfxsignalhandler_template") { } sources = [ - "$faultloggerd_path/common/cutil/dfx_cutil.c", "dfx_signal_handler.c", "dfx_signalhandler_exception.c", "musl_log.c", @@ -130,6 +129,7 @@ if (defined(ohos_lite)) { "_LIBCPP_HAS_MUSL_LIBC", "__BUILD_LINUX_WITH_CLANG", "ENABLE_SIGHAND_MUSL_LOG", + "ENABLE_MUSL_CUTIL", ] ldflags = [ "-nostdlib" ] diff --git a/interfaces/innerkits/signal_handler/dfx_dumprequest.c b/interfaces/innerkits/signal_handler/dfx_dumprequest.c index f0c95b827..0e8efe834 100644 --- a/interfaces/innerkits/signal_handler/dfx_dumprequest.c +++ b/interfaces/innerkits/signal_handler/dfx_dumprequest.c @@ -18,20 +18,14 @@ #include "dfx_dumprequest.h" -#include #include #include #include #include -#include #include #include -#include #include #include -#include -#include -#include #include #include #include @@ -40,14 +34,25 @@ #include #include #include -#include -#include - -#include "dfx_cutil.h" +#include +#include #include "dfx_define.h" #include "dfx_dump_request.h" -#include "dfx_log.h" #include "dfx_signalhandler_exception.h" +#include "errno.h" +#include "linux/capability.h" +#include "stdbool.h" +#include "string.h" +#ifndef DFX_SIGNAL_LIBC +#include +#include "dfx_cutil.h" +#include "dfx_log.h" +#else +#include "musl_cutil.h" +#include "musl_log.h" +#endif + +#include "info/fatal_message.h" #ifdef LOG_DOMAIN #undef LOG_DOMAIN @@ -110,6 +115,18 @@ static bool IsDumpSignal(int signo) return signo == SIGDUMP || signo == SIGLEAK_STACK; } +static const char* GetCrashDescription(const int32_t errCode) +{ + size_t i; + + for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) { + if (errCode == g_crashExceptionMap[i].errCode) { + return g_crashExceptionMap[i].str; + } + } + return g_crashExceptionMap[i - 1].str; /* the end of map is "unknown reason" */ +} + static void FillCrashExceptionAndReport(const int err) { struct CrashDumpException exception; diff --git a/interfaces/innerkits/signal_handler/dfx_signal_handler.c b/interfaces/innerkits/signal_handler/dfx_signal_handler.c index 2328b2e6c..7c6bb88cb 100644 --- a/interfaces/innerkits/signal_handler/dfx_signal_handler.c +++ b/interfaces/innerkits/signal_handler/dfx_signal_handler.c @@ -18,19 +18,14 @@ #define _GNU_SOURCE 1 #endif -#include #include #include #include #include #include #include -#include #include #include -#include -#include -#include #include #include #include @@ -39,23 +34,29 @@ #include #include #include -#include -#include - -#include "dfx_cutil.h" +#include +#include #include "dfx_define.h" #include "dfx_dump_request.h" #include "dfx_signalhandler_exception.h" +#include "errno.h" +#include "linux/capability.h" +#include "stdbool.h" +#include "string.h" #ifndef DFX_SIGNAL_LIBC #include +#include "dfx_cutil.h" #include "dfx_log.h" #else +#include "musl_cutil.h" #include "musl_log.h" #endif + #ifdef is_ohos_lite #include "dfx_dumprequest.h" #endif +#include "info/fatal_message.h" #ifdef LOG_DOMAIN #undef LOG_DOMAIN @@ -222,6 +223,18 @@ static bool FillDebugMessageLocked(int32_t signo, siginfo_t *si) return true; } +static const char* GetCrashDescription(const int32_t errCode) +{ + size_t i; + + for (i = 0; i < sizeof(g_crashExceptionMap) / sizeof(g_crashExceptionMap[0]); i++) { + if (errCode == g_crashExceptionMap[i].errCode) { + return g_crashExceptionMap[i].str; + } + } + return g_crashExceptionMap[i - 1].str; /* the end of map is "unknown reason" */ +} + static void FillCrashExceptionAndReport(const int err) { struct CrashDumpException exception; diff --git a/interfaces/innerkits/signal_handler/encaps.json b/interfaces/innerkits/signal_handler/encaps.json index a859cec83..6d5f4ebad 100644 --- a/interfaces/innerkits/signal_handler/encaps.json +++ b/interfaces/innerkits/signal_handler/encaps.json @@ -1,6 +1 @@ -{ - "encaps": { - "ohos.encaps.count": 1, - "ohos.encaps.fork.source": 2 - } -} \ No newline at end of file +{"encaps":{"ohos.encaps.count":1,"ohos.encaps.fork.source":2}} \ No newline at end of file diff --git a/interfaces/innerkits/signal_handler/include/dfx_dumprequest.h b/interfaces/innerkits/signal_handler/include/dfx_dumprequest.h index 7a668b7a7..92a9294db 100644 --- a/interfaces/innerkits/signal_handler/include/dfx_dumprequest.h +++ b/interfaces/innerkits/signal_handler/include/dfx_dumprequest.h @@ -15,6 +15,8 @@ #ifndef DFX_DUMPREQUEST_H #define DFX_DUMPREQUEST_H +#include + #include "dfx_dump_request.h" #ifdef __cplusplus diff --git a/interfaces/innerkits/unwinder/BUILD.gn b/interfaces/innerkits/unwinder/BUILD.gn index 47750b9bf..9ba0cfb44 100644 --- a/interfaces/innerkits/unwinder/BUILD.gn +++ b/interfaces/innerkits/unwinder/BUILD.gn @@ -1,4 +1,4 @@ -# Copyright (c) 2023-2025 Huawei Device Co., Ltd. +# Copyright (c) 2023-2024 Huawei Device Co., Ltd. # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -14,41 +14,41 @@ import("//base/hiviewdfx/faultloggerd/faultloggerd.gni") dfx_unwinder_sources = [ - "src/ark/dfx_ark.cpp", - "src/ark/dfx_hap.cpp", - "src/elf/dfx_elf.cpp", - "src/elf/dfx_elf_parser.cpp", - "src/elf/dfx_mmap.cpp", - "src/elf/dfx_symbols.cpp", - "src/elf/elf_factory.cpp", - "src/elf/elf_factory_selector.cpp", - "src/maps/dfx_map.cpp", - "src/maps/dfx_maps.cpp", - "src/memory/dfx_accessors.cpp", - "src/memory/dfx_memory.cpp", - "src/registers/dfx_regs.cpp", - "src/registers/dfx_regs_arm.cpp", - "src/registers/dfx_regs_arm64.cpp", - "src/registers/dfx_regs_loongarch64.cpp", - "src/registers/dfx_regs_riscv64.cpp", - "src/registers/dfx_regs_x86_64.cpp", - "src/registers/getcontext_x86_64.S", - "src/unwind_local/thread_context.cpp", - "src/utils/dfx_config.cpp", - "src/utils/dfx_frame_formatter.cpp", - "src/utils/dfx_instr_statistic.cpp", - "src/utils/dfx_instructions.cpp", - "src/utils/dfx_ptrace.cpp", - "src/utils/unwinder_config.cpp", + "arch_util.cpp", + "dfx_accessors.cpp", + "dfx_ark.cpp", + "dfx_config.cpp", + "dfx_elf.cpp", + "dfx_elf_parser.cpp", + "dfx_frame_formatter.cpp", + "dfx_hap.cpp", + "dfx_instr_statistic.cpp", + "dfx_instructions.cpp", + "dfx_map.cpp", + "dfx_maps.cpp", + "dfx_memory.cpp", + "dfx_mmap.cpp", + "dfx_ptrace.cpp", + "dfx_regs.cpp", + "dfx_regs_arm.cpp", + "dfx_regs_arm64.cpp", + "dfx_regs_loongarch64.cpp", + "dfx_regs_riscv64.cpp", + "dfx_regs_x86_64.cpp", + "dfx_signal.cpp", + "dfx_symbols.cpp", + "getcontext_x86_64.S", + "thread_context.cpp", "unwinder.cpp", + "unwinder_config.cpp", ] -dfx_exidx_sources = [ "src/unwind_entry_parser/exidx_entry_parser.cpp" ] +dfx_exidx_sources = [ "arm_exidx.cpp" ] dfx_dwarf_sources = [ - "src/unwind_entry_parser/dwarf_cfa_instructions.cpp", - "src/unwind_entry_parser/dwarf_entry_parser.cpp", - "src/unwind_entry_parser/dwarf_op.cpp", + "dwarf_cfa_instructions.cpp", + "dwarf_op.cpp", + "dwarf_section.cpp", ] if (defined(ohos_lite)) { @@ -65,15 +65,15 @@ if (defined(ohos_lite)) { public_configs = [ ":ohos_lite_config" ] include_dirs = [ + "include", "$c_utils_include_path", "$faultloggerd_common_path/dfxlog", "$faultloggerd_common_path/dfxutil", "$faultloggerd_interfaces_path/common", - "include", "$hilog_lite_include_path", ] - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] sources = dfx_unwinder_sources sources += dfx_exidx_sources sources += dfx_dwarf_sources @@ -95,15 +95,15 @@ if (defined(ohos_lite)) { public_configs = [ ":ohos_lite_config" ] include_dirs = [ + "include", "$c_utils_include_path", "$faultloggerd_common_path/dfxlog", "$faultloggerd_common_path/dfxutil", "$faultloggerd_interfaces_path/common", - "include", "$hilog_lite_include_path", ] - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] sources = dfx_unwinder_sources sources += dfx_exidx_sources sources += dfx_dwarf_sources @@ -126,10 +126,10 @@ if (defined(ohos_lite)) { visibility = [ "*:*" ] include_dirs = [ + "include", "$faultloggerd_common_path/dfxlog", "$faultloggerd_common_path/dfxutil", "$faultloggerd_interfaces_path/common", - "include", ] defines = [ @@ -165,13 +165,16 @@ if (defined(ohos_lite)) { ":mixstack_config", "$faultloggerd_common_path/build:coverage_flags", ] - defines = [ "DFX_ENABLE_TRACE" ] + defines = [ + "DFX_UNWIND_ERROR", + "DFX_ENABLE_TRACE", + ] if (target_cpu == "arm64") { defines += [ "ENABLE_PARAMETER" ] } if (target_cpu != "x86_64") { - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] } sources = dfx_unwinder_sources sources += dfx_exidx_sources @@ -183,6 +186,9 @@ if (defined(ohos_lite)) { "$faultloggerd_common_path/trace:dfx_trace_dlsym", ] + if (is_ohos && !is_mingw && !is_emulator) { + sources += [ "dfx_xz_utils.cpp" ] + } version_script = "libunwinder.map" public_external_deps = [ "lzma:lzma_shared" ] external_deps = [ @@ -211,7 +217,7 @@ if (defined(ohos_lite)) { ] if (target_cpu != "x86_64") { - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] } sources = dfx_unwinder_sources sources += dfx_exidx_sources @@ -223,6 +229,9 @@ if (defined(ohos_lite)) { "$faultloggerd_common_path/trace:dfx_trace_dlsym", ] + if (is_ohos && !is_mingw && !is_emulator) { + sources += [ "dfx_xz_utils.cpp" ] + } public_external_deps = [ "lzma:lzma_shared" ] external_deps = [ "bounds_checking_function:libsec_shared", @@ -242,7 +251,7 @@ if (defined(ohos_lite)) { defines = [ "DFX_LOG_HILOG_BASE" ] if (target_cpu != "x86_64") { - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] } sources = dfx_unwinder_sources sources += dfx_exidx_sources @@ -254,6 +263,9 @@ if (defined(ohos_lite)) { "$faultloggerd_common_path/trace:dfx_trace_dlsym", ] + if (is_ohos && !is_mingw && !is_emulator) { + sources += [ "dfx_xz_utils.cpp" ] + } public_external_deps = [ "lzma:lzma_static" ] external_deps = [ "bounds_checking_function:libsec_static", @@ -272,11 +284,12 @@ if (defined(ohos_lite)) { ] defines = [ "DFX_LOG_UNWIND", + "DFX_UNWIND_ERROR", "INSTR_STATISTIC_ENABLE", ] if (target_cpu != "x86_64") { - dfx_unwinder_sources -= [ "src/registers/getcontext_x86_64.S" ] + dfx_unwinder_sources -= [ "getcontext_x86_64.S" ] } sources = dfx_unwinder_sources sources += dfx_exidx_sources @@ -288,6 +301,9 @@ if (defined(ohos_lite)) { "$faultloggerd_common_path/trace:dfx_trace_dlsym", ] + if (is_ohos && !is_mingw && !is_emulator) { + sources += [ "dfx_xz_utils.cpp" ] + } public_external_deps = [ "lzma:lzma_shared" ] external_deps = [ "bounds_checking_function:libsec_shared", @@ -319,24 +335,20 @@ if (defined(ohos_lite)) { } ohos_static_library("unwinder_host") { - public_configs = [ - ":unwinder_host_config", - ":lzma_config", - ] + public_configs = [ ":unwinder_host_config" ] sources = [ - "src/ark/dfx_hap.cpp", - "src/elf/dfx_elf.cpp", - "src/elf/dfx_elf_parser.cpp", - "src/elf/dfx_mmap.cpp", - "src/elf/dfx_symbols.cpp", - "src/elf/elf_factory.cpp", - "src/elf/elf_factory_selector.cpp", - "src/maps/dfx_map.cpp", - "src/maps/dfx_maps.cpp", - "src/memory/dfx_memory.cpp", - "src/utils/unwinder_config.cpp", + "dfx_elf.cpp", + "dfx_elf_parser.cpp", + "dfx_hap.cpp", + "dfx_map.cpp", + "dfx_maps.cpp", + "dfx_memory.cpp", + "dfx_mmap.cpp", + "dfx_symbols.cpp", + "unwinder_config.cpp", ] if (is_ohos && !is_mingw && !is_emulator) { + sources += [ "dfx_xz_utils.cpp" ] public_external_deps = [ "lzma:lzma_static" ] } deps = [ diff --git a/interfaces/innerkits/unwinder/arch_util.cpp b/interfaces/innerkits/unwinder/arch_util.cpp new file mode 100644 index 000000000..4d429d4f8 --- /dev/null +++ b/interfaces/innerkits/unwinder/arch_util.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "arch_util.h" + +#include +#include "dfx_define.h" +#include "dfx_log.h" +#include "string_util.h" + +namespace OHOS { +namespace HiviewDFX { +ArchType GetCurrentArch() +{ + ArchType curArch = ArchType::ARCH_UNKNOWN; +#if defined(__arm__) + curArch = ArchType::ARCH_ARM; +#elif defined(__aarch64__) + curArch = ArchType::ARCH_ARM64; +#elif defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 + curArch = ArchType::ARCH_RISCV64; +#elif defined(__i386__) + curArch = ArchType::ARCH_X86; +#elif defined(__x86_64__) + curArch = ArchType::ARCH_X86_64; +#elif defined(__loongarch__) + curArch = ArchType::ARCH_LOONGARCH; +#else +#error "Unsupported architecture" +#endif + return curArch; +} + +ArchType GetArchFromUname(const std::string& machine) +{ + if (StartsWith(machine, "arm")) { + if (machine == "armv8l") { + return ArchType::ARCH_ARM64; + } + return ArchType::ARCH_ARM; + } else if (machine == "aarch64") { + return ArchType::ARCH_ARM64; + } else if (machine == "riscv64") { + return ArchType::ARCH_RISCV64; + } else if (machine == "x86_64") { + return ArchType::ARCH_X86_64; + } else if (machine == "x86" || machine == "i686") { + return ArchType::ARCH_X86; + } else if (machine == "loongarch64") { + return ArchType::ARCH_LOONGARCH; + } else { + return ArchType::ARCH_UNKNOWN; + } +} + +const std::string GetArchName(ArchType arch) +{ + switch (arch) { + case ArchType::ARCH_X86: + return "X86_32"; + case ArchType::ARCH_X86_64: + return "X86_64"; + case ArchType::ARCH_ARM: + return "ARM"; + case ArchType::ARCH_ARM64: + return "ARM64"; + case ArchType::ARCH_RISCV64: + return "RISCV64"; + case ArchType::ARCH_LOONGARCH: + return "LOONGARCH"; + default: + return "Unsupport"; + } +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/exidx_entry_parser.cpp b/interfaces/innerkits/unwinder/arm_exidx.cpp similarity index 84% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/exidx_entry_parser.cpp rename to interfaces/innerkits/unwinder/arm_exidx.cpp index 3a08e2ab3..c977a2374 100644 --- a/interfaces/innerkits/unwinder/src/unwind_entry_parser/exidx_entry_parser.cpp +++ b/interfaces/innerkits/unwinder/arm_exidx.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "exidx_entry_parser.h" +#include "arm_exidx.h" #include #include "dfx_define.h" @@ -32,7 +32,7 @@ namespace { #undef LOG_DOMAIN #undef LOG_TAG #define LOG_DOMAIN 0xD002D11 -#define LOG_TAG "DfxExidxEntryParser" +#define LOG_TAG "DfxArmExidx" #define ARM_EXIDX_CANT_UNWIND 0x00000001 #define ARM_EXIDX_COMPACT 0x80000000 @@ -88,7 +88,13 @@ void ExidxContext::AddUpVsp(int32_t imm) } } -void ExidxEntryParser::FlushInstr() +ArmExidx::ArmExidx(std::shared_ptr memory) : memory_(memory) +{ + (void)memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData)); + context_.Reset(DfxRegsQut::GetQutRegsSize()); +} + +inline void ArmExidx::FlushInstr() { if (rsState_->cfaReg == 0) { rsState_->cfaReg = REG_SP; @@ -124,7 +130,7 @@ void ExidxEntryParser::FlushInstr() context_.Reset(); } -inline void ExidxEntryParser::LogRawData() +inline void ArmExidx::LogRawData() { std::string logStr("Raw Data:"); for (const uint8_t data : ops_) { @@ -133,7 +139,7 @@ inline void ExidxEntryParser::LogRawData() DFXLOGU("%{public}s", logStr.c_str()); } -bool ExidxEntryParser::SearchEntry(uintptr_t pc, const UnwindTableInfo &uti, struct UnwindEntryInfo& uei) +bool ArmExidx::SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei) { uintptr_t tableLen = uti.tableLen / ARM_EXIDX_TABLE_SIZE; uintptr_t tableData = uti.tableData; @@ -182,7 +188,7 @@ bool ExidxEntryParser::SearchEntry(uintptr_t pc, const UnwindTableInfo &uti, str return true; } -bool ExidxEntryParser::ExtractEntryData(uintptr_t entryOffset) +bool ArmExidx::ExtractEntryData(uintptr_t entryOffset) { DFXLOGU("Exidx entryOffset: %{public}llx", (uint64_t)entryOffset); ops_.clear(); @@ -235,7 +241,7 @@ bool ExidxEntryParser::ExtractEntryData(uintptr_t entryOffset) return ExtractEntryTab(extabAddr); } -bool ExidxEntryParser::ExtractEntryTabByPersonality(uintptr_t& tabOffset, uint32_t& data, uint8_t& tableCount) +bool ArmExidx::ExtractEntryTabByPersonality(uintptr_t& tabOffset, uint32_t& data, uint8_t& tableCount) { if ((data & ARM_EXIDX_COMPACT) == 0) { DFXLOGU("Arm generic personality, data: %{public}x.", data); @@ -286,7 +292,7 @@ bool ExidxEntryParser::ExtractEntryTabByPersonality(uintptr_t& tabOffset, uint32 return true; } -bool ExidxEntryParser::ExtractEntryTab(uintptr_t tabOffset) +bool ArmExidx::ExtractEntryTab(uintptr_t tabOffset) { uint32_t data = 0; DFXLOGU("Exidx tabOffset: %{public}llx", static_cast(tabOffset)); @@ -299,7 +305,7 @@ bool ExidxEntryParser::ExtractEntryTab(uintptr_t tabOffset) if (!ExtractEntryTabByPersonality(tabOffset, data, tableCount)) { return false; } - + if (tableCount > 5) { // 5 : 5 operators lastErrorData_.SetCode(UNW_ERROR_NOT_SUPPORT); return false; @@ -323,7 +329,7 @@ bool ExidxEntryParser::ExtractEntryTab(uintptr_t tabOffset) return true; } -inline bool ExidxEntryParser::GetOpCode() +inline bool ArmExidx::GetOpCode() { if (ops_.empty()) { return false; @@ -334,50 +340,44 @@ inline bool ExidxEntryParser::GetOpCode() return true; } -bool ExidxEntryParser::Eval(uintptr_t entryOffset) +bool ArmExidx::Eval(uintptr_t entryOffset) { if (!ExtractEntryData(entryOffset)) { return false; } DecodeTable decodeTable[] = { - {0xc0, 0x00, &ExidxEntryParser::Decode00xxxxxx}, - {0xc0, 0x40, &ExidxEntryParser::Decode01xxxxxx}, - {0xf0, 0x80, &ExidxEntryParser::Decode1000iiiiiiiiiiii}, - {0xf0, 0x90, &ExidxEntryParser::Decode1001nnnn}, - {0xf0, 0xa0, &ExidxEntryParser::Decode1010nnnn}, - {0xff, 0xb0, &ExidxEntryParser::Decode10110000}, - {0xff, 0xb1, &ExidxEntryParser::Decode101100010000iiii}, - {0xff, 0xb2, &ExidxEntryParser::Decode10110010uleb128}, - {0xff, 0xb3, &ExidxEntryParser::Decode10110011sssscccc}, - {0xfc, 0xb4, &ExidxEntryParser::Decode101101nn}, - {0xf8, 0xb8, &ExidxEntryParser::Decode10111nnn}, - {0xff, 0xc6, &ExidxEntryParser::Decode11000110sssscccc}, - {0xff, 0xc7, &ExidxEntryParser::Decode110001110000iiii}, - {0xfe, 0xc8, &ExidxEntryParser::Decode1100100nsssscccc}, - {0xc8, 0xc8, &ExidxEntryParser::Decode11001yyy}, - {0xf8, 0xc0, &ExidxEntryParser::Decode11000nnn}, - {0xf8, 0xd0, &ExidxEntryParser::Decode11010nnn}, - {0xc0, 0xc0, &ExidxEntryParser::Decode11xxxyyy} + {0xc0, 0x00, &ArmExidx::Decode00xxxxxx}, + {0xc0, 0x40, &ArmExidx::Decode01xxxxxx}, + {0xf0, 0x80, &ArmExidx::Decode1000iiiiiiiiiiii}, + {0xf0, 0x90, &ArmExidx::Decode1001nnnn}, + {0xf0, 0xa0, &ArmExidx::Decode1010nnnn}, + {0xff, 0xb0, &ArmExidx::Decode10110000}, + {0xff, 0xb1, &ArmExidx::Decode101100010000iiii}, + {0xff, 0xb2, &ArmExidx::Decode10110010uleb128}, + {0xff, 0xb3, &ArmExidx::Decode10110011sssscccc}, + {0xfc, 0xb4, &ArmExidx::Decode101101nn}, + {0xf8, 0xb8, &ArmExidx::Decode10111nnn}, + {0xff, 0xc6, &ArmExidx::Decode11000110sssscccc}, + {0xff, 0xc7, &ArmExidx::Decode110001110000iiii}, + {0xfe, 0xc8, &ArmExidx::Decode1100100nsssscccc}, + {0xc8, 0xc8, &ArmExidx::Decode11001yyy}, + {0xf8, 0xc0, &ArmExidx::Decode11000nnn}, + {0xf8, 0xd0, &ArmExidx::Decode11010nnn}, + {0xc0, 0xc0, &ArmExidx::Decode11xxxyyy} }; context_.Reset(); while (Decode(decodeTable, sizeof(decodeTable) / sizeof(decodeTable[0]))); return true; } -bool ExidxEntryParser::Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr rs) +bool ArmExidx::Step(uintptr_t entryOffset, std::shared_ptr rs) { - if (memory_ == nullptr || rs == nullptr) { - DFXLOGE("memory or rs is nullptr"); + if (rs == nullptr) { return false; } rsState_ = rs; - UnwindEntryInfo uei; - if (!SearchEntry(pc, uti, uei)) { - DFXLOGE("Failed to search unwind entry"); - return false; - } - uintptr_t entryOffset = reinterpret_cast(uei.unwindInfo); + if (!Eval(entryOffset)) { return false; } @@ -386,14 +386,14 @@ bool ExidxEntryParser::Step(uintptr_t pc, const UnwindTableInfo& uti, std::share return true; } -inline bool ExidxEntryParser::DecodeSpare() +inline bool ArmExidx::DecodeSpare() { DFXLOGU("Exidx Decode Spare"); lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_SPARE); return false; } -bool ExidxEntryParser::Decode(DecodeTable decodeTable[], size_t size) +inline bool ArmExidx::Decode(DecodeTable decodeTable[], size_t size) { if (!GetOpCode()) { return false; @@ -412,21 +412,21 @@ bool ExidxEntryParser::Decode(DecodeTable decodeTable[], size_t size) return ret; } -inline bool ExidxEntryParser::Decode00xxxxxx() +inline bool ArmExidx::Decode00xxxxxx() { // 00xxxxxx: vsp = vsp + (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive context_.AddUpVsp(((curOp_ & 0x3f) << 2) + 4); return true; } -inline bool ExidxEntryParser::Decode01xxxxxx() +inline bool ArmExidx::Decode01xxxxxx() { // 01xxxxxx: vsp = vsp - (xxxxxx << 2) + 4. Covers range 0x04-0x100 inclusive context_.AddUpVsp(-(((curOp_ & 0x3f) << 2) + 4)); return true; } -bool ExidxEntryParser::Decode1000iiiiiiiiiiii() +inline bool ArmExidx::Decode1000iiiiiiiiiiii() { uint16_t registers = ((curOp_ & 0x0f) << 8); if (!GetOpCode()) { @@ -453,7 +453,7 @@ bool ExidxEntryParser::Decode1000iiiiiiiiiiii() return true; } -bool ExidxEntryParser::Decode1001nnnn() +inline bool ArmExidx::Decode1001nnnn() { uint8_t bits = curOp_ & 0xf; if (bits == REG_ARM_R13 || bits == REG_ARM_R15) { @@ -477,7 +477,7 @@ bool ExidxEntryParser::Decode1001nnnn() return true; } -bool ExidxEntryParser::Decode1010nnnn() +inline bool ArmExidx::Decode1010nnnn() { // 10100nnn: Pop r4-r[4+nnn] // 10101nnn: Pop r4-r[4+nnn], r14 @@ -504,14 +504,14 @@ bool ExidxEntryParser::Decode1010nnnn() return true; } -inline bool ExidxEntryParser::Decode10110000() +inline bool ArmExidx::Decode10110000() { DFXLOGU("10110000: Finish"); lastErrorData_.SetCode(UNW_ERROR_ARM_EXIDX_FINISH); return true; } -bool ExidxEntryParser::Decode101100010000iiii() +inline bool ArmExidx::Decode101100010000iiii() { if (!GetOpCode()) { return false; @@ -533,7 +533,7 @@ bool ExidxEntryParser::Decode101100010000iiii() return true; } -bool ExidxEntryParser::Decode10110010uleb128() +inline bool ArmExidx::Decode10110010uleb128() { // 10110010 uleb128 vsp = vsp + 0x204 + (uleb128 << 2) uint8_t shift = 0; @@ -551,7 +551,7 @@ bool ExidxEntryParser::Decode10110010uleb128() return true; } -inline bool ExidxEntryParser::Decode10110011sssscccc() +inline bool ArmExidx::Decode10110011sssscccc() { // Pop VFP double precision registers D[ssss]-D[ssss+cccc] by FSTMFDX if (!GetOpCode()) { @@ -563,12 +563,12 @@ inline bool ExidxEntryParser::Decode10110011sssscccc() return true; } -inline bool ExidxEntryParser::Decode101101nn() +inline bool ArmExidx::Decode101101nn() { return DecodeSpare(); } -inline bool ExidxEntryParser::Decode10111nnn() +inline bool ArmExidx::Decode10111nnn() { // 10111nnn: Pop VFP double-precision registers D[8]-D[8+nnn] by FSTMFDX uint8_t popRegCount = (curOp_ & 0x07) + 1; @@ -577,7 +577,7 @@ inline bool ExidxEntryParser::Decode10111nnn() return true; } -inline bool ExidxEntryParser::Decode11000110sssscccc() +inline bool ArmExidx::Decode11000110sssscccc() { // 11000110 sssscccc: Intel Wireless MMX pop wR[ssss]-wR[ssss+cccc] (see remark e) if (!GetOpCode()) { @@ -586,7 +586,7 @@ inline bool ExidxEntryParser::Decode11000110sssscccc() return Decode11000nnn(); } -bool ExidxEntryParser::Decode110001110000iiii() +inline bool ArmExidx::Decode110001110000iiii() { // Intel Wireless MMX pop wCGR registers under mask {wCGR3,2,1,0} if (!GetOpCode()) { @@ -607,7 +607,7 @@ bool ExidxEntryParser::Decode110001110000iiii() return true; } -inline bool ExidxEntryParser::Decode1100100nsssscccc() +inline bool ArmExidx::Decode1100100nsssscccc() { // 11001000 sssscccc: Pop VFP double precision registers D[16+ssss]-D[16+ssss+cccc] by VPUSH // 11001001 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] by VPUSH @@ -620,13 +620,13 @@ inline bool ExidxEntryParser::Decode1100100nsssscccc() return true; } -inline bool ExidxEntryParser::Decode11001yyy() +inline bool ArmExidx::Decode11001yyy() { // 11001yyy: Spare (yyy != 000, 001) return DecodeSpare(); } -inline bool ExidxEntryParser::Decode11000nnn() +inline bool ArmExidx::Decode11000nnn() { // Intel Wireless MMX pop wR[10]-wR[10+nnn] uint8_t popRegCount = (curOp_ & 0x0f) + 1; @@ -635,7 +635,7 @@ inline bool ExidxEntryParser::Decode11000nnn() return true; } -inline bool ExidxEntryParser::Decode11010nnn() +inline bool ArmExidx::Decode11010nnn() { // Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by VPUSH (seeremark d) uint8_t popRegCount = (curOp_ & 0x0f) + 1; @@ -644,7 +644,7 @@ inline bool ExidxEntryParser::Decode11010nnn() return true; } -inline bool ExidxEntryParser::Decode11xxxyyy() +inline bool ArmExidx::Decode11xxxyyy() { // 11xxxyyy: Spare (xxx != 000, 001, 010) return DecodeSpare(); diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/arm_exidx_instructions.txt b/interfaces/innerkits/unwinder/arm_exidx_instructions.txt similarity index 100% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/arm_exidx_instructions.txt rename to interfaces/innerkits/unwinder/arm_exidx_instructions.txt diff --git a/interfaces/innerkits/unwinder/src/memory/dfx_accessors.cpp b/interfaces/innerkits/unwinder/dfx_accessors.cpp similarity index 99% rename from interfaces/innerkits/unwinder/src/memory/dfx_accessors.cpp rename to interfaces/innerkits/unwinder/dfx_accessors.cpp index e8a06d24c..c1a854a5f 100644 --- a/interfaces/innerkits/unwinder/src/memory/dfx_accessors.cpp +++ b/interfaces/innerkits/unwinder/dfx_accessors.cpp @@ -16,9 +16,12 @@ #include "dfx_accessors.h" #include +#include #include +#include #include #include +#include #include "dfx_define.h" #include "dfx_errors.h" #include "dfx_log.h" diff --git a/interfaces/innerkits/unwinder/src/ark/dfx_ark.cpp b/interfaces/innerkits/unwinder/dfx_ark.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/ark/dfx_ark.cpp rename to interfaces/innerkits/unwinder/dfx_ark.cpp diff --git a/interfaces/innerkits/unwinder/src/utils/dfx_config.cpp b/interfaces/innerkits/unwinder/dfx_config.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/dfx_config.cpp rename to interfaces/innerkits/unwinder/dfx_config.cpp diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp b/interfaces/innerkits/unwinder/dfx_elf.cpp similarity index 58% rename from interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp rename to interfaces/innerkits/unwinder/dfx_elf.cpp index 9398e59ac..7c71b1b42 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_elf.cpp +++ b/interfaces/innerkits/unwinder/dfx_elf.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2025 Huawei Device Co., Ltd. + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -38,7 +38,9 @@ #include "dfx_maps.h" #include "dfx_trace_dlsym.h" #include "dwarf_define.h" -#include "elf_factory.h" +#if defined(ENABLE_MINIDEBUGINFO) +#include "dfx_xz_utils.h" +#endif #include "string_util.h" #include "unwinder_config.h" @@ -49,6 +51,7 @@ namespace { #undef LOG_TAG #define LOG_DOMAIN 0xD002D11 #define LOG_TAG "DfxElf" + #if is_ohos && !is_mingw enum HdrSection { SECTION_TEXT = 0, @@ -59,6 +62,127 @@ enum HdrSection { #endif } +std::shared_ptr DfxElf::Create(const std::string& path) +{ + auto elf = std::make_shared(path); + if (elf->IsValid()) { + return elf; + } + return nullptr; +} + +std::shared_ptr DfxElf::CreateFromHap(const std::string& file, std::shared_ptr prevMap, + uint64_t& offset) +{ + // elf header is in the first mmap area + // c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header + // c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region + // c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap + // c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap + if (prevMap == nullptr) { + DFXLOGE("current hap mapitem has no prev mapitem, maybe pc is wrong?"); + return nullptr; + } + if (!StartsWith(file, "/proc") || !EndsWith(file, ".hap")) { + DFXLOGD("Illegal file path, please check file: %{public}s", file.c_str()); + return nullptr; + } + int fd = OHOS_TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY)); + if (fd < 0) { + DFXLOGE("Failed to open hap file, errno(%{public}d)", errno); + return nullptr; + } + auto fileSize = GetFileSize(fd); + size_t elfSize = 0; + size_t size = prevMap->end - prevMap->begin; + do { + auto mmap = std::make_shared(); + if (!mmap->Init(fd, size, (off_t)prevMap->offset)) { + DFXLOGE("Failed to mmap program header in hap."); + break; + } + + elfSize = GetElfSize(mmap->Get()); + if (elfSize <= 0 || elfSize + prevMap->offset > static_cast(fileSize)) { + DFXLOGE("Invalid elf size? elf size: %{public}d, hap size: %{public}d", (int)elfSize, (int)fileSize); + elfSize = 0; + break; + } + + offset -= prevMap->offset; + } while (false); + + if (elfSize != 0) { + DFXLOGU("elfSize: %{public}zu", elfSize); + auto elf = std::make_shared(fd, elfSize, prevMap->offset); + if (elf->IsValid()) { + close(fd); + elf->SetBaseOffset(prevMap->offset); + return elf; + } + } + close(fd); + return nullptr; +} + +DfxElf::DfxElf(const std::string& file) +{ + if (mmap_ == nullptr && (!file.empty())) { + DFXLOGU("file: %{public}s", file.c_str()); +#if defined(is_ohos) && is_ohos + if (!DfxMaps::IsLegalMapItem(file)) { + DFXLOGD("Illegal map file, please check file: %{public}s", file.c_str()); + return; + } +#endif + std::string realPath = file; + if (!StartsWith(file, "/proc/")) { // sandbox file should not be check by realpath function + if (!RealPath(file, realPath)) { + DFXLOGW("Failed to realpath %{public}s, errno(%{public}d)", file.c_str(), errno); + return; + } + } +#if defined(is_mingw) && is_mingw + int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY | O_BINARY)); +#else + int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY)); +#endif + if (fd > 0) { + auto size = static_cast(GetFileSize(fd)); + mmap_ = std::make_shared(); + if (!mmap_->Init(fd, size, 0)) { + DFXLOGE("Failed to mmap init."); + } + close(fd); + } else { + DFXLOGE("Failed to open file: %{public}s", file.c_str()); + } + } + Init(); +} + +DfxElf::DfxElf(const int fd, const size_t elfSz, const off_t offset) +{ + if (mmap_ == nullptr) { + mmap_ = std::make_shared(); + if (!mmap_->Init(fd, elfSz, offset)) { + DFXLOGE("Failed to mmap init elf in hap."); + } + } + Init(); +} + +DfxElf::DfxElf(uint8_t* decompressedData, size_t size) +{ + if (mmap_ == nullptr) { + mmap_ = std::make_shared(); + // this mean the embedded elf initialization. + mmap_->Init(decompressedData, size); + mmap_->SetNeedUnmap(false); + } + Init(); +} + void DfxElf::Init() { uti_.namePtr = 0; @@ -80,6 +204,56 @@ void DfxElf::Clear() } } +bool DfxElf::IsEmbeddedElfValid() +{ +#if defined(ENABLE_MINIDEBUGINFO) + if (embeddedElf_ == nullptr) { + return InitEmbeddedElf(); + } + return embeddedElf_ != nullptr && embeddedElf_->IsValid(); +#endif + return false; +} + +std::shared_ptr DfxElf::GetEmbeddedElf() +{ + return embeddedElf_; +} + +std::shared_ptr DfxElf::GetMiniDebugInfo() +{ + return miniDebugInfo_; +} + +bool DfxElf::InitEmbeddedElf() +{ +#if defined(ENABLE_MINIDEBUGINFO) + DFX_TRACE_SCOPED_DLSYM("InitEmbeddedElf"); + if (!UnwinderConfig::GetEnableMiniDebugInfo() || miniDebugInfo_ == nullptr || GetMmapPtr() == nullptr) { + return false; + } + uint8_t* addr = miniDebugInfo_->offset + const_cast(GetMmapPtr()); + embeddedElfData_ = std::make_shared>(); + if (embeddedElfData_ == nullptr) { + DFXLOGE("Create embeddedElfData failed."); + return false; + } + if (XzDecompress(addr, miniDebugInfo_->size, embeddedElfData_)) { + // embeddedElfData_ store the decompressed bytes. + // use these bytes to construct an elf. + embeddedElf_ = std::make_shared(embeddedElfData_->data(), embeddedElfData_->size()); + if (embeddedElf_ != nullptr && embeddedElf_->IsValid()) { + return true; + } else { + DFXLOGE("Failed to parse Embedded Elf."); + } + } else { + DFXLOGE("Failed to decompressed .gnu_debugdata seciton."); + } +#endif + return false; +} + bool DfxElf::InitHeaders() { if (mmap_ == nullptr) { @@ -110,6 +284,9 @@ bool DfxElf::InitHeaders() if (elfParse_ != nullptr) { valid_ = true; elfParse_->InitHeaders(); +#if defined(ENABLE_MINIDEBUGINFO) + miniDebugInfo_ = elfParse_->GetMiniDebugInfo(); +#endif } return valid_; } @@ -255,22 +432,78 @@ void DfxElf::SetBuildId(const std::string& buildId) buildId_ = buildId; } -std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize) -{ - return ElfParser::ParseHexBuildId(noteAddr, noteSize); -} - std::string DfxElf::GetBuildId() { if (buildId_.empty()) { if (!IsValid()) { return ""; } - return elfParse_->GetBuildId(); + ShdrInfo shdr; + if ((GetSectionInfo(shdr, NOTE_GNU_BUILD_ID) || GetSectionInfo(shdr, NOTES)) && GetMmapPtr() != nullptr) { + std::string buildIdHex = GetBuildId((uint64_t)((char*)GetMmapPtr() + shdr.offset), shdr.size); + if (!buildIdHex.empty()) { + buildId_ = ToReadableBuildId(buildIdHex); + DFXLOGU("Elf buildId: %{public}s", buildId_.c_str()); + } + } } return buildId_; } +std::string DfxElf::GetBuildId(uint64_t noteAddr, uint64_t noteSize) +{ + uint64_t tmp; + if (__builtin_add_overflow(noteAddr, noteSize, &tmp)) { + DFXLOGE("noteAddr overflow"); + return ""; + } + uint64_t offset = 0; + while (offset < noteSize) { + ElfW(Nhdr) nhdr; + if (noteSize - offset < sizeof(nhdr)) { + return ""; + } + uint64_t ptr = noteAddr + offset; + if (memcpy_s(&nhdr, sizeof(nhdr), reinterpret_cast(ptr), sizeof(nhdr)) != 0) { + DFXLOGE("memcpy_s nhdr failed"); + return ""; + } + offset += sizeof(nhdr); + if (noteSize - offset < nhdr.n_namesz) { + return ""; + } + if (nhdr.n_namesz > 0) { + std::string name(nhdr.n_namesz, '\0'); + ptr = noteAddr + offset; + if (memcpy_s(&(name[0]), nhdr.n_namesz, reinterpret_cast(ptr), nhdr.n_namesz) != 0) { + DFXLOGE("memcpy_s note name failed"); + return ""; + } + // Trim trailing \0 as GNU is stored as a C string in the ELF file. + if (name.size() != 0 && name.back() == '\0') { + name.resize(name.size() - 1); + } + // Align nhdr.n_namesz to next power multiple of 4. See man 5 elf. + offset += (nhdr.n_namesz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary + if (name != "GNU" || nhdr.n_type != NT_GNU_BUILD_ID) { + offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary + continue; + } + if (noteSize - offset < nhdr.n_descsz || nhdr.n_descsz == 0) { + return ""; + } + std::string buildIdRaw(nhdr.n_descsz, '\0'); + ptr = noteAddr + offset; + if (memcpy_s(&buildIdRaw[0], nhdr.n_descsz, reinterpret_cast(ptr), nhdr.n_descsz) != 0) { + return ""; + } + return buildIdRaw; + } + // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. + offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary + } + return ""; +} uintptr_t DfxElf::GetGlobalPointer() { @@ -280,6 +513,25 @@ uintptr_t DfxElf::GetGlobalPointer() return elfParse_->GetGlobalPointer(); } +std::string DfxElf::ToReadableBuildId(const std::string& buildIdHex) +{ + if (buildIdHex.empty()) { + return ""; + } + static const char HEXTABLE[] = "0123456789abcdef"; + static const int HEXLENGTH = 16; + static const int HEX_EXPAND_PARAM = 2; + const size_t len = buildIdHex.length(); + std::string buildId(len * HEX_EXPAND_PARAM, '\0'); + + for (size_t i = 0; i < len; i++) { + unsigned int n = buildIdHex[i]; + buildId[i * HEX_EXPAND_PARAM] = HEXTABLE[(n >> 4) % HEXLENGTH]; // 4 : higher 4 bit of uint8 + buildId[i * HEX_EXPAND_PARAM + 1] = HEXTABLE[n % HEXLENGTH]; + } + return buildId; +} + bool DfxElf::GetSectionInfo(ShdrInfo& shdr, const std::string secName) { if (!IsValid()) { @@ -296,36 +548,48 @@ bool DfxElf::GetSectionData(unsigned char* buf, uint64_t size, std::string secNa return elfParse_->GetSectionData(buf, size, secName); } -GnuDebugDataHdr DfxElf::GetGnuDebugDataHdr() +const std::vector& DfxElf::GetElfSymbols() { - if (!IsValid()) { - return {}; + if (!elfSymbols_.empty()) { + return elfSymbols_; } - return elfParse_->GetGnuDebugDataHdr(); -} - -bool DfxElf::IsMiniDebugInfoValid() -{ - if (miniDebugInfo_ == nullptr) { + elfSymbols_ = elfParse_->GetElfSymbols(false); #if defined(ENABLE_MINIDEBUGINFO) - MiniDebugInfoFactory miniDebugInfoFactory(elfParse_->GetGnuDebugDataHdr()); - miniDebugInfo_ = miniDebugInfoFactory.Create(); -#endif + if (IsEmbeddedElfValid()) { + auto symbols = embeddedElf_->elfParse_->GetElfSymbols(false); + DFXLOGU("Get EmbeddedElf ElfSymbols, size: %{public}zu", symbols.size()); + elfSymbols_.insert(elfSymbols_.end(), symbols.begin(), symbols.end()); } - return miniDebugInfo_ != nullptr; +#endif + std::sort(elfSymbols_.begin(), elfSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { + return sym1.value < sym2.value; + }); + auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; + elfSymbols_.erase(std::unique(elfSymbols_.begin(), elfSymbols_.end(), pred), elfSymbols_.end()); + elfSymbols_.shrink_to_fit(); + DFXLOGU("GetElfSymbols, size: %{public}zu", elfSymbols_.size()); + return elfSymbols_; } -const std::set& DfxElf::GetFuncSymbols() +const std::vector& DfxElf::GetFuncSymbols() { - if (!IsValid() || !funcSymbols_.empty()) { + if (!funcSymbols_.empty()) { return funcSymbols_; } - if (IsMiniDebugInfoValid()) { - funcSymbols_ = miniDebugInfo_->elfParse_->GetFuncSymbols(); - DFXLOGU("Get MiniDebugInfo FuncSymbols, size: %{public}zu", funcSymbols_.size()); + funcSymbols_ = elfParse_->GetElfSymbols(true); +#if defined(ENABLE_MINIDEBUGINFO) + if (IsEmbeddedElfValid()) { + auto symbols = embeddedElf_->elfParse_->GetElfSymbols(true); + DFXLOGU("Get EmbeddedElf FuncSymbols, size: %{public}zu", symbols.size()); + funcSymbols_.insert(funcSymbols_.end(), symbols.begin(), symbols.end()); } - const auto &symbols = elfParse_->GetFuncSymbols(); - funcSymbols_.insert(symbols.begin(), symbols.end()); +#endif + std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { + return sym1.value < sym2.value; + }); + auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; + funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end()); + funcSymbols_.shrink_to_fit(); DFXLOGU("GetFuncSymbols, size: %{public}zu", funcSymbols_.size()); return funcSymbols_; } @@ -336,47 +600,62 @@ bool DfxElf::GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol) if (FindFuncSymbol(addr, funcSymbols_, elfSymbol)) { return true; } - bool findSymbol = elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); - if (!findSymbol && IsMiniDebugInfoValid()) { - findSymbol = miniDebugInfo_->elfParse_->GetFuncSymbolByAddr(addr, elfSymbol); + bool findSymbol = false; +#if defined(ENABLE_MINIDEBUGINFO) + if (IsEmbeddedElfValid() && + embeddedElf_->elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) { + funcSymbols_.emplace_back(elfSymbol); + findSymbol = true; + } +#endif + + if (!findSymbol && elfParse_->GetElfSymbolByAddr(addr, elfSymbol)) { + funcSymbols_.emplace_back(elfSymbol); + findSymbol = true; } if (findSymbol) { - funcSymbols_.emplace(elfSymbol); + std::sort(funcSymbols_.begin(), funcSymbols_.end(), [](const ElfSymbol& sym1, const ElfSymbol& sym2) { + return sym1.value < sym2.value; + }); + auto pred = [](ElfSymbol a, ElfSymbol b) { return a.value == b.value; }; + funcSymbols_.erase(std::unique(funcSymbols_.begin(), funcSymbols_.end(), pred), funcSymbols_.end()); + funcSymbols_.shrink_to_fit(); DFXLOGU("GetFuncInfoLazily, size: %{public}zu", funcSymbols_.size()); + return true; } - return findSymbol; + return false; } bool DfxElf::GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol) { - if (!IsValid()) { - return false; - } if (UnwinderConfig::GetEnableLoadSymbolLazily()) { return GetFuncInfoLazily(addr, elfSymbol); } - const auto &symbols = GetFuncSymbols(); + auto symbols = GetFuncSymbols(); return FindFuncSymbol(addr, symbols, elfSymbol); } -bool DfxElf::FindFuncSymbol(uint64_t addr, const std::set& symbols, ElfSymbol& elfSymbol) +bool DfxElf::FindFuncSymbol(uint64_t addr, const std::vector& symbols, ElfSymbol& elfSymbol) { DFX_TRACE_SCOPED_DLSYM("FindFuncSymbol"); if (symbols.empty()) { return false; } - // Find the first position that is not less than value - ElfSymbol tmpSym; - tmpSym.value = addr; - auto next = symbols.upper_bound(tmpSym); - if (next != symbols.begin()) { - next--; - } - if (next->value <= addr && addr < (next->value + next->size)) { - elfSymbol = *next; - return true; + size_t begin = 0; + size_t end = symbols.size(); + while (begin < end) { + size_t mid = begin + (end - begin) / 2; + const auto& symbol = symbols[mid]; + if (addr < symbol.value) { + end = mid; + } else if (addr < (symbol.value + symbol.size)) { + elfSymbol = symbol; + return true; + } else { + begin = mid + 1; + } } return false; } @@ -415,7 +694,9 @@ bool DfxElf::FillUnwindTableByEhhdrLocal(struct DwarfEhFrameHdr* hdr, struct Unw uintptr_t ptr = (uintptr_t)(&(hdr->ehFrame)); DFXLOGU("[%{public}d]: hdr: %{public}" PRIx64 ", ehFrame: %{public}" PRIx64 "", __LINE__, (uint64_t)hdr, (uint64_t)ptr); - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); DFXLOGU("[%{public}d]: gp: %{public}" PRIx64 ", ehFramePtrEnc: %{public}x, fdeCountEnc: %{public}x", __LINE__, (uint64_t)uti->gp, hdr->ehFramePtrEnc, hdr->fdeCountEnc); memory->SetDataOffset(uti->gp); @@ -583,8 +864,8 @@ bool DfxElf::FindSection(struct dl_phdr_info* info, const std::string secName, S if (strlen(file) == 0) { file = PROC_SELF_EXE_PATH; } - RegularElfFactory elfFactory(file); - auto elf = elfFactory.Create(); + + auto elf = Create(file); if (elf == nullptr) { return false; } @@ -745,5 +1026,24 @@ bool DfxElf::IsValidElf(const void* ptr, size_t size) } return true; } + +size_t DfxElf::GetElfSize(const void* ptr) +{ + if (!IsValidElf(ptr, SELFMAG)) { + return 0; + } + + const uint8_t* data = static_cast(ptr); + uint8_t classType = data[EI_CLASS]; + if (classType == ELFCLASS32) { + const Elf32_Ehdr* ehdr = reinterpret_cast(data); + return static_cast(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); + } else if (classType == ELFCLASS64) { + const Elf64_Ehdr* ehdr = reinterpret_cast(data); + return static_cast(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); + } + DFXLOGW("classType(%{public}d) error", classType); + return 0; +} } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_elf_parser.cpp b/interfaces/innerkits/unwinder/dfx_elf_parser.cpp similarity index 75% rename from interfaces/innerkits/unwinder/src/elf/dfx_elf_parser.cpp rename to interfaces/innerkits/unwinder/dfx_elf_parser.cpp index 58ef81a0d..4b54923c8 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_elf_parser.cpp +++ b/interfaces/innerkits/unwinder/dfx_elf_parser.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021-2025 Huawei Device Co., Ltd. + * Copyright (c) 2021-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -45,7 +45,7 @@ namespace { #define LOG_TAG "DfxElfParser" } -bool ElfParser::Read(uintptr_t pos, void *buf, size_t size) +bool ElfParser::Read(uintptr_t pos, void* buf, size_t size) { if (mmap_->Read(pos, buf, size) == size) { return true; @@ -170,9 +170,9 @@ bool ElfParser::ParseProgramHeaders(const EhdrType& ehdr) return true; } -const GnuDebugDataHdr& ElfParser::GetGnuDebugDataHdr() const +std::shared_ptr ElfParser::GetMiniDebugInfo() { - return gnuDebugDataHdr_; + return minidebugInfo_; } template @@ -195,9 +195,9 @@ bool ElfParser::ExtractSectionHeadersInfo(const EhdrType& ehdr, ShdrType& shdr) } if (shdr.sh_size != 0 && secName == GNU_DEBUGDATA) { - gnuDebugDataHdr_.address = reinterpret_cast(shdr.sh_offset + - static_cast(mmap_->Get())); - gnuDebugDataHdr_.size = static_cast(shdr.sh_size); + minidebugInfo_ = std::make_shared(); + minidebugInfo_->offset = static_cast(shdr.sh_offset); + minidebugInfo_->size = static_cast(shdr.sh_size); } ShdrInfo shdrInfo; @@ -255,7 +255,7 @@ bool ElfParser::ParseSectionHeaders(const EhdrType& ehdr) if (!ExtractSectionHeadersInfo(ehdr, shdr)) { return false; } - + return true; } @@ -312,18 +312,18 @@ bool ElfParser::IsFunc(const SymType sym) } template -bool ElfParser::ParseFuncSymbols() +bool ElfParser::ParseElfSymbols(bool isFunc) { if (symShdrs_.empty()) { return false; } - funcSymbols_.clear(); + elfSymbols_.clear(); for (const auto& iter : symShdrs_) { const auto& shdr = iter; - ParseFuncSymbols(shdr); + ParseElfSymbols(shdr, isFunc); } - return (funcSymbols_.size() > 0); + return (elfSymbols_.size() > 0); } template @@ -340,7 +340,7 @@ bool ElfParser::ReadSymType(const ElfShdr& shdr, const uint32_t idx, SymType& sy } template -bool ElfParser::ParseFuncSymbols(const ElfShdr& shdr) +bool ElfParser::ParseElfSymbols(ElfShdr shdr, bool isFunc) { ShdrInfo linkShdrInfo; if (!GetSectionInfo(linkShdrInfo, shdr.link)) { @@ -354,20 +354,20 @@ bool ElfParser::ParseFuncSymbols(const ElfShdr& shdr) continue; } ElfSymbol elfSymbol; - if (!ParseFuncSymbolName(linkShdrInfo, sym, elfSymbol.nameStr)) { + if (isFunc && (!ParseElfSymbolName(linkShdrInfo, sym, elfSymbol.nameStr))) { continue; } elfSymbol.value = static_cast(sym.st_value); elfSymbol.size = static_cast(sym.st_size); elfSymbol.name = static_cast(sym.st_name); - funcSymbols_.emplace(elfSymbol); + elfSymbols_.emplace_back(elfSymbol); } - DFXLOGU("elfSymbols.size: %{public}" PRIuPTR "", funcSymbols_.size()); + DFXLOGU("elfSymbols.size: %{public}" PRIuPTR "", elfSymbols_.size()); return true; } template -bool ElfParser::ParseFuncSymbolName(const ShdrInfo& linkShdr, SymType sym, std::string& nameStr) +bool ElfParser::ParseElfSymbolName(ShdrInfo linkShdr, SymType sym, std::string& nameStr) { if (!IsFunc(sym) || (static_cast(sym.st_name) >= linkShdr.size) || mmap_->Get() == nullptr) { return false; @@ -378,7 +378,7 @@ bool ElfParser::ParseFuncSymbolName(const ShdrInfo& linkShdr, SymType sym, std:: } template -bool ElfParser::ParseFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) +bool ElfParser::ParseElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) { if (symShdrs_.empty()) { return false; @@ -398,7 +398,7 @@ bool ElfParser::ParseFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) } if ((sym.st_value <= addr) && (addr < (sym.st_value + sym.st_size)) && - ParseFuncSymbolName(linkShdrInfo, sym, elfSymbol.nameStr)) { + ParseElfSymbolName(linkShdrInfo, sym, elfSymbol.nameStr)) { elfSymbol.value = static_cast(sym.st_value); elfSymbol.size = static_cast(sym.st_size); elfSymbol.name = static_cast(sym.st_name); @@ -477,94 +477,6 @@ bool ElfParser::GetSectionData(unsigned char* buf, uint64_t size, std::string se return false; } -std::string ElfParser::GetBuildId() -{ - ShdrInfo shdr; - std::string buildId = ""; - if ((GetSectionInfo(shdr, NOTE_GNU_BUILD_ID) || GetSectionInfo(shdr, NOTES)) && mmap_->Get() != nullptr) { - std::string buildIdHex = ParseHexBuildId((uint64_t)((char *)mmap_->Get() + shdr.offset), shdr.size); - if (!buildIdHex.empty()) { - buildId = ToReadableBuildId(buildIdHex); - DFXLOGU("Elf buildId: %{public}s", buildId.c_str()); - } - } - return buildId; -} - -std::string ElfParser::ParseHexBuildId(uint64_t noteAddr, uint64_t noteSize) -{ - uint64_t tmp; - if (__builtin_add_overflow(noteAddr, noteSize, &tmp)) { - DFXLOGE("noteAddr overflow"); - return ""; - } - uint64_t offset = 0; - while (offset < noteSize) { - ElfW(Nhdr) nhdr; - if (noteSize - offset < sizeof(nhdr)) { - return ""; - } - uint64_t ptr = noteAddr + offset; - if (memcpy_s(&nhdr, sizeof(nhdr), reinterpret_cast(ptr), sizeof(nhdr)) != 0) { - DFXLOGE("memcpy_s nhdr failed"); - return ""; - } - offset += sizeof(nhdr); - if (noteSize - offset < nhdr.n_namesz) { - return ""; - } - if (nhdr.n_namesz > 0) { - std::string name(nhdr.n_namesz, '\0'); - ptr = noteAddr + offset; - if (memcpy_s(&(name[0]), nhdr.n_namesz, reinterpret_cast(ptr), nhdr.n_namesz) != 0) { - DFXLOGE("memcpy_s note name failed"); - return ""; - } - // Trim trailing \0 as GNU is stored as a C string in the ELF file. - if (name.size() != 0 && name.back() == '\0') { - name.resize(name.size() - 1); - } - // Align nhdr.n_namesz to next power multiple of 4. See man 5 elf. - offset += (nhdr.n_namesz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary - if (name != "GNU" || nhdr.n_type != NT_GNU_BUILD_ID) { - offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary - continue; - } - if (noteSize - offset < nhdr.n_descsz || nhdr.n_descsz == 0) { - return ""; - } - std::string buildIdRaw(nhdr.n_descsz, '\0'); - ptr = noteAddr + offset; - if (memcpy_s(&buildIdRaw[0], nhdr.n_descsz, reinterpret_cast(ptr), nhdr.n_descsz) != 0) { - return ""; - } - return buildIdRaw; - } - // Align hdr.n_descsz to next power multiple of 4. See man 5 elf. - offset += (nhdr.n_descsz + 3) & ~3; // 3 : Align the offset to a 4-byte boundary - } - return ""; -} - -std::string ElfParser::ToReadableBuildId(const std::string& buildIdHex) -{ - if (buildIdHex.empty()) { - return ""; - } - const char hexTable[] = "0123456789abcdef"; - const int hexLength = 16; - const int hexExpandParam = 2; - const size_t len = buildIdHex.length(); - std::string buildId(len * hexExpandParam, '\0'); - - for (size_t i = 0; i < len; i++) { - unsigned int n = buildIdHex[i]; - buildId[i * hexExpandParam] = hexTable[(n >> 4) % hexLength]; // 4 : higher 4 bit of uint8 - buildId[i * hexExpandParam + 1] = hexTable[n % hexLength]; - } - return buildId; -} - bool ElfParser32::InitHeaders() { return ParseAllHeaders(); @@ -607,26 +519,26 @@ uintptr_t ElfParser64::GetGlobalPointer() return dtPltGotAddr_; } -const std::set& ElfParser32::GetFuncSymbols() +const std::vector& ElfParser32::GetElfSymbols(bool isFunc) { - ParseFuncSymbols(); - return funcSymbols_; + ParseElfSymbols(isFunc); + return elfSymbols_; } -const std::set& ElfParser64::GetFuncSymbols() +const std::vector& ElfParser64::GetElfSymbols(bool isFunc) { - ParseFuncSymbols(); - return funcSymbols_; + ParseElfSymbols(isFunc); + return elfSymbols_; } -bool ElfParser32::GetFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) +bool ElfParser32::GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) { - return ParseFuncSymbolByAddr(addr, elfSymbol); + return ParseElfSymbolByAddr(addr, elfSymbol); } -bool ElfParser64::GetFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) +bool ElfParser64::GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) { - return ParseFuncSymbolByAddr(addr, elfSymbol); + return ParseElfSymbolByAddr(addr, elfSymbol); } } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/utils/dfx_frame_formatter.cpp b/interfaces/innerkits/unwinder/dfx_frame_formatter.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/dfx_frame_formatter.cpp rename to interfaces/innerkits/unwinder/dfx_frame_formatter.cpp diff --git a/interfaces/innerkits/unwinder/src/ark/dfx_hap.cpp b/interfaces/innerkits/unwinder/dfx_hap.cpp similarity index 97% rename from interfaces/innerkits/unwinder/src/ark/dfx_hap.cpp rename to interfaces/innerkits/unwinder/dfx_hap.cpp index a5f9f3559..caf997b13 100644 --- a/interfaces/innerkits/unwinder/src/ark/dfx_hap.cpp +++ b/interfaces/innerkits/unwinder/dfx_hap.cpp @@ -19,7 +19,6 @@ #include "dfx_log.h" #include "dfx_maps.h" #include "dfx_memory.h" -#include "dfx_util.h" #include "string_util.h" namespace OHOS { @@ -153,7 +152,7 @@ bool DfxHap::ParseHapMemData(const pid_t pid, std::shared_ptr map) abcLoadOffset_ = map->offset; abcDataSize_ = map->end - map->begin; abcDataPtr_ = std::make_unique(abcDataSize_); - auto size = ReadProcMemByPid(pid, map->begin, abcDataPtr_.get(), abcDataSize_); + auto size = DfxMemory::ReadProcMemByPid(pid, map->begin, abcDataPtr_.get(), abcDataSize_); if (size != abcDataSize_) { DFXLOGW("ReadProcMemByPid(%{public}d) return size(%{public}zu), real size(%{public}zu)", pid, size, abcDataSize_); diff --git a/interfaces/innerkits/unwinder/src/utils/dfx_instr_statistic.cpp b/interfaces/innerkits/unwinder/dfx_instr_statistic.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/dfx_instr_statistic.cpp rename to interfaces/innerkits/unwinder/dfx_instr_statistic.cpp diff --git a/interfaces/innerkits/unwinder/src/utils/dfx_instructions.cpp b/interfaces/innerkits/unwinder/dfx_instructions.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/dfx_instructions.cpp rename to interfaces/innerkits/unwinder/dfx_instructions.cpp diff --git a/interfaces/innerkits/unwinder/src/maps/dfx_map.cpp b/interfaces/innerkits/unwinder/dfx_map.cpp similarity index 93% rename from interfaces/innerkits/unwinder/src/maps/dfx_map.cpp rename to interfaces/innerkits/unwinder/dfx_map.cpp index ddff038a2..8003e1346 100644 --- a/interfaces/innerkits/unwinder/src/maps/dfx_map.cpp +++ b/interfaces/innerkits/unwinder/dfx_map.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -28,7 +28,6 @@ #include "dfx_hap.h" #include "dfx_log.h" #include "dfx_util.h" -#include "elf_factory_selector.h" #include "string_util.h" namespace OHOS { @@ -350,14 +349,23 @@ const std::shared_ptr DfxMap::GetElf(pid_t pid) DFXLOGE("Invalid map, name empty."); return nullptr; } - auto elfFactory = ElfFactorySelector::Select(*this, pid); - if (elfFactory != nullptr) { - elf = elfFactory->Create(); - } - if (elf != nullptr && !elf->IsValid()) { - elf = nullptr; - } DFXLOGU("GetElf name: %{public}s", name.c_str()); + if (EndsWith(name, ".hap")) { + elf = DfxElf::CreateFromHap(name, prevMap, offset); + } else if (IsVdsoMap()) { +#if is_ohos && !is_mingw + size_t size = end - begin; + shmmData = std::make_shared>(size); + size_t byte = DfxMemory::ReadProcMemByPid(pid, begin, shmmData->data(), size); + if (byte != size) { + DFXLOGE("Failed to read shmm data"); + return nullptr; + } + elf = std::make_shared(shmmData->data(), byte); +#endif + } else { + elf = DfxElf::Create(name); + } } return elf; } diff --git a/interfaces/innerkits/unwinder/src/maps/dfx_maps.cpp b/interfaces/innerkits/unwinder/dfx_maps.cpp similarity index 99% rename from interfaces/innerkits/unwinder/src/maps/dfx_maps.cpp rename to interfaces/innerkits/unwinder/dfx_maps.cpp index 64950b62d..7352e59a5 100644 --- a/interfaces/innerkits/unwinder/src/maps/dfx_maps.cpp +++ b/interfaces/innerkits/unwinder/dfx_maps.cpp @@ -18,7 +18,6 @@ #include #include #include -#include #if is_mingw #include "dfx_nonlinux_define.h" #else @@ -26,6 +25,7 @@ #endif #include "dfx_define.h" +#include "dfx_elf.h" #include "dfx_log.h" #include "dfx_trace_dlsym.h" #include "string_printf.h" diff --git a/interfaces/innerkits/unwinder/src/memory/dfx_memory.cpp b/interfaces/innerkits/unwinder/dfx_memory.cpp similarity index 86% rename from interfaces/innerkits/unwinder/src/memory/dfx_memory.cpp rename to interfaces/innerkits/unwinder/dfx_memory.cpp index e2e2785ed..5bb75e844 100644 --- a/interfaces/innerkits/unwinder/src/memory/dfx_memory.cpp +++ b/interfaces/innerkits/unwinder/dfx_memory.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,10 +16,12 @@ #include "dfx_memory.h" #include #include +#if is_ohos && !is_mingw +#include +#endif #include "dfx_define.h" #include "dfx_errors.h" #include "dfx_log.h" -#include "dfx_util.h" #include "dwarf_define.h" namespace OHOS { @@ -36,32 +38,6 @@ static const int FOUR_BYTE_SIZE = 4; static const int EIGHT_BYTE_SIZE = 8; } -#if is_ohos && ! is_mingw -DfxMemory::DfxMemory(const UnwindType& unwindType, std::shared_ptr accessors) -{ - switch (unwindType) { - case UNWIND_TYPE_LOCAL: - acc_ = std::make_shared(); - break; - case UNWIND_TYPE_REMOTE: - acc_ = std::make_shared(); - break; - case UNWIND_TYPE_CUSTOMIZE: - if (accessors != nullptr) { - acc_ = std::make_shared(accessors); - } - break; - case UNWIND_TYPE_CUSTOMIZE_LOCAL: - if (accessors != nullptr) { - acc_ = std::make_shared(accessors); - } - break; - default: - break; - } -} -#endif - bool DfxMemory::ReadReg(int regIdx, uintptr_t* val) { if (acc_ != nullptr && acc_->AccessReg(regIdx, val, ctx_) == UNW_ERROR_NONE) { @@ -319,28 +295,50 @@ uintptr_t DfxMemory::ReadEncodedValue(uintptr_t& addr, uint8_t encoding) } return val; } - #if is_ohos && !is_mingw size_t DfxMemory::ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size) { - return OHOS::HiviewDFX::ReadProcMemByPid(pid, addr, data, size); -} -#endif + constexpr size_t maxSize = 64; + struct iovec RemoteIovs[maxSize]; -int DfxMemory::GetMapByPc(uintptr_t pc, std::shared_ptr& map) const -{ - if (acc_ == nullptr) { - return UNW_ERROR_INVALID_MEMORY; - } - return acc_->GetMapByPc(pc, map, ctx_); -} + uint64_t cur = addr; + size_t totalRead = 0; + struct iovec dataIov = { + .iov_base = &reinterpret_cast(data)[totalRead], + .iov_len = size, + }; + size_t iovecsIndex = 0; + while (size > 0) { + if (cur >= UINTPTR_MAX) { + return totalRead; + } + RemoteIovs[iovecsIndex].iov_base = reinterpret_cast(cur); + uintptr_t misalign = cur & static_cast(getpagesize() - 1); + size_t iovLen = std::min(getpagesize() - misalign, size); -int DfxMemory::FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti) const -{ - if (acc_ == nullptr) { - return UNW_ERROR_INVALID_MEMORY; + size -= iovLen; + if (__builtin_add_overflow(cur, iovLen, &cur)) { + return totalRead; + } + + RemoteIovs[iovecsIndex].iov_len = iovLen; + ++iovecsIndex; + if (iovecsIndex >= maxSize || size <= 0) { + ssize_t count = process_vm_readv(pid, &dataIov, 1, RemoteIovs, iovecsIndex, 0); + if (count == -1) { + return totalRead; + } + totalRead += static_cast(count); + if (iovecsIndex >= maxSize) { + iovecsIndex -= maxSize; + } + dataIov.iov_base = &reinterpret_cast(data)[totalRead]; + dataIov.iov_len = size; + } } - return acc_->FindUnwindTable(pc, uti, ctx_); + + return totalRead; } +#endif } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_mmap.cpp b/interfaces/innerkits/unwinder/dfx_mmap.cpp similarity index 90% rename from interfaces/innerkits/unwinder/src/elf/dfx_mmap.cpp rename to interfaces/innerkits/unwinder/dfx_mmap.cpp index 987632637..8e7f7f70c 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_mmap.cpp +++ b/interfaces/innerkits/unwinder/dfx_mmap.cpp @@ -44,22 +44,20 @@ bool DfxMmap::Init(const int fd, const size_t size, const off_t offset) size_ = 0; return false; } - needUnmap_ = true; size_ = size; DFXLOGD("mmap size %{public}zu", size_); return true; } -bool DfxMmap::Init(std::vector&& data) +bool DfxMmap::Init(uint8_t *decompressedData, size_t size) { - if (data.size() == 0) { + if (!decompressedData || size == 0) { return false; } - data_ = std::move(data); - mmap_ = data_.data(); - size_ = data_.size(); - needUnmap_ = false; + // this pointer was managed by shared_ptr will not occur double free issue. + mmap_ = decompressedData; + size_ = size; return true; } diff --git a/interfaces/innerkits/unwinder/src/utils/dfx_ptrace.cpp b/interfaces/innerkits/unwinder/dfx_ptrace.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/dfx_ptrace.cpp rename to interfaces/innerkits/unwinder/dfx_ptrace.cpp diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs.cpp b/interfaces/innerkits/unwinder/dfx_regs.cpp similarity index 94% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs.cpp rename to interfaces/innerkits/unwinder/dfx_regs.cpp index 5b81d156a..9f6f43b2a 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs.cpp @@ -68,18 +68,12 @@ std::shared_ptr DfxRegs::CreateFromRegs(const UnwindMode mode, const ui DFXLOGE("The number of long groups is too short"); return dfxregs; } - switch (mode) { - case UnwindMode::DWARF_UNWIND: - dfxregs->SetRegsData(regs, REG_LAST); - break; - case UnwindMode::FRAMEPOINTER_UNWIND: - dfxregs->SetFromFpMiniRegs(regs, FP_MINI_REGS_SIZE); - break; - case UnwindMode::MINIMAL_UNWIND: - dfxregs->SetFromQutMiniRegs(regs, QUT_MINI_REGS_SIZE); - break; - default: - break; + if (mode == UnwindMode::DWARF_UNWIND) { + dfxregs->SetRegsData(regs, REG_LAST); + } else if (mode == UnwindMode::FRAMEPOINTER_UNWIND) { + dfxregs->SetFromFpMiniRegs(regs, FP_MINI_REGS_SIZE); + } else if (mode == UnwindMode::MINIMAL_UNWIND) { + dfxregs->SetFromQutMiniRegs(regs, QUT_MINI_REGS_SIZE); } return dfxregs; } diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs_arm.cpp b/interfaces/innerkits/unwinder/dfx_regs_arm.cpp similarity index 99% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs_arm.cpp rename to interfaces/innerkits/unwinder/dfx_regs_arm.cpp index fb9eb809c..caf82de24 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs_arm.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs_arm.cpp @@ -19,6 +19,7 @@ #include #include "dfx_define.h" #include "dfx_log.h" +#include "dfx_elf.h" #include "string_printf.h" #define ARM_NR_sigreturn 119 diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs_arm64.cpp b/interfaces/innerkits/unwinder/dfx_regs_arm64.cpp similarity index 61% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs_arm64.cpp rename to interfaces/innerkits/unwinder/dfx_regs_arm64.cpp index 39e57b031..1432ddb64 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs_arm64.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs_arm64.cpp @@ -16,11 +16,13 @@ #if defined(__aarch64__) #include "dfx_regs.h" +#include #include #include #include #include #include "dfx_define.h" +#include "dfx_elf.h" #include "dfx_log.h" #include "string_printf.h" @@ -31,11 +33,39 @@ void DfxRegsArm64::SetFromUcontext(const ucontext_t &context) if (regsData_.size() < REG_LAST) { return; } - for (uint16_t index = REG_AARCH64_X0; index <= REG_AARCH64_X30; index++) { - regsData_[index] = static_cast(context.uc_mcontext.regs[index]); - } - regsData_[REG_AARCH64_X31] = static_cast(context.uc_mcontext.sp); // sp register - regsData_[REG_AARCH64_PC] = static_cast(context.uc_mcontext.pc); // pc register + regsData_[REG_AARCH64_X0] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X0]); + regsData_[REG_AARCH64_X1] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X1]); + regsData_[REG_AARCH64_X2] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X2]); + regsData_[REG_AARCH64_X3] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X3]); + regsData_[REG_AARCH64_X4] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X4]); + regsData_[REG_AARCH64_X5] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X5]); + regsData_[REG_AARCH64_X6] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X6]); + regsData_[REG_AARCH64_X7] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X7]); + regsData_[REG_AARCH64_X8] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X8]); + regsData_[REG_AARCH64_X9] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X9]); + regsData_[REG_AARCH64_X10] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X10]); + regsData_[REG_AARCH64_X11] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X11]); + regsData_[REG_AARCH64_X12] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X12]); + regsData_[REG_AARCH64_X13] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X13]); + regsData_[REG_AARCH64_X14] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X14]); + regsData_[REG_AARCH64_X15] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X15]); + regsData_[REG_AARCH64_X16] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X16]); + regsData_[REG_AARCH64_X17] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X17]); + regsData_[REG_AARCH64_X18] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X18]); + regsData_[REG_AARCH64_X19] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X19]); + regsData_[REG_AARCH64_X20] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X20]); + regsData_[REG_AARCH64_X21] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X21]); + regsData_[REG_AARCH64_X22] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X22]); + regsData_[REG_AARCH64_X23] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X23]); + regsData_[REG_AARCH64_X24] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X24]); + regsData_[REG_AARCH64_X25] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X25]); + regsData_[REG_AARCH64_X26] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X26]); + regsData_[REG_AARCH64_X27] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X27]); + regsData_[REG_AARCH64_X28] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X28]); + regsData_[REG_AARCH64_X29] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X29]); + regsData_[REG_AARCH64_X30] = static_cast(context.uc_mcontext.regs[REG_AARCH64_X30]); + regsData_[REG_AARCH64_X31] = static_cast(context.uc_mcontext.sp); + regsData_[REG_AARCH64_PC] = static_cast(context.uc_mcontext.pc); } void DfxRegsArm64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size) diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs_loongarch64.cpp b/interfaces/innerkits/unwinder/dfx_regs_loongarch64.cpp similarity index 60% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs_loongarch64.cpp rename to interfaces/innerkits/unwinder/dfx_regs_loongarch64.cpp index 6bbd28368..9dae682d2 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs_loongarch64.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs_loongarch64.cpp @@ -16,25 +16,56 @@ #if defined(__loongarch_lp64) #include "dfx_regs.h" +#include #include #include #include #include #include "dfx_define.h" #include "dfx_log.h" +#include "dfx_elf.h" #include "string_printf.h" namespace OHOS { namespace HiviewDFX { void DfxRegsLoongArch64::SetFromUcontext(const ucontext_t &context) { - if (regsData_.size() < REG_LAST) { - return; - } - for (uint16_t index = REG_LOONGARCH64_R0; index <= REG_LOONGARCH64_R31; index++) { - regsData_[index] = static_cast(context.uc_mcontext.__gregs[index]); - } - regsData_[REG_LOONGARCH64_PC] = (static_cast(context.uc_mcontext.__pc)); // 32:pc + std::vector regs; + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R0])); // 0:r0 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R1])); // 1:r1 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R2])); // 2:r2 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R3])); // 3:r3 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R4])); // 4:r4 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R5])); // 5:r5 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R6])); // 6:r6 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R7])); // 7:r7 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R8])); // 8:r8 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R9])); // 9:r9 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R10])); // 10:r10 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R11])); // 11:r11 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R12])); // 12:r12 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R13])); // 13:r13 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R14])); // 14:r14 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R15])); // 15:r15 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R16])); // 16:r16 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R17])); // 17:r17 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R18])); // 18:r18 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R19])); // 19:r19 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R20])); // 20:r20 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R21])); // 21:r21 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R22])); // 22:r22 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R23])); // 23:r23 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R24])); // 24:r24 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R25])); // 25:r25 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R26])); // 26:r26 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R27])); // 27:r27 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R28])); // 28:r28 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R29])); // 29:r29 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R30])); // 30:r30 + regs.emplace_back(uintptr_t(context.uc_mcontext.__gregs[REG_LOONGARCH64_R31])); // 31:r31 + regs.emplace_back(uintptr_t(context.uc_mcontext.__pc)); // 32:pc + + SetRegsData(regs); } void DfxRegsLoongArch64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size) diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs_riscv64.cpp b/interfaces/innerkits/unwinder/dfx_regs_riscv64.cpp similarity index 60% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs_riscv64.cpp rename to interfaces/innerkits/unwinder/dfx_regs_riscv64.cpp index 41c3a8926..2ab1af7ce 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs_riscv64.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs_riscv64.cpp @@ -16,6 +16,7 @@ #if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 #include "dfx_regs.h" +#include #include #include #include @@ -23,6 +24,7 @@ #include "dfx_define.h" #include "dfx_log.h" +#include "dfx_elf.h" #include "string_printf.h" namespace OHOS { @@ -32,9 +34,38 @@ void DfxRegsRiscv64::SetFromUcontext(const ucontext_t &context) if (regsData_.size() < REG_LAST) { return; } - for (uint16_t index = REG_RISCV64_X0; index <= REG_RISCV64_X31; index++) { - regsData_[index] = static_cast(context.uc_mcontext.__gregs[index]); - } + regsData_[REG_RISCV64_X0] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X0]); + regsData_[REG_RISCV64_X1] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X1]); + regsData_[REG_RISCV64_X2] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X2]); + regsData_[REG_RISCV64_X3] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X3]); + regsData_[REG_RISCV64_X4] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X4]); + regsData_[REG_RISCV64_X5] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X5]); + regsData_[REG_RISCV64_X6] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X6]); + regsData_[REG_RISCV64_X7] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X7]); + regsData_[REG_RISCV64_X8] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X8]); + regsData_[REG_RISCV64_X9] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X9]); + regsData_[REG_RISCV64_X10] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X10]); + regsData_[REG_RISCV64_X11] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X11]); + regsData_[REG_RISCV64_X12] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X12]); + regsData_[REG_RISCV64_X13] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X13]); + regsData_[REG_RISCV64_X14] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X14]); + regsData_[REG_RISCV64_X15] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X15]); + regsData_[REG_RISCV64_X16] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X16]); + regsData_[REG_RISCV64_X17] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X17]); + regsData_[REG_RISCV64_X18] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X18]); + regsData_[REG_RISCV64_X19] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X19]); + regsData_[REG_RISCV64_X20] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X20]); + regsData_[REG_RISCV64_X21] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X21]); + regsData_[REG_RISCV64_X22] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X22]); + regsData_[REG_RISCV64_X23] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X23]); + regsData_[REG_RISCV64_X24] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X24]); + regsData_[REG_RISCV64_X25] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X25]); + regsData_[REG_RISCV64_X26] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X26]); + regsData_[REG_RISCV64_X27] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X27]); + regsData_[REG_RISCV64_X28] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X28]); + regsData_[REG_RISCV64_X29] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X29]); + regsData_[REG_RISCV64_X30] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X30]); + regsData_[REG_RISCV64_X31] = static_cast(context.uc_mcontext.__gregs[REG_RISCV64_X31]); } void DfxRegsRiscv64::SetFromFpMiniRegs(const uintptr_t* regs, const size_t size) diff --git a/interfaces/innerkits/unwinder/src/registers/dfx_regs_x86_64.cpp b/interfaces/innerkits/unwinder/dfx_regs_x86_64.cpp similarity index 99% rename from interfaces/innerkits/unwinder/src/registers/dfx_regs_x86_64.cpp rename to interfaces/innerkits/unwinder/dfx_regs_x86_64.cpp index f21f9a6bc..b66f2fda8 100644 --- a/interfaces/innerkits/unwinder/src/registers/dfx_regs_x86_64.cpp +++ b/interfaces/innerkits/unwinder/dfx_regs_x86_64.cpp @@ -24,6 +24,7 @@ #include "dfx_define.h" #include "dfx_log.h" +#include "dfx_elf.h" #include "string_printf.h" namespace OHOS { diff --git a/common/dfxutil/dfx_signal.cpp b/interfaces/innerkits/unwinder/dfx_signal.cpp similarity index 99% rename from common/dfxutil/dfx_signal.cpp rename to interfaces/innerkits/unwinder/dfx_signal.cpp index 233365ea0..bc3ca5b45 100644 --- a/common/dfxutil/dfx_signal.cpp +++ b/interfaces/innerkits/unwinder/dfx_signal.cpp @@ -16,6 +16,7 @@ #include "dfx_signal.h" #include +#include #include #include "dfx_define.h" #include "dfx_log.h" diff --git a/interfaces/innerkits/unwinder/src/elf/dfx_symbols.cpp b/interfaces/innerkits/unwinder/dfx_symbols.cpp similarity index 98% rename from interfaces/innerkits/unwinder/src/elf/dfx_symbols.cpp rename to interfaces/innerkits/unwinder/dfx_symbols.cpp index fc459a578..11073d47f 100644 --- a/interfaces/innerkits/unwinder/src/elf/dfx_symbols.cpp +++ b/interfaces/innerkits/unwinder/dfx_symbols.cpp @@ -119,12 +119,12 @@ bool DfxSymbols::ParseSymbols(std::vector& symbols, std::shared_ptrGetFuncSymbols(); + auto elfSymbols = elf->GetFuncSymbols(); std::string symbolsPath = filePath; if (elf->GetBaseOffset() != 0) { symbolsPath += ("!" + elf->GetElfName()); } - for (const auto &elfSymbol : elfSymbols) { + for (auto elfSymbol : elfSymbols) { symbols.emplace_back(elfSymbol.value, elfSymbol.size, elfSymbol.nameStr, Demangle(elfSymbol.nameStr), symbolsPath); } diff --git a/interfaces/innerkits/unwinder/dfx_xz_utils.cpp b/interfaces/innerkits/unwinder/dfx_xz_utils.cpp new file mode 100644 index 000000000..8fe4654e9 --- /dev/null +++ b/interfaces/innerkits/unwinder/dfx_xz_utils.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "dfx_xz_utils.h" +#include "dfx_trace_dlsym.h" +#include "7zCrc.h" +#include "Xz.h" +#include "XzCrc64.h" +#include + +namespace OHOS { +namespace HiviewDFX { + +#define EXPAND_FACTOR 2 + +static void* XzAlloc(ISzAllocPtr, size_t size) +{ + return malloc(size); +} + +static void XzFree(ISzAllocPtr, void *address) +{ + free(address); +} + +bool XzDecompress(const uint8_t *src, size_t srcLen, std::shared_ptr> out) +{ + DFX_TRACE_SCOPED_DLSYM("XzDecompress"); + ISzAlloc alloc; + CXzUnpacker state; + alloc.Alloc = XzAlloc; + alloc.Free = XzFree; + XzUnpacker_Construct(&state, &alloc); + CrcGenerateTable(); + Crc64GenerateTable(); + size_t srcOff = 0; + size_t dstOff = 0; + std::vector dst(srcLen, ' '); + ECoderStatus status = CODER_STATUS_NOT_FINISHED; + while (status == CODER_STATUS_NOT_FINISHED) { + dst.resize(dst.size() * EXPAND_FACTOR); + size_t srcRemain = srcLen - srcOff; + size_t dstRemain = dst.size() - dstOff; + int res = XzUnpacker_Code(&state, + reinterpret_cast(&dst[dstOff]), &dstRemain, + reinterpret_cast(&src[srcOff]), &srcRemain, + true, CODER_FINISH_ANY, &status); + if (res != SZ_OK) { + XzUnpacker_Free(&state); + return false; + } + srcOff += srcRemain; + dstOff += dstRemain; + } + XzUnpacker_Free(&state); + if (!XzUnpacker_IsStreamWasFinished(&state)) { + return false; + } + dst.resize(dstOff); + *out = std::move(dst); + return true; +} +} // namespace HiviewDFX +} // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_cfa.txt b/interfaces/innerkits/unwinder/dwarf_cfa.txt similarity index 100% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_cfa.txt rename to interfaces/innerkits/unwinder/dwarf_cfa.txt diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_cfa_instructions.cpp b/interfaces/innerkits/unwinder/dwarf_cfa_instructions.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_cfa_instructions.cpp rename to interfaces/innerkits/unwinder/dwarf_cfa_instructions.cpp diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_op.cpp b/interfaces/innerkits/unwinder/dwarf_op.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_op.cpp rename to interfaces/innerkits/unwinder/dwarf_op.cpp diff --git a/interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_entry_parser.cpp b/interfaces/innerkits/unwinder/dwarf_section.cpp similarity index 84% rename from interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_entry_parser.cpp rename to interfaces/innerkits/unwinder/dwarf_section.cpp index 1c5997a7e..5d2c77d11 100644 --- a/interfaces/innerkits/unwinder/src/unwind_entry_parser/dwarf_entry_parser.cpp +++ b/interfaces/innerkits/unwinder/dwarf_section.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "dwarf_entry_parser.h" +#include "dwarf_section.h" #include #include "dfx_log.h" #include "dfx_trace_dlsym.h" @@ -25,16 +25,21 @@ namespace { #undef LOG_DOMAIN #undef LOG_TAG #define LOG_DOMAIN 0xD002D11 -#define LOG_TAG "DfxDwarfEntryParser" +#define LOG_TAG "DfxDwarfSection" } -bool DwarfEntryParser::LinearSearchEntry(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei) + +DwarfSection::DwarfSection(std::shared_ptr memory) : memory_(memory) +{ + (void)memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData)); +} + +bool DwarfSection::LinearSearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei) { - DFX_TRACE_SCOPED_DLSYM("DwarfEntryParserLinearSearchEntry"); + DFX_TRACE_SCOPED_DLSYM("DwarfSectionLinearSearchEntry"); uintptr_t fdeCount = uti.tableLen; uintptr_t tableData = uti.tableData; DFXLOGU("LinearSearchEntry tableData:%{public}p, tableLen: %{public}u", (void*)tableData, (uint32_t)fdeCount); - uintptr_t i = 0; - uintptr_t ptr = tableData; + uintptr_t i = 0, ptr = tableData; FrameDescEntry fdeInfo; while (i++ < fdeCount && ptr < uti.endPc) { uintptr_t fdeAddr = ptr; @@ -52,9 +57,9 @@ bool DwarfEntryParser::LinearSearchEntry(uintptr_t pc, const UnwindTableInfo& ut return false; } -bool DwarfEntryParser::SearchEntry(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei) +bool DwarfSection::SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei) { - DFX_TRACE_SCOPED_DLSYM("DwarfEntryParserSearchEntry"); + DFX_TRACE_SCOPED_DLSYM("DwarfSectionSearchEntry"); MAYBE_UNUSED auto segbase = uti.segbase; uintptr_t fdeCount = uti.tableLen; uintptr_t tableData = uti.tableData; @@ -109,26 +114,16 @@ bool DwarfEntryParser::SearchEntry(uintptr_t pc, const UnwindTableInfo& uti, Unw return true; } -bool DwarfEntryParser::Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr rs) +bool DwarfSection::Step(uintptr_t pc, uintptr_t fdeAddr, std::shared_ptr rs) { - DFX_TRACE_SCOPED_DLSYM("DwarfEntryParserStep"); - if (memory_ == nullptr || rs == nullptr) { - DFXLOGE("memory or rs is nullptr!"); - return false; - } - struct UnwindEntryInfo uei; - if ((!uti.isLinear && !SearchEntry(pc, uti, uei)) || (uti.isLinear && !LinearSearchEntry(pc, uti, uei))) { - DFXLOGU("Failed to search unwind entry"); - return false; - } - memory_->SetDataOffset(uti.segbase); - + DFX_TRACE_SCOPED_DLSYM("DwarfSectionStep"); FrameDescEntry fdeInfo; - if (!ParseFde((uintptr_t)uei.unwindInfo, (uintptr_t)uei.unwindInfo, fdeInfo)) { + if (!ParseFde(fdeAddr, fdeAddr, fdeInfo)) { DFXLOGE("Failed to parse fde?"); - lastErrorData_.SetAddrAndCode((uintptr_t)uei.unwindInfo, UNW_ERROR_DWARF_INVALID_FDE); + lastErrorData_.SetAddrAndCode(fdeAddr, UNW_ERROR_DWARF_INVALID_FDE); return false; } + if (pc < fdeInfo.pcStart || pc >= fdeInfo.pcEnd) { DFXLOGU("pc: %{public}p, FDE start: %{public}p, end: %{public}p", (void*)pc, (void*)fdeInfo.pcStart, (void*)fdeInfo.pcEnd); @@ -143,7 +138,7 @@ bool DwarfEntryParser::Step(uintptr_t pc, const UnwindTableInfo& uti, std::share return true; } -bool DwarfEntryParser::GetCieOrFde(uintptr_t& addr, FrameDescEntry& fdeInfo) +bool DwarfSection::GetCieOrFde(uintptr_t& addr, FrameDescEntry& fdeInfo) { uintptr_t ptr = addr; bool isCieEntry = false; @@ -165,7 +160,7 @@ bool DwarfEntryParser::GetCieOrFde(uintptr_t& addr, FrameDescEntry& fdeInfo) return true; } -void DwarfEntryParser::ParseCieOrFdeHeader(uintptr_t& ptr, FrameDescEntry& fdeInfo, bool& isCieEntry) +void DwarfSection::ParseCieOrFdeHeader(uintptr_t& ptr, FrameDescEntry& fdeInfo, bool& isCieEntry) { uint32_t value32 = 0; memory_->Read(ptr, &value32, true); @@ -203,7 +198,7 @@ void DwarfEntryParser::ParseCieOrFdeHeader(uintptr_t& ptr, FrameDescEntry& fdeIn } } -bool DwarfEntryParser::ParseFde(uintptr_t fdeAddr, uintptr_t fdePtr, FrameDescEntry& fdeInfo) +bool DwarfSection::ParseFde(uintptr_t fdeAddr, uintptr_t fdePtr, FrameDescEntry& fdeInfo) { DFXLOGU("fdeAddr: %{public}" PRIx64 "", (uint64_t)fdeAddr); if (!fdeEntries_.empty()) { @@ -231,7 +226,7 @@ bool DwarfEntryParser::ParseFde(uintptr_t fdeAddr, uintptr_t fdePtr, FrameDescEn return true; } -bool DwarfEntryParser::FillInFde(uintptr_t ptr, FrameDescEntry& fdeInfo) +bool DwarfSection::FillInFde(uintptr_t ptr, FrameDescEntry& fdeInfo) { if (!ParseCie(fdeInfo.cieAddr, fdeInfo.cieAddr, fdeInfo.cie)) { DFXLOGE("Failed to parse CIE?"); @@ -268,7 +263,7 @@ bool DwarfEntryParser::FillInFde(uintptr_t ptr, FrameDescEntry& fdeInfo) return true; } -bool DwarfEntryParser::ParseCie(uintptr_t cieAddr, uintptr_t ciePtr, CommonInfoEntry& cieInfo) +bool DwarfSection::ParseCie(uintptr_t cieAddr, uintptr_t ciePtr, CommonInfoEntry& cieInfo) { DFXLOGU("cieAddr: %{public}" PRIx64 "", (uint64_t)cieAddr); if (!cieEntries_.empty()) { @@ -298,7 +293,7 @@ bool DwarfEntryParser::ParseCie(uintptr_t cieAddr, uintptr_t ciePtr, CommonInfoE return true; } -void DwarfEntryParser::ParseAugData(uintptr_t& ptr, CommonInfoEntry& cieInfo, const std::vector& augStr) +void DwarfSection::ParseAugData(uintptr_t& ptr, CommonInfoEntry& cieInfo, const std::vector& augStr) { MAYBE_UNUSED uintptr_t augSize = memory_->ReadUleb128(ptr); DFXLOGU("augSize: %{public}" PRIxPTR "", augSize); @@ -328,7 +323,7 @@ void DwarfEntryParser::ParseAugData(uintptr_t& ptr, CommonInfoEntry& cieInfo, co } } -bool DwarfEntryParser::FillInCie(uintptr_t ptr, CommonInfoEntry& cieInfo) +bool DwarfSection::FillInCie(uintptr_t ptr, CommonInfoEntry& cieInfo) { uint8_t version; memory_->Read(ptr, &version, true); @@ -381,7 +376,7 @@ bool DwarfEntryParser::FillInCie(uintptr_t ptr, CommonInfoEntry& cieInfo) } cieInfo.hasAugmentationData = true; ParseAugData(ptr, cieInfo, augStr); - + return true; } } // namespace HiviewDFX diff --git a/interfaces/innerkits/unwinder/src/registers/getcontext_x86_64.S b/interfaces/innerkits/unwinder/getcontext_x86_64.S similarity index 100% rename from interfaces/innerkits/unwinder/src/registers/getcontext_x86_64.S rename to interfaces/innerkits/unwinder/getcontext_x86_64.S diff --git a/interfaces/innerkits/unwinder/include/unwind_entry_parser_factory.h b/interfaces/innerkits/unwinder/include/arch_util.h similarity index 49% rename from interfaces/innerkits/unwinder/include/unwind_entry_parser_factory.h rename to interfaces/innerkits/unwinder/include/arch_util.h index d39cdc2b7..7c10abae5 100644 --- a/interfaces/innerkits/unwinder/include/unwind_entry_parser_factory.h +++ b/interfaces/innerkits/unwinder/include/arch_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -12,29 +12,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef UNWIND_ENTRY_PARSER_FACTORY_H -#define UNWIND_ENTRY_PARSER_FACTORY_H -#include -#include +#ifndef ARCH_UTIL_H +#define ARCH_UTIL_H + +#include +#include +#include +#include "dfx_define.h" +#include "unwind_define.h" -#include "dwarf_entry_parser.h" -#include "exidx_entry_parser.h" namespace OHOS { namespace HiviewDFX { -class UnwindEntryParserFactory { -public: - static std::shared_ptr CreateUnwindEntryParser(std::shared_ptr memory) - { - std::shared_ptr unwindEntryParser = nullptr; -#if defined(__arm__) - unwindEntryParser = std::make_shared(memory); -#else - unwindEntryParser = std::make_shared(memory); -#endif - return unwindEntryParser; - } -}; +ArchType GetCurrentArch(); +ArchType GetArchFromUname(const std::string& machine); +const std::string GetArchName(ArchType arch); } // nameapace HiviewDFX } // nameapace OHOS #endif diff --git a/interfaces/innerkits/unwinder/include/exidx_entry_parser.h b/interfaces/innerkits/unwinder/include/arm_exidx.h similarity index 77% rename from interfaces/innerkits/unwinder/include/exidx_entry_parser.h rename to interfaces/innerkits/unwinder/include/arm_exidx.h index c67e041cd..762db1a74 100644 --- a/interfaces/innerkits/unwinder/include/exidx_entry_parser.h +++ b/interfaces/innerkits/unwinder/include/arm_exidx.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,8 +13,8 @@ * limitations under the License. */ -#ifndef EXIDX_ENTRY_PARSER_H -#define EXIDX_ENTRY_PARSER_H +#ifndef ARM_EXIDX_H +#define ARM_EXIDX_H #include #include @@ -23,7 +23,6 @@ #include "dfx_errors.h" #include "dfx_memory.h" #include "unwind_context.h" -#include "unwind_entry_parser.h" namespace OHOS { namespace HiviewDFX { @@ -39,22 +38,24 @@ public: void AddUpVsp(int32_t imm); }; -class ExidxEntryParser : public UnwindEntryParser { +class ArmExidx { public: - explicit ExidxEntryParser(const std::shared_ptr& memory) : UnwindEntryParser(memory) - { - context_.Reset(DfxRegsQut::GetQutRegsSize()); - } - ~ExidxEntryParser() override = default; + explicit ArmExidx(std::shared_ptr memory); + virtual ~ArmExidx() = default; + + bool SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei); + bool Step(uintptr_t entryOffset, std::shared_ptr rs); + + const uint16_t& GetLastErrorCode() { return lastErrorData_.GetCode(); } + const uint64_t& GetLastErrorAddr() { return lastErrorData_.GetAddr(); } - bool Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr rs) override; private: struct DecodeTable { uint8_t mask; uint8_t result; - bool (ExidxEntryParser::*decoder)(); + bool (ArmExidx::*decoder)(); }; - bool SearchEntry(uintptr_t pc, const UnwindTableInfo &uti, struct UnwindEntryInfo& uei) override; + bool Eval(uintptr_t entryOffset); void FlushInstr(); @@ -83,7 +84,11 @@ private: bool Decode11010nnn(); bool Decode11xxxyyy(); bool DecodeSpare(); + +protected: + UnwindErrorData lastErrorData_; std::shared_ptr rsState_; + std::shared_ptr memory_; ExidxContext context_; std::deque ops_; uint8_t curOp_ = 0; diff --git a/interfaces/innerkits/unwinder/include/dfx_elf.h b/interfaces/innerkits/unwinder/include/dfx_elf.h index cc2db9197..4b37c39ec 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf.h @@ -16,10 +16,8 @@ #ifndef DFX_ELF_H #define DFX_ELF_H -#include #include #include -#include #include "dfx_elf_parser.h" #include "dfx_map.h" @@ -33,11 +31,17 @@ struct DlCbData { class DfxElf final { public: - DfxElf() { Init(); } - explicit DfxElf (const std::shared_ptr& mmap) : mmap_(mmap) { Init(); } + static std::shared_ptr Create(const std::string& file); + static std::shared_ptr CreateFromHap(const std::string& file, std::shared_ptr prevMap, + uint64_t& offset); + explicit DfxElf(const std::string& file); + explicit DfxElf(const int fd, const size_t elfSz, const off_t offset); + DfxElf(uint8_t* decompressedData, size_t size); ~DfxElf() { Clear(); } - void SetMmap(const std::shared_ptr& mmap) { mmap_ = mmap; } + static bool IsValidElf(const void* ptr, size_t size); + static size_t GetElfSize(const void* ptr); + bool IsValid(); uint8_t GetClassType(); ArchType GetArchType(); @@ -46,7 +50,6 @@ public: std::string GetBuildId(); void SetBuildId(const std::string& buildId); static std::string GetBuildId(uint64_t noteAddr, uint64_t noteSize); - GnuDebugDataHdr GetGnuDebugDataHdr(); uintptr_t GetGlobalPointer(); int64_t GetLoadBias(); uint64_t GetLoadBase(uint64_t mapStart, uint64_t mapOffset); @@ -63,18 +66,24 @@ public: size_t GetMmapSize(); bool Read(uintptr_t pos, void* buf, size_t size); const std::unordered_map& GetPtLoads(); - const std::set& GetFuncSymbols(); + const std::vector& GetElfSymbols(); + const std::vector& GetFuncSymbols(); bool GetFuncInfo(uint64_t addr, ElfSymbol& elfSymbol); + bool GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol); bool GetSectionInfo(ShdrInfo& shdr, const std::string secName); bool GetSectionData(unsigned char* buf, uint64_t size, std::string secName); int FindUnwindTableInfo(uintptr_t pc, std::shared_ptr map, struct UnwindTableInfo& uti); static int FindUnwindTableLocal(uintptr_t pc, struct UnwindTableInfo& uti); + static std::string ToReadableBuildId(const std::string& buildIdHex); + bool IsEmbeddedElfValid(); + std::shared_ptr GetEmbeddedElf(); + std::shared_ptr GetMiniDebugInfo(); protected: void Init(); void Clear(); bool InitHeaders(); - bool IsMiniDebugInfoValid(); + bool InitEmbeddedElf(); #if is_ohos && !is_mingw static int DlPhdrCb(struct dl_phdr_info* info, size_t size, void* data); static void ParsePhdr(struct dl_phdr_info* info, const ElfW(Phdr)* (&pHdrSections)[4], const uintptr_t pc); @@ -86,9 +95,7 @@ protected: #endif bool FillUnwindTableByEhhdr(struct DwarfEhFrameHdr* hdr, uintptr_t shdrBase, struct UnwindTableInfo* uti); static bool FillUnwindTableByExidx(ShdrInfo shdr, uintptr_t loadBase, struct UnwindTableInfo* uti); - bool FindFuncSymbol(uint64_t addr, const std::set& symbols, ElfSymbol& elfSymbol); - bool IsValidElf(const void* ptr, size_t size); - bool GetFuncInfoLazily(uint64_t addr, ElfSymbol& elfSymbol); + bool FindFuncSymbol(uint64_t addr, const std::vector& symbols, ElfSymbol& elfSymbol); private: bool valid_ = false; @@ -103,8 +110,11 @@ private: bool hasTableInfo_ = false; std::shared_ptr mmap_ = nullptr; std::unique_ptr elfParse_ = nullptr; - std::set funcSymbols_ {}; - std::shared_ptr miniDebugInfo_ = nullptr; + std::vector elfSymbols_ {}; + std::vector funcSymbols_ {}; + std::shared_ptr embeddedElf_ = nullptr; + std::shared_ptr miniDebugInfo_ = nullptr; + std::shared_ptr> embeddedElfData_ = nullptr; }; } // namespace HiviewDFX } // namespace OHOS diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_define.h b/interfaces/innerkits/unwinder/include/dfx_elf_define.h index 6bc939491..63d001fda 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_define.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_define.h @@ -54,10 +54,6 @@ struct ElfSymbol { uint16_t shndx = 0; uint64_t value = 0; uint64_t size = 0; - bool operator<(const ElfSymbol& other) const - { - return value < other.value; - } }; struct ElfShdr { @@ -88,8 +84,8 @@ struct __attribute__((packed)) DwarfEhFrameHdr { ElfW(Addr) ehFrame; }; -struct GnuDebugDataHdr { - uintptr_t address = 0; +struct MiniDebugInfo { + uint64_t offset = 0; uintptr_t size = 0; }; diff --git a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h index b4c844377..24c58db39 100644 --- a/interfaces/innerkits/unwinder/include/dfx_elf_parser.h +++ b/interfaces/innerkits/unwinder/include/dfx_elf_parser.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -55,16 +54,14 @@ public: virtual uint64_t GetStartOffset() { return startOffset_; } virtual std::string GetElfName() = 0; virtual uintptr_t GetGlobalPointer() = 0; - virtual const std::set& GetFuncSymbols() = 0; + virtual const std::vector& GetElfSymbols(bool isFunc) = 0; virtual bool GetSectionInfo(ShdrInfo& shdr, const uint32_t idx); virtual bool GetSectionInfo(ShdrInfo& shdr, const std::string& secName); virtual bool GetSectionData(unsigned char *buf, uint64_t size, std::string secName); - virtual bool GetFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) = 0; + virtual bool GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) = 0; const std::unordered_map& GetPtLoads() {return ptLoads_;} bool Read(uintptr_t pos, void *buf, size_t size); - const GnuDebugDataHdr& GetGnuDebugDataHdr() const; - std::string GetBuildId(); - static std::string ParseHexBuildId(uint64_t noteAddr, uint64_t noteSize); + std::shared_ptr GetMiniDebugInfo(); protected: size_t MmapSize(); template @@ -80,13 +77,13 @@ protected: template bool IsFunc(const SymType sym); template - bool ParseFuncSymbols(); + bool ParseElfSymbols(bool isFunc); template - bool ParseFuncSymbols(const ElfShdr& shdr); + bool ParseElfSymbols(ElfShdr shdr, bool isFunc); template - bool ParseFuncSymbolName(const ShdrInfo& linkShdr, SymType sym, std::string& nameStr); + bool ParseElfSymbolName(ShdrInfo linkShdr, SymType sym, std::string& nameStr); template - bool ParseFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol); + bool ParseElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol); template bool ParseElfDynamic(); template @@ -95,17 +92,16 @@ protected: bool GetSectionNameByIndex(std::string& nameStr, const uint32_t name); template bool ReadSymType(const ElfShdr& shdr, const uint32_t idx, SymType& sym); - std::string ToReadableBuildId(const std::string& buildIdHex); protected: - std::set funcSymbols_; + std::vector elfSymbols_; uint64_t dynamicOffset_ = 0; uintptr_t dtPltGotAddr_ = 0; uintptr_t dtStrtabAddr_ = 0; uintptr_t dtStrtabSize_ = 0; uintptr_t dtSonameOffset_ = 0; std::string soname_ = ""; - GnuDebugDataHdr gnuDebugDataHdr_; + std::shared_ptr minidebugInfo_ = nullptr; private: std::shared_ptr mmap_; @@ -128,8 +124,8 @@ public: bool InitHeaders() override; std::string GetElfName() override; uintptr_t GetGlobalPointer() override; - const std::set& GetFuncSymbols() override; - bool GetFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) override; + const std::vector& GetElfSymbols(bool isFunc) override; + bool GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) override; }; class ElfParser64 : public ElfParser { @@ -139,8 +135,8 @@ public: bool InitHeaders() override; std::string GetElfName() override; uintptr_t GetGlobalPointer() override; - const std::set& GetFuncSymbols() override; - bool GetFuncSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) override; + const std::vector& GetElfSymbols(bool isFunc) override; + bool GetElfSymbolByAddr(uint64_t addr, ElfSymbol& elfSymbol) override; }; } // namespace HiviewDFX diff --git a/interfaces/innerkits/unwinder/include/dfx_map.h b/interfaces/innerkits/unwinder/include/dfx_map.h index a9248ea67..ee15a76ca 100644 --- a/interfaces/innerkits/unwinder/include/dfx_map.h +++ b/interfaces/innerkits/unwinder/include/dfx_map.h @@ -68,6 +68,9 @@ public: uint64_t elfOffset = 0; uint64_t elfStartOffset = 0; int32_t symbolFileIndex = -1; // symbols file index +#if is_ohos && !is_mingw + std::shared_ptr> shmmData = nullptr; +#endif // use for find inline bool operator==(const std::string &sname) const { diff --git a/interfaces/innerkits/unwinder/include/dfx_memory.h b/interfaces/innerkits/unwinder/include/dfx_memory.h index 5de7d94bc..e3d818972 100644 --- a/interfaces/innerkits/unwinder/include/dfx_memory.h +++ b/interfaces/innerkits/unwinder/include/dfx_memory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -27,7 +27,7 @@ namespace HiviewDFX { class DfxMemory { public: DfxMemory() = default; - explicit DfxMemory(const UnwindType& unwindType, std::shared_ptr accessors = nullptr); + explicit DfxMemory(std::shared_ptr acc) : acc_(acc) {} virtual ~DfxMemory() = default; void SetCtx(void* ctx) { ctx_ = ctx; } @@ -73,8 +73,6 @@ public: #if is_ohos && !is_mingw static size_t ReadProcMemByPid(const pid_t pid, const uint64_t addr, void* data, size_t size); #endif - int FindUnwindTable(uintptr_t pc, UnwindTableInfo& uti) const; - int GetMapByPc(uintptr_t pc, std::shared_ptr& map) const; private: std::shared_ptr acc_ = nullptr; void* ctx_ = nullptr; diff --git a/interfaces/innerkits/unwinder/include/dfx_mmap.h b/interfaces/innerkits/unwinder/include/dfx_mmap.h index cf72d33d2..8cb49b3fa 100644 --- a/interfaces/innerkits/unwinder/include/dfx_mmap.h +++ b/interfaces/innerkits/unwinder/include/dfx_mmap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -33,7 +33,7 @@ public: virtual ~DfxMmap() { Clear(); } bool Init(const int fd, const size_t size, const off_t offset = 0); - bool Init(std::vector&& data); + bool Init(uint8_t *decompressedData, size_t size); void Clear(); inline void* Get() @@ -44,13 +44,13 @@ public: return nullptr; } inline size_t Size() { return size_; } + inline void SetNeedUnmap(bool need) { needUnmap_ = need; } size_t Read(uintptr_t& addr, void* val, size_t size, bool incre = false) override; private: void *mmap_ = MAP_FAILED; size_t size_ = 0; - std::vector data_; bool needUnmap_ = true; }; } // namespace HiviewDFX diff --git a/common/dfxutil/dfx_signal.h b/interfaces/innerkits/unwinder/include/dfx_signal.h similarity index 100% rename from common/dfxutil/dfx_signal.h rename to interfaces/innerkits/unwinder/include/dfx_signal.h diff --git a/interfaces/innerkits/unwinder/include/elf_factory_selector.h b/interfaces/innerkits/unwinder/include/dfx_xz_utils.h similarity index 65% rename from interfaces/innerkits/unwinder/include/elf_factory_selector.h rename to interfaces/innerkits/unwinder/include/dfx_xz_utils.h index a2bbb5e40..a0b110d88 100644 --- a/interfaces/innerkits/unwinder/include/elf_factory_selector.h +++ b/interfaces/innerkits/unwinder/include/dfx_xz_utils.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,19 +13,16 @@ * limitations under the License. */ -#ifndef ELF_FACTORY_SELECTOR_H -#define ELF_FACTORY_SELECTOR_H - +#ifndef DFX_XZ_UTILS_H +#define DFX_XZ_UTILS_H +#include #include -#include "elf_factory.h" -#include "dfx_map.h" +#include namespace OHOS { namespace HiviewDFX { -class ElfFactorySelector { -public: - static std::shared_ptr Select(DfxMap& map, pid_t pid = 0); -}; -} // namespace HiviewDFX -} // namespace OHOS -#endif +__attribute__ ((visibility("hidden"))) bool XzDecompress(const uint8_t *src, size_t srcLen, + std::shared_ptr> out); +} // namespace HiviewDFX +} // namespace OHOS +#endif \ No newline at end of file diff --git a/interfaces/innerkits/unwinder/include/dwarf_entry_parser.h b/interfaces/innerkits/unwinder/include/dwarf_section.h similarity index 68% rename from interfaces/innerkits/unwinder/include/dwarf_entry_parser.h rename to interfaces/innerkits/unwinder/include/dwarf_section.h index e522f4ac5..253390780 100644 --- a/interfaces/innerkits/unwinder/include/dwarf_entry_parser.h +++ b/interfaces/innerkits/unwinder/include/dwarf_section.h @@ -1,53 +1,61 @@ -/* - * Copyright (c) 2023 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef DWARF_ENTRY_PARSER_H -#define DWARF_ENTRY_PARSER_H - -#include -#include -#include -#include "dwarf_define.h" -#include "dfx_errors.h" -#include "dfx_memory.h" -#include "dfx_regs.h" -#include "unwind_context.h" -#include "unwind_entry_parser.h" - -namespace OHOS { -namespace HiviewDFX { -class DwarfEntryParser : public UnwindEntryParser { -public: - explicit DwarfEntryParser(const std::shared_ptr& memory) : UnwindEntryParser(memory) {} - ~DwarfEntryParser() override = default; - bool Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr rs) override; -protected: - bool SearchEntry(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei) override; - bool ParseFde(uintptr_t fdeAddr, uintptr_t fdePtr, FrameDescEntry& fdeInfo); - bool ParseCie(uintptr_t cieAddr, uintptr_t ciePtr, CommonInfoEntry& cieInfo); -private: - bool LinearSearchEntry(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei); - bool GetCieOrFde(uintptr_t& addr, FrameDescEntry& fdeInfo); - void ParseCieOrFdeHeader(uintptr_t& ptr, FrameDescEntry& fdeInfo, bool& isCieEntry); - bool FillInFde(uintptr_t ptr, FrameDescEntry& fdeInfo); - bool FillInCie(uintptr_t ptr, CommonInfoEntry& cieInfo); - void ParseAugData(uintptr_t& ptr, CommonInfoEntry& cieInfo, const std::vector& augStr); - uint32_t cie32Value_ = 0; - uint64_t cie64Value_ = 0; - std::unordered_map fdeEntries_; - std::unordered_map cieEntries_; -}; -} // nameapace HiviewDFX -} // nameapace OHOS -#endif +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef DFX_DWARF_SECTION_H +#define DFX_DWARF_SECTION_H + +#include +#include +#include +#include "dwarf_define.h" +#include "dfx_errors.h" +#include "dfx_memory.h" +#include "dfx_regs.h" +#include "unwind_context.h" + +namespace OHOS { +namespace HiviewDFX { +class DwarfSection { +public: + explicit DwarfSection(std::shared_ptr memory); + virtual ~DwarfSection() = default; + + bool LinearSearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei); + bool SearchEntry(uintptr_t pc, struct UnwindTableInfo uti, struct UnwindEntryInfo& uei); + bool Step(uintptr_t pc, uintptr_t fdeAddr, std::shared_ptr rs); + + const uint16_t& GetLastErrorCode() { return lastErrorData_.GetCode(); } + const uint64_t& GetLastErrorAddr() { return lastErrorData_.GetAddr(); } + +protected: + bool GetCieOrFde(uintptr_t& addr, FrameDescEntry& fdeInfo); + void ParseCieOrFdeHeader(uintptr_t& ptr, FrameDescEntry& fdeInfo, bool& isCieEntry); + bool ParseFde(uintptr_t fdeAddr, uintptr_t fdePtr, FrameDescEntry& fdeInfo); + bool FillInFde(uintptr_t ptr, FrameDescEntry& fdeInfo); + bool ParseCie(uintptr_t cieAddr, uintptr_t ciePtr, CommonInfoEntry& cieInfo); + bool FillInCie(uintptr_t ptr, CommonInfoEntry& cieInfo); + void ParseAugData(uintptr_t& ptr, CommonInfoEntry& cieInfo, const std::vector& augStr); + +protected: + std::shared_ptr memory_; + UnwindErrorData lastErrorData_; + uint32_t cie32Value_ = 0; + uint64_t cie64Value_ = 0; +private: + std::unordered_map fdeEntries_; + std::unordered_map cieEntries_; +}; +} // nameapace HiviewDFX +} // nameapace OHOS +#endif diff --git a/interfaces/innerkits/unwinder/include/elf_factory.h b/interfaces/innerkits/unwinder/include/elf_factory.h deleted file mode 100644 index ec7b9a4eb..000000000 --- a/interfaces/innerkits/unwinder/include/elf_factory.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ELF_FACTORY_H -#define ELF_FACTORY_H - -#include -#include -#include "dfx_define.h" -#include "dfx_elf.h" -#include "dfx_map.h" - -namespace OHOS { -namespace HiviewDFX { -class ElfFactory { -public: - virtual ~ElfFactory() = default; - virtual std::shared_ptr Create() = 0; -}; - -class RegularElfFactory : public ElfFactory { -public: - explicit RegularElfFactory(const std::string& filePath) : filePath_(filePath) {} - ~RegularElfFactory() override = default; - std::shared_ptr Create() override; -private: - std::string filePath_; -}; - -#if defined(ENABLE_MINIDEBUGINFO) -class MiniDebugInfoFactory : public ElfFactory { -public: - explicit MiniDebugInfoFactory(const GnuDebugDataHdr& gnuDebugDataHdr) : gnuDebugDataHdr_(gnuDebugDataHdr) {} - ~MiniDebugInfoFactory() override = default; - std::shared_ptr Create() override; -private: - bool XzDecompress(const uint8_t *src, size_t srcLen, std::vector& out); - GnuDebugDataHdr gnuDebugDataHdr_{}; -}; -#endif - -class CompressHapElfFactory : public ElfFactory { -public: - explicit CompressHapElfFactory(std::string filePath, std::shared_ptr prevMap) - : filePath_(std::move(filePath)), prevMap_(prevMap) {} - ~CompressHapElfFactory() override = default; - std::shared_ptr Create() override; -private: - bool VerifyElf(int fd, size_t& elfSize); - const std::string filePath_; - std::shared_ptr prevMap_; -}; - -class VdsoElfFactory : public ElfFactory { -public: - explicit VdsoElfFactory(uint64_t begin, size_t size, pid_t pid) : begin_(begin), size_(size), pid_(pid) {} - ~VdsoElfFactory() override = default; - std::shared_ptr Create() override; -private: - VdsoElfFactory() = delete; - MAYBE_UNUSED uint64_t begin_ = 0; - MAYBE_UNUSED size_t size_ = 0; - MAYBE_UNUSED pid_t pid_ = 0; -}; -} // namespace HiviewDFX -} // namespace OHOS -#endif diff --git a/interfaces/innerkits/unwinder/include/fp_unwinder.h b/interfaces/innerkits/unwinder/include/fp_unwinder.h index 40789612e..f08157925 100644 --- a/interfaces/innerkits/unwinder/include/fp_unwinder.h +++ b/interfaces/innerkits/unwinder/include/fp_unwinder.h @@ -29,7 +29,7 @@ #include #include "dfx_ark.h" #include "dfx_define.h" -#include "stack_utils.h" +#include "stack_util.h" namespace OHOS { namespace HiviewDFX { @@ -53,11 +53,11 @@ public: return 0; } if (gettid() == getpid()) { - if (!StackUtils::Instance().GetMainStackRange(stackBottom_, stackTop_)) { + if (!GetMainStackRange(stackBottom_, stackTop_)) { return 0; } } else { - if (!StackUtils::GetSelfStackRange(stackBottom_, stackTop_)) { + if (!GetSelfStackRange(stackBottom_, stackTop_)) { return 0; } } diff --git a/interfaces/innerkits/unwinder/include/unwind_context.h b/interfaces/innerkits/unwinder/include/unwind_context.h index c1422a01f..f9cc71473 100644 --- a/interfaces/innerkits/unwinder/include/unwind_context.h +++ b/interfaces/innerkits/unwinder/include/unwind_context.h @@ -22,8 +22,8 @@ #include "byte_order.h" #include "dfx_errors.h" -#include "dfx_regs_qut.h" #include "unwind_define.h" +#include "unwind_loc.h" namespace OHOS { namespace HiviewDFX { @@ -71,41 +71,6 @@ struct UnwindContext { std::shared_ptr map = nullptr; struct UnwindTableInfo di; }; - -enum RegLocEnum : uint8_t { - REG_LOC_UNUSED = 0, // register has same value as in prev. frame - REG_LOC_UNDEFINED, // register isn't saved at all - REG_LOC_VAL_OFFSET, // register that is the value, cfa = cfa + off - REG_LOC_MEM_OFFSET, // register saved at CFA-relative address, cfa = [r14 + off], r14 = [cfa + off] - REG_LOC_REGISTER, // register saved in another register, cfa = [r14], pc = [lr] - REG_LOC_VAL_EXPRESSION, // register value is expression result, r11 = cfa + expr_result - REG_LOC_MEM_EXPRESSION, // register stored in expression result, r11 = [cfa + expr_result] -}; - -struct RegLoc { - RegLocEnum type = REG_LOC_UNUSED; /* see DWARF_LOC_* macros. */ - intptr_t val = 0; -}; - -// saved register status after running call frame instructions -// it should describe how register saved -struct RegLocState { - RegLocState() { locs.resize(DfxRegsQut::GetQutRegsSize()); } - explicit RegLocState(size_t locsSize) { locs.resize(locsSize); } - ~RegLocState() = default; - - uintptr_t pcStart = 0; - uintptr_t pcEnd = 0; - uint32_t cfaReg = 0; // cfa = [r14] - union { - int32_t cfaRegOffset = 0; // cfa = cfa + offset - uintptr_t cfaExprPtr; // cfa = expr - }; - bool returnAddressUndefined = false; - bool returnAddressSame = false; - uint16_t returnAddressRegister = 0; // lr - std::vector locs; -}; } // namespace HiviewDFX } // namespace OHOS #endif diff --git a/interfaces/innerkits/unwinder/include/unwind_entry_parser.h b/interfaces/innerkits/unwinder/include/unwind_entry_parser.h deleted file mode 100644 index b8ea2baca..000000000 --- a/interfaces/innerkits/unwinder/include/unwind_entry_parser.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef UNWIND_ENTRY_PARSER_H -#define UNWIND_ENTRY_PARSER_H - -#include -#include -#include - -#include "dfx_memory.h" -#include "unwind_context.h" - -namespace OHOS { -namespace HiviewDFX { -class UnwindEntryParser { -public: - explicit UnwindEntryParser(const std::shared_ptr& memory) : memory_(memory) {} - virtual ~UnwindEntryParser() = default; - virtual bool Step(uintptr_t pc, const UnwindTableInfo& uti, std::shared_ptr rs) = 0; - uint16_t GetLastErrorCode() { return lastErrorData_.GetCode(); } - uint64_t GetLastErrorAddr() { return lastErrorData_.GetAddr(); } -protected: - virtual bool SearchEntry(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei) = 0; - UnwindErrorData lastErrorData_ {}; - std::shared_ptr memory_ = nullptr; -}; -} // nameapace HiviewDFX -} // nameapace OHOS -#endif diff --git a/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.h b/interfaces/innerkits/unwinder/include/unwind_loc.h similarity index 31% rename from interfaces/innerkits/dump_catcher/kernel_stack_async_collector.h rename to interfaces/innerkits/unwinder/include/unwind_loc.h index 9feb157a6..223fa46ad 100644 --- a/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.h +++ b/interfaces/innerkits/unwinder/include/unwind_loc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,48 +13,52 @@ * limitations under the License. */ -#ifndef DFX_ASYNC_KERNEL_STACK_H -#define DFX_ASYNC_KERNEL_STACK_H +#ifndef UNWIND_LOC_H +#define UNWIND_LOC_H -#include #include -#include #include -#include +#include + +#include "dfx_regs_qut.h" +#include "unwind_define.h" namespace OHOS { namespace HiviewDFX { +enum RegLocEnum : uint8_t { + REG_LOC_UNUSED = 0, // register has same value as in prev. frame + REG_LOC_UNDEFINED, // register isn't saved at all + REG_LOC_VAL_OFFSET, // register that is the value, cfa = cfa + off + REG_LOC_MEM_OFFSET, // register saved at CFA-relative address, cfa = [r14 + off], r14 = [cfa + off] + REG_LOC_REGISTER, // register saved in another register, cfa = [r14], pc = [lr] + REG_LOC_VAL_EXPRESSION, // register value is expression result, r11 = cfa + expr_result + REG_LOC_MEM_EXPRESSION, // register stored in expression result, r11 = [cfa + expr_result] +}; -class KernelStackAsyncCollector { -public: - enum ErrorCode : int32_t { - STACK_SUCCESS = 0, - STACK_ECREATE, - STACK_EOPEN, - STACK_EIOCTL, - STACK_TIMEOUT, - STACK_DEFERRED, - STACK_OVER_LIMIT, - STACK_NO_PROCESS, - STACK_UNKNOWN, - }; - using KernelResult = std::pair; - - KernelResult GetProcessStackWithTimeout(int pid, uint32_t timeoutMs) const; - - bool NotifyStartCollect(int pid); - KernelResult GetCollectedStackResult(); -private: - static void CollectKernelStackTask(int pid, std::promise result); - static bool CheckProcessValid(int pid); - static ErrorCode ToErrCode(int kernelErr); +struct RegLoc { + RegLocEnum type = REG_LOC_UNUSED; /* see DWARF_LOC_* macros. */ + intptr_t val = 0; +}; - static constexpr int maxAsyncTaskNum_ = 2; - static std::atomic asyncCount_; +// saved register status after running call frame instructions +// it should describe how register saved +struct RegLocState { + RegLocState() { locs.resize(DfxRegsQut::GetQutRegsSize()); } + explicit RegLocState(size_t locsSize) { locs.resize(locsSize); } + ~RegLocState() = default; - std::future stackFuture_; + uintptr_t pcStart = 0; + uintptr_t pcEnd = 0; + uint32_t cfaReg = 0; // cfa = [r14] + union { + int32_t cfaRegOffset = 0; // cfa = cfa + offset + uintptr_t cfaExprPtr; // cfa = expr + }; + bool returnAddressUndefined = false; + bool returnAddressSame = false; + uint16_t returnAddressRegister = 0; // lr + std::vector locs; }; - } // namespace HiviewDFX } // namespace OHOS -#endif \ No newline at end of file +#endif diff --git a/interfaces/innerkits/unwinder/include/unwinder.h b/interfaces/innerkits/unwinder/include/unwinder.h index 8b8ba88d6..1587f3eb4 100644 --- a/interfaces/innerkits/unwinder/include/unwinder.h +++ b/interfaces/innerkits/unwinder/include/unwinder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at diff --git a/interfaces/innerkits/unwinder/libunwinder.map b/interfaces/innerkits/unwinder/libunwinder.map index ef361e5e7..a9164ff85 100644 --- a/interfaces/innerkits/unwinder/libunwinder.map +++ b/interfaces/innerkits/unwinder/libunwinder.map @@ -40,9 +40,11 @@ OHOS::HiviewDFX::UnwinderConfig::enableLoadSymbolLazily_*; OHOS::HiviewDFX::UnwinderConfig::enableMiniDebugInfo_*; OHOS::HiviewDFX::DfxConfig::GetConfig*; + OHOS::HiviewDFX::DfxElf::Create*; OHOS::HiviewDFX::DfxElf::Clear*; OHOS::HiviewDFX::DfxElf::DfxElf*; OHOS::HiviewDFX::DfxElf::IsValid*; + OHOS::HiviewDFX::DfxElf::GetLoadBias*; OHOS::HiviewDFX::DfxElf::GetBuildId*; OHOS::HiviewDFX::DfxElf::FindUnwindTableInfo*; OHOS::HiviewDFX::DfxElf::GetBaseOffset*; @@ -77,11 +79,11 @@ OHOS::HiviewDFX::DfxPtrace::Detach*; OHOS::HiviewDFX::DfxPtrace::Attach*; OHOS::HiviewDFX::DfxMemory::ReadProcMemByPid*; + OHOS::HiviewDFX::DfxSignal::PrintSignal*; + OHOS::HiviewDFX::DfxSignal::IsAddrAvailable*; "vtable for OHOS::HiviewDFX::DfxRegsArm"; "vtable for OHOS::HiviewDFX::DfxRegsArm64"; "vtable for OHOS::HiviewDFX::DfxRegsRiscv64"; - "vtable for OHOS::HiviewDFX::RegularElfFactory"; - "vtable for OHOS::HiviewDFX::CompressHapElfFactory"; OHOS::HiviewDFX::DfxFrameFormatter::GetFrameStr*; OHOS::HiviewDFX::DfxFrameFormatter::GetFramesStr*; OHOS::HiviewDFX::DfxElf::GetStartVaddr*; @@ -102,14 +104,9 @@ OHOS::HiviewDFX::LocalThreadContextMix::GetMapByPc*; OHOS::HiviewDFX::LocalThreadContextMix::FindUnwindTable*; OHOS::HiviewDFX::LocalThreadContextMix::AccessMem*; - OHOS::HiviewDFX::RegularElfFactory::Create*; - OHOS::HiviewDFX::CompressHapElfFactory::Create*; OHOS::HiviewDFX::GetFileSize*; OHOS::HiviewDFX::TrimAndDupStr*; OHOS::HiviewDFX::DfxEnableTraceDlsym*; - OHOS::HiviewDFX::StackUtils::Instance*; - OHOS::HiviewDFX::StackUtils::GetMainStackRange*; - OHOS::HiviewDFX::StackUtils::GetSelfStackRange*; }; local: *; diff --git a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp b/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp deleted file mode 100644 index e4427bbcb..000000000 --- a/interfaces/innerkits/unwinder/src/elf/elf_factory.cpp +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "elf_factory.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dfx_define.h" -#include "dfx_log.h" -#include "dfx_maps.h" -#include "dfx_trace_dlsym.h" -#include "dfx_util.h" -#if defined(ENABLE_MINIDEBUGINFO) -#include "7zCrc.h" -#include "unwinder_config.h" -#include "Xz.h" -#include "XzCrc64.h" -#endif - -namespace OHOS { -namespace HiviewDFX { -namespace { -#undef LOG_DOMAIN -#undef LOG_TAG -#define LOG_DOMAIN 0xD002D11 -#define LOG_TAG "ElfFactory" -} -#if defined(ENABLE_MINIDEBUGINFO) -std::shared_ptr MiniDebugInfoFactory::Create() -{ - DFX_TRACE_SCOPED_DLSYM("CreateMiniDebugInfo"); - if (!UnwinderConfig::GetEnableMiniDebugInfo()) { - return nullptr; - } - - std::vector miniDebugInfoData; - if (!XzDecompress(reinterpret_cast(gnuDebugDataHdr_.address), - gnuDebugDataHdr_.size, miniDebugInfoData)) { - DFXLOGE("Failed to decompressed .gnu_debugdata seciton."); - return nullptr; - } - // miniDebugInfoData store the decompressed bytes. - // use these bytes to construct an elf. - auto mMap = std::make_shared(); - if (!mMap->Init(std::move(miniDebugInfoData))) { - DFXLOGE("Failed to init mmap_!"); - return nullptr; - } - auto miniDebugInfo = std::make_shared(mMap); - if (!miniDebugInfo->IsValid()) { - DFXLOGE("Failed to parse mini debuginfo Elf."); - return nullptr; - } - return miniDebugInfo; -} - -static void* XzAlloc(ISzAllocPtr, size_t size) -{ - return malloc(size); -} - -static void XzFree(ISzAllocPtr, void *address) -{ - free(address); -} - -bool MiniDebugInfoFactory::XzDecompress(const uint8_t *src, size_t srcLen, std::vector& out) -{ - DFX_TRACE_SCOPED_DLSYM("XzDecompress"); - ISzAlloc alloc; - CXzUnpacker state; - alloc.Alloc = XzAlloc; - alloc.Free = XzFree; - XzUnpacker_Construct(&state, &alloc); - CrcGenerateTable(); - Crc64GenerateTable(); - size_t srcOff = 0; - size_t dstOff = 0; - out.resize(srcLen); - ECoderStatus status = CODER_STATUS_NOT_FINISHED; - constexpr uint16_t expandFactor = 2; - while (status == CODER_STATUS_NOT_FINISHED) { - out.resize(out.size() * expandFactor); - size_t srcRemain = srcLen - srcOff; - size_t dstRemain = out.size() - dstOff; - int res = XzUnpacker_Code(&state, - reinterpret_cast(&out[dstOff]), &dstRemain, - reinterpret_cast(&src[srcOff]), &srcRemain, - true, CODER_FINISH_ANY, &status); - if (res != SZ_OK) { - XzUnpacker_Free(&state); - return false; - } - srcOff += srcRemain; - dstOff += dstRemain; - } - XzUnpacker_Free(&state); - if (!XzUnpacker_IsStreamWasFinished(&state)) { - return false; - } - out.resize(dstOff); - return true; -} -#endif - -std::shared_ptr RegularElfFactory::Create() -{ - std::shared_ptr regularElf = std::make_shared(); - if (filePath_.empty()) { - DFXLOGE("file path is empty!"); - return regularElf; - } - DFXLOGU("file: %{public}s", filePath_.c_str()); -#if defined(is_ohos) && is_ohos - if (!DfxMaps::IsLegalMapItem(filePath_)) { - DFXLOGD("Illegal map file, please check file: %{public}s", filePath_.c_str()); - return regularElf; - } -#endif - std::string realPath = filePath_; - // sandbox file should not be check by realpath function,as start with "/proc/" - if (!StartsWith(filePath_, "/proc/") && !RealPath(filePath_, realPath)) { - DFXLOGW("Failed to realpath %{public}s, errno(%{public}d)", filePath_.c_str(), errno); - return regularElf; - } -#if defined(is_mingw) && is_mingw - int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY | O_BINARY)); -#else - int fd = OHOS_TEMP_FAILURE_RETRY(open(realPath.c_str(), O_RDONLY)); -#endif - if (fd <= 0) { - DFXLOGE("Failed to open file: %{public}s, errno(%d)", filePath_.c_str(), errno); - return regularElf; - } - do { - auto size = static_cast(GetFileSize(fd)); - auto mMap = std::make_shared(); - if (!mMap->Init(fd, size, 0)) { - DFXLOGE("Failed to mmap init."); - break; - } - regularElf->SetMmap(mMap); - } while (false); - close(fd); - return regularElf; -} - -std::shared_ptr VdsoElfFactory::Create() -{ -#if is_ohos && !is_mingw - std::vector shmmData(size_); - size_t byte = ReadProcMemByPid(pid_, begin_, shmmData.data(), size_); - if (byte != size_) { - DFXLOGE("Failed to read shmm data"); - return nullptr; - } - - auto mMap = std::make_shared(); - if (!mMap->Init(std::move(shmmData))) { - DFXLOGE("Failed to init mmap_!"); - return nullptr; - } - auto vdsoElf = std::make_shared(mMap); - if (!vdsoElf->IsValid()) { - DFXLOGE("Failed to parse Embedded Elf."); - return nullptr; - } - return vdsoElf; -#endif - return nullptr; -} - - -std::shared_ptr CompressHapElfFactory::Create() -{ - /* - elf header is in the first mmap area - c3840000-c38a6000 r--p 00174000 /data/storage/el1/bundle/entry.hap <- program header - c38a6000-c3945000 r-xp 001d9000 /data/storage/el1/bundle/entry.hap <- pc is in this region - c3945000-c394b000 r--p 00277000 /data/storage/el1/bundle/entry.hap - c394b000-c394c000 rw-p 0027c000 /data/storage/el1/bundle/entry.hap - */ - if (prevMap_ == nullptr) { - DFXLOGE("current hap map item or prev map item , maybe pc is wrong?"); - return nullptr; - } - if (!StartsWith(filePath_, "/proc") || !EndsWith(filePath_, ".hap")) { - DFXLOGD("Illegal file path, please check file: %{public}s", filePath_.c_str()); - return nullptr; - } - int fd = OHOS_TEMP_FAILURE_RETRY(open(filePath_.c_str(), O_RDONLY)); - if (fd < 0) { - DFXLOGE("Failed to open hap file, errno(%{public}d)", errno); - return nullptr; - } - std::shared_ptr compressHapElf = nullptr; - do { - size_t elfSize = 0; - if (!VerifyElf(fd, elfSize)) { - break; - } - DFXLOGU("elfSize: %{public}zu", elfSize); - auto mMap = std::make_shared(); - if (!mMap->Init(fd, elfSize, prevMap_->offset)) { - DFXLOGE("Failed to init mmap_!"); - break; - } - compressHapElf = std::make_shared(mMap); - if (!compressHapElf->IsValid()) { - DFXLOGE("Failed to parse compress hap Elf."); - compressHapElf = nullptr; - break; - } - } while (false); - close(fd); - return compressHapElf; -} - -bool CompressHapElfFactory::VerifyElf(int fd, size_t& elfSize) -{ - size_t size = prevMap_->end - prevMap_->begin; - auto mmap = std::make_shared(); - if (!mmap->Init(fd, size, static_cast(prevMap_->offset))) { - DFXLOGE("Failed to mmap program header in hap."); - return false; - } - elfSize = 0; - const uint8_t* data = static_cast(mmap->Get()); - if (memcmp(data, ELFMAG, SELFMAG) != 0) { - DFXLOGD("Invalid elf hdr?"); - return false; - } - uint8_t classType = data[EI_CLASS]; - if (classType == ELFCLASS32) { - const Elf32_Ehdr* ehdr = reinterpret_cast(data); - elfSize = static_cast(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); - } else if (classType == ELFCLASS64) { - const Elf64_Ehdr* ehdr = reinterpret_cast(data); - elfSize = static_cast(ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum)); - } - auto fileSize = GetFileSize(fd); - if (elfSize <= 0 || elfSize + prevMap_->offset > static_cast(fileSize)) { - DFXLOGE("Invalid elf size? elf size: %{public}d, hap size: %{public}d", (int)elfSize, (int)fileSize); - elfSize = 0; - return false; - } - return true; -} -} // namespace HiviewDFX -} // namespace OHOS diff --git a/interfaces/innerkits/unwinder/src/unwind_local/thread_context.cpp b/interfaces/innerkits/unwinder/thread_context.cpp similarity index 98% rename from interfaces/innerkits/unwinder/src/unwind_local/thread_context.cpp rename to interfaces/innerkits/unwinder/thread_context.cpp index 4b798bf03..f0ec58a1a 100644 --- a/interfaces/innerkits/unwinder/src/unwind_local/thread_context.cpp +++ b/interfaces/innerkits/unwinder/thread_context.cpp @@ -26,7 +26,6 @@ #include "dfx_define.h" #include "dfx_log.h" -#include "dfx_elf.h" #ifndef is_ohos_lite #include "file_ex.h" #else @@ -167,7 +166,7 @@ NO_SANITIZE void CopyContextAndWaitTimeout(int sig, siginfo_t *si, void *context } if (tid != getpid()) { - if (!StackUtils::GetSelfStackRange(ctxPtr->stackBottom, ctxPtr->stackTop)) { + if (!GetSelfStackRange(ctxPtr->stackBottom, ctxPtr->stackTop)) { DFXLOGW("Failed to get stack range with tid(%{public}d)", tid); } } @@ -357,7 +356,7 @@ NO_SANITIZE bool LocalThreadContextMix::CheckStatusValidate(int status, int32_t NO_SANITIZE bool LocalThreadContextMix::GetSelfStackRangeInSignal() { std::unique_lock lock(mtx_); - return StackUtils::GetSelfStackRange(stackBottom_, stackTop_); + return GetSelfStackRange(stackBottom_, stackTop_); } NO_SANITIZE void LocalThreadContextMix::CopyRegister(void *context) diff --git a/interfaces/innerkits/unwinder/unwinder.cpp b/interfaces/innerkits/unwinder/unwinder.cpp index 3a74f3054..4ce5a142d 100644 --- a/interfaces/innerkits/unwinder/unwinder.cpp +++ b/interfaces/innerkits/unwinder/unwinder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023-2025 Huawei Device Co., Ltd. + * Copyright (c) 2023-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -19,6 +19,9 @@ #include #include +#if defined(__arm__) +#include "arm_exidx.h" +#endif #include "dfx_ark.h" #include "dfx_define.h" #include "dfx_errors.h" @@ -32,13 +35,13 @@ #include "dfx_symbols.h" #include "dfx_trace_dlsym.h" #include "dfx_util.h" -#include "elapsed_time.h" +#include "dwarf_section.h" #include "fp_unwinder.h" -#include "stack_utils.h" +#include "stack_util.h" #include "string_printf.h" #include "string_util.h" #include "thread_context.h" -#include "unwind_entry_parser_factory.h" +#include "elapsed_time.h" namespace OHOS { namespace HiviewDFX { @@ -55,8 +58,8 @@ public: if (needMaps) { maps_ = DfxMaps::Create(); } + acc_ = std::make_shared(); enableFpCheckMapExec_ = true; - memory_ = std::make_shared(UNWIND_TYPE_LOCAL); Init(); } @@ -69,8 +72,8 @@ public: } DfxEnableTraceDlsym(true); maps_ = DfxMaps::Create(pid, crash); + acc_ = std::make_shared(); enableFpCheckMapExec_ = true; - memory_ = std::make_shared(UNWIND_TYPE_REMOTE); Init(); } @@ -82,8 +85,8 @@ public: } DfxEnableTraceDlsym(true); maps_ = DfxMaps::Create(pid, crash); + acc_ = std::make_shared(); enableFpCheckMapExec_ = true; - memory_ = std::make_shared(UNWIND_TYPE_REMOTE); Init(); } @@ -95,12 +98,12 @@ public: } else { pid_ = UNWIND_TYPE_CUSTOMIZE; } + acc_ = std::make_shared(accessors); enableFpCheckMapExec_ = false; enableFillFrames_ = false; #if defined(__aarch64__) pacMask_ = pacMaskDefault_; #endif - memory_ = std::make_shared(UNWIND_TYPE_CUSTOMIZE, accessors); Init(); } @@ -224,7 +227,7 @@ private: void InitParam() { #if defined(ENABLE_MIXSTACK) - enableMixstack_ = DfxParam::IsEnableMixstack(); + enableMixstack_ = DfxParam::EnableMixstack(); #endif } bool GetMainStackRangeInner(uintptr_t& stackBottom, uintptr_t& stackTop); @@ -233,9 +236,9 @@ private: void DoPcAdjust(uintptr_t& pc); void AddFrame(const StepFrame& frame, std::shared_ptr map); bool FindCache(uintptr_t pc, std::shared_ptr& map, std::shared_ptr& rs); - bool AddFrameMap(const StepFrame& frame, std::shared_ptr& map); + bool AddFrameMap(const StepFrame& frame, std::shared_ptr& map, void* ctx); bool UnwindArkFrame(StepFrame& frame, const std::shared_ptr& map, bool& stopUnwind); - bool ParseUnwindTable(uintptr_t pc, std::shared_ptr& rs); + bool ParseUnwindTable(uintptr_t pc, std::shared_ptr& rs, void* ctx, bool& unwinderResult); void UpdateRegsState(StepFrame& frame, void* ctx, bool& unwinderResult, std::shared_ptr& rs); bool CheckFrameValid(const StepFrame& frame, const std::shared_ptr& map, uintptr_t prevSp); bool StepInner(const bool isSigFrame, StepFrame& frame, void *ctx); @@ -270,6 +273,7 @@ private: int32_t pid_ = 0; uintptr_t pacMask_ = 0; std::vector jitCache_ = {}; + std::shared_ptr acc_ = nullptr; std::shared_ptr memory_ = nullptr; std::unordered_map stepCache_ {}; std::shared_ptr regs_ = nullptr; @@ -277,7 +281,10 @@ private: std::vector pcs_ {}; std::vector frames_ {}; UnwindErrorData lastErrorData_ {}; - std::shared_ptr unwindEntryParser_ = nullptr; +#if defined(__arm__) + std::shared_ptr armExidx_ = nullptr; +#endif + std::shared_ptr dwarfSection_ = nullptr; uintptr_t firstFrameSp_ {0}; }; @@ -465,7 +472,12 @@ void Unwinder::SetFrames(std::vector& frames) void Unwinder::Impl::Init() { Destroy(); - unwindEntryParser_ = UnwindEntryParserFactory::CreateUnwindEntryParser(memory_); + memory_ = std::make_shared(acc_); +#if defined(__arm__) + armExidx_ = std::make_shared(memory_); +#endif + dwarfSection_ = std::make_shared(memory_); + InitParam(); #if defined(ENABLE_MIXSTACK) DFXLOGD("Unwinder mixstack enable: %{public}d", enableMixstack_); @@ -480,7 +492,9 @@ void Unwinder::Impl::Clear() enableMixstack_ = true; pcs_.clear(); frames_.clear(); - lastErrorData_ = {}; + if (memset_s(&lastErrorData_, sizeof(UnwindErrorData), 0, sizeof(UnwindErrorData)) != 0) { + DFXLOGE("Failed to memset lastErrorData"); + } } void Unwinder::Impl::Destroy() @@ -502,7 +516,7 @@ bool Unwinder::Impl::GetMainStackRangeInner(uintptr_t& stackBottom, uintptr_t& s { if (maps_ != nullptr && !maps_->GetStackRange(stackBottom, stackTop)) { return false; - } else if (maps_ == nullptr && !StackUtils::Instance().GetMainStackRange(stackBottom, stackTop)) { + } else if (maps_ == nullptr && !GetMainStackRange(stackBottom, stackTop)) { return false; } return true; @@ -512,7 +526,7 @@ bool Unwinder::Impl::GetArkStackRangeInner(uintptr_t& arkMapStart, uintptr_t& ar { if (maps_ != nullptr && !maps_->GetArkStackRange(arkMapStart, arkMapEnd)) { return false; - } else if (maps_ == nullptr && !StackUtils::Instance().GetArkStackRange(arkMapStart, arkMapEnd)) { + } else if (maps_ == nullptr && !GetArkStackRange(arkMapStart, arkMapEnd)) { return false; } return true; @@ -523,7 +537,7 @@ bool Unwinder::Impl::GetStackRange(uintptr_t& stackBottom, uintptr_t& stackTop) if (gettid() == getpid()) { return GetMainStackRangeInner(stackBottom, stackTop); } - return StackUtils::GetSelfStackRange(stackBottom, stackTop); + return GetSelfStackRange(stackBottom, stackTop); } bool Unwinder::Impl::UnwindLocalWithTid(const pid_t tid, size_t maxFrameNum, size_t skipFrameNum) @@ -915,9 +929,9 @@ bool Unwinder::Impl::FindCache(uintptr_t pc, std::shared_ptr& map, std:: return false; } -bool Unwinder::Impl::AddFrameMap(const StepFrame& frame, std::shared_ptr& map) +bool Unwinder::Impl::AddFrameMap(const StepFrame& frame, std::shared_ptr& map, void* ctx) { - int mapRet = memory_->GetMapByPc(frame.pc, map); + int mapRet = acc_->GetMapByPc(frame.pc, map, ctx); if (mapRet != UNW_ERROR_NONE) { if (frame.isJsFrame) { DFXLOGW("Failed to get map with ark, frames size: %{public}zu", frames_.size()); @@ -954,22 +968,48 @@ bool Unwinder::Impl::UnwindArkFrame(StepFrame& frame, const std::shared_ptr& rs) +bool Unwinder::Impl::ParseUnwindTable(uintptr_t pc, std::shared_ptr& rs, void* ctx, bool& unwinderResult) { // find unwind table and entry UnwindTableInfo uti; - int utiRet = memory_->FindUnwindTable(pc, uti); + int utiRet = acc_->FindUnwindTable(pc, uti, ctx); if (utiRet != UNW_ERROR_NONE) { lastErrorData_.SetAddrAndCode(pc, utiRet); DFXLOGU("Failed to find unwind table ret: %{public}d", utiRet); return false; } - rs = std::make_shared(); // parse instructions and get cache rs - if (!unwindEntryParser_->Step(pc, uti, rs)) { - lastErrorData_.SetAddrAndCode(unwindEntryParser_->GetLastErrorAddr(), unwindEntryParser_->GetLastErrorCode()); - DFXLOGU("Step unwind entry failed"); - return false; + struct UnwindEntryInfo uei; + rs = std::make_shared(); +#if defined(__arm__) + if (!unwinderResult && uti.format == UNW_INFO_FORMAT_ARM_EXIDX) { + if (!armExidx_->SearchEntry(pc, uti, uei)) { + lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode()); + DFXLOGE("Failed to search unwind entry"); + return false; + } + if (!armExidx_->Step((uintptr_t)uei.unwindInfo, rs)) { + lastErrorData_.SetAddrAndCode(armExidx_->GetLastErrorAddr(), armExidx_->GetLastErrorCode()); + DFXLOGU("Step exidx section error"); + } else { + unwinderResult = true; + } + } +#endif + if (!unwinderResult && uti.format == UNW_INFO_FORMAT_REMOTE_TABLE) { + if ((uti.isLinear == false && !dwarfSection_->SearchEntry(pc, uti, uei)) || + (uti.isLinear == true && !dwarfSection_->LinearSearchEntry(pc, uti, uei))) { + lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode()); + DFXLOGU("Failed to search unwind entry"); + return false; + } + memory_->SetDataOffset(uti.segbase); + if (!dwarfSection_->Step(pc, (uintptr_t)uei.unwindInfo, rs)) { + lastErrorData_.SetAddrAndCode(dwarfSection_->GetLastErrorAddr(), dwarfSection_->GetLastErrorCode()); + DFXLOGU("Step dwarf section error"); + } else { + unwinderResult = true; + } } return true; } @@ -1055,7 +1095,7 @@ bool Unwinder::Impl::StepInner(const bool isSigFrame, StepFrame& frame, void *ct } // 2. find map and process frame - if (!AddFrameMap(frame, map)) { + if (!AddFrameMap(frame, map, ctx)) { return false; } if (isSigFrame) { @@ -1075,8 +1115,12 @@ bool Unwinder::Impl::StepInner(const bool isSigFrame, StepFrame& frame, void *ct } break; } + // 3. find unwind table and entry, parse instructions and get cache rs - hasRegLocState = ParseUnwindTable(frame.pc, rs); + if (!ParseUnwindTable(frame.pc, rs, ctx, hasRegLocState)) { + break; + } + // 4. update rs cache if (hasRegLocState && enableCache_) { StepCache cache; @@ -1314,13 +1358,12 @@ bool Unwinder::Impl::GetLockInfo(int32_t tid, char* buf, size_t sz) uintptr_t lockAddr; UnwindContext context; context.pid = tid; - memory_->SetCtx(&context); - if (!memory_->ReadMem(lockPtrAddr, &lockAddr)) { + if (acc_->AccessMem(lockPtrAddr, &lockAddr, &context) != UNW_ERROR_NONE) { DFXLOGW("Failed to find lock addr."); return false; } - size_t rsize = ReadProcMemByPid(tid, lockAddr, buf, sz); + size_t rsize = DfxMemory::ReadProcMemByPid(tid, lockAddr, buf, sz); if (rsize != sz) { DFXLOGW("Failed to fetch lock content, read size:%{public}zu expected size:%{public}zu", rsize, sz); return false; diff --git a/interfaces/innerkits/unwinder/src/utils/unwinder_config.cpp b/interfaces/innerkits/unwinder/unwinder_config.cpp similarity index 100% rename from interfaces/innerkits/unwinder/src/utils/unwinder_config.cpp rename to interfaces/innerkits/unwinder/unwinder_config.cpp diff --git a/test/benchmarktest/unwind/BUILD.gn b/test/benchmarktest/unwind/BUILD.gn index 5ccaa12b1..06055e59e 100644 --- a/test/benchmarktest/unwind/BUILD.gn +++ b/test/benchmarktest/unwind/BUILD.gn @@ -47,7 +47,8 @@ if (!defined(ohos_lite)) { "unwind_local_benchmark.cpp", "unwind_remote_benchmark.cpp", ] - sources += [ "$faultloggerd_interfaces_path/innerkits/unwinder/src/utils/dfx_ptrace.cpp" ] + sources += + [ "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_ptrace.cpp" ] deps = [ "$faultloggerd_common_path/dfxlog:dfx_hilog", "$faultloggerd_common_path/dfxutil:dfx_util", diff --git a/test/benchmarktest/unwinder/BUILD.gn b/test/benchmarktest/unwinder/BUILD.gn index 3b60a0287..49646cc6f 100644 --- a/test/benchmarktest/unwinder/BUILD.gn +++ b/test/benchmarktest/unwinder/BUILD.gn @@ -35,7 +35,10 @@ if (!defined(ohos_lite)) { ldflags = [ "-rdynamic" ] defines = [ "LOCK_TO_CPU" ] if (libunwinder_debug) { - defines += [ "DFX_LOG_UNWIND" ] + defines += [ + "DFX_LOG_UNWIND", + "DFX_UNWIND_ERROR", + ] } sources = [ "$faultloggerd_test_path/benchmarktest/main/main_benchmark.cpp", diff --git a/test/fuzztest/faultloggerdunwinder_fuzzer/BUILD.gn b/test/fuzztest/faultloggerdunwinder_fuzzer/BUILD.gn index 47771dd92..a72465401 100644 --- a/test/fuzztest/faultloggerdunwinder_fuzzer/BUILD.gn +++ b/test/fuzztest/faultloggerdunwinder_fuzzer/BUILD.gn @@ -37,6 +37,10 @@ if (defined(ohos_lite)) { "$faultloggerd_path/interfaces/innerkits/unwinder/include", ] + if (is_ohos && !is_mingw && !is_emulator) { + defines = [ "ENABLE_XZUTIL" ] + } + sources = [ "faultloggerdunwinder_fuzzer.cpp" ] deps = [ "$faultloggerd_path/common/dfxlog:dfx_hilog", diff --git a/test/fuzztest/faultloggerdunwinder_fuzzer/faultloggerdunwinder_fuzzer.cpp b/test/fuzztest/faultloggerdunwinder_fuzzer/faultloggerdunwinder_fuzzer.cpp index 3ab51a242..041d8dcda 100644 --- a/test/fuzztest/faultloggerdunwinder_fuzzer/faultloggerdunwinder_fuzzer.cpp +++ b/test/fuzztest/faultloggerdunwinder_fuzzer/faultloggerdunwinder_fuzzer.cpp @@ -22,6 +22,7 @@ #include "dfx_config.h" #include "dfx_hap.h" #include "dfx_regs.h" +#include "dfx_xz_utils.h" #include "dwarf_op.h" #include "faultloggerd_fuzzertest_common.h" #include "thread_context.h" @@ -263,6 +264,19 @@ void TestDfxInstrStatistic(const uint8_t* data, size_t size) statistic.DumpInstrStatResult(result); } +void TestDfxXzUtils(const uint8_t* data, size_t size) +{ + uint8_t src; + if (size < sizeof(src)) { + return; + } + + STREAM_TO_VALUEINFO(data, src); + + std::shared_ptr> out; + XzDecompress(&src, size, out); +} + void FaultloggerdUnwinderTest(const uint8_t* data, size_t size) { TestDfxConfig(); @@ -273,6 +287,9 @@ void FaultloggerdUnwinderTest(const uint8_t* data, size_t size) #endif TestThreadContext(data, size); TestDfxInstrStatistic(data, size); +#if defined(ENABLE_XZUTIL) + TestDfxXzUtils(data, size); +#endif sleep(1); } } // namespace HiviewDFX diff --git a/test/systemtest/faultloggerd_system_test.cpp b/test/systemtest/faultloggerd_system_test.cpp index c54307122..d88fe6d1b 100644 --- a/test/systemtest/faultloggerd_system_test.cpp +++ b/test/systemtest/faultloggerd_system_test.cpp @@ -1135,7 +1135,7 @@ HWTEST_F(FaultLoggerdSystemTest, FaultLoggerdSystemTest102, TestSize.Level2) FAIL(); } cloneStack = static_cast(static_cast(cloneStack) + stackSz - 1); - int childPid = clone(RunInNewPidNs, cloneStack, SIGCHLD, nullptr); + int childPid = clone(RunInNewPidNs, cloneStack, CLONE_NEWPID | SIGCHLD, nullptr); bool isSuccess = childPid > 0; if (!isSuccess) { ASSERT_FALSE(isSuccess); diff --git a/test/unittest/common/param_test.cpp b/test/unittest/common/param_test.cpp index 9dd4174c9..356476431 100644 --- a/test/unittest/common/param_test.cpp +++ b/test/unittest/common/param_test.cpp @@ -41,7 +41,7 @@ public: HWTEST_F(ParamTest, DfxParamTest001, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxParamTest001: start."; - ASSERT_EQ(DfxParam::IsEnableMixstack(), true); + ASSERT_EQ(DfxParam::EnableMixstack(), true); GTEST_LOG_(INFO) << "DfxParamTest001: end."; } diff --git a/test/unittest/dump_catcher/BUILD.gn b/test/unittest/dump_catcher/BUILD.gn index a97b2eea7..5c64ca12e 100644 --- a/test/unittest/dump_catcher/BUILD.gn +++ b/test/unittest/dump_catcher/BUILD.gn @@ -30,7 +30,6 @@ if (defined(ohos_lite)) { "$faultloggerd_interfaces_path/common", "$faultloggerd_path/interfaces/innerkits/backtrace/include", "$faultloggerd_path/interfaces/innerkits/dump_catcher/include", - "$faultloggerd_path/interfaces/innerkits/dump_catcher", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client/include", "$faultloggerd_path/interfaces/innerkits/formatter/include", "$faultloggerd_path/test/utils", @@ -67,22 +66,18 @@ if (defined(ohos_lite)) { "$faultloggerd_interfaces_path/common", "$faultloggerd_path/interfaces/innerkits/backtrace/include", "$faultloggerd_path/interfaces/innerkits/dump_catcher/include", - "$faultloggerd_path/interfaces/innerkits/dump_catcher", "$faultloggerd_path/interfaces/innerkits/faultloggerd_client/include", "$faultloggerd_path/interfaces/innerkits/formatter/include", "$faultloggerd_path/test/utils", ] sources = [ - "$faultloggerd_path/interfaces/innerkits/dump_catcher/kernel_stack_async_collector.cpp", "dumpcatcher_command_test.cpp", "dumpcatcher_interfaces_test.cpp", - "kernelstack_async_collector_test.cpp", ] cflags_cc = [ "-Dprivate=public" ] deps = [ - "$faultloggerd_common_path/dfxlog:dfx_hilog_base", "$faultloggerd_interfaces_path/innerkits/backtrace:libbacktrace_local", "$faultloggerd_interfaces_path/innerkits/formatter:libjson_stack_formatter", "$faultloggerd_path/interfaces/innerkits/dump_catcher:libdfx_dumpcatcher", diff --git a/test/unittest/dump_catcher/dumpcatcher_command_test.cpp b/test/unittest/dump_catcher/dumpcatcher_command_test.cpp index 28ee6c464..989d1c008 100644 --- a/test/unittest/dump_catcher/dumpcatcher_command_test.cpp +++ b/test/unittest/dump_catcher/dumpcatcher_command_test.cpp @@ -16,7 +16,6 @@ #include #include -#include #include #include "dfx_define.h" @@ -250,12 +249,34 @@ HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest014, TestSize.Level2) /** * @tc.name: DumpCatcherCommandTest015 - * @tc.desc: test dumpcatcher command: -p [accountmgr] -t [main thread] -T [1500] + * @tc.desc: test dumpcatcher abnormal scenario * @tc.type: FUNC */ HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest015, TestSize.Level2) { GTEST_LOG_(INFO) << "DumpCatcherCommandTest015: start."; + std::shared_ptr dump = make_shared(); + std::string msg = ""; + bool ret = dump->DoDumpCurrTid(0, msg, 0); + ASSERT_EQ(ret, false); + ret = dump->DoDumpLocalTid(-1, msg, 0); + ASSERT_EQ(ret, false); + ret = dump->DoDumpLocalPid(-1, msg, 0); + ASSERT_EQ(ret, false); + std::vector pidV; + ret = dump->DumpCatchMultiPid(pidV, msg); + ASSERT_EQ(ret, false); + GTEST_LOG_(INFO) << "DumpCatcherCommandTest015: end."; +} + +/** + * @tc.name: DumpCatcherCommandTest016 + * @tc.desc: test dumpcatcher command: -p [accountmgr] -t [main thread] -T [1500] + * @tc.type: FUNC + */ +HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest016, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DumpCatcherCommandTest016: start."; int testPid = GetProcessPid("accountmgr"); int timeout = 1500; string testCommand = "dumpcatcher -p " + to_string(testPid) + " -t " + to_string(testPid); @@ -267,8 +288,8 @@ HWTEST_F(DumpCatcherCommandTest, DumpCatcherCommandTest015, TestSize.Level2) log[1] = log[1] + "accountmgr"; int len = sizeof(log) / sizeof(log[0]); int count = GetKeywordsNum(dumpRes, log, len); - EXPECT_EQ(count, len) << "DumpCatcherCommandTest015 Failed"; - GTEST_LOG_(INFO) << "DumpCatcherCommandTest015: end."; + EXPECT_EQ(count, len) << "DumpCatcherCommandTest016 Failed"; + GTEST_LOG_(INFO) << "DumpCatcherCommandTest016: end."; } } // namespace HiviewDFX } // namepsace OHOS \ No newline at end of file diff --git a/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp b/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp index f8520b7ad..32ccce9d8 100644 --- a/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp +++ b/test/unittest/dump_catcher/dumpcatcher_interfaces_test.cpp @@ -26,7 +26,6 @@ #include "dfx_json_formatter.h" #include "dfx_test_util.h" #include "faultloggerd_client.h" -#include "kernel_stack_async_collector.h" #include "procinfo.h" using namespace testing; @@ -1109,34 +1108,5 @@ HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest040, TestSize.Level EXPECT_TRUE(result.first == -1); GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest040: end."; } - -/** - * @tc.name: DumpCatcherInterfacesTest041 - * @tc.desc: test dumpcatch self scenario - * @tc.type: FUNC - */ -HWTEST_F(DumpCatcherInterfacesTest, DumpCatcherInterfacesTest041, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest041: start."; - auto sleep = [] { - std::this_thread::sleep_for(std::chrono::seconds(10)); - }; - for (int i = 0; i < 10; i++) { - std::thread t(sleep); - t.detach(); - } - DfxDumpCatcher dump; - std::string stack; - bool result = dump.DumpCatch(getpid(), 0, stack); - ASSERT_EQ(result, true); - - result = dump.DumpCatch(getpid(), getpid(), stack); - ASSERT_EQ(result, true); - - std::vector pids; - result = dump.DumpCatchMultiPid(pids, stack); - ASSERT_EQ(result, false); - GTEST_LOG_(INFO) << "DumpCatcherInterfacesTest041: end."; -} } // namespace HiviewDFX } // namepsace OHOS diff --git a/test/unittest/dump_catcher/kernelstack_async_collector_test.cpp b/test/unittest/dump_catcher/kernelstack_async_collector_test.cpp deleted file mode 100644 index 38e089bc4..000000000 --- a/test/unittest/dump_catcher/kernelstack_async_collector_test.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include -#include -#include - -#include "dfx_define.h" -#include "dfx_test_util.h" -#include "kernel_stack_async_collector.h" - -using namespace testing; -using namespace testing::ext; -using namespace testing::mt; - -namespace OHOS { -namespace HiviewDFX { -std::atomic g_count = 0; -class KernelStackAsyncCollectorTest : public testing::Test { -public: - static void SetUpTestCase() {}; - static void TearDownTestCase() {}; - void SetUp() {}; - void TearDown() {}; -}; - -/** - * @tc.name: KernelStackAsyncCollectorTest001 - * @tc.desc: test KernelStackAsyncCollectorTest NotifyStartCollect interface - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest001, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest001: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - KernelStackAsyncCollector stackCollector; - pid_t tid = gettid(); - ASSERT_TRUE(stackCollector.NotifyStartCollect(tid)); - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetCollectedStackResult(); - ASSERT_NE(stack.first, KernelStackAsyncCollector::STACK_SUCCESS); - ASSERT_TRUE(stack.second.empty()); - sleep(1); - stack = stackCollector.GetCollectedStackResult(); - ASSERT_EQ(stack.first, KernelStackAsyncCollector::STACK_SUCCESS); - ASSERT_TRUE(stack.second.find(std::to_string(tid)) != std::string::npos); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest001: end."; -} - -/** - * @tc.name: KernelStackAsyncCollectorTest002 - * @tc.desc: test KernelStackAsyncCollectorTest NotifyStartCollect interface - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest002, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest002: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - KernelStackAsyncCollector stackCollector; - pid_t tid = gettid(); - int waitTime = 0; - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetProcessStackWithTimeout(tid, waitTime); - ASSERT_NE(stack.first, KernelStackAsyncCollector::STACK_SUCCESS); - ASSERT_TRUE(stack.second.empty()); - - waitTime = 1000; // 1000 : 1000ms - stack = stackCollector.GetProcessStackWithTimeout(tid, waitTime); - ASSERT_EQ(stack.first, KernelStackAsyncCollector::STACK_SUCCESS); - ASSERT_TRUE(stack.second.find(std::to_string(tid)) != std::string::npos); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest002: end."; -} - -static void NotifyCollectStackTest() -{ - KernelStackAsyncCollector stackCollector; - pid_t tid = gettid(); - if (stackCollector.NotifyStartCollect(tid)) { - sleep(1); - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetCollectedStackResult(); - ASSERT_EQ(stack.first, KernelStackAsyncCollector::STACK_SUCCESS); - ASSERT_TRUE(stack.second.find(std::to_string(tid)) != std::string::npos); - g_count++; - } -} - -static void CollectStackWithTimeoutTest() -{ - constexpr int waitTime = 1000; // 1000 : 1000ms - pid_t tid = gettid(); - KernelStackAsyncCollector stackCollector; - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetProcessStackWithTimeout(tid, waitTime); - if (stack.first == KernelStackAsyncCollector::STACK_SUCCESS) { - ASSERT_TRUE(stack.second.find(std::to_string(tid)) != std::string::npos); - g_count++; - } -} - -/** - * @tc.name: KernelStackAsyncCollectorTest003 - * @tc.desc: test KernelStackAsyncCollectorTest NotifyStartCollect interface - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest003, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest003: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - int threadCount = 3; - SET_THREAD_NUM(threadCount); - GTEST_RUN_TASK(NotifyCollectStackTest); - sleep(2); // 2 : 2s - ASSERT_EQ(g_count, threadCount); - threadCount = 10; - SET_THREAD_NUM(threadCount); - g_count = 0; - GTEST_RUN_TASK(NotifyCollectStackTest); - ASSERT_LT(g_count, threadCount); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest003: end."; -} - -/** - * @tc.name: KernelStackAsyncCollectorTest004 - * @tc.desc: test KernelStackAsyncCollectorTest GetProcessStackWithTimeout interface - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest004, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest004: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - g_count = 0; - int threadCount = 3; - SET_THREAD_NUM(threadCount); - GTEST_RUN_TASK(CollectStackWithTimeoutTest); - sleep(2); // 2 : 2s - ASSERT_EQ(g_count, threadCount); - threadCount = 10; - SET_THREAD_NUM(threadCount); - g_count = 0; - GTEST_RUN_TASK(CollectStackWithTimeoutTest); - ASSERT_LT(g_count, threadCount); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest004: end."; -} - -/** - * @tc.name: KernelStackAsyncCollectorTest005 - * @tc.desc: test KernelStackAsyncCollectorTest NotifyStartCollect interface in abnormal case - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest005, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest005: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - KernelStackAsyncCollector stackCollector; - pid_t tid = 0; - ASSERT_TRUE(stackCollector.NotifyStartCollect(tid)); - sleep(1); // 1 : 1s - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetCollectedStackResult(); - ASSERT_EQ(stack.first, KernelStackAsyncCollector::STACK_NO_PROCESS); - ASSERT_TRUE(stack.second.empty()); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest005: end."; -} - -/** - * @tc.name: KernelStackAsyncCollectorTest006 - * @tc.desc: test KernelStackAsyncCollectorTest GetProcessStackWithTimeout interface in abnormal case - * @tc.type: FUNC - */ -HWTEST_F(KernelStackAsyncCollectorTest, KernelStackAsyncCollectorTest006, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest006: start."; - std::string res = ExecuteCommands("uname"); - bool isSuccess = res.find("Linux") == std::string::npos; - if (!isSuccess) { - ASSERT_FALSE(isSuccess); - return; - } - KernelStackAsyncCollector stackCollector; - int waitTime = 1000; // 1000 : 1000ms - KernelStackAsyncCollector::KernelResult stack = stackCollector.GetProcessStackWithTimeout(0, waitTime); - ASSERT_EQ(stack.first, KernelStackAsyncCollector::STACK_NO_PROCESS); - ASSERT_TRUE(stack.second.empty()); - GTEST_LOG_(INFO) << "KernelStackAsyncCollectorTest006: end."; -} -} // namespace HiviewDFX -} // namepsace OHOS \ No newline at end of file diff --git a/test/unittest/unwind/BUILD.gn b/test/unittest/unwind/BUILD.gn index b752469b6..e7eb06a8b 100644 --- a/test/unittest/unwind/BUILD.gn +++ b/test/unittest/unwind/BUILD.gn @@ -32,7 +32,6 @@ ohos_unittest("test_unwind") { sources = [ "accessors_test.cpp", "ark_test.cpp", - "elf_factory_test.cpp", "elf_imitate.cpp", "elf_test.cpp", "fp_unwinder_test.cpp", @@ -42,8 +41,8 @@ ohos_unittest("test_unwind") { "regs_test.cpp", "signal_test.cpp", "symbols_test.cpp", - "unwind_entry_parser_test.cpp", "unwinder_test.cpp", + "xz_util_test.cpp", ] cflags_cc = [ "-Dprivate=public" ] deps = [ @@ -120,32 +119,32 @@ ohos_unittest("test_exidx") { configs = [ "$faultloggerd_common_path/build:coverage_flags" ] defines = [ "DFX_LOG_UNWIND", + "DFX_UNWIND_ERROR", "is_ohos=${is_ohos}", "is_emulator=${is_emulator}", "TEST_ARM_EXIDX", ] sources = [ - "$faultloggerd_interfaces_path/innerkits/unwinder/src/ark/dfx_ark.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/dfx_elf.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/dfx_elf_parser.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/dfx_mmap.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/dfx_symbols.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/elf_factory.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/elf/elf_factory_selector.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/maps/dfx_map.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/maps/dfx_maps.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/memory/dfx_accessors.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/memory/dfx_memory.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/registers/dfx_regs.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/registers/dfx_regs_arm.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/unwind_entry_parser/exidx_entry_parser.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/utils/dfx_config.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/utils/dfx_frame_formatter.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/utils/dfx_instructions.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/utils/dfx_ptrace.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/arch_util.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/arm_exidx.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_accessors.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_ark.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_config.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_elf.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_elf_parser.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_frame_formatter.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_instructions.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_map.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_maps.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_memory.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_mmap.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_ptrace.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_regs.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_regs_arm.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_symbols.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_xz_utils.cpp", "arm_exidx_test.cpp", ] - cflags_cc = [ "-Dprivate=public" ] deps = [ "$faultloggerd_common_path/dfxlog:dfx_hilog", "$faultloggerd_common_path/dfxutil:dfx_util", @@ -174,7 +173,7 @@ ohos_unittest("test_dwarf") { ] configs = [ "$faultloggerd_path/common/build:coverage_flags" ] sources = [ - "$faultloggerd_interfaces_path/innerkits/unwinder/src/unwind_entry_parser/dwarf_cfa_instructions.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dwarf_cfa_instructions.cpp", "dwarf_test.cpp", ] cflags_cc = [ "-Dprivate=public" ] @@ -203,10 +202,12 @@ ohos_unittest("test_unwind_supporting") { ] defines = [ "is_ohos=${is_ohos}" ] sources = [ - "$faultloggerd_interfaces_path/innerkits/unwinder/src/ark/dfx_ark.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/ark/dfx_hap.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/maps/dfx_maps.cpp", - "$faultloggerd_interfaces_path/innerkits/unwinder/src/memory/dfx_memory.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/arch_util.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_ark.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_hap.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_maps.cpp", + "$faultloggerd_interfaces_path/innerkits/unwinder/dfx_memory.cpp", + "arch_util_test.cpp", "dfx_hap_test.cpp", ] deps = [ diff --git a/test/unittest/unwind/arch_util_test.cpp b/test/unittest/unwind/arch_util_test.cpp new file mode 100644 index 000000000..d78bcaa3c --- /dev/null +++ b/test/unittest/unwind/arch_util_test.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "arch_util.h" +#include "unwind_define.h" + +using namespace OHOS::HiviewDFX; +using namespace testing::ext; +using namespace std; + +namespace OHOS { +namespace HiviewDFX { +class ArchUtilTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() {} + void TearDown() {} +}; + +/** + * @tc.name: ArchUtilTest001 + * @tc.desc: test ArchUtil functions + * @tc.type: FUNC + */ +HWTEST_F(ArchUtilTest, ArchUtilTest001, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "ArchUtilTest001: start."; + utsname systemName; +#if defined(__arm__) + if ((uname(&systemName)) != 0) { + ASSERT_EQ(GetArchFromUname(systemName.machine), ArchType::ARCH_ARM); + } + ASSERT_EQ(GetCurrentArch(), ArchType::ARCH_ARM); +#elif defined(__aarch64__) + if ((uname(&systemName)) != 0) { + ASSERT_EQ(GetArchFromUname(systemName.machine), ArchType::ARCH_ARM64); + } + ASSERT_EQ(GetCurrentArch(), ArchType::ARCH_ARM64); +#elif defined(__i386__) + if ((uname(&systemName)) != 0) { + ASSERT_EQ(GetArchFromUname(systemName.machine), ArchType::ARCH_X86); + } + ASSERT_EQ(GetCurrentArch(), ArchType::ARCH_X86); +#elif defined(__x86_64__) + if ((uname(&systemName)) != 0) { + ASSERT_EQ(GetArchFromUname(systemName.machine), ArchType::ARCH_X86_64); + } + ASSERT_EQ(GetCurrentArch(), ArchType::ARCH_X86_64); +#else + if ((uname(&systemName)) != 0) { + ASSERT_EQ(GetArchFromUname(systemName.machine), ArchType::ARCH_UNKNOWN); + } + ASSERT_EQ(GetCurrentArch(), ArchType::ARCH_UNKNOWN); +#endif + ASSERT_EQ(GetArchName(ArchType::ARCH_X86), "X86_32"); + ASSERT_EQ(GetArchName(ArchType::ARCH_X86_64), "X86_64"); + ASSERT_EQ(GetArchName(ArchType::ARCH_ARM), "ARM"); + ASSERT_EQ(GetArchName(ArchType::ARCH_ARM64), "ARM64"); + ASSERT_EQ(GetArchName(ArchType::ARCH_RISCV64), "RISCV64"); + ASSERT_EQ(GetArchName(ArchType::ARCH_UNKNOWN), "Unsupport"); + GTEST_LOG_(INFO) << "ArchUtilTest001: end."; +} + +/** + * @tc.name: ArchUtilTest002 + * @tc.desc: test ArchUtil GetArchFromUname + * @tc.type: FUNC + */ +HWTEST_F(ArchUtilTest, ArchUtilTest002, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "ArchUtilTest002: start."; + std::unordered_map machineMap = { + {"arm", ArchType::ARCH_ARM}, + {"armv8l", ArchType::ARCH_ARM64}, + {"aarch64", ArchType::ARCH_ARM64}, + {"riscv64", ArchType::ARCH_RISCV64}, + {"x86_64", ArchType::ARCH_X86_64}, + {"x86", ArchType::ARCH_X86}, + }; + + std::unordered_map::iterator it; + for (it = machineMap.begin(); it != machineMap.end(); it++) { + ArchType archType = GetArchFromUname(it->first); + ASSERT_EQ(archType, it->second); + } + std::string machine = "test"; + ArchType archType = GetArchFromUname(machine); + ASSERT_EQ(archType, ArchType::ARCH_UNKNOWN); + GTEST_LOG_(INFO) << "ArchUtilTest002: end."; +} +} // namespace HiviewDFX +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/unwind/arm_exidx_test.cpp b/test/unittest/unwind/arm_exidx_test.cpp index 6a97727f3..29fdbd84f 100644 --- a/test/unittest/unwind/arm_exidx_test.cpp +++ b/test/unittest/unwind/arm_exidx_test.cpp @@ -24,7 +24,7 @@ #include "dfx_define.h" #define private public #define protected public -#include "exidx_entry_parser.h" +#include "arm_exidx.h" #undef private #undef protected #include "dfx_memory.h" @@ -61,8 +61,9 @@ void ArmExidxTest::TearDown() HWTEST_F(ArmExidxTest, ArmExidxTest001, TestSize.Level2) { GTEST_LOG_(INFO) << "ArmExidxTest001: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); uint32_t values[] = {0x1, 0x1}; uintptr_t entryOffset = (uintptr_t)(&values[0]); // cant unwind @@ -78,8 +79,9 @@ HWTEST_F(ArmExidxTest, ArmExidxTest001, TestSize.Level2) HWTEST_F(ArmExidxTest, ArmExidxTest002, TestSize.Level2) { GTEST_LOG_(INFO) << "ArmExidxTest002: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); // inline compact model uint32_t values[] = {0x7fff2340, 0x80c0c0c0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); @@ -100,8 +102,9 @@ HWTEST_F(ArmExidxTest, ArmExidxTest002, TestSize.Level2) HWTEST_F(ArmExidxTest, ArmExidxTest003, TestSize.Level2) { GTEST_LOG_(INFO) << "ArmExidxTest003: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); //personality 0 uint32_t values0[] = {0x7fff2340, 0x00001111, 0x80c0c0c0}; @@ -150,223 +153,226 @@ HWTEST_F(ArmExidxTest, ArmExidxTest003, TestSize.Level2) } /** * @tc.name: ArmExidxTest004 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest004, TestSize.Level2) { // 00xxxxxx: vsp = vsp + (xxxxxx << 2) + 4 GTEST_LOG_(INFO) << "ArmExidxTest004: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x810010b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x44); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaRegOffset, 0x44); GTEST_LOG_(INFO) << "ArmExidxTest004: end."; } /** * @tc.name: ArmExidxTest005 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest005, TestSize.Level2) { // 01xxxxxx: vsp = vsp - (xxxxxx << 2) - 4 GTEST_LOG_(INFO) << "ArmExidxTest005: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x810041b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, -8); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaRegOffset, -8); GTEST_LOG_(INFO) << "ArmExidxTest005: end."; } /** * @tc.name: ArmExidxTest006 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest006, TestSize.Level2) { // 10000000 00000000: Refuse to unwind GTEST_LOG_(INFO) << "ArmExidxTest006: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x81008000}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - ASSERT_TRUE(exidx.Eval(entryOffset)); + + ASSERT_TRUE(exidx.Step(entryOffset, rs)); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_CANT_UNWIND); GTEST_LOG_(INFO) << "ArmExidxTest006: end."; } /** * @tc.name: ArmExidxTest007 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest007, TestSize.Level2) { // 1000iiii iiiiiiii (i not all 0) GTEST_LOG_(INFO) << "ArmExidxTest007: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x81008811}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 12); - ASSERT_EQ(exidx.rsState_->locs[3].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[3].val, -4); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 12); + ASSERT_EQ(rs->locs[3].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[3].val, -4); GTEST_LOG_(INFO) << "ArmExidxTest007: end."; } /** * @tc.name: ArmExidxTest008 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest008, TestSize.Level2) { // 10011101 || 10011111 GTEST_LOG_(INFO) << "ArmExidxTest008: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x81009db0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - ASSERT_TRUE(exidx.Eval(entryOffset)); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_RESERVED_VALUE); values[2] = 0x81009fb0; - ASSERT_TRUE(exidx.Eval(entryOffset)); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_RESERVED_VALUE); GTEST_LOG_(INFO) << "ArmExidxTest008: end."; } /** * @tc.name: ArmExidxTest009 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest009, TestSize.Level2) { GTEST_LOG_(INFO) << "ArmExidxTest009: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x81009bb0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + // 1001nnnn(nnnn != 13, 15) - ASSERT_EQ(exidx.rsState_->cfaReg, 11U); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0); + ASSERT_EQ(rs->cfaReg, 11U); + ASSERT_EQ(rs->cfaRegOffset, 0); GTEST_LOG_(INFO) << "ArmExidxTest009: end."; } /** * @tc.name: ArmExidxTest010 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest010, TestSize.Level2) { //10100nnn Pop r4-r[4+nnn] GTEST_LOG_(INFO) << "ArmExidxTest010: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100a7b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 32); - ASSERT_EQ(exidx.rsState_->locs[0].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[0].val, -20); - ASSERT_EQ(exidx.rsState_->locs[1].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[1].val, -4); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 32); + ASSERT_EQ(rs->locs[0].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[0].val, -20); + ASSERT_EQ(rs->locs[1].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[1].val, -4); GTEST_LOG_(INFO) << "ArmExidxTest010: end."; } /** * @tc.name: ArmExidxTest011 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest011, TestSize.Level2) { // 10101nnn Pop r4-r[4+nnn], r14 GTEST_LOG_(INFO) << "ArmExidxTest011: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100afb0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 36); - ASSERT_EQ(exidx.rsState_->locs[0].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[0].val, -24); - ASSERT_EQ(exidx.rsState_->locs[1].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[1].val, -8); - ASSERT_EQ(exidx.rsState_->locs[4].type, REG_LOC_MEM_OFFSET); - ASSERT_EQ(exidx.rsState_->locs[4].val, -4); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 36); + ASSERT_EQ(rs->locs[0].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[0].val, -24); + ASSERT_EQ(rs->locs[1].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[1].val, -8); + ASSERT_EQ(rs->locs[4].type, REG_LOC_MEM_OFFSET); + ASSERT_EQ(rs->locs[4].val, -4); GTEST_LOG_(INFO) << "ArmExidxTest011: end."; } /** * @tc.name: ArmExidxTest012 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest012, TestSize.Level2) { // 10110000 Finish GTEST_LOG_(INFO) << "ArmExidxTest012: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b0b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_FINISH); GTEST_LOG_(INFO) << "ArmExidxTest012: end."; } /** * @tc.name: ArmExidxTest013 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest013, TestSize.Level2) { // 10110001 00000000: Spare GTEST_LOG_(INFO) << "ArmExidxTest013: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b100}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_SPARE); // 10110001 xxxxyyyy spare @@ -376,96 +382,92 @@ HWTEST_F(ArmExidxTest, ArmExidxTest013, TestSize.Level2) /** * @tc.name: ArmExidxTest014 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest014, TestSize.Level2) { // 10110001 0000iiii(i not all 0) Pop integer registers under mask{r3, r2,r1,r0} GTEST_LOG_(INFO) << "ArmExidxTest014: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b108}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 4); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 4); GTEST_LOG_(INFO) << "ArmExidxTest014: end."; } /** * @tc.name: ArmExidxTest015 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest015, TestSize.Level2) { // 10110010 uleb128 vsp = vsp + 0x204 + (uleb128 << 2) GTEST_LOG_(INFO) << "ArmExidxTest015: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b208}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x224); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x224); GTEST_LOG_(INFO) << "ArmExidxTest015: end."; } /** * @tc.name: ArmExidxTest016 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest016, TestSize.Level2) { // 10110011 sssscccc: Pop VFP double precision registers D[ssss]-D[ssss+cccc] saved by FSTMFDX GTEST_LOG_(INFO) << "ArmExidxTest016: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b302}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x1c); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x1c); GTEST_LOG_(INFO) << "ArmExidxTest016: end."; } /** * @tc.name: ArmExidxTest017 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest017, TestSize.Level2) { // 10111nnn: VFP double-precision registers D[8]-D[8+nnn] saved by FSTMFDX GTEST_LOG_(INFO) << "ArmExidxTest016: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); - + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100b9b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x14); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x14); GTEST_LOG_(INFO) << "ArmExidxTest016: end."; } /** * @tc.name: ArmExidxTest018 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest018, TestSize.Level2) @@ -477,52 +479,50 @@ HWTEST_F(ArmExidxTest, ArmExidxTest018, TestSize.Level2) * 11000111 xxxxyyyy (xxxx!=0000): spare */ GTEST_LOG_(INFO) << "ArmExidxTest018: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); + + // 11000nnn (nnn != 6,7) uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100c1b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x10); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x10); // 11000110 sssscccc values[2] = 0x8100c602; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x18); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x18); // 11000111 00000000 : spare values[2] = 0x8100c700; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_SPARE); // 11000111 0000iiii : Intel Wireless MMX pop wCGR register under mask {wCGR3,2,1,0} values[2] = 0x8100c70f; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x10); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x10); //11000111 xxxxyyyy (xxxx!=0000): spare values[2] = 0x8100c71f; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_SPARE); GTEST_LOG_(INFO) << "ArmExidxTest018: end."; } /** * @tc.name: ArmExidxTest019 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest019, TestSize.Level2) @@ -534,57 +534,56 @@ HWTEST_F(ArmExidxTest, ArmExidxTest019, TestSize.Level2) * 11001yyy(yyy != 000, 001) Spare */ GTEST_LOG_(INFO) << "ArmExidxTest019: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); + // 11001000 sssscccc uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100c801}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x10); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x10); // 11001001 sssscccc values[2] = 0x8100c902; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x18); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x18); // 11001yyy(yyy != 000, 001) Spare values[2] = 0x8100cbb0; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_SPARE); GTEST_LOG_(INFO) << "ArmExidxTest019: end."; } /** * @tc.name: ArmExidxTest020 - * @tc.desc: test Eval + * @tc.desc: test Step * @tc.type: FUNC */ HWTEST_F(ArmExidxTest, ArmExidxTest020, TestSize.Level2) { GTEST_LOG_(INFO) << "ArmExidxTest020: start."; - std::shared_ptr memory = std::make_shared(UNWIND_TYPE_LOCAL); - ExidxEntryParser exidx(memory); + std::shared_ptr acc = std::make_shared(); + std::shared_ptr memory = std::make_shared(acc); + ArmExidx exidx(memory); + std::shared_ptr rs = std::make_shared(); + // 11010nnn Pop VFP double-precision registers D[8]-D[8+nnn] saved (as if) by VPUSH (seeremark d) uint32_t values[] = {0x7fff2340, 0x00001111, 0x8100d1b0}; uintptr_t entryOffset = (uintptr_t)(&values[0]); - exidx.rsState_ = std::make_shared(); - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); - ASSERT_EQ(exidx.rsState_->cfaRegOffset, 0x10); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); + ASSERT_EQ(rs->cfaRegOffset, 0x10); // 11xxxyyy: Spare (xxx != 000, 001, 010) values[2] = 0x8100f8b0; - ASSERT_TRUE(exidx.Eval(entryOffset)); - exidx.FlushInstr(); - ASSERT_EQ(exidx.rsState_->cfaReg, REG_SP); + ASSERT_TRUE(exidx.Step(entryOffset, rs)); + ASSERT_EQ(rs->cfaReg, REG_SP); ASSERT_EQ(exidx.GetLastErrorCode(), UNW_ERROR_ARM_EXIDX_SPARE); GTEST_LOG_(INFO) << "ArmExidxTest020: end."; } diff --git a/test/unittest/unwind/dwarf_test.cpp b/test/unittest/unwind/dwarf_test.cpp index f46b497df..c004117c0 100644 --- a/test/unittest/unwind/dwarf_test.cpp +++ b/test/unittest/unwind/dwarf_test.cpp @@ -34,6 +34,7 @@ #include "string_ex.h" #include "dfx_define.h" +#include "dfx_elf.h" #include "dfx_instructions.h" #include "dfx_log.h" #include "dfx_memory.h" @@ -41,11 +42,10 @@ #include "dwarf_cfa_instructions.h" #include "dwarf_define.h" #include "dwarf_op.h" -#include "dwarf_entry_parser.h" -#include "elf_factory.h" +#include "dwarf_section.h" #include "thread_context.h" #include "unwind_arm64_define.h" -#include "unwind_context.h" +#include "unwind_loc.h" using namespace OHOS::HiviewDFX; using namespace testing::ext; @@ -62,14 +62,10 @@ public: void TearDown() {} }; -class DwarfEntryParserTest : public DwarfEntryParser { +class DwarfSectionTest : public DwarfSection { public: - explicit DwarfEntryParserTest(std::shared_ptr memory) : DwarfEntryParser(memory) {}; - ~DwarfEntryParserTest() {}; - bool SearchEntryTest(uintptr_t pc, const UnwindTableInfo& uti, UnwindEntryInfo& uei) - { - return SearchEntry(pc, uti, uei); - } + explicit DwarfSectionTest(std::shared_ptr memory) : DwarfSection(memory) {}; + ~DwarfSectionTest() {}; bool ParseFdeTest(uintptr_t addr, FrameDescEntry &fde) { return ParseFde(addr, addr, fde); @@ -531,17 +527,18 @@ HWTEST_F(DwarfTest, DwarfTest001, TestSize.Level2) struct UnwindTableInfo uti; ASSERT_EQ(DfxElf::FindUnwindTableLocal(pc, uti), 0); - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); - DwarfEntryParserTest dwarfEntryParser(memory); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); + DwarfSectionTest dwarfSection(memory); struct UnwindEntryInfo pi; - ASSERT_EQ(true, dwarfEntryParser.SearchEntryTest(pc, uti, pi)); + ASSERT_EQ(true, dwarfSection.SearchEntry(pc, uti, pi)); FrameDescEntry fde; - ASSERT_EQ(true, dwarfEntryParser.ParseFdeTest(reinterpret_cast(pi.unwindInfo), fde)); + ASSERT_EQ(true, dwarfSection.ParseFdeTest(reinterpret_cast(pi.unwindInfo), fde)); ASSERT_GT(fde.cieAddr, 0); CommonInfoEntry cie; - ASSERT_EQ(true, dwarfEntryParser.ParseCieTest(fde.cieAddr, cie)); + ASSERT_EQ(true, dwarfSection.ParseCieTest(fde.cieAddr, cie)); RegLocState rsState; DwarfCfaInstructions instructions(memory); @@ -736,8 +733,7 @@ int32_t RedirectStdErrToFile(const std::string& path) HWTEST_F(DwarfTest, DwarfTest002, TestSize.Level2) { GTEST_LOG_(INFO) << "DwarfTest002: start."; - RegularElfFactory elfFactory("/data/test/dwarf_test_aarch64_elf"); - auto elf = elfFactory.Create(); + auto elf = DfxElf::Create("/data/test/dwarf_test_aarch64_elf"); ASSERT_NE(elf, nullptr); uint64_t loadbase = reinterpret_cast(elf->GetMmapPtr()); elf->SetLoadBase(loadbase); @@ -762,8 +758,9 @@ HWTEST_F(DwarfTest, DwarfTest002, TestSize.Level2) ASSERT_EQ(info.endPc, endPc); ASSERT_NE(info.format, -1); auto testElfFdeResult = ParseFdeResultFromFile(); - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); - DwarfEntryParserTest dwarfEntryParser(memory); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); + DwarfSectionTest dwarfSection(memory); ASSERT_EQ(testElfFdeResult.size(), info.tableLen); // cie int index = 0; for (auto& fdeResult : testElfFdeResult) { @@ -772,16 +769,16 @@ HWTEST_F(DwarfTest, DwarfTest002, TestSize.Level2) ASSERT_LT(pc, fdeResult->relPcEnd + loadbase); struct UnwindEntryInfo pi; - ASSERT_EQ(true, dwarfEntryParser.SearchEntryTest(pc, info, pi)); + ASSERT_EQ(true, dwarfSection.SearchEntry(pc, info, pi)); FrameDescEntry fde; - ASSERT_EQ(true, dwarfEntryParser.ParseFdeTest(reinterpret_cast(pi.unwindInfo), fde)); + ASSERT_EQ(true, dwarfSection.ParseFdeTest(reinterpret_cast(pi.unwindInfo), fde)); ASSERT_GT(fde.cieAddr, 0); ASSERT_EQ(fde.pcStart, fdeResult->relPcStart + loadbase); ASSERT_EQ(fde.pcEnd, fdeResult->relPcEnd + loadbase); CommonInfoEntry cie; - ASSERT_EQ(true, dwarfEntryParser.ParseCieTest(fde.cieAddr, cie)); + ASSERT_EQ(true, dwarfSection.ParseCieTest(fde.cieAddr, cie)); remove("/data/test/dwarf_test_aarch64_elf_result2"); int oldFd = RedirectStdErrToFile("/data/test/dwarf_test_aarch64_elf_result2"); diff --git a/test/unittest/unwind/elf_factory_test.cpp b/test/unittest/unwind/elf_factory_test.cpp deleted file mode 100644 index 66cd29ed8..000000000 --- a/test/unittest/unwind/elf_factory_test.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include -#include -#include - -#include "dfx_maps.h" -#include "dfx_symbols.h" -#include "dfx_test_util.h" -#include "elf_factory_selector.h" -#include "unwinder_config.h" - -using namespace testing; -using namespace testing::ext; -using namespace std; - -namespace OHOS { -namespace HiviewDFX { -namespace { - constexpr const char* const DUMPCATCHER_ELF_FILE = "/system/bin/dumpcatcher"; -} -class ElfFactoryTest : public testing::Test { -public: - static void SetUpTestCase() {} - static void TearDownTestCase() {} - void SetUp() {} - void TearDown() {} -}; - -/** - * @tc.name: ElfFactoryTest001 - * @tc.desc: test VdsoElfFactory normal case - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest001, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest001: start."; - std::string res = ExecuteCommands("uname"); - bool linuxKernel = res.find("Linux") != std::string::npos; - if (linuxKernel) { - ASSERT_TRUE(linuxKernel); - return; - } - pid_t pid = GetProcessPid(FOUNDATION_NAME); - auto maps = DfxMaps::Create(pid); - std::vector> shmmMaps; - ASSERT_TRUE(maps->FindMapsByName("[shmm]", shmmMaps)); - std::shared_ptr shmmMap = nullptr; - for (auto map : shmmMaps) { - if (map->IsMapExec()) { - shmmMap = map; - break; - } - } - ASSERT_TRUE(shmmMap != nullptr); - VdsoElfFactory factory(shmmMap->begin, shmmMap->end - shmmMap->begin, pid); - auto shmmElf = factory.Create(); - ASSERT_TRUE(shmmElf != nullptr); - std::vector shmmSyms; - DfxSymbols::ParseSymbols(shmmSyms, shmmElf, ""); - GTEST_LOG_(INFO) << "shmm symbols size" << shmmSyms.size(); - ASSERT_GT(shmmSyms.size(), 0); - for (const auto& sym : shmmSyms) { - GTEST_LOG_(INFO) << sym.ToDebugString(); - } - GTEST_LOG_(INFO) << "ElfFactoryTest001 : end."; -} - -/** - * @tc.name: ElfFactoryTest002 - * @tc.desc: test VdsoElfFactory using not vdso exec map case - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest002, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest002: start."; - pid_t pid = GetProcessPid(FOUNDATION_NAME); - auto dfxMaps = DfxMaps::Create(pid); - std::vector> maps; - ASSERT_TRUE(dfxMaps->FindMapsByName("libunwinder.z.so", maps)); - for (const auto& map : maps) { - if (map->IsMapExec()) { - VdsoElfFactory factory(map->begin, map->end - map->begin, pid); - auto elf = factory.Create(); - ASSERT_TRUE(elf == nullptr); - break; - } - } - GTEST_LOG_(INFO) << "ElfFactoryTest002 : end."; -} - -/** - * @tc.name: ElfFactoryTest003 - * @tc.desc: test VdsoElfFactory using abnormal param - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest003, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest003: start."; - uint64_t begin = 0; - size_t size = 0; - pid_t pid = 0; - VdsoElfFactory factory(begin, size, pid); - auto elf = factory.Create(); - ASSERT_TRUE(elf == nullptr); - GTEST_LOG_(INFO) << "ElfFactoryTest003 : end."; -} - -#ifndef __x86_64__ -/** - * @tc.name: ElfFactoryTest004 - * @tc.desc: test MiniDebugInfoFactory normal case - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest004, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest004: start."; - UnwinderConfig::SetEnableMiniDebugInfo(true); - RegularElfFactory regularElfFactory(DUMPCATCHER_ELF_FILE); - auto elf = regularElfFactory.Create(); - ASSERT_TRUE(elf->IsValid()); - auto gnuDebugDataHdr = elf->GetGnuDebugDataHdr(); - ASSERT_TRUE(gnuDebugDataHdr.size != 0); - MiniDebugInfoFactory miniDebugInfoFactory(gnuDebugDataHdr); - elf = miniDebugInfoFactory.Create(); - ASSERT_TRUE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest004: end."; -} - -/** - * @tc.name: ElfFactoryTest005 - * @tc.desc: test MiniDebugInfoFactory normal case with test parsing symbol - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest005, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest005: start."; - UnwinderConfig::SetEnableMiniDebugInfo(true); - RegularElfFactory regularElfFactory(DUMPCATCHER_ELF_FILE); - auto elf = regularElfFactory.Create(); - ASSERT_TRUE(elf->IsValid()); - auto gnuDebugDataHdr = elf->GetGnuDebugDataHdr(); - ASSERT_TRUE(gnuDebugDataHdr.size != 0); - MiniDebugInfoFactory miniDebugInfoFactory(gnuDebugDataHdr); - elf = miniDebugInfoFactory.Create(); - ASSERT_TRUE(elf->IsValid()); - std::vector symbols; - DfxSymbols::ParseSymbols(symbols, elf, ""); - GTEST_LOG_(INFO) << "symbols size" << symbols.size(); - ASSERT_GT(symbols.size(), 0); - for (const auto& symbol : symbols) { - GTEST_LOG_(INFO) << symbol.ToDebugString(); - } - GTEST_LOG_(INFO) << "ElfFactoryTest005: end."; -} - -/** - * @tc.name: ElfFactoryTest006 - * @tc.desc: test MiniDebugInfoFactory disable minidebuginfo case - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest006, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest006: start."; - UnwinderConfig::SetEnableMiniDebugInfo(false); - RegularElfFactory regularElfFactory(DUMPCATCHER_ELF_FILE); - auto elf = regularElfFactory.Create(); - ASSERT_TRUE(elf->IsValid()); - auto gnuDebugDataHdr = elf->GetGnuDebugDataHdr(); - ASSERT_TRUE(gnuDebugDataHdr.size != 0); - MiniDebugInfoFactory miniDebugInfoFactory(gnuDebugDataHdr); - elf = miniDebugInfoFactory.Create(); - ASSERT_TRUE(elf == nullptr); - GTEST_LOG_(INFO) << "ElfFactoryTest006: end."; -} - -/** - * @tc.name: ElfFactoryTest007 - * @tc.desc: test MiniDebugInfoFactory using abnormal param - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest007, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest007: start."; - UnwinderConfig::SetEnableMiniDebugInfo(true); - GnuDebugDataHdr hdr; - MiniDebugInfoFactory miniDebugInfoFactory(hdr); - auto elf = miniDebugInfoFactory.Create(); - ASSERT_TRUE(elf == nullptr); - GTEST_LOG_(INFO) << "ElfFactoryTest007: end."; -} - -/** - * @tc.name: ElfFactoryTest008 - * @tc.desc: test MiniDebugInfoFactory using abnormal param - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest008, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest008: start."; - UnwinderConfig::SetEnableMiniDebugInfo(false); - GnuDebugDataHdr hdr; - MiniDebugInfoFactory miniDebugInfoFactory(hdr); - auto elf = miniDebugInfoFactory.Create(); - ASSERT_TRUE(elf == nullptr); - GTEST_LOG_(INFO) << "ElfFactoryTest008: end."; -} -#endif - -/** - * @tc.name: ElfFactoryTest009 - * @tc.desc: test ElfFactoryTest with 64 bit ELF - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest009, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest009: start."; - const char* elf64File = "/data/test/resource/testdata/elf_test"; - RegularElfFactory factory(elf64File); - auto elf = factory.Create(); - ASSERT_TRUE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest009: end."; -} - -/** - * @tc.name: ElfFactoryTest010 - * @tc.desc: ElfFactoryTest with 32 bit ELF - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest010, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest010: start."; - const char* elf32File = "/data/test/resource/testdata/elf32_test"; - RegularElfFactory factory(elf32File); - auto elf = factory.Create(); - ASSERT_TRUE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest010: end."; -} - -/** - * @tc.name: ElfFactoryTest011 - * @tc.desc: test DfxElf functions with empty file path - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest011, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest002: start."; - std::string filePath = ""; - RegularElfFactory factory(filePath); - auto elf = factory.Create(); - ASSERT_FALSE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest011: end."; -} - -/** - * @tc.name: ElfFactoryTest012 - * @tc.desc: test DfxElf functions with invalid filePath - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest012, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest012: start."; - std::string filePath = "[anno:stack:2345]"; - RegularElfFactory factory(filePath); - auto elf = factory.Create(); - ASSERT_FALSE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest012: end."; -} - -/** - * @tc.name: ElfFactoryTest013 - * @tc.desc: ElfFactorySelector in normal case - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest013, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest013: start."; - pid_t pid = GetProcessPid(FOUNDATION_NAME); - auto dfxMaps = DfxMaps::Create(pid); - auto maps = dfxMaps->GetMaps(); - for (const auto& map : maps) { - auto elfFactory = ElfFactorySelector::Select(*(map.get()), pid); - auto elf = elfFactory->Create(); - if (map->IsVdsoMap()) { - ASSERT_TRUE(elf->IsValid()); - GTEST_LOG_(INFO) << elf->GetElfName(); - ASSERT_TRUE(elf->GetElfName().find("shmm") != std::string::npos || - elf->GetElfName().find("vdso") != std::string::npos); - } else if (DfxMaps::IsLegalMapItem(map->name) && map->IsMapExec()) { - ASSERT_TRUE(elf->IsValid()) << map->name; - } - } - GTEST_LOG_(INFO) << "ElfFactoryTest013: end."; -} - -/** - * @tc.name: ElfFactoryTest014 - * @tc.desc: ElfFactorySelector using abnormal param - * @tc.type: FUNC - */ -HWTEST_F(ElfFactoryTest, ElfFactoryTest014, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "ElfFactoryTest014: start."; - DfxMap map; - auto elfFactory = ElfFactorySelector::Select(map); - auto elf = elfFactory->Create(); - ASSERT_FALSE(elf->IsValid()); - GTEST_LOG_(INFO) << "ElfFactoryTest014: end."; -} -} -} \ No newline at end of file diff --git a/test/unittest/unwind/elf_imitate.cpp b/test/unittest/unwind/elf_imitate.cpp index 68ed80eca..dca173a2e 100644 --- a/test/unittest/unwind/elf_imitate.cpp +++ b/test/unittest/unwind/elf_imitate.cpp @@ -756,7 +756,7 @@ bool ElfImitate::ParseElfSymbols() } else { elfSymbol.shndx = static_cast(std::stoul(strVec[INDEX_I6])); } - funcSymbols_.push_back(elfSymbol); + elfSymbols_.push_back(elfSymbol); } return true; } @@ -793,12 +793,12 @@ bool ElfImitate::GetSectionInfo(ShdrInfo& shdr, const std::string& securityName) return false; } -const std::vector& ElfImitate::GetFuncSymbols() +const std::vector& ElfImitate::GetElfSymbols() { - if (funcSymbols_.empty()) { + if (elfSymbols_.empty()) { ParseElfSymbols(); } - return funcSymbols_; + return elfSymbols_; } uint64_t ElfImitate::GetLoadBase(uint64_t mapStart, uint64_t mapOffset) { @@ -834,7 +834,7 @@ bool ElfImitate::IsFunc(const ElfSymbol symbol) bool ElfImitate::ParseSymbols(std::vector& symbols, const std::string& filePath) { - std::vector elfSymbols = GetFuncSymbols(); + std::vector elfSymbols = GetElfSymbols(); for (auto elfSymbol : elfSymbols) { if (IsFunc(elfSymbol)) { if (elfSymbol.value == 0 || elfSymbol.size == 0) { diff --git a/test/unittest/unwind/elf_test.cpp b/test/unittest/unwind/elf_test.cpp index d4f511fdc..60b72bfb5 100644 --- a/test/unittest/unwind/elf_test.cpp +++ b/test/unittest/unwind/elf_test.cpp @@ -21,7 +21,6 @@ #include #include "dfx_elf.h" #include "elf_imitate.h" -#include "elf_factory.h" #include "unwinder_config.h" using namespace OHOS::HiviewDFX; @@ -53,41 +52,41 @@ std::vector interestedSections = { ".dynsym", ".eh_frame_hdr", ".eh HWTEST_F(DfxElfTest, DfxElfTest001, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxElfTest001: start."; - RegularElfFactory factory(ELF32_FILE); - auto elf = factory.Create(); - ASSERT_TRUE(elf != nullptr); + DfxElf elf(ELF32_FILE); + ASSERT_TRUE(elf.IsValid()); ElfImitate elfImitate; ShdrInfo shdr; ShdrInfo shdrImitate; bool ret = elfImitate.ParseAllHeaders(ElfImitate::ElfFileType::ELF32); ASSERT_TRUE(ret); for (size_t i = 0; i < interestedSections.size(); i++) { - elf->GetSectionInfo(shdr, interestedSections[i]); + elf.GetSectionInfo(shdr, interestedSections[i]); elfImitate.GetSectionInfo(shdrImitate, interestedSections[i]); GTEST_LOG_(INFO) << interestedSections[i]; ASSERT_EQ(shdr.addr, shdrImitate.addr); ASSERT_EQ(shdr.offset, shdrImitate.offset); ASSERT_EQ(shdr.size, shdrImitate.size); } - ASSERT_EQ(elf->GetArchType(), elfImitate.GetArchType()); - ASSERT_EQ(elf->GetElfSize(), elfImitate.GetElfSize()); - ASSERT_EQ(elf->GetLoadBias(), elfImitate.GetLoadBias()); + ASSERT_EQ(elf.GetArchType(), elfImitate.GetArchType()); + ASSERT_EQ(elf.GetElfSize(), elfImitate.GetElfSize()); + ASSERT_EQ(elf.GetLoadBias(), elfImitate.GetLoadBias()); - auto load = elf->GetPtLoads(); + auto load = elf.GetPtLoads(); auto loadImitate = elfImitate.GetPtLoads(); ASSERT_EQ(load[PT_LOAD_OFFSET].offset, loadImitate[PT_LOAD_OFFSET].offset); ASSERT_EQ(load[PT_LOAD_OFFSET].tableSize, loadImitate[PT_LOAD_OFFSET].tableSize); ASSERT_EQ(load[PT_LOAD_OFFSET].tableVaddr, loadImitate[PT_LOAD_OFFSET].tableVaddr); - ASSERT_EQ(elf->GetClassType(), elfImitate.GetClassType()); - ASSERT_EQ(elf->GetLoadBase(0xf78c0000, 0), elfImitate.GetLoadBase(0xf78c0000, 0)); - ASSERT_EQ(elf->GetStartPc(), elfImitate.GetStartPc()); - ASSERT_EQ(elf->GetEndPc(), elfImitate.GetEndPc()); - ASSERT_EQ(elf->GetRelPc(0xf78c00f0, 0xf78c0000, 0), elfImitate.GetRelPc(0xf78c00f0, 0xf78c0000, 0)); - ASSERT_EQ(elf->GetBuildId(), "8e5a30338be326934ff93c998dcd0d22fe345870"); - EXPECT_NE(elf->GetGlobalPointer(), 0); - EXPECT_FALSE(elf->GetFuncSymbols().empty()); - EXPECT_GT(elf->GetMmapSize(), 0); + ASSERT_EQ(elf.GetClassType(), elfImitate.GetClassType()); + ASSERT_EQ(elf.GetLoadBase(0xf78c0000, 0), elfImitate.GetLoadBase(0xf78c0000, 0)); + ASSERT_EQ(elf.GetStartPc(), elfImitate.GetStartPc()); + ASSERT_EQ(elf.GetEndPc(), elfImitate.GetEndPc()); + ASSERT_EQ(elf.GetRelPc(0xf78c00f0, 0xf78c0000, 0), elfImitate.GetRelPc(0xf78c00f0, 0xf78c0000, 0)); + ASSERT_EQ(elf.GetBuildId(), "8e5a30338be326934ff93c998dcd0d22fe345870"); + EXPECT_NE(DfxElf::Create(ELF32_FILE), nullptr); + EXPECT_NE(elf.GetGlobalPointer(), 0); + EXPECT_FALSE(elf.GetElfSymbols().empty()); + EXPECT_GT(elf.GetMmapSize(), 0); GTEST_LOG_(INFO) << "DfxElfTest001: end."; } @@ -99,9 +98,8 @@ HWTEST_F(DfxElfTest, DfxElfTest001, TestSize.Level2) HWTEST_F(DfxElfTest, DfxElfTest002, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxElfTest002: start."; - RegularElfFactory factory(ELF64_FILE); - auto elf = factory.Create(); - ASSERT_TRUE(elf != nullptr); + DfxElf elf(ELF64_FILE); + ASSERT_TRUE(elf.IsValid()); ElfImitate elfImitate; ShdrInfo shdr; ShdrInfo shdrImitate; @@ -109,31 +107,31 @@ HWTEST_F(DfxElfTest, DfxElfTest002, TestSize.Level2) ASSERT_TRUE(ret); for (size_t i = 0; i < interestedSections.size(); i++) { GTEST_LOG_(INFO) << interestedSections[i]; - elf->GetSectionInfo(shdr, interestedSections[i]); + elf.GetSectionInfo(shdr, interestedSections[i]); elfImitate.GetSectionInfo(shdrImitate, interestedSections[i]); ASSERT_EQ(shdr.addr, shdrImitate.addr); ASSERT_EQ(shdr.offset, shdrImitate.offset); ASSERT_EQ(shdr.size, shdrImitate.size); } - ASSERT_EQ(elf->GetArchType(), elfImitate.GetArchType()); - ASSERT_EQ(elf->GetElfSize(), elfImitate.GetElfSize()); - ASSERT_EQ(elf->GetLoadBias(), elfImitate.GetLoadBias()); + ASSERT_EQ(elf.GetArchType(), elfImitate.GetArchType()); + ASSERT_EQ(elf.GetElfSize(), elfImitate.GetElfSize()); + ASSERT_EQ(elf.GetLoadBias(), elfImitate.GetLoadBias()); - auto load = elf->GetPtLoads(); + auto load = elf.GetPtLoads(); auto loadImitate = elfImitate.GetPtLoads(); ASSERT_EQ(load[PT_LOAD_OFFSET64].offset, loadImitate[PT_LOAD_OFFSET64].offset); ASSERT_EQ(load[PT_LOAD_OFFSET64].tableSize, loadImitate[PT_LOAD_OFFSET64].tableSize); ASSERT_EQ(load[PT_LOAD_OFFSET64].tableVaddr, loadImitate[PT_LOAD_OFFSET64].tableVaddr); - ASSERT_EQ(elf->GetClassType(), elfImitate.GetClassType()); - ASSERT_EQ(elf->GetLoadBase(0xf78c0000, 0), elfImitate.GetLoadBase(0xf78c0000, 0)); - ASSERT_EQ(elf->GetStartPc(), elfImitate.GetStartPc()); - ASSERT_EQ(elf->GetEndPc(), elfImitate.GetEndPc()); - ASSERT_EQ(elf->GetRelPc(0xf78c00f0, 0xf78c0000, 0), elfImitate.GetRelPc(0xf78c00f0, 0xf78c0000, 0)); - ASSERT_EQ(elf->GetBuildId(), "24c55dccc5baaaa140da0083207abcb8d523e248"); - EXPECT_NE(elf->GetGlobalPointer(), 0); - EXPECT_FALSE(elf->GetFuncSymbols().empty()); - EXPECT_GT(elf->GetMmapSize(), 0); + ASSERT_EQ(elf.GetClassType(), elfImitate.GetClassType()); + ASSERT_EQ(elf.GetLoadBase(0xf78c0000, 0), elfImitate.GetLoadBase(0xf78c0000, 0)); + ASSERT_EQ(elf.GetStartPc(), elfImitate.GetStartPc()); + ASSERT_EQ(elf.GetEndPc(), elfImitate.GetEndPc()); + ASSERT_EQ(elf.GetRelPc(0xf78c00f0, 0xf78c0000, 0), elfImitate.GetRelPc(0xf78c00f0, 0xf78c0000, 0)); + ASSERT_EQ(elf.GetBuildId(), "24c55dccc5baaaa140da0083207abcb8d523e248"); + EXPECT_NE(elf.GetGlobalPointer(), 0); + EXPECT_FALSE(elf.GetElfSymbols().empty()); + EXPECT_GT(elf.GetMmapSize(), 0); GTEST_LOG_(INFO) << "DfxElfTest002: end."; } @@ -145,11 +143,13 @@ HWTEST_F(DfxElfTest, DfxElfTest002, TestSize.Level2) HWTEST_F(DfxElfTest, DfxElfTest003, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxElfTest003: start."; - DfxElf elf(nullptr); + DfxElf elf(""); ASSERT_FALSE(elf.IsValid()); ASSERT_EQ(elf.GetClassType(), ELFCLASSNONE); ASSERT_EQ(elf.GetElfSize(), 0); ASSERT_TRUE(elf.GetBuildId().empty()); + EXPECT_EQ(DfxElf::Create("123"), nullptr); + ASSERT_TRUE(DfxElf::ToReadableBuildId("").empty()); EXPECT_EQ(elf.GetGlobalPointer(), 0); ShdrInfo shdrInfo; EXPECT_FALSE(elf.GetSectionInfo(shdrInfo, "")); @@ -167,19 +167,15 @@ HWTEST_F(DfxElfTest, DfxElfTest004, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxElfTest004: start."; UnwinderConfig::SetEnableMiniDebugInfo(true); - RegularElfFactory factory(DUMPCATCHER_ELF_FILE); - auto elf = factory.Create(); - ASSERT_TRUE(elf->IsValid()); - auto symbols = elf->GetFuncSymbols(); - GTEST_LOG_(INFO) << "DfxElfTest004: symbols1 size:" << symbols.size(); - - UnwinderConfig::SetEnableMiniDebugInfo(false); - auto regularElf = factory.Create(); - ASSERT_TRUE(regularElf->IsValid()); - auto regularSymbols = regularElf->GetFuncSymbols(); - GTEST_LOG_(INFO) << "DfxElfTest004: symbols2 size:" << regularSymbols.size(); - ASSERT_GE(regularSymbols.size(), 0); - ASSERT_GE(symbols.size(), regularSymbols.size()); + DfxElf elf(DUMPCATCHER_ELF_FILE); + ASSERT_TRUE(elf.IsValid()); + ASSERT_TRUE(elf.IsEmbeddedElfValid()); + auto symbols1 = elf.GetFuncSymbols(); + GTEST_LOG_(INFO) << "DfxElfTest004: symbols1 size:" << symbols1.size(); + auto symbols2 = elf.GetEmbeddedElf()->GetFuncSymbols(); + GTEST_LOG_(INFO) << "DfxElfTest004: symbols2 size:" << symbols2.size(); + ASSERT_GE(symbols2.size(), 0); + ASSERT_GE(symbols1.size(), symbols2.size()); GTEST_LOG_(INFO) << "DfxElfTest004: end."; } #endif @@ -191,19 +187,31 @@ HWTEST_F(DfxElfTest, DfxElfTest004, TestSize.Level2) */ HWTEST_F(DfxElfTest, DfxElfTest005, TestSize.Level2) { - auto elfFile = std::make_shared(nullptr); + auto elfFile = std::make_shared(""); ASSERT_NE(elfFile, nullptr); EXPECT_STREQ(elfFile->GetBuildId().c_str(), ""); } /** * @tc.name: DfxElfTest006 - * @tc.desc: test SetBaseOffset function and GetBaseOffset function + * @tc.desc: test GetBuildId function when input illegal elf file path * @tc.type: FUNC */ HWTEST_F(DfxElfTest, DfxElfTest006, TestSize.Level2) { - auto elf = std::make_shared(nullptr); + auto elfFile = std::make_shared("/proc/illegal"); + ASSERT_NE(elfFile, nullptr); + EXPECT_STREQ(elfFile->GetBuildId().c_str(), ""); +} + +/** + * @tc.name: DfxElfTest007 + * @tc.desc: test SetBaseOffset function and GetBaseOffset function + * @tc.type: FUNC + */ +HWTEST_F(DfxElfTest, DfxElfTest007, TestSize.Level2) +{ + auto elf = std::make_shared(""); ASSERT_EQ(elf->GetBaseOffset(), 0); elf->SetBaseOffset(1); ASSERT_EQ(elf->GetBaseOffset(), 1); diff --git a/test/unittest/unwind/include/elf_imitate.h b/test/unittest/unwind/include/elf_imitate.h index f78a3fb1c..82fcda1de 100644 --- a/test/unittest/unwind/include/elf_imitate.h +++ b/test/unittest/unwind/include/elf_imitate.h @@ -63,7 +63,7 @@ public: int64_t GetLoadBias() { return loadBias_; } uint64_t GetStartVaddr() { return startVaddr_; } uint64_t GetEndVaddr() { return endVaddr_; } - const std::vector& GetFuncSymbols(); + const std::vector& GetElfSymbols(); bool GetSectionInfo(ShdrInfo& shdr, const std::string& securityName); const std::unordered_map& GetPtLoads() {return ptLoads_;} uint8_t GetClassType() { return classType_;} @@ -81,7 +81,7 @@ protected: bool ParseElfSymbols(); protected: - std::vector funcSymbols_; + std::vector elfSymbols_; private: std::vector StringSplit(std::string src, const std::string split); diff --git a/test/unittest/unwind/memory_test.cpp b/test/unittest/unwind/memory_test.cpp index a5c18e43a..ad2866cbd 100644 --- a/test/unittest/unwind/memory_test.cpp +++ b/test/unittest/unwind/memory_test.cpp @@ -28,8 +28,7 @@ #include "dfx_ptrace.h" #include "dfx_test_util.h" #include "dwarf_define.h" -#include "elf_factory.h" -#include "stack_utils.h" +#include "stack_util.h" using namespace OHOS::HiviewDFX; using namespace testing::ext; @@ -57,7 +56,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest001, TestSize.Level2) uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}; UnwindContext ctx; ctx.regs = DfxRegs::CreateFromRegs(UnwindMode::DWARF_UNWIND, regs, sizeof(regs) / sizeof(regs[0])); - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t value; bool ret = memory->ReadReg(0, &value); @@ -78,7 +78,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest002, TestSize.Level2) uintptr_t addr = reinterpret_cast(&values[0]); uintptr_t value; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); bool ret = memory->Read(addr, &value, false); EXPECT_EQ(true, ret) << "DfxMemoryTest002: ret:" << ret; @@ -109,9 +110,9 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest003, TestSize.Level2) GTEST_LOG_(INFO) << "DfxMemoryTest003: start."; uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; UnwindContext ctx; - ASSERT_TRUE(StackUtils::GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); - ctx.stackCheck = true; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + ASSERT_TRUE(GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); uintptr_t value; @@ -148,9 +149,9 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest004, TestSize.Level2) GTEST_LOG_(INFO) << "DfxMemoryTest004: start."; uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; UnwindContext ctx; - ASSERT_TRUE(StackUtils::GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); - ctx.stackCheck = true; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + ASSERT_TRUE(GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); uint8_t tmp8; @@ -178,9 +179,9 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest005, TestSize.Level2) GTEST_LOG_(INFO) << "DfxMemoryTest005: start."; uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; UnwindContext ctx; - ASSERT_TRUE(StackUtils::GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); - ctx.stackCheck = true; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + ASSERT_TRUE(GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); uintptr_t valuePrel32; @@ -205,9 +206,9 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest006, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxMemoryTest006: start."; UnwindContext ctx; - ASSERT_TRUE(StackUtils::GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); - ctx.stackCheck = true; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + ASSERT_TRUE(GetSelfStackRange(ctx.stackBottom, ctx.stackTop)); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); ASSERT_EQ(memory->GetEncodedSize(DW_EH_PE_absptr), sizeof(uintptr_t)); ASSERT_EQ(memory->GetEncodedSize(DW_EH_PE_sdata1), 1); @@ -228,7 +229,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest007, TestSize.Level2) uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}; UnwindContext ctx; ctx.regs = DfxRegs::CreateFromRegs(UnwindMode::DWARF_UNWIND, regs, sizeof(regs) / sizeof(regs[0])); - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t value; bool ret = memory->ReadReg(0, &value); @@ -253,7 +255,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest008, TestSize.Level2) uintptr_t value; UnwindContext ctx; ctx.pid = pid; - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); bool ret = memory->Read(addr, &value, false); @@ -295,7 +298,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest009, TestSize.Level2) DfxPtrace::Attach(pid); UnwindContext ctx; ctx.pid = pid; - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); uintptr_t value; @@ -344,7 +348,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest010, TestSize.Level2) UnwindContext ctx; ctx.pid = pid; - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); uint8_t tmp8; @@ -385,7 +390,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest011, TestSize.Level2) DfxPtrace::Attach(getppid()); UnwindContext ctx; ctx.pid = getppid(); - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); uintptr_t addr = reinterpret_cast(&values[0]); std::string resultStr; @@ -420,7 +426,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest012, TestSize.Level2) DfxPtrace::Attach(pid); UnwindContext ctx; ctx.pid = pid; - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); memory->SetCtx(&ctx); ASSERT_EQ(memory->GetEncodedSize(DW_EH_PE_absptr), sizeof(uintptr_t)); ASSERT_EQ(memory->GetEncodedSize(DW_EH_PE_sdata1), 1); @@ -444,7 +451,8 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest012, TestSize.Level2) HWTEST_F(DfxMemoryTest, DfxMemoryTest013, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxMemoryTest013: start."; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); uintptr_t val; EXPECT_FALSE(memory->ReadReg(0, &val)); uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}; @@ -464,6 +472,46 @@ HWTEST_F(DfxMemoryTest, DfxMemoryTest013, TestSize.Level2) EXPECT_FALSE(memory->Read(addr, nullptr, false)); GTEST_LOG_(INFO) << "DfxMemoryTest013: end."; } + +/** + * @tc.name: DfxMemoryTest014 + * @tc.desc: test DfxMemory class ReadProcMemByPid + * @tc.type: FUNC + */ +HWTEST_F(DfxMemoryTest, DfxMemoryTest014, TestSize.Level2) +{ + GTEST_LOG_(INFO) << "DfxMemoryTest014: start."; + std::string res = ExecuteCommands("uname"); + bool linuxKernel = res.find("Linux") != std::string::npos; + if (linuxKernel) { + ASSERT_TRUE(linuxKernel); + return; + } + pid_t pid = GetProcessPid(FOUNDATION_NAME); + auto maps = DfxMaps::Create(pid); + std::vector> shmmMaps; + ASSERT_TRUE(maps->FindMapsByName("[shmm]", shmmMaps)); + std::shared_ptr shmmMap = nullptr; + for (auto map : shmmMaps) { + if (map->IsMapExec()) { + shmmMap = map; + break; + } + } + ASSERT_TRUE(shmmMap != nullptr); + auto shmmData = std::make_shared>(shmmMap->end - shmmMap->begin); + DfxMemory::ReadProcMemByPid(pid, shmmMap->begin, shmmData->data(), shmmMap->end - shmmMap->begin); + auto shmmElf = std::make_shared(shmmData->data(), shmmMap->end - shmmMap->begin); + ASSERT_TRUE(shmmElf->IsValid()); + std::vector shmmSyms; + DfxSymbols::ParseSymbols(shmmSyms, shmmElf, ""); + GTEST_LOG_(INFO) << "shmm symbols size" << shmmSyms.size(); + ASSERT_GT(shmmSyms.size(), 0); + for (auto& sym : shmmSyms) { + GTEST_LOG_(INFO) << sym.ToDebugString(); + } + GTEST_LOG_(INFO) << "DfxMemoryTest014 : end."; +} } } // namespace HiviewDFX } // namespace OHOS diff --git a/test/unittest/unwind/symbols_test.cpp b/test/unittest/unwind/symbols_test.cpp index e0c815002..c088b8afc 100644 --- a/test/unittest/unwind/symbols_test.cpp +++ b/test/unittest/unwind/symbols_test.cpp @@ -20,7 +20,7 @@ #include #include #include -#include "elf_factory.h" +#include "dfx_elf.h" #include "elf_imitate.h" #include "unwinder_config.h" @@ -50,8 +50,7 @@ public: HWTEST_F(DfxSymbolsTest, DfxSymbolsTest001, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxSymbolsTest001: start."; - RegularElfFactory factory(ELF32_FILE); - auto elf = factory.Create(); + std::shared_ptr elf = make_shared(ELF32_FILE); ASSERT_TRUE(elf->IsValid()); ElfImitate elfImitate; elfImitate.ParseAllHeaders(ElfImitate::ElfFileType::ELF32); @@ -92,8 +91,7 @@ HWTEST_F(DfxSymbolsTest, DfxSymbolsTest001, TestSize.Level2) HWTEST_F(DfxSymbolsTest, DfxSymbolsTest002, TestSize.Level2) { GTEST_LOG_(INFO) << "DfxSymbolsTest002: start."; - RegularElfFactory factory(ELF64_FILE); - auto elf = factory.Create(); + std::shared_ptr elf = make_shared(ELF64_FILE); ASSERT_TRUE(elf->IsValid()); ElfImitate elfImitate; elfImitate.ParseAllHeaders(ElfImitate::ElfFileType::ELF64); @@ -138,9 +136,9 @@ HWTEST_F(DfxSymbolsTest, DfxSymbolsTest003, TestSize.Level2) GTEST_LOG_(INFO) << "DfxSymbolsTest003: start."; UnwinderConfig::SetEnableMiniDebugInfo(true); std::vector dfxSymbols; - RegularElfFactory factory(DUMPCATCHER_ELF_FILE); - auto elf = factory.Create(); + std::shared_ptr elf = make_shared(DUMPCATCHER_ELF_FILE); ASSERT_TRUE(elf->IsValid()); + ASSERT_TRUE(elf->IsEmbeddedElfValid()); DfxSymbols::ParseSymbols(dfxSymbols, elf, DUMPCATCHER_ELF_FILE); GTEST_LOG_(INFO) << "DfxSymbolsTest003: symbols size:" << dfxSymbols.size(); ASSERT_GE(dfxSymbols.size(), 0); diff --git a/test/unittest/unwind/unwind_entry_parser_test.cpp b/test/unittest/unwind/unwind_entry_parser_test.cpp deleted file mode 100644 index 2f0776c3a..000000000 --- a/test/unittest/unwind/unwind_entry_parser_test.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2025 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include - -#include -#include -#include - -#include "dfx_maps.h" -#include "dfx_memory.h" -#include "dfx_ptrace.h" -#include "dfx_regs.h" -#include "dfx_regs_get.h" -#include "dfx_test_util.h" -#include "unwind_context.h" -#include "unwind_define.h" -#include "unwind_entry_parser_factory.h" - - -using namespace testing; -using namespace testing::ext; -using namespace std; - -namespace OHOS { -namespace HiviewDFX { -class UnwindEntryParserTest : public testing::Test { -public: - static void SetUpTestCase() {} - static void TearDownTestCase() {} - void SetUp() {} - void TearDown() {} -}; - -/** - * @tc.name: UnwindEntryParser001 - * @tc.desc: test UnwindEntryParser in local case - * @tc.type: FUNC - */ -HWTEST_F(UnwindEntryParserTest, UnwindEntryParseTest001, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "UnwindEntryParser001: start."; - auto regs = DfxRegs::Create(); - auto regsData = regs->RawData(); - GetLocalRegs(regsData); - UnwindContext context; - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); - memory->SetCtx(&context); - UnwindTableInfo uti; - ASSERT_TRUE(memory->FindUnwindTable(regs->GetPc(), uti) == UNW_ERROR_NONE); - auto unwindEntryParser = UnwindEntryParserFactory::CreateUnwindEntryParser(memory); - std::shared_ptr rs = std::make_shared(); - ASSERT_TRUE(unwindEntryParser->Step(regs->GetPc(), uti, rs)); - GTEST_LOG_(INFO) << "UnwindEntryParser001: end."; -} - -/** - * @tc.name: UnwindEntryParser002 - * @tc.desc: test UnwindEntryParser in remote case - * @tc.type: FUNC - */ -HWTEST_F(UnwindEntryParserTest, UnwindEntryParseTest002, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "UnwindEntryParser002: start."; - pid_t childPid = fork(); - if (childPid != 0) { - ASSERT_TRUE(DfxPtrace::Attach(childPid)); - auto regs = DfxRegs::CreateRemoteRegs(childPid); - UnwindContext context; - context.pid = childPid; - context.regs = regs; - context.maps = DfxMaps::Create(childPid); - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); - memory->SetCtx(&context); - std::shared_ptr map = nullptr; - uintptr_t pc = regs->GetPc(); - ASSERT_TRUE(memory->GetMapByPc(pc, map) == UNW_ERROR_NONE); - UnwindTableInfo uti; - ASSERT_TRUE(memory->FindUnwindTable(pc, uti) == UNW_ERROR_NONE); - auto unwindEntryParser = UnwindEntryParserFactory::CreateUnwindEntryParser(memory); - std::shared_ptr rs = std::make_shared(); - ASSERT_TRUE(unwindEntryParser->Step(pc, uti, rs)); - DfxPtrace::Detach(childPid); - } else { - const int sleepTime = 2; - sleep(sleepTime); - _exit(0); - } - GTEST_LOG_(INFO) << "UnwindEntryParser002: end."; -} - -/** - * @tc.name: UnwindEntryParser003 - * @tc.desc: test UnwindEntryParser in abnomal case - * @tc.type: FUNC - */ -HWTEST_F(UnwindEntryParserTest, UnwindEntryParseTest003, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "UnwindEntryParser003: start."; - std::shared_ptr memory = nullptr; - int pc = 0; - auto unwindEntryParser = UnwindEntryParserFactory::CreateUnwindEntryParser(memory); - std::shared_ptr rs = std::make_shared(); - UnwindTableInfo uti; - ASSERT_FALSE(unwindEntryParser->Step(pc, uti, rs)); - GTEST_LOG_(INFO) << "UnwindEntryParser003: end."; -} - -/** - * @tc.name: UnwindEntryParser004 - * @tc.desc: test UnwindEntryParser in abnomal pc case - * @tc.type: FUNC - */ -HWTEST_F(UnwindEntryParserTest, UnwindEntryParseTest004, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "UnwindEntryParser004: start."; - pid_t childPid = fork(); - if (childPid != 0) { - ASSERT_TRUE(DfxPtrace::Attach(childPid)); - auto regs = DfxRegs::CreateRemoteRegs(childPid); - UnwindContext context; - context.pid = childPid; - context.regs = regs; - context.maps = DfxMaps::Create(childPid); - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); - memory->SetCtx(&context); - uintptr_t pc = regs->GetPc(); - std::shared_ptr map = nullptr; - ASSERT_TRUE(memory->GetMapByPc(pc, map) == UNW_ERROR_NONE); - UnwindTableInfo uti; - ASSERT_TRUE(memory->FindUnwindTable(pc, uti) == UNW_ERROR_NONE); - auto unwindEntryParser = UnwindEntryParserFactory::CreateUnwindEntryParser(memory); - std::shared_ptr rs = std::make_shared(); - ASSERT_FALSE(unwindEntryParser->Step(0, uti, rs)); - DfxPtrace::Detach(childPid); - } else { - const int sleepTime = 2; - sleep(sleepTime); - _exit(0); - } - GTEST_LOG_(INFO) << "UnwindEntryParser004: end."; -} - -/** - * @tc.name: UnwindEntryParser005 - * @tc.desc: test UnwindEntryParser in abnomal UnwindTableInfo case - * @tc.type: FUNC - */ -HWTEST_F(UnwindEntryParserTest, UnwindEntryParseTest005, TestSize.Level2) -{ - GTEST_LOG_(INFO) << "UnwindEntryParser005: start."; - pid_t childPid = fork(); - if (childPid != 0) { - ASSERT_TRUE(DfxPtrace::Attach(childPid)); - auto regs = DfxRegs::CreateRemoteRegs(childPid); - UnwindContext context; - context.pid = childPid; - context.regs = regs; - context.maps = DfxMaps::Create(childPid); - auto memory = std::make_shared(UNWIND_TYPE_REMOTE); - memory->SetCtx(&context); - auto unwindEntryParser = UnwindEntryParserFactory::CreateUnwindEntryParser(memory); - UnwindTableInfo uti; - std::shared_ptr rs = std::make_shared(); - ASSERT_FALSE(unwindEntryParser->Step(regs->GetPc(), uti, rs)); - DfxPtrace::Detach(childPid); - } else { - const int sleepTime = 2; - sleep(sleepTime); - _exit(0); - } - GTEST_LOG_(INFO) << "UnwindEntryParser005: end."; -} -} -} \ No newline at end of file diff --git a/test/unittest/unwind/unwinder_test.cpp b/test/unittest/unwind/unwinder_test.cpp index 832ffa450..99cc846d8 100644 --- a/test/unittest/unwind/unwinder_test.cpp +++ b/test/unittest/unwind/unwinder_test.cpp @@ -922,7 +922,8 @@ HWTEST_F(UnwinderTest, AccessMemTest001, TestSize.Level2) { GTEST_LOG_(INFO) << "AccessMemTest001: start."; auto unwinder = std::make_shared(); - auto memory = std::make_shared(UNWIND_TYPE_LOCAL); + auto acc = std::make_shared(); + auto memory = std::make_shared(acc); uintptr_t val; EXPECT_FALSE(memory->ReadReg(0, &val)); uintptr_t regs[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa}; @@ -933,7 +934,7 @@ HWTEST_F(UnwinderTest, AccessMemTest001, TestSize.Level2) uint8_t values[] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; uintptr_t addr = reinterpret_cast(&values[0]); - EXPECT_FALSE(unwinder->AccessMem(memory.get(), addr, nullptr)); + EXPECT_FALSE(unwinder->AccessMem(&memory, addr, nullptr)); GTEST_LOG_(INFO) << "AccessMemTest001: end."; } diff --git a/interfaces/innerkits/unwinder/src/elf/elf_factory_selector.cpp b/test/unittest/unwind/xz_util_test.cpp similarity index 33% rename from interfaces/innerkits/unwinder/src/elf/elf_factory_selector.cpp rename to test/unittest/unwind/xz_util_test.cpp index 1c5574680..a88bab490 100644 --- a/interfaces/innerkits/unwinder/src/elf/elf_factory_selector.cpp +++ b/test/unittest/unwind/xz_util_test.cpp @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2025 Huawei Device Co., Ltd. + * Copyright (c) 2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -13,31 +12,53 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "dfx_log.h" -#include "elf_factory.h" -#include "elf_factory_selector.h" -#include "string_util.h" +#include +#include +#include +#include +#include "dfx_elf.h" +#include "dfx_xz_utils.h" +#include "unwinder_config.h" + +using namespace OHOS::HiviewDFX; +using namespace testing::ext; +using namespace std; + +#define DUMPCATCHER_ELF_FILE "/system/bin/dumpcatcher" namespace OHOS { namespace HiviewDFX { + +class DfxXzUtilTest : public testing::Test { +public: + static void SetUpTestCase(void) {} + static void TearDownTestCase(void) {} + void SetUp() {} + void TearDonw() {} +}; + namespace { -#undef LOG_DOMAIN -#undef LOG_TAG -#define LOG_DOMAIN 0xD002D11 -#define LOG_TAG "ElfFactorySelector" -} -std::shared_ptr ElfFactorySelector::Select(DfxMap& map, pid_t pid) +/** + * @tc.name: DfxXzUtilTest001 + * @tc.desc: test XzUtil functions + * @tc.type: FUNC + */ +#if !is_emulator +HWTEST_F(DfxXzUtilTest, DfxXzUtilTest001, TestSize.Level2) { - std::shared_ptr elfFactory = nullptr; - if (StartsWith(map.name, "/proc") && EndsWith(map.name, ".hap")) { - elfFactory = std::make_shared(map.name, map.prevMap); - map.offset -= map.prevMap->offset; - } else if (map.IsVdsoMap()) { - elfFactory = std::make_shared(map.begin, map.end - map.begin, pid); - } else { - elfFactory = std::make_shared(map.name); - } - return elfFactory; + GTEST_LOG_(INFO) << "DfxXzUtilTest001: start."; + UnwinderConfig::SetEnableMiniDebugInfo(true); + DfxElf elf(DUMPCATCHER_ELF_FILE); + ASSERT_TRUE(elf.IsValid()); + auto minidebugInfo = elf.GetMiniDebugInfo(); + ASSERT_TRUE(minidebugInfo != nullptr); + uint8_t *addr = minidebugInfo->offset + const_cast(elf.GetMmapPtr()); + std::shared_ptr> decompressedElf = std::make_shared>();; + ASSERT_TRUE(XzDecompress(addr, minidebugInfo->size, decompressedElf)); + ASSERT_TRUE(decompressedElf->size() > minidebugInfo->size); + GTEST_LOG_(INFO) << "DfxXzUtilTest001: end."; +} +#endif } } // namespace HiviewDFX } // namespace OHOS \ No newline at end of file diff --git a/tools/process_dump/dfx_unwind_async_thread.cpp b/tools/process_dump/dfx_unwind_async_thread.cpp index 20a7cfae1..028a843df 100644 --- a/tools/process_dump/dfx_unwind_async_thread.cpp +++ b/tools/process_dump/dfx_unwind_async_thread.cpp @@ -22,7 +22,6 @@ #include "dfx_regs.h" #include "dfx_ring_buffer_wrapper.h" #include "dfx_trace.h" -#include "dfx_util.h" #ifdef PARSE_LOCK_OWNER #include "lock_parser.h" #endif @@ -98,7 +97,7 @@ void DfxUnwindAsyncThread::GetSubmitterStack(std::vector &submitterFra auto map = mapVec.front(); size_t size = map->end - map->begin; auto tableData = std::make_shared>(size); - size_t byte = ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size); + size_t byte = DfxMemory::ReadProcMemByPid(thread_->threadInfo_.nsTid, map->begin, tableData->data(), size); if (byte != size) { DFXLOGE("Failed to read unique_table from target"); return; diff --git a/tools/process_dump/faultlogger_client_msg.h b/tools/process_dump/faultlogger_client_msg.h index a10278d90..818831533 100644 --- a/tools/process_dump/faultlogger_client_msg.h +++ b/tools/process_dump/faultlogger_client_msg.h @@ -38,10 +38,4 @@ struct FaultDFXLOGIInner { std::map sectionMaps; }; -#if defined(__arm__) -static_assert(sizeof(FaultDFXLOGIInner) == 96, "faultlogger plugin must be modify together!!!"); -#elif defined(__aarch64__) -static_assert(sizeof(FaultDFXLOGIInner) == 168, "faultlogger plugin must be modify together!!!"); -#endif - #endif //FAULTLOGGER_CLIENT_MSG_H_ diff --git a/tools/process_dump/process_dumper.cpp b/tools/process_dump/process_dumper.cpp index 069a12187..92bf8dcab 100644 --- a/tools/process_dump/process_dumper.cpp +++ b/tools/process_dump/process_dumper.cpp @@ -79,7 +79,6 @@ namespace { const char *const BLOCK_CRASH_PROCESS = "faultloggerd.priv.block_crash_process.enabled"; const char *const GLOBAL_REGION = "const.global.region"; const char *const LOGSYSTEM_VERSION_TYPE = "const.logsystem.versiontype"; -MAYBE_UNUSED const char *const MIXSTACK_ENABLE = "faultloggerd.priv.mixstack.enabled"; const int MAX_FILE_COUNT = 5; const int ARG_MAX_NUM = 131072; @@ -175,7 +174,7 @@ void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr) size_t entryOffset = offsetof(FdTable, entries); uint64_t addr = fdTableAddr + entryOffset; FdEntry entrys[fds]; - if (ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) { + if (DfxMemory::ReadProcMemByPid(nsPid, addr, entrys, sizeof(FdEntry) * fds) != sizeof(FdEntry) * fds) { DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno)); return; } @@ -188,7 +187,7 @@ void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr) size_t overflowOffset = offsetof(FdTable, overflow); uintptr_t overflow = 0; uint64_t tmp = fdTableAddr + overflowOffset; - if (ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) { + if (DfxMemory::ReadProcMemByPid(nsPid, tmp, &overflow, sizeof(overflow)) != sizeof(overflow)) { return; } if (!overflow) { @@ -196,7 +195,8 @@ void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr) } size_t overflowLength; - if (ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength)) != sizeof(overflowLength)) { + if (DfxMemory::ReadProcMemByPid(nsPid, overflow, &overflowLength, sizeof(overflowLength)) + != sizeof(overflowLength)) { return; } if (overflowLength > ARG_MAX_NUM) { @@ -205,7 +205,7 @@ void FillFdsaninfo(OpenFilesList &list, pid_t nsPid, uint64_t fdTableAddr) std::vector overflowFdEntrys(overflowLength); uint64_t address = overflow + offsetof(FdTableOverflow, entries); - if (ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) != + if (DfxMemory::ReadProcMemByPid(nsPid, address, overflowFdEntrys.data(), sizeof(FdEntry) * overflowLength) != sizeof(FdEntry) * overflowLength) { DFXLOGE("[%{public}d]: read nsPid mem error %{public}s", __LINE__, strerror(errno)); return; @@ -582,7 +582,7 @@ void ProcessDumper::UpdateFatalMessageWhenDebugSignal(const ProcessDumpRequest& auto debugMsgPtr = reinterpret_cast(request.siginfo.si_value.sival_ptr); debug_msg_t dMsg = {0}; - if (ReadProcMemByPid(pid, debugMsgPtr, &dMsg, sizeof(dMsg)) != sizeof(debug_msg_t)) { + if (DfxMemory::ReadProcMemByPid(pid, debugMsgPtr, &dMsg, sizeof(dMsg)) != sizeof(debug_msg_t)) { DFXLOGE("Get debug_msg_t failed."); return; } @@ -613,7 +613,7 @@ std::string ProcessDumper::ReadCrashObjMemory(pid_t tid, uintptr_t addr, size_t static_cast(addr)); size_t size = (length + step - 1) / step; std::vector memory(size, 0); - if (ReadProcMemByPid(tid, addr, memory.data(), length) != length) { + if (DfxMemory::ReadProcMemByPid(tid, addr, memory.data(), length) != length) { DFXLOGE("[%{public}d]: read target mem error %{public}s", __LINE__, strerror(errno)); memoryContent += "\n"; return memoryContent; -- Gitee