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 DFXLOGW("Failed to dlopen librustc_demangle, %{public}s", dlerror());
60 return false;
61 }
62
63 g_rustDemangleFn = (RustDemangleFn)dlsym(rustDemangleLibHandle, "rustc_demangle");
64 if (g_rustDemangleFn == nullptr) {
65 DFXLOGW("Failed to dlsym rustc_demangle, %{public}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 DFXLOGU("nameStr: %{public}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 DFXLOGU("Symbol relPc: %{public}" PRIx64 ", funcName: %{public}s, funcOffset: %{public}" PRIx64 "",
117 relPc, funcName.c_str(), funcOffset);
118 return true;
119 }
120 return false;
121 }
122
Demangle(const std::string& buf)123 std::string DfxSymbols::Demangle(const std::string& buf)
124 {
125 DFX_TRACE_SCOPED_DLSYM("Demangle");
126 if ((buf.length() < 2) || (buf[0] != '_')) { // 2 : min buf length
127 return buf;
128 }
129
130 std::string funcName;
131 const char *bufStr = buf.c_str();
132 if (StartsWith(buf, LINKER_PREFIX)) {
133 bufStr += LINKER_PREFIX.size();
134 funcName += LINKER_PREFIX_NAME;
135 }
136
137 int status = 0;
138 char* demangledStr = nullptr;
139 if (buf[1] == 'Z') {
140 demangledStr = abi::__cxa_demangle(bufStr, nullptr, nullptr, &status);
141 }
142 #ifdef RUSTC_DEMANGLE
143 if (buf[1] == 'R') {
144 std::lock_guard<std::mutex> lck(g_mutex);
145 if (FindRustDemangleFunction()) {
146 demangledStr = g_rustDemangleFn(bufStr);
147 }
148 }
149 #endif
150 std::string demangleName;
151 if (demangledStr != nullptr) {
152 demangleName = std::string(demangledStr);
153 std::free(demangledStr);
154 } else {
155 demangleName = std::string(bufStr);
156 }
157 funcName += demangleName;
158 return funcName;
159 }
160 } // namespace HiviewDFX
161 } // namespace OHOS
162