1/*
2 * Copyright (c) 2021-2022 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#ifndef HIPERF_SYMBOLS_H
17#define HIPERF_SYMBOLS_H
18
19#include <cinttypes>
20#include <iomanip>
21#include <sstream>
22#include <string>
23
24#include "dfx_elf.h"
25#include "dfx_symbol.h"
26#include "perf_file_format.h"
27#include "utilities.h"
28
29#define HIPERF_ELF_READ_USE_MMAP
30
31namespace OHOS {
32namespace Developtools {
33namespace HiPerf {
34using namespace OHOS::HiviewDFX;
35
36constexpr const char KERNEL_MMAP_NAME[] = "[kernel.kallsyms]";
37constexpr const char KERNEL_MODULES_EXT_NAME[] = ".ko";
38constexpr const char KERNEL_ELF_NAME[] = "vmlinux";
39constexpr const char MMAP_VDSO_NAME[] = "[vdso]";
40constexpr const char MMAP_ANONYMOUS_NAME[] = "[anon]";
41constexpr const char MMAP_ANONYMOUS_OHOS_NAME[] = "//anon";
42
43const std::string NOTE_GNU_BUILD_ID = ".note.gnu.build-id";
44const std::string EH_FRAME_HR = ".eh_frame_hdr";
45const std::string EH_FRAME = ".eh_frame";
46const std::string ARM_EXIDX = ".ARM.exidx";
47const std::string SYMTAB = ".symtab";
48const std::string DYNSYM = ".dynsym";
49const std::string GNU_DEBUGDATA = ".gnu_debugdata";
50const std::string PLT = ".plt";
51const std::string LINKER_PREFIX = "__dl_";
52const std::string LINKER_PREFIX_NAME = "[linker]";
53
54const int MAX_SYMBOLS_TYPE_NAME_LEN = 10;
55
56const pid_t SYSMGR_PID = 2;
57const std::string SYSMGR_NAME = "sysmgr";
58const std::string SYSMGR_FILE_NAME = "sysmgr.elf";
59const std::string DEVHOST_FILE_NAME = "devhost.elf";
60const std::string DEVHOST_LINUX_FILE_NAME = "/lib/libdh-linux.so";
61const std::string DEVHOST_LINUX_PREFIX = "/liblinux/";
62
63class FileSymbol {
64    [[maybe_unused]] uint64_t vaddr_ = 0;
65    [[maybe_unused]] uint64_t len_ = 0;
66    std::string name_ = "";
67    std::string demangle_ = ""; // demangle string
68    FileSymbol(uint64_t vaddr, uint64_t len, const char *name, const char *demangle)
69        : vaddr_(vaddr), len_(len), name_(name), demangle_(demangle)
70    {
71    }
72};
73
74enum SymbolsFileType {
75    SYMBOL_KERNEL_FILE,
76    SYMBOL_KERNEL_MODULE_FILE,
77    SYMBOL_KERNEL_THREAD_FILE,
78    // .hap!elf, normal elf.
79    SYMBOL_ELF_FILE,
80    SYMBOL_JAVA_FILE,
81    SYMBOL_JS_FILE,
82    SYMBOL_HAP_FILE,
83    SYMBOL_UNKNOW_FILE,
84};
85
86class SymbolsFile {
87public:
88    SymbolsFileType symbolFileType_;
89    std::string filePath_ = "";
90    int32_t id_ = -1; // used to report protobuf file
91
92    // [14] .text             PROGBITS         00000000002c5000  000c5000
93    // min exec addr , general it point to .text
94    // we make a default value for min compare
95    static const uint64_t maxVaddr = std::numeric_limits<uint64_t>::max();
96
97    uint64_t textExecVaddr_ = maxVaddr;
98    uint64_t textExecVaddrFileOffset_ = 0;
99    uint64_t textExecVaddrRange_ = maxVaddr;
100    std::shared_ptr<DfxMap> map_ = nullptr;
101
102    SymbolsFile(SymbolsFileType symbolType, const std::string path)
103        : symbolFileType_(symbolType), filePath_(path) {};
104    virtual ~SymbolsFile();
105
106    virtual std::shared_ptr<DfxElf> GetElfFile()
107    {
108        return nullptr;
109    }
110
111    // create the symbols file object
112    static std::unique_ptr<SymbolsFile> CreateSymbolsFile(
113        SymbolsFileType = SYMBOL_UNKNOW_FILE, const std::string symbolFilePath = EMPTY_STRING, pid_t pid = 0);
114    static std::unique_ptr<SymbolsFile> CreateSymbolsFile(const std::string &symbolFilePath, pid_t pid = 0);
115
116    // set symbols path
117    bool setSymbolsFilePath(const std::string &symbolsSearchPath)
118    {
119        std::vector<std::string> symbolsSearchPaths = {symbolsSearchPath};
120        return setSymbolsFilePath(symbolsSearchPaths);
121    };
122    bool setSymbolsFilePath(const std::vector<std::string> &);
123    virtual bool IsAbc()
124    {
125        return false;
126    }
127
128    virtual void SetBoolValue(bool value);
129    // load symbol from file
130    virtual bool LoadSymbols([[maybe_unused]] std::shared_ptr<DfxMap> map = nullptr,
131                             [[maybe_unused]] const std::string &symbolFilePath = EMPTY_STRING)
132    {
133        HLOGV("virtual dummy function called");
134        symbolsLoaded_ = true;
135        return false;
136    };
137    // load debug info for unwind
138    virtual bool LoadDebugInfo(std::shared_ptr<DfxMap> map = nullptr,
139                               [[maybe_unused]] const std::string &symbolFilePath = EMPTY_STRING)
140    {
141        HLOGV("virtual dummy function called");
142        debugInfoLoaded_ = true;
143        return false;
144    };
145
146    virtual const std::unordered_map<uint64_t, ElfLoadInfo> GetPtLoads()
147    {
148        std::unordered_map<uint64_t, ElfLoadInfo> loadInfoMap;
149        return loadInfoMap;
150    }
151
152    // get the build if from symbols
153    const std::string GetBuildId() const;
154
155    virtual void EnableMiniDebugInfo() {}
156    // get the symbols vector
157    const std::vector<DfxSymbol> &GetSymbols();
158    const std::vector<DfxSymbol *> &GetMatchedSymbols();
159
160    // get vaddr(in symbol) from ip(real addr , after mmap reloc)
161    virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const;
162
163    // get symbols from vaddr
164    const DfxSymbol GetSymbolWithVaddr(uint64_t vaddrInFile);
165
166    // get the section info , like .ARM.exidx
167    virtual bool GetSectionInfo([[maybe_unused]] const std::string &name,
168                                [[maybe_unused]] uint64_t &sectionVaddr,
169                                [[maybe_unused]] uint64_t &sectionSize,
170                                [[maybe_unused]] uint64_t &sectionFileOffset) const
171    {
172        HLOGV("virtual dummy function called");
173        return false;
174    }
175#ifndef __arm__
176    // get hdr info for unwind , need provide the fde table location and entry count
177    virtual bool GetHDRSectionInfo([[maybe_unused]] uint64_t &ehFrameHdrElfOffset,
178                                   [[maybe_unused]] uint64_t &fdeTableElfOffset,
179                                   [[maybe_unused]] uint64_t &fdeTableSize)
180    {
181        HLOGV("virtual dummy function called");
182        return false;
183    }
184#endif
185    // load from symbols from the perf.data format
186    static std::unique_ptr<SymbolsFile> LoadSymbolsFromSaved(const SymbolFileStruct &);
187    // save the symbols to perf.data format
188    void ExportSymbolToFileFormat(SymbolFileStruct &symbolFileStruct);
189
190    bool SymbolsLoaded()
191    {
192        return symbolsLoaded_;
193    }
194
195    void AddSymbol(DfxSymbol symbol);
196
197    // this means we are in recording
198    // will try read some elf in runtime path
199    static bool onRecording_;
200    static bool needParseJsFunc_;
201    std::vector<DfxSymbol> symbols_ {};
202    std::vector<DfxSymbol *> matchedSymbols_ {};
203    std::map<uint64_t, DfxSymbol> symbolsMap_;
204    virtual DfxSymbol GetSymbolWithPcAndMap(uint64_t pc, std::shared_ptr<DfxMap> map)
205    {
206        return DfxSymbol();
207    }
208
209    // set map info
210    void SetMapsInfo(std::shared_ptr<DfxMap> map)
211    {
212        map_ = map;
213    }
214
215protected:
216    bool symbolsLoaded_ = false;
217    bool symbolsLoadResult_ = false;
218    bool debugInfoLoaded_ = false;
219    bool debugInfoLoadResult_ = false;
220    const std::string FindSymbolFile(const std::vector<std::string> &,
221                                     std::string symboleFilePath = EMPTY_STRING) const;
222
223    std::string SearchReadableFile(const std::vector<std::string> &searchPaths,
224                                   const std::string &filePath) const;
225    bool UpdateBuildIdIfMatch(std::string buildId);
226    std::string buildId_ = "";
227    std::vector<std::string> symbolsFileSearchPaths_;
228
229    std::vector<FileSymbol> fileSymbols_ {};
230    std::mutex mutex_;
231
232    void AdjustSymbols();
233    void SortMatchedSymbols();
234    bool CheckPathReadable(const std::string &path) const;
235
236    FRIEND_TEST(SymbolsFileTest, FindSymbolFile);
237    FRIEND_TEST(SymbolsFileTest, UpdateBuildIdIfMatch);
238    FRIEND_TEST(SymbolsFileTest, exportSymbolToFileFormat);
239    FRIEND_TEST(SymbolsFileTest, exportSymbolToFileFormatMatched);
240    friend class VirtualRuntimeTest;
241    FRIEND_TEST(ReportJsonFileTest, ProcessSymbolsFiles);
242    FRIEND_TEST(ReportProtobufFileTest, ProcessSymbolsFiles);
243    friend class ReportProtobufFileTest;
244};
245} // namespace HiPerf
246} // namespace Developtools
247} // namespace OHOS
248#endif // HIPERF_SYMBOLS_H
249