1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "dwarf_unwinder.h"
17
18 #include <securec.h>
19 #include <libunwind.h>
20 #include <libunwind_i-ohos.h>
21 #include "dfx_define.h"
22 #include "dfx_config.h"
23
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace {
27 #undef LOG_DOMAIN
28 #undef LOG_TAG
29 #define LOG_DOMAIN 0xD002D11
30 #define LOG_TAG "DfxDwarfUnwinder"
31 constexpr int32_t MIN_VALID_FRAME_COUNT = 3;
32 }
33
DwarfUnwinder()34 DwarfUnwinder::DwarfUnwinder()
35 {
36 frames_.clear();
37 }
38
~DwarfUnwinder()39 DwarfUnwinder::~DwarfUnwinder()
40 {
41 frames_.clear();
42 }
43
GetFrames() const44 const std::vector<DfxFrame>& DwarfUnwinder::GetFrames() const
45 {
46 return frames_;
47 }
48
UpdateFrameFuncName(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,DfxFrame & frame)49 void DwarfUnwinder::UpdateFrameFuncName(unw_addr_space_t as,
50 std::shared_ptr<DfxSymbols> symbol, DfxFrame& frame)
51 {
52 if (symbol != nullptr) {
53 symbol->GetNameAndOffsetByPc(as, frame.pc, frame.funcName, frame.funcOffset);
54 }
55 }
56
Unwind(size_t skipFrameNum)57 bool DwarfUnwinder::Unwind(size_t skipFrameNum)
58 {
59 unw_addr_space_t as;
60 unw_init_local_address_space(&as);
61 if (as == nullptr) {
62 return false;
63 }
64 auto symbol = std::make_shared<DfxSymbols>();
65
66 unw_context_t context;
67 (void)memset_s(&context, sizeof(unw_context_t), 0, sizeof(unw_context_t));
68 unw_getcontext(&context);
69
70 bool ret = UnwindWithContext(as, context, symbol, skipFrameNum + 1);
71 unw_destroy_local_address_space(as);
72 return ret;
73 }
74
UnwindWithContext(unw_addr_space_t as,unw_context_t & context,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum)75 bool DwarfUnwinder::UnwindWithContext(unw_addr_space_t as, unw_context_t& context,
76 std::shared_ptr<DfxSymbols> symbol, size_t skipFrameNum)
77 {
78 if (as == nullptr) {
79 return false;
80 }
81
82 unw_cursor_t cursor;
83 unw_init_local_with_as(as, &cursor, &context);
84 size_t index = 0;
85 size_t curIndex = 0;
86 unw_word_t prevPc = 0;
87 do {
88 // skip 0 stack, as this is dump catcher. Caller don't need it.
89 if (index < skipFrameNum) {
90 index++;
91 continue;
92 }
93 curIndex = index - skipFrameNum;
94
95 DfxFrame frame;
96 frame.index = curIndex;
97 if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t*)(&(frame.pc)))) {
98 break;
99 }
100
101 if (unw_get_reg(&cursor, UNW_REG_SP, (unw_word_t*)(&(frame.sp)))) {
102 break;
103 }
104
105 if (frame.index > 1 && prevPc == frame.pc) {
106 break;
107 }
108 prevPc = frame.pc;
109
110 frame.relPc = unw_get_rel_pc(&cursor);
111 unw_word_t sz = unw_get_previous_instr_sz(&cursor);
112 if ((frame.index > 0) && (frame.relPc > sz)) {
113 frame.relPc -= sz;
114 frame.pc -= sz;
115 #if defined(__arm__)
116 unw_set_adjust_pc(&cursor, frame.pc);
117 #endif
118 }
119
120 struct map_info* map = unw_get_map(&cursor);
121 bool isValidFrame = true;
122 if ((map != nullptr) && (strlen(map->path) < SYMBOL_BUF_SIZE - 1)) {
123 UpdateFrameFuncName(as, symbol, frame);
124 frame.mapName = std::string(map->path);
125 if (frame.mapName.find(".hap") != std::string::npos) {
126 char libraryName[PATH_LEN] = { 0 };
127 if (unw_get_library_name_by_map(map, libraryName, PATH_LEN - 1) == 0) {
128 frame.mapName = frame.mapName + "!" + std::string(libraryName);
129 }
130 }
131 } else {
132 isValidFrame = false;
133 }
134
135 if (isValidFrame && (frame.relPc == 0) && (frame.mapName.find("Ark") == std::string::npos)) {
136 isValidFrame = false;
137 }
138
139 if (frame.index < MIN_VALID_FRAME_COUNT || isValidFrame) {
140 frames_.emplace_back(frame);
141 } else {
142 break;
143 }
144
145 index++;
146 } while ((unw_step(&cursor) > 0) && (curIndex < DfxConfig::GetConfig().maxFrameNums));
147 return (frames_.size() > 0);
148 }
149 } // namespace HiviewDFX
150 } // namespace OHOS
151