• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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