123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- /*===- InstrProfilingPlatformAIX.c - Profile data AIX platform ------------===*\
- |*
- |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- |* See https://llvm.org/LICENSE.txt for license information.
- |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- |*
- \*===----------------------------------------------------------------------===*/
- #if defined(_AIX)
- #ifdef __64BIT__
- #define __XCOFF64__
- #endif
- #include <errno.h>
- #include <stdlib.h>
- #include <string.h>
- #error #include <sys/ldr.h>
- #error #include <xcoff.h>
- #include "InstrProfiling.h"
- #include "InstrProfilingInternal.h"
- #define BIN_ID_PREFIX "xcoff_binary_id:"
- // If found, write the build-id into the Result buffer.
- static size_t FindBinaryId(char *Result, size_t Size) {
- unsigned long EntryAddr = (unsigned long)__builtin_return_address(0);
- // Use loadquery to get information about loaded modules; loadquery writes
- // its result into a buffer of unknown size.
- char Buf[1024];
- size_t BufSize = sizeof(Buf);
- char *BufPtr = Buf;
- int RC = -1;
- errno = 0;
- RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);
- if (RC == -1 && errno == ENOMEM) {
- BufSize = 64000; // should be plenty for any program.
- BufPtr = malloc(BufSize);
- if (BufPtr != 0)
- RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);
- }
- if (RC == -1)
- goto done;
- // Locate the ld_xinfo corresponding to this module.
- struct ld_xinfo *CurInfo = (struct ld_xinfo *)BufPtr;
- while (1) {
- unsigned long CurTextStart = (uint64_t)CurInfo->ldinfo_textorg;
- unsigned long CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize;
- if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd) {
- // Found my slot. Now search for the build-id.
- char *p = (char *)CurInfo->ldinfo_textorg;
- FILHDR *f = (FILHDR *)p;
- AOUTHDR *a = (AOUTHDR *)(p + FILHSZ);
- SCNHDR *s =
- (SCNHDR *)(p + FILHSZ + f->f_opthdr + SCNHSZ * (a->o_snloader - 1));
- LDHDR *ldhdr = (LDHDR *)(p + s->s_scnptr);
- // This is the loader string table
- char *lstr = (char *)ldhdr + ldhdr->l_stoff;
- // If the build-id exists, it's the first entry.
- // Each entry is comprised of a 2-byte size component, followed by the
- // data.
- size_t len = *(short *)lstr;
- char *str = (char *)(lstr + 2);
- size_t PrefixLen = sizeof(BIN_ID_PREFIX) - 1;
- if (len > PrefixLen && (len - PrefixLen) <= Size &&
- strncmp(str, BIN_ID_PREFIX, PrefixLen) == 0) {
- memcpy(Result, str + PrefixLen, len - PrefixLen);
- RC = len - PrefixLen;
- goto done;
- }
- break;
- }
- if (CurInfo->ldinfo_next == 0u)
- break;
- CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next);
- }
- done:
- if (BufSize != sizeof(Buf) && BufPtr != 0)
- free(BufPtr);
- return RC;
- }
- static int StrToHexError = 0;
- static uint8_t StrToHex(char c) {
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 0xa;
- if (c >= 'A' && c <= 'F')
- return c - 'A' + 0xa;
- StrToHexError = 1;
- return 0;
- }
- COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {
- // 200 bytes should be enough for the build-id hex string.
- static char Buf[200];
- // Profile reading tools expect this to be 8-bytes long.
- static int64_t BinaryIdLen = 0;
- static uint8_t *BinaryIdData = 0;
- // -1 means we already checked for a BinaryId and didn't find one.
- if (BinaryIdLen == -1)
- return 0;
- // Are we being called for the first time?
- if (BinaryIdLen == 0) {
- if (getenv("LLVM_PROFILE_NO_BUILD_ID"))
- goto fail;
- int BuildIdLen = FindBinaryId(Buf, sizeof(Buf));
- if (BuildIdLen <= 0)
- goto fail;
- if (Buf[BuildIdLen - 1] == '\0')
- BuildIdLen--;
- // assume even number of digits/chars, so 0xabc must be 0x0abc
- if ((BuildIdLen % 2) != 0 || BuildIdLen == 0)
- goto fail;
- // The numeric ID is represented as an ascii string in the loader section,
- // so convert it to raw binary.
- BinaryIdLen = BuildIdLen / 2;
- BinaryIdData = (uint8_t *)Buf;
- // Skip "0x" prefix if it exists.
- if (Buf[0] == '0' && Buf[1] == 'x') {
- BinaryIdLen -= 1;
- BinaryIdData += 2;
- }
- StrToHexError = 0;
- for (int i = 0; i < BinaryIdLen; i++)
- BinaryIdData[i] = (StrToHex(BinaryIdData[2 * i]) << 4) +
- StrToHex(BinaryIdData[2 * i + 1]);
- if (StrToHexError)
- goto fail;
- if (getenv("LLVM_PROFILE_VERBOSE")) {
- char *StrBuf = (char *)COMPILER_RT_ALLOCA(2 * BinaryIdLen + 1);
- for (int i = 0; i < (int)BinaryIdLen; i++)
- sprintf(&StrBuf[2 * i], "%02x", BinaryIdData[i]);
- PROF_NOTE("Writing binary id: %s\n", StrBuf);
- }
- }
- uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen);
- if (Writer && lprofWriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,
- BinaryIdPadding) == -1)
- return -1; // Return -1 rather goto fail to match the NT_GNU_BUILD_ID path.
- return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;
- fail:
- if (getenv("LLVM_PROFILE_VERBOSE"))
- fprintf(stderr, "no or invalid binary id: %.*s\n", (int)sizeof(Buf), Buf);
- BinaryIdLen = -1;
- return 0;
- }
- // Empty stubs to allow linking object files using the registration-based scheme
- COMPILER_RT_VISIBILITY
- void __llvm_profile_register_function(void *Data_) {}
- COMPILER_RT_VISIBILITY
- void __llvm_profile_register_names_function(void *NamesStart,
- uint64_t NamesSize) {}
- // The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in
- // {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds"})
- // are always live when linking on AIX, regardless if the .o's being linked
- // reference symbols from the profile library (for example when no files were
- // compiled with -fprofile-generate). That's because these symbols are kept
- // alive through references in constructor functions that are always live in the
- // default linking model on AIX (-bcdtors:all). The __start_SECNAME and
- // __stop_SECNAME symbols are only resolved by the linker when the SECNAME
- // section exists. So for the scenario where the user objects have no such
- // section (i.e. when they are compiled with -fno-profile-generate), we always
- // define these zero length variables in each of the above 4 sections.
- static int dummy_cnts[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
- static int dummy_bits[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);
- static int dummy_data[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
- static const int dummy_name[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
- static int dummy_vnds[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
- static int dummy_orderfile[0] COMPILER_RT_SECTION(
- COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME);
- // To avoid GC'ing of the dummy variables by the linker, reference them in an
- // array and reference the array in the runtime registration code
- // (InstrProfilingRuntime.cpp)
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wcast-qual"
- #endif
- COMPILER_RT_VISIBILITY
- void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
- (void *)&dummy_data, (void *)&dummy_name,
- (void *)&dummy_vnds, (void *)&dummy_orderfile};
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
- #endif
|