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 <hilog/log.h>
20 #include <libunwind.h>
21 #include <libunwind_i-ohos.h>
22 #include "dfx_define.h"
23 #include "dfx_config.h"
24
25 namespace OHOS {
26 namespace HiviewDFX {
27 namespace {
28 #undef LOG_DOMAIN
29 #undef LOG_TAG
30 #define LOG_DOMAIN 0xD002D11
31 #define LOG_TAG "DfxDwarfUnwinder"
32 constexpr int32_t MIN_VALID_FRAME_COUNT = 3;
33 }
34
DwarfUnwinder()35 DwarfUnwinder::DwarfUnwinder()
36 {
37 frames_.clear();
38 }
39
~DwarfUnwinder()40 DwarfUnwinder::~DwarfUnwinder()
41 {
42 frames_.clear();
43 }
44
GetFrames() const45 const std::vector<DfxFrame>& DwarfUnwinder::GetFrames() const
46 {
47 return frames_;
48 }
49
UpdateFrameFuncName(unw_addr_space_t as,std::shared_ptr<DfxSymbols> symbol,DfxFrame & frame)50 void DwarfUnwinder::UpdateFrameFuncName(unw_addr_space_t as,
51 std::shared_ptr<DfxSymbols> symbol, DfxFrame& frame)
52 {
53 if (symbol != nullptr) {
54 symbol->GetNameAndOffsetByPc(as, frame.pc, frame.funcName, frame.funcOffset);
55 }
56 }
57
Unwind(size_t skipFrameNum,size_t maxFrameNums)58 bool DwarfUnwinder::Unwind(size_t skipFrameNum, size_t maxFrameNums)
59 {
60 unw_addr_space_t as;
61 unw_init_local_address_space(&as);
62 if (as == nullptr) {
63 return false;
64 }
65 auto symbol = std::make_shared<DfxSymbols>();
66
67 unw_context_t context;
68 (void)memset_s(&context, sizeof(unw_context_t), 0, sizeof(unw_context_t));
69 unw_getcontext(&context);
70
71 bool ret = UnwindWithContext(as, context, symbol, skipFrameNum + 1, maxFrameNums);
72 unw_destroy_local_address_space(as);
73 return ret;
74 }
75
UnwindWithContext(unw_addr_space_t as,unw_context_t & context,std::shared_ptr<DfxSymbols> symbol,size_t skipFrameNum,size_t maxFrameNums)76 bool DwarfUnwinder::UnwindWithContext(unw_addr_space_t as, unw_context_t& context,
77 std::shared_ptr<DfxSymbols> symbol, size_t skipFrameNum, size_t maxFrameNums)
78 {
79 if (as == nullptr) {
80 return false;
81 }
82
83 unw_cursor_t cursor;
84 unw_init_local_with_as(as, &cursor, &context);
85 size_t index = 0;
86 size_t curIndex = 0;
87 unw_word_t prevFrameSp = 0;
88 unw_word_t prevFramePc = 0;
89 do {
90 // skip 0 stack, as this is dump catcher. Caller don't need it.
91 if (index < skipFrameNum) {
92 uint64_t skipPc = 0;
93 skipPc = unw_get_rel_pc(&cursor);
94 struct map_info* skipMap = unw_get_map(&cursor);
95 std::string skipMapName = "";
96 if ((skipMap != nullptr) && (strlen(skipMap->path) < LINE_BUF_SIZE - 1)) {
97 skipMapName = std::string(skipMap->path);
98 }
99 HILOG_INFO(LOG_CORE,
100 " skip frame #%{public}zu pc %{public}" PRIu64 " %{public}s",
101 index,
102 skipPc,
103 skipMapName.c_str());
104 index++;
105 continue;
106 }
107 curIndex = index - skipFrameNum;
108
109 DfxFrame frame;
110 frame.index = curIndex;
111 if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t*)(&(frame.pc)))) {
112 break;
113 }
114
115 if (unw_get_reg(&cursor, UNW_REG_SP, (unw_word_t*)(&(frame.sp)))) {
116 break;
117 }
118
119 if (prevFrameSp == frame.sp && prevFramePc == frame.pc) {
120 break;
121 }
122 prevFrameSp = frame.sp;
123 prevFramePc = frame.pc;
124 frame.relPc = unw_get_rel_pc(&cursor);
125 unw_word_t sz = unw_get_previous_instr_sz(&cursor);
126 if ((frame.index > 0) && (frame.relPc > sz)) {
127 frame.relPc -= sz;
128 frame.pc -= sz;
129 #if defined(__arm__)
130 unw_set_adjust_pc(&cursor, frame.pc);
131 #endif
132 }
133
134 struct map_info* map = unw_get_map(&cursor);
135 bool isValidFrame = true;
136 if ((map != nullptr) && (strlen(map->path) < LINE_BUF_SIZE - 1)) {
137 UpdateFrameFuncName(as, symbol, frame);
138 frame.mapName = std::string(map->path);
139 if (frame.mapName.find(".hap") != std::string::npos) {
140 char libraryName[PATH_LEN] = { 0 };
141 if (unw_get_library_name_by_map(map, libraryName, PATH_LEN - 1) == 0) {
142 frame.mapName = frame.mapName + "!" + std::string(libraryName);
143 }
144 }
145 } else {
146 isValidFrame = false;
147 }
148
149 if (isValidFrame && (frame.relPc == 0) && (frame.mapName.find("Ark") == std::string::npos)) {
150 isValidFrame = false;
151 }
152
153 if (frame.index < MIN_VALID_FRAME_COUNT || isValidFrame) {
154 frames_.emplace_back(frame);
155 } else {
156 break;
157 }
158
159 index++;
160 } while ((unw_step(&cursor) > 0) && (curIndex < maxFrameNums));
161 return (frames_.size() > 0);
162 }
163 } // namespace HiviewDFX
164 } // namespace OHOS
165