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