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