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