forked from OSchip/llvm-project
[PR] Instrumentation: Add support for opening libs based on links /proc/self/map_files
Summary: This commit adds support for opening libs based on links /proc/self/map_files. For this we're getting current virtual address and searching the lib in the directory with such address range. After that, we're getting full path to the binary by using readlink function. Direct read from link in /proc/self/map_files entries is not possible because of lack of permissions. Elvina Yakubova, Advanced Software Technology Lab, Huawei (cherry picked from FBD30092422)
This commit is contained in:
parent
6665c628ea
commit
2ffd6e2b43
|
@ -264,6 +264,23 @@ void reportNumber(const char *Msg, uint64_t Num, uint32_t Base) {
|
|||
|
||||
void report(const char *Msg) { __write(2, Msg, strLen(Msg)); }
|
||||
|
||||
unsigned long hexToLong(const char *Str, char Terminator = '\0') {
|
||||
unsigned long Res = 0;
|
||||
while (*Str != Terminator) {
|
||||
Res <<= 4;
|
||||
if ('0' <= *Str && *Str <= '9')
|
||||
Res += *Str++ - '0';
|
||||
else if ('a' <= *Str && *Str <= 'f')
|
||||
Res += *Str++ - 'a' + 10;
|
||||
else if ('A' <= *Str && *Str <= 'F')
|
||||
Res += *Str++ - 'A' + 10;
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
// We use a stack-allocated buffer for string manipulation in many pieces of
|
||||
// this code, including the code that prints each line of the fdata file. This
|
||||
|
|
|
@ -566,12 +566,82 @@ FunctionDescription::FunctionDescription(const uint8_t *FuncDesc) {
|
|||
/// Read and mmap descriptions written by BOLT from the executable's notes
|
||||
/// section
|
||||
#if defined(HAVE_ELF_H) and !defined(__APPLE__)
|
||||
|
||||
void *__attribute__((noinline)) __get_pc() {
|
||||
return __builtin_extract_return_addr(__builtin_return_address(0));
|
||||
}
|
||||
|
||||
/// Get string with address and parse it to hex pair <StartAddress, EndAddress>
|
||||
bool parseAddressRange(const char *Str, uint64_t &StartAddress,
|
||||
uint64_t &EndAddress) {
|
||||
if (!Str)
|
||||
return false;
|
||||
// Parsed string format: <hex1>-<hex2>
|
||||
StartAddress = hexToLong(Str, '-');
|
||||
while (*Str && *Str != '-')
|
||||
++Str;
|
||||
if (!*Str)
|
||||
return false;
|
||||
++Str; // swallow '-'
|
||||
EndAddress = hexToLong(Str);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Get full path to the real binary by getting current virtual address
|
||||
/// and searching for the appropriate link in address range in
|
||||
/// /proc/self/map_files
|
||||
static char *getBinaryPath() {
|
||||
const uint32_t BufSize = 1024;
|
||||
const uint32_t NameMax = 256;
|
||||
const char DirPath[] = "/proc/self/map_files/";
|
||||
static char TargetPath[NameMax] = {};
|
||||
char Buf[BufSize];
|
||||
|
||||
if (TargetPath[0] != '\0')
|
||||
return TargetPath;
|
||||
|
||||
unsigned long CurAddr = (unsigned long)__get_pc();
|
||||
uint64_t FDdir = __open(DirPath,
|
||||
/*flags=*/0 /*O_RDONLY*/,
|
||||
/*mode=*/0666);
|
||||
assert(static_cast<int64_t>(FDdir) > 0,
|
||||
"failed to open /proc/self/map_files");
|
||||
|
||||
while (long Nread = __getdents(FDdir, (struct dirent *)Buf, BufSize)) {
|
||||
assert(static_cast<int64_t>(Nread) != -1, "failed to get folder entries");
|
||||
|
||||
struct dirent *d;
|
||||
for (long Bpos = 0; Bpos < Nread; Bpos += d->d_reclen) {
|
||||
d = (struct dirent *)(Buf + Bpos);
|
||||
|
||||
uint64_t StartAddress, EndAddress;
|
||||
if (!parseAddressRange(d->d_name, StartAddress, EndAddress))
|
||||
continue;
|
||||
if (CurAddr < StartAddress || CurAddr > EndAddress)
|
||||
continue;
|
||||
char FindBuf[NameMax];
|
||||
char *C = strCopy(FindBuf, DirPath, NameMax);
|
||||
C = strCopy(C, d->d_name, NameMax - (C - FindBuf));
|
||||
*C = '\0';
|
||||
uint32_t Ret = __readlink(FindBuf, TargetPath, sizeof(TargetPath));
|
||||
assert(Ret != -1 && Ret != BufSize, "readlink error");
|
||||
TargetPath[Ret] = '\0';
|
||||
return TargetPath;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ProfileWriterContext readDescriptions() {
|
||||
ProfileWriterContext Result;
|
||||
uint64_t FD = __open("/proc/self/exe",
|
||||
char *BinPath = getBinaryPath();
|
||||
assert(BinPath && BinPath[0] != '\0', "failed to find binary path");
|
||||
|
||||
uint64_t FD = __open(BinPath,
|
||||
/*flags=*/0 /*O_RDONLY*/,
|
||||
/*mode=*/0666);
|
||||
assert(static_cast<int64_t>(FD) > 0, "Failed to open /proc/self/exe");
|
||||
assert(static_cast<int64_t>(FD) > 0, "failed to open binary path");
|
||||
|
||||
Result.FileDesc = FD;
|
||||
|
||||
// mmap our binary to memory
|
||||
|
|
Loading…
Reference in New Issue