1 /*
2 * Copyright (c) 2021-2022 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 /* This files real do unwind. */
17
18 #include "dfx_unwind_remote.h"
19
20 #include <algorithm>
21 #include <cstdio>
22 #include <cstring>
23 #include <elf.h>
24 #include <link.h>
25 #include <securec.h>
26 #include <sys/ptrace.h>
27 #include "dfx_config.h"
28 #include "dfx_define.h"
29 #include "dfx_logger.h"
30 #include "dfx_maps.h"
31 #include "dfx_process.h"
32 #include "dfx_regs.h"
33 #include "dfx_ring_buffer_wrapper.h"
34 #include "dfx_symbols_cache.h"
35 #include "dfx_thread.h"
36 #include "dfx_util.h"
37 #include "libunwind.h"
38 #include "libunwind_i-ohos.h"
39 #include "process_dumper.h"
40
41 namespace OHOS {
42 namespace HiviewDFX {
43 namespace {
44 // we should have at least 2 frames, one is pc and the other is lr
45 // if pc and lr are both invalid, just try fp
46 static const int MIN_VALID_FRAME_COUNT = 3;
47 static constexpr size_t MAX_BUILD_ID_LENGTH = 32;
48 }
49
GetInstance()50 DfxUnwindRemote &DfxUnwindRemote::GetInstance()
51 {
52 static DfxUnwindRemote ins;
53 return ins;
54 }
55
DfxUnwindRemote()56 DfxUnwindRemote::DfxUnwindRemote()
57 {
58 as_ = nullptr;
59 std::unique_ptr<DfxSymbolsCache> cache(new DfxSymbolsCache());
60 cache_ = std::move(cache);
61 }
62
UnwindProcess(std::shared_ptr<DfxProcess> process)63 bool DfxUnwindRemote::UnwindProcess(std::shared_ptr<DfxProcess> process)
64 {
65 bool ret = false;
66 if (!process) {
67 DfxLogWarn("%s::can not unwind null process.", __func__);
68 return ret;
69 }
70
71 auto threads = process->GetThreads();
72 if (threads.empty()) {
73 DfxLogWarn("%s::no thread under target process.", __func__);
74 return ret;
75 }
76
77 as_ = unw_create_addr_space(&_UPT_accessors, 0);
78 if (!as_) {
79 DfxLogWarn("%s::failed to create address space.", __func__);
80 return ret;
81 }
82
83 unw_set_target_pid(as_, ProcessDumper::GetInstance().GetTargetPid());
84 unw_set_caching_policy(as_, UNW_CACHE_GLOBAL);
85 do {
86 // only need to unwind crash thread in crash scenario
87 if (!process->GetIsSignalDump() && !DfxConfig::GetInstance().GetDumpOtherThreads()) {
88 ret = UnwindThread(process, threads[0]);
89 if (!ret) {
90 UnwindThreadFallback(process, threads[0]);
91 }
92
93 if (threads[0]->GetIsCrashThread() && (!process->GetIsSignalDump())) {
94 process->PrintProcessMapsByConfig();
95 }
96 break;
97 }
98
99 size_t index = 0;
100 for (auto thread : threads) {
101 if (index == 1) {
102 process->PrintThreadsHeaderByConfig();
103 }
104 if (index != 0) {
105 DfxRingBufferWrapper::GetInstance().AppendMsg("\n");
106 }
107
108 if (thread->Attach()) {
109 UnwindThread(process, thread);
110 thread->Detach();
111 }
112
113 if (thread->GetIsCrashThread() && (!process->GetIsSignalDump())) {
114 process->PrintProcessMapsByConfig();
115 }
116 index++;
117 }
118 ret = true;
119 } while (false);
120
121 unw_destroy_addr_space(as_);
122 as_ = nullptr;
123 return ret;
124 }
125
DfxUnwindRemoteDoAdjustPc(unw_cursor_t & cursor,uint64_t pc)126 uint64_t DfxUnwindRemote::DfxUnwindRemoteDoAdjustPc(unw_cursor_t & cursor, uint64_t pc)
127 {
128 DfxLogDebug("%s :: pc(0x%x).", __func__, pc);
129
130 uint64_t ret = 0;
131
132 if (pc <= ARM_EXEC_STEP_NORMAL) {
133 ret = pc; // pc zero is abnormal case, so we don't adjust pc.
134 } else {
135 #if defined(__arm__)
136 ret = pc - unw_get_previous_instr_sz(&cursor);
137 #elif defined(__aarch64__)
138 ret = pc - ARM_EXEC_STEP_NORMAL;
139 #elif defined(__x86_64__)
140 ret = pc - 1;
141 #endif
142 }
143
144 DfxLogDebug("%s :: ret(0x%x).", __func__, ret);
145 return ret;
146 }
147
GetReadableBuildId(uint8_t * buildId,size_t length)148 std::string DfxUnwindRemote::GetReadableBuildId(uint8_t* buildId, size_t length)
149 {
150 if (length > MAX_BUILD_ID_LENGTH) {
151 std::string ret = "Wrong Build-Id length:" + std::to_string(length);
152 return ret;
153 }
154
155 static const char hexTable[] = "0123456789abcdef";
156 uint8_t* buildIdPtr = buildId;
157 std::string buildIdStr;
158 for (size_t i = 0; i < length; i++) {
159 buildIdStr.push_back(hexTable[*buildIdPtr >> 4]); // 4 : higher 4 bit of uint8
160 buildIdStr.push_back(hexTable[*buildIdPtr & 0xf]);
161 buildIdPtr++;
162 }
163 return buildIdStr;
164 }
165
DfxUnwindRemoteDoUnwindStep(size_t const & index,std::shared_ptr<DfxThread> & thread,unw_cursor_t & cursor,std::shared_ptr<DfxProcess> process)166 bool DfxUnwindRemote::DfxUnwindRemoteDoUnwindStep(size_t const & index,
167 std::shared_ptr<DfxThread> & thread, unw_cursor_t & cursor, std::shared_ptr<DfxProcess> process)
168 {
169 bool ret = false;
170 uint64_t framePc;
171 static unw_word_t oldPc = 0;
172 if (unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t*)(&framePc))) {
173 DfxLogWarn("Fail to get current pc.");
174 return ret;
175 }
176
177 uint64_t frameSp;
178 if (unw_get_reg(&cursor, UNW_REG_SP, (unw_word_t*)(&frameSp))) {
179 DfxLogWarn("Fail to get stack pointer.");
180 return ret;
181 }
182
183 if (oldPc == framePc && index != 0) {
184 DfxLogWarn("%s :: repeated pc(0x%lx), stop.", __func__, framePc);
185 return ret;
186 }
187 oldPc = framePc;
188
189 uint64_t relPc = unw_get_rel_pc(&cursor);
190 if (index != 0) {
191 relPc = DfxUnwindRemoteDoAdjustPc(cursor, relPc);
192 framePc = DfxUnwindRemoteDoAdjustPc(cursor, framePc);
193 #if defined(__arm__)
194 unw_set_adjust_pc(&cursor, framePc);
195 #endif
196 }
197
198 if (relPc == 0) {
199 relPc = framePc;
200 }
201
202 auto frame = std::make_shared<DfxFrame>();
203 frame->SetFrameRelativePc(relPc);
204 frame->SetFramePc(framePc);
205 frame->SetFrameSp(frameSp);
206 frame->SetFrameIndex(index);
207 ret = UpdateAndPrintFrameInfo(cursor, thread, frame,
208 (thread->GetIsCrashThread() && !process->GetIsSignalDump()));
209 if (ret) {
210 thread->AddFrame(frame);
211 }
212
213 DfxLogDebug("%s :: index(%d), framePc(0x%x), frameSp(0x%x).", __func__, index, framePc, frameSp);
214 return ret;
215 }
216
UpdateAndPrintFrameInfo(unw_cursor_t & cursor,std::shared_ptr<DfxThread> thread,std::shared_ptr<DfxFrame> frame,bool enableBuildId)217 bool DfxUnwindRemote::UpdateAndPrintFrameInfo(unw_cursor_t& cursor, std::shared_ptr<DfxThread> thread,
218 std::shared_ptr<DfxFrame> frame, bool enableBuildId)
219 {
220 struct map_info* mapInfo = unw_get_map(&cursor);
221 bool isValidFrame = true;
222 if (mapInfo != nullptr) {
223 std::string mapPath = std::string(mapInfo->path);
224 frame->SetFrameMapName(mapPath);
225 std::string funcName;
226 uint64_t funcOffset;
227 if (cache_->GetNameAndOffsetByPc(as_, frame->GetFramePc(), funcName, funcOffset)) {
228 frame->SetFrameFuncName(funcName);
229 frame->SetFrameFuncOffset(funcOffset);
230 }
231
232 if (enableBuildId && buildIds_.find(mapPath) != buildIds_.end()) {
233 frame->SetBuildId(buildIds_[mapPath]);
234 } else if (enableBuildId && buildIds_.find(mapPath) == buildIds_.end()) {
235 uint8_t* buildId = nullptr;
236 size_t length = 0;
237 std::string buildIdStr = "";
238 if (unw_get_build_id(mapInfo, &buildId, &length)) {
239 buildIdStr = GetReadableBuildId(buildId, length);
240 }
241 if (!buildIdStr.empty()) {
242 buildIds_.insert(std::pair<std::string, std::string>(std::string(mapPath), buildIdStr));
243 frame->SetBuildId(buildIdStr);
244 }
245 }
246 } else {
247 std::string tips = "Not mapped ";
248 std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
249 if (regs != nullptr) {
250 tips.append(regs->GetSpecialRegisterName(frame->GetFramePc()));
251 }
252 frame->SetFrameMapName(tips);
253 isValidFrame = false;
254 }
255
256 bool ret = frame->GetFrameIndex() < MIN_VALID_FRAME_COUNT || isValidFrame;
257 if (ret) {
258 DfxRingBufferWrapper::GetInstance().AppendMsg(frame->PrintFrame());
259 }
260 return ret;
261 }
262
UnwindThread(std::shared_ptr<DfxProcess> process,std::shared_ptr<DfxThread> thread)263 bool DfxUnwindRemote::UnwindThread(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread)
264 {
265 if (!thread) {
266 DfxLogError("NULL thread needs unwind.");
267 return false;
268 }
269
270 bool isCrash = thread->GetIsCrashThread() && (process->GetIsSignalDump() == false);
271 pid_t nsTid = isCrash ? ProcessDumper::GetInstance().GetTargetNsPid() : thread->GetRealTid();
272 pid_t tid = thread->GetThreadId();
273 char buf[LOG_BUF_LEN] = {0};
274 int ret = snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "Tid:%d, Name:%s\n", tid, thread->GetThreadName().c_str());
275 if (ret <= 0) {
276 DfxLogError("%s :: snprintf_s failed, line: %d.", __func__, __LINE__);
277 }
278 DfxRingBufferWrapper::GetInstance().AppendMsg(std::string(buf));
279 void *context = _UPT_create(nsTid);
280 if (!context) {
281 DfxRingBufferWrapper::GetInstance().AppendBuf("Failed to create unwind context for %d.\n", nsTid);
282 return false;
283 }
284
285 if (!as_) {
286 as_ = unw_create_addr_space(&_UPT_accessors, 0);
287 if (!as_) {
288 DfxRingBufferWrapper::GetInstance().AppendBuf("Unwind address space is not exist for %d.\n", nsTid);
289 _UPT_destroy(context);
290 return false;
291 }
292 unw_set_caching_policy(as_, UNW_CACHE_GLOBAL);
293 }
294
295 unw_cursor_t cursor;
296 int unwRet = unw_init_remote(&cursor, as_, context);
297 if (unwRet != 0) {
298 DfxRingBufferWrapper::GetInstance().AppendBuf("Failed to init cursor for thread:%d code:%d.\n", nsTid, unwRet);
299 _UPT_destroy(context);
300 return false;
301 }
302
303 std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
304 if (regs != nullptr) {
305 std::vector<uintptr_t> regsVector = regs->GetRegsData();
306 unw_set_context(&cursor, regsVector.data(), regsVector.size());
307 }
308
309 size_t index = 0;
310 do {
311 // store current frame
312 if (!DfxUnwindRemoteDoUnwindStep(index, thread, cursor, process)) {
313 break;
314 }
315 index++;
316
317 // find next frame
318 unwRet = unw_step(&cursor);
319 } while ((unwRet > 0) && (index < BACK_STACK_MAX_STEPS));
320 thread->SetThreadUnwStopReason(unwRet);
321 if (isCrash) {
322 if (regs != nullptr) {
323 DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
324 }
325 if (DfxConfig::GetInstance().GetDisplayFaultStack()) {
326 thread->CreateFaultStack(nsTid);
327 thread->PrintThreadFaultStackByConfig();
328 }
329 }
330 _UPT_destroy(context);
331 return true;
332 }
333
UnwindThreadFallback(std::shared_ptr<DfxProcess> process,std::shared_ptr<DfxThread> thread)334 void DfxUnwindRemote::UnwindThreadFallback(std::shared_ptr<DfxProcess> process, std::shared_ptr<DfxThread> thread)
335 {
336 // As we failed to init libunwind, just print pc and lr for first two frames
337 std::shared_ptr<DfxRegs> regs = thread->GetThreadRegs();
338 if (regs == nullptr) {
339 DfxRingBufferWrapper::GetInstance().AppendMsg("RegisterInfo is not existed for crash process");
340 return;
341 }
342
343 std::shared_ptr<DfxElfMaps> maps = process->GetMaps();
344 if (maps == nullptr) {
345 DfxRingBufferWrapper::GetInstance().AppendMsg("MapsInfo is not existed for crash process");
346 return;
347 }
348
349 auto createFrame = [maps, thread] (int index, uintptr_t pc) {
350 std::shared_ptr<DfxElfMap> map;
351 auto frame = std::make_shared<DfxFrame>();
352 frame->SetFramePc(pc);
353 frame->SetFrameIndex(index);
354 thread->AddFrame(frame);
355 if (maps->FindMapByAddr(pc, map)) {
356 frame->SetFrameMap(map);
357 frame->CalculateRelativePc(map);
358 frame->SetFrameMapName(map->GetMapPath());
359 } else {
360 frame->SetFrameRelativePc(pc);
361 frame->SetFrameMapName(index == 0 ? "Not mapped pc" : "Not mapped lr");
362 }
363 DfxRingBufferWrapper::GetInstance().AppendMsg(frame->PrintFrame());
364 };
365
366 createFrame(0, regs->GetPC());
367 createFrame(1, regs->GetLR());
368 DfxRingBufferWrapper::GetInstance().AppendMsg(regs->PrintRegs());
369 }
370 } // namespace HiviewDFX
371 } // namespace OHOS
372