• 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 "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