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 30namespace OHOS { 31namespace HiviewDFX { 32using RustDemangleFn = char*(*)(const char *); 33namespace { 34#undef LOG_DOMAIN 35#undef LOG_TAG 36#define LOG_DOMAIN 0xD002D11 37#define LOG_TAG "DfxSymbols" 38 39const std::string LINKER_PREFIX = "__dl_"; 40const std::string LINKER_PREFIX_NAME = "[linker]"; 41 42#ifdef RUSTC_DEMANGLE 43static std::mutex g_mutex; 44static bool g_hasTryLoadRustDemangleLib = false; 45static RustDemangleFn g_rustDemangleFn = nullptr; 46#endif 47} 48 49#ifdef RUSTC_DEMANGLE 50bool 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 73bool 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 90bool 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 102bool 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 123std::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