From 2ffd6e2b430e00206ce60174f03f32ff6da6f051 Mon Sep 17 00:00:00 2001 From: Elvina Yakubova Date: Tue, 19 Jan 2021 02:08:55 +0800 Subject: [PATCH] [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) --- bolt/runtime/common.h | 17 ++++++++++ bolt/runtime/instr.cpp | 74 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 2 deletions(-) diff --git a/bolt/runtime/common.h b/bolt/runtime/common.h index c2648df50a77..2be89f757d30 100644 --- a/bolt/runtime/common.h +++ b/bolt/runtime/common.h @@ -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 diff --git a/bolt/runtime/instr.cpp b/bolt/runtime/instr.cpp index bab860f26274..474158662805 100644 --- a/bolt/runtime/instr.cpp +++ b/bolt/runtime/instr.cpp @@ -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 +bool parseAddressRange(const char *Str, uint64_t &StartAddress, + uint64_t &EndAddress) { + if (!Str) + return false; + // Parsed string format: - + 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(FDdir) > 0, + "failed to open /proc/self/map_files"); + + while (long Nread = __getdents(FDdir, (struct dirent *)Buf, BufSize)) { + assert(static_cast(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(FD) > 0, "Failed to open /proc/self/exe"); + assert(static_cast(FD) > 0, "failed to open binary path"); + Result.FileDesc = FD; // mmap our binary to memory