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
49 #ifdef RUSTC_DEMANGLE
FindRustDemangleFunction()50 bool DfxSymbols::FindRustDemangleFunction()
51 {
52 if (g_hasTryLoadRustDemangleLib) {
53 return (g_rustDemangleFn != nullptr);
54 }
55
56 g_hasTryLoadRustDemangleLib = true;
57 void* rustDemangleLibHandle = dlopen("librustc_demangle.z.so", RTLD_LAZY | RTLD_NODELETE);
58 if (rustDemangleLibHandle == nullptr) {
59 LOGW("Failed to dlopen librustc_demangle, %s", dlerror());
60 return false;
61 }
62
63 g_rustDemangleFn = (RustDemangleFn)dlsym(rustDemangleLibHandle, "rustc_demangle");
64 if (g_rustDemangleFn == nullptr) {
65 LOGW("Failed to dlsym rustc_demangle, %s", dlerror());
66 dlclose(rustDemangleLibHandle);
67 return false;
68 }
69 return true;
70 }
71 #endif
72
ParseSymbols(std::vector<DfxSymbol> & symbols,std::shared_ptr<DfxElf> elf,const std::string & filePath)73 bool DfxSymbols::ParseSymbols(std::vector<DfxSymbol>& symbols, std::shared_ptr<DfxElf> elf, const std::string& filePath)
74 {
75 if (elf == nullptr) {
76 return false;
77 }
78 auto elfSymbols = elf->GetFuncSymbols();
79 std::string symbolsPath = filePath;
80 if (elf->GetBaseOffset() != 0) {
81 symbolsPath += ("!" + elf->GetElfName());
82 }
83 for (auto elfSymbol : elfSymbols) {
84 symbols.emplace_back(elfSymbol.value, elfSymbol.size,
85 elfSymbol.nameStr, Demangle(elfSymbol.nameStr), symbolsPath);
86 }
87 return true;
88 }
89
AddSymbolsByPlt(std::vector<DfxSymbol> & symbols,std::shared_ptr<DfxElf> elf,const std::string & filePath)90 bool DfxSymbols::AddSymbolsByPlt(std::vector<DfxSymbol>& symbols, std::shared_ptr<DfxElf> elf,
91 const std::string& filePath)
92 {
93 if (elf == nullptr) {
94 return false;
95 }
96 ShdrInfo shdr;
97 elf->GetSectionInfo(shdr, PLT);
98 symbols.emplace_back(shdr.addr, shdr.size, PLT, filePath);
99 return true;
100 }
101
GetFuncNameAndOffsetByPc(uint64_t relPc,std::shared_ptr<DfxElf> elf,std::string & funcName,uint64_t & funcOffset)102 bool DfxSymbols::GetFuncNameAndOffsetByPc(uint64_t relPc, std::shared_ptr<DfxElf> elf,
103 std::string& funcName, uint64_t& funcOffset)
104 {
105 #if defined(__arm__)
106 relPc = relPc | 1;
107 #endif
108 ElfSymbol elfSymbol;
109 if ((elf != nullptr) && elf->GetFuncInfo(relPc, elfSymbol)) {
110 LOGU("nameStr: %s", elfSymbol.nameStr.c_str());
111 funcName = Demangle(elfSymbol.nameStr);
112 funcOffset = relPc - elfSymbol.value;
113 #if defined(__arm__)
114 funcOffset &= ~1;
115 #endif
116 LOGU("Symbol relPc: %" PRIx64 ", funcName: %s, funcOffset: %" PRIx64 "", relPc, funcName.c_str(), funcOffset);
117 return true;
118 }
119 return false;
120 }
121
Demangle(const std::string & buf)122 std::string DfxSymbols::Demangle(const std::string& buf)
123 {
124 DFX_TRACE_SCOPED_DLSYM("Demangle");
125 if ((buf.length() < 2) || (buf[0] != '_')) { // 2 : min buf length
126 return buf;
127 }
128
129 std::string funcName;
130 const char *bufStr = buf.c_str();
131 if (StartsWith(buf, LINKER_PREFIX)) {
132 bufStr += LINKER_PREFIX.size();
133 funcName += LINKER_PREFIX_NAME;
134 }
135
136 int status = 0;
137 char* demangledStr = nullptr;
138 if (buf[1] == 'Z') {
139 demangledStr = abi::__cxa_demangle(bufStr, nullptr, nullptr, &status);
140 }
141 #ifdef RUSTC_DEMANGLE
142 if (buf[1] == 'R') {
143 std::lock_guard<std::mutex> lck(g_mutex);
144 if (FindRustDemangleFunction()) {
145 demangledStr = g_rustDemangleFn(bufStr);
146 }
147 }
148 #endif
149 std::string demangleName;
150 if (demangledStr != nullptr) {
151 demangleName = std::string(demangledStr);
152 std::free(demangledStr);
153 } else {
154 demangleName = std::string(bufStr);
155 }
156 funcName += demangleName;
157 return funcName;
158 }
159 } // namespace HiviewDFX
160 } // namespace OHOS
161