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 "dfx_symbols.h"
17
18 #include <algorithm>
19 #include <cstdlib>
20 #include <cxxabi.h>
21 #ifdef RUSTC_DEMANGLE
22 #include <dlfcn.h>
23 #endif
24
25 #include "dfx_define.h"
26 #include "dfx_log.h"
27 #include "dfx_trace_dlsym.h"
28 #include "string_util.h"
29
30 namespace OHOS {
31 namespace HiviewDFX {
32 using RustDemangleFn = char*(*)(const char *);
33 namespace {
34 #undef LOG_DOMAIN
35 #undef LOG_TAG
36 #define LOG_DOMAIN 0xD002D11
37 #define LOG_TAG "DfxSymbols"
38
39 const std::string LINKER_PREFIX = "__dl_";
40 const std::string LINKER_PREFIX_NAME = "[linker]";
41
42 #ifdef RUSTC_DEMANGLE
43 static std::mutex g_mutex;
44 static bool g_hasTryLoadRustDemangleLib = false;
45 static RustDemangleFn g_rustDemangleFn = nullptr;
46 #endif
47
48 #if defined(CJ_DEMANGLE) && defined (__LP64__)
49 using CJDemangleFn = char*(*)(const char *);
50 static std::mutex g_cj_mutex;
51 static bool g_hasTryLoadCJDemangleLib = false;
52 static CJDemangleFn g_cjDemangleFn = nullptr;
53 #endif
54 }
55
56 #if defined(CJ_DEMANGLE) && defined(__LP64__)
FindCJDemangleFunction()57 bool DfxSymbols::FindCJDemangleFunction()
58 {
59 if (g_hasTryLoadCJDemangleLib) {
60 return (g_cjDemangleFn != nullptr);
61 }
62
63 g_hasTryLoadCJDemangleLib = true;
64 void* cjDemangleLibHandle = dlopen("libcangjie-demangle.so", RTLD_LAZY | RTLD_NODELETE);
65 if (cjDemangleLibHandle == nullptr) {
66 DFXLOGE("Failed to dlopen libcangjie-demangle.so, %{public}s", dlerror());
67 return false;
68 }
69 g_cjDemangleFn = (CJDemangleFn)dlsym(cjDemangleLibHandle, "CJ_MRT_Demangle");
70 if (g_cjDemangleFn == nullptr) {
71 DFXLOGE("Failed to dlsym CJ_MRT_Demangle, %{public}s", dlerror());
72 dlclose(cjDemangleLibHandle);
73 return false;
74 }
75 return true;
76 }
77 #endif
78
79 #ifdef RUSTC_DEMANGLE
FindRustDemangleFunction()80 bool DfxSymbols::FindRustDemangleFunction()
81 {
82 if (g_hasTryLoadRustDemangleLib) {
83 return (g_rustDemangleFn != nullptr);
84 }
85
86 g_hasTryLoadRustDemangleLib = true;
87 void* rustDemangleLibHandle = dlopen("librustc_demangle.z.so", RTLD_LAZY | RTLD_NODELETE);
88 if (rustDemangleLibHandle == nullptr) {
89 DFXLOGW("Failed to dlopen librustc_demangle, %{public}s", dlerror());
90 return false;
91 }
92
93 g_rustDemangleFn = (RustDemangleFn)dlsym(rustDemangleLibHandle, "rustc_demangle");
94 if (g_rustDemangleFn == nullptr) {
95 DFXLOGW("Failed to dlsym rustc_demangle, %{public}s", dlerror());
96 dlclose(rustDemangleLibHandle);
97 return false;
98 }
99 return true;
100 }
101 #endif
102
ParseSymbols(std::vector<DfxSymbol> & symbols,std::shared_ptr<DfxElf> elf,const std::string & filePath)103 bool DfxSymbols::ParseSymbols(std::vector<DfxSymbol>& symbols, std::shared_ptr<DfxElf> elf, const std::string& filePath)
104 {
105 if (elf == nullptr) {
106 return false;
107 }
108 const auto &elfSymbols = elf->GetFuncSymbols();
109 std::string symbolsPath = filePath;
110 if (elf->GetBaseOffset() != 0) {
111 symbolsPath += ("!" + elf->GetElfName());
112 }
113 for (const auto &elfSymbol : elfSymbols) {
114 symbols.emplace_back(elfSymbol.value, elfSymbol.size,
115 elfSymbol.nameStr, Demangle(elfSymbol.nameStr), symbolsPath);
116 }
117 return true;
118 }
119
AddSymbolsByPlt(std::vector<DfxSymbol> & symbols,std::shared_ptr<DfxElf> elf,const std::string & filePath)120 bool DfxSymbols::AddSymbolsByPlt(std::vector<DfxSymbol>& symbols, std::shared_ptr<DfxElf> elf,
121 const std::string& filePath)
122 {
123 if (elf == nullptr) {
124 return false;
125 }
126 ShdrInfo shdr;
127 elf->GetSectionInfo(shdr, PLT);
128 symbols.emplace_back(shdr.addr, shdr.size, PLT, filePath);
129 return true;
130 }
131
GetFuncNameAndOffsetByPc(uint64_t relPc,std::shared_ptr<DfxElf> elf,std::string & funcName,uint64_t & funcOffset)132 bool DfxSymbols::GetFuncNameAndOffsetByPc(uint64_t relPc, std::shared_ptr<DfxElf> elf,
133 std::string& funcName, uint64_t& funcOffset)
134 {
135 #if defined(__arm__)
136 relPc = relPc | 1;
137 #endif
138 ElfSymbol elfSymbol;
139 if ((elf != nullptr) && elf->GetFuncInfo(relPc, elfSymbol)) {
140 DFXLOGU("nameStr: %{public}s", elfSymbol.nameStr.c_str());
141 funcName = Demangle(elfSymbol.nameStr);
142 funcOffset = relPc - elfSymbol.value;
143 #if defined(__arm__)
144 funcOffset &= ~1;
145 #endif
146 DFXLOGU("Symbol relPc: %{public}" PRIx64 ", funcName: %{public}s, funcOffset: %{public}" PRIx64 "",
147 relPc, funcName.c_str(), funcOffset);
148 return true;
149 }
150 return false;
151 }
152
Demangle(const std::string & buf)153 std::string DfxSymbols::Demangle(const std::string& buf)
154 {
155 DFX_TRACE_SCOPED_DLSYM("Demangle");
156 if ((buf.length() < 2) || (buf[0] != '_')) { // 2 : min buf length
157 return buf;
158 }
159
160 std::string funcName;
161 const char *bufStr = buf.c_str();
162 if (StartsWith(buf, LINKER_PREFIX)) {
163 bufStr += LINKER_PREFIX.size();
164 funcName += LINKER_PREFIX_NAME;
165 }
166
167 int status = 0;
168 char* demangledStr = nullptr;
169 if (buf[1] == 'Z') {
170 demangledStr = abi::__cxa_demangle(bufStr, nullptr, nullptr, &status);
171 }
172 #ifdef RUSTC_DEMANGLE
173 if (buf[1] == 'R') {
174 std::lock_guard<std::mutex> lck(g_mutex);
175 if (FindRustDemangleFunction()) {
176 demangledStr = g_rustDemangleFn(bufStr);
177 }
178 }
179 #endif
180
181 #if defined(CJ_DEMANGLE) && defined(__LP64__)
182 if ((buf[1] == 'C') && (demangledStr == nullptr)) {
183 std::lock_guard<std::mutex> lck(g_cj_mutex);
184 if (FindCJDemangleFunction()) {
185 demangledStr = g_cjDemangleFn(bufStr);
186 }
187 }
188 #endif
189
190 std::string demangleName;
191 if (demangledStr != nullptr) {
192 demangleName = std::string(demangledStr);
193 std::free(demangledStr);
194 } else {
195 demangleName = std::string(bufStr);
196 }
197 funcName += demangleName;
198 return funcName;
199 }
200 } // namespace HiviewDFX
201 } // namespace OHOS
202