* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
* libkperf licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
* PURPOSE.
* See the Mulan PSL v2 for more details.
* Author: Mr.Li
* Create: 2024-04-03
* Description: Provide a complete set of symbolic analysis tools, perform operations such as
* module records, address analysis and stack conversion.
******************************************************************************/
#ifndef USER_SYMBOL_H
#define USER_SYMBOL_H
#include <sys/stat.h>
#include <sys/mman.h>
#include <mutex>
#include <unordered_map>
#include <map>
#include <memory>
#include <vector>
#include <iostream>
#include <string>
#include "llvm/DebugInfo/Symbolize/Symbolize.h"
#include <linux/types.h>
#include "safe_handler.h"
#include "linked_list.h"
#ifndef ELF_LLVM
#include <elf++.hh>
#endif
#include "symbol.h"
using namespace llvm;
using namespace symbolize;
namespace KUNPENG_SYM {
enum class RecordModuleType { RECORD_ALL = 0, RECORD_NO_DWARF = 1 };
struct ModuleMap {
unsigned long start;
unsigned long end;
std::string moduleName;
std::string mntPoint;
bool isExecFile = false;
RecordModuleType moduleType;
bool isFile = true;
};
#ifndef ELF_LLVM
struct ElfMap {
unsigned long start;
unsigned long end;
std::string symbolName;
} __attribute__((aligned(8)));
using ELF_SYM = elf::sym;
using ELF = elf::elf;
class ParserElf
{
public:
explicit ParserElf(const ELF &elf) : elf(elf){};
ELF_SYM *FindSymbol(unsigned long addr);
void Emplace(unsigned long addr, const ELF_SYM &elfSym);
private:
ELF elf;
std::map<unsigned long, ELF_SYM> symTab;
};
#endif
struct ElfHdr {
char elfFormat[4];
char elfClass;
char elfData;
unsigned char elfVersion;
};
struct ElfNoteHeader {
int nameSize;
int descSize;
int type;
};
struct JavaEntry {
unsigned long start;
unsigned long end;
std::string symbolName;
std::string fileName;
unsigned int line;
};
class MyElf {
public:
MyElf(const std::string& filePath) : filePath(filePath){};
~MyElf() {
if (base) {
munmap(base, lim);
}
};
int LoadMmap();
const void* Load(off_t offset, size_t size);
int ElfGetBuildId(char** buildId);
bool IsExecFile();
private:
template<typename Ehdr, typename Phdr, typename Shdr>
int ElfParser(char** buildId);
template<typename Ehdr>
bool CheckIsExecFile();
int CheckElfHeader();
ElfHdr* elfHdr = nullptr;
void* base;
size_t lim;
std::string filePath;
};
class JavaElf
{
public:
JavaElf() = default;
explicit JavaElf(int pid) : pid(pid) {};
int FindElf(unsigned long addr, struct JavaEntry& entry);
private:
volatile bool hasLoad = false;
int pid = -1;
std::map<unsigned long, JavaEntry> symbolList;
};
static LLVMSymbolizer Symbolizer;
using SYMBOL_MAP = std::unordered_map<pid_t, std::unordered_map<__u64, struct Symbol *>>;
using SYMBOL_UNMAP = std::vector<Symbol*>;
using STACK_MAP = std::unordered_map<pid_t, std::unordered_map<std::string, struct Stack*>>;
using MODULE_MAP = std::unordered_map<pid_t, std::vector<std::shared_ptr<ModuleMap>>>;
#ifndef ELF_LLVM
using ELF_MAP = std::unordered_map<std::string, ParserElf>;
#endif
class SymbolUtils final {
public:
SymbolUtils() = default;
~SymbolUtils() = default;
static void FreeSymbol(struct Symbol* symbol);
static bool IsFile(const char* fileName);
static unsigned long SymStoul(const std::string& addrStr);
static bool IsNumber(const std::string& str);
static void FreeStackAsm(struct StackAsm** stackAsm);
static void StrCpy(char* dst, int dstLen, const char* src);
};
class SymbolResolve {
public:
static SymbolResolve* GetInstance()
{
if (instance == nullptr) {
std::lock_guard<std::mutex> lock(mutex);
if (instance == nullptr) {
instance = new SymbolResolve();
}
}
return instance;
}
int RecordModule(int pid, RecordModuleType recordModuleType);
void FreeModule(int pid);
int RecordKernel();
int UpdateModule(int pid, RecordModuleType recordModuleType);
int UpdateModule(int pid, const char* moduleName, unsigned long startAddr, RecordModuleType recordModuleType);
void Clear();
std::shared_ptr<ModuleMap> AddrToModule(std::vector<std::shared_ptr<ModuleMap>>& processModule, unsigned long addr);
struct Stack* StackToHash(int pid, unsigned long* stack, int nr);
struct Symbol* MapAddr(int pid, unsigned long addr);
struct StackAsm* MapAsmCode(const char* moduleName, unsigned long startAddr, unsigned long endAddr);
struct Symbol* MapCodeAddr(const char* moduleName, unsigned long startAddr);
int GetBuildId(const char *moduleName, char **buildId);
int GetAsmCodeByAddr(const char* moduleName, unsigned long startAddr, unsigned long endAddr, char** asmCode);
#ifndef ELF_LLVM
int RecordElf(const char* fileName);
#endif
private:
#ifndef ELF_LLVM
void SearchElfInfo(ParserElf &myElf, unsigned long addr, struct Symbol* symbol, unsigned long *offset);
#endif
char* GetCharFromStr(const std::string& str);
struct Symbol* MapKernelAddr(unsigned long addr);
struct Symbol* MapUserAddr(int pid, unsigned long addr);
struct StackAsm* MapAsmCodeStack(const std::string& moduleName, unsigned long startAddr, unsigned long endAddr);
std::vector<std::shared_ptr<ModuleMap>> FindDiffMaps(const std::vector<std::shared_ptr<ModuleMap>>& oldMaps,
const std::vector<std::shared_ptr<ModuleMap>>& newMaps) const;
std::map<int, JavaElf> javaElfArr;
std::map<std::string, char*> strToCharMap;
SYMBOL_MAP symbolMap{};
SYMBOL_UNMAP symbolUnmap{};
STACK_MAP stackMap{};
MODULE_MAP moduleMap{};
std::vector<std::shared_ptr<Symbol>> ksymArray;
SymbolResolve()
{}
SymbolResolve(const SymbolResolve&) = delete;
SymbolResolve& operator=(const SymbolResolve&) = delete;
~SymbolResolve()
{}
#ifndef ELF_LLVM
ELF_MAP elfMap{};
#endif
SafeHandler<int> moduleSafeHandler;
SafeHandler<std::string> dwarfSafeHandler;
SafeHandler<std::string> elfSafeHandler;
SafeHandler<int> symSafeHandler;
SafeHandler<std::string> dwarfLoadHandler;
static std::mutex kernelMutex;
static SymbolResolve* instance;
static std::mutex mutex;
};
}
#endif