Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
35233 views
/*===- InstrProfilingPlatformAIX.c - Profile data AIX platform ------------===*\1|*2|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3|* See https://llvm.org/LICENSE.txt for license information.4|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5|*6\*===----------------------------------------------------------------------===*/78#if defined(_AIX)910#ifdef __64BIT__11#define __XCOFF64__12#endif13#include <errno.h>14#include <stdlib.h>15#include <string.h>16#include <sys/ldr.h>17#include <xcoff.h>1819#include "InstrProfiling.h"20#include "InstrProfilingInternal.h"2122#define BIN_ID_PREFIX "xcoff_binary_id:"2324// If found, write the build-id into the Result buffer.25static size_t FindBinaryId(char *Result, size_t Size) {26unsigned long EntryAddr = (unsigned long)__builtin_return_address(0);2728// Use loadquery to get information about loaded modules; loadquery writes29// its result into a buffer of unknown size.30char Buf[1024];31size_t BufSize = sizeof(Buf);32char *BufPtr = Buf;33int RC = -1;3435errno = 0;36RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);37if (RC == -1 && errno == ENOMEM) {38BufSize = 64000; // should be plenty for any program.39BufPtr = malloc(BufSize);40if (BufPtr != 0)41RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);42}4344if (RC == -1)45goto done;4647// Locate the ld_xinfo corresponding to this module.48struct ld_xinfo *CurInfo = (struct ld_xinfo *)BufPtr;49while (1) {50unsigned long CurTextStart = (uint64_t)CurInfo->ldinfo_textorg;51unsigned long CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize;52if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd) {53// Found my slot. Now search for the build-id.54char *p = (char *)CurInfo->ldinfo_textorg;5556FILHDR *f = (FILHDR *)p;57AOUTHDR *a = (AOUTHDR *)(p + FILHSZ);58SCNHDR *s =59(SCNHDR *)(p + FILHSZ + f->f_opthdr + SCNHSZ * (a->o_snloader - 1));60LDHDR *ldhdr = (LDHDR *)(p + s->s_scnptr);61// This is the loader string table62char *lstr = (char *)ldhdr + ldhdr->l_stoff;6364// If the build-id exists, it's the first entry.65// Each entry is comprised of a 2-byte size component, followed by the66// data.67size_t len = *(short *)lstr;68char *str = (char *)(lstr + 2);69size_t PrefixLen = sizeof(BIN_ID_PREFIX) - 1;70if (len > PrefixLen && (len - PrefixLen) <= Size &&71strncmp(str, BIN_ID_PREFIX, PrefixLen) == 0) {72memcpy(Result, str + PrefixLen, len - PrefixLen);73RC = len - PrefixLen;74goto done;75}76break;77}78if (CurInfo->ldinfo_next == 0u)79break;80CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next);81}82done:83if (BufSize != sizeof(Buf) && BufPtr != 0)84free(BufPtr);85return RC;86}8788static int StrToHexError = 0;89static uint8_t StrToHex(char c) {90if (c >= '0' && c <= '9')91return c - '0';92if (c >= 'a' && c <= 'f')93return c - 'a' + 0xa;94if (c >= 'A' && c <= 'F')95return c - 'A' + 0xa;96StrToHexError = 1;97return 0;98}99100COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {101// 200 bytes should be enough for the build-id hex string.102static char Buf[200];103// Profile reading tools expect this to be 8-bytes long.104static int64_t BinaryIdLen = 0;105static uint8_t *BinaryIdData = 0;106107// -1 means we already checked for a BinaryId and didn't find one.108if (BinaryIdLen == -1)109return 0;110111// Are we being called for the first time?112if (BinaryIdLen == 0) {113if (getenv("LLVM_PROFILE_NO_BUILD_ID"))114goto fail;115116int BuildIdLen = FindBinaryId(Buf, sizeof(Buf));117if (BuildIdLen <= 0)118goto fail;119120if (Buf[BuildIdLen - 1] == '\0')121BuildIdLen--;122123// assume even number of digits/chars, so 0xabc must be 0x0abc124if ((BuildIdLen % 2) != 0 || BuildIdLen == 0)125goto fail;126127// The numeric ID is represented as an ascii string in the loader section,128// so convert it to raw binary.129BinaryIdLen = BuildIdLen / 2;130BinaryIdData = (uint8_t *)Buf;131132// Skip "0x" prefix if it exists.133if (Buf[0] == '0' && Buf[1] == 'x') {134BinaryIdLen -= 1;135BinaryIdData += 2;136}137138StrToHexError = 0;139for (int i = 0; i < BinaryIdLen; i++)140BinaryIdData[i] = (StrToHex(BinaryIdData[2 * i]) << 4) +141StrToHex(BinaryIdData[2 * i + 1]);142143if (StrToHexError)144goto fail;145146if (getenv("LLVM_PROFILE_VERBOSE")) {147char *StrBuf = (char *)COMPILER_RT_ALLOCA(2 * BinaryIdLen + 1);148for (int i = 0; i < (int)BinaryIdLen; i++)149sprintf(&StrBuf[2 * i], "%02x", BinaryIdData[i]);150PROF_NOTE("Writing binary id: %s\n", StrBuf);151}152}153154uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen);155if (Writer && lprofWriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,156BinaryIdPadding) == -1)157return -1; // Return -1 rather goto fail to match the NT_GNU_BUILD_ID path.158159return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;160161fail:162if (getenv("LLVM_PROFILE_VERBOSE"))163fprintf(stderr, "no or invalid binary id: %.*s\n", (int)sizeof(Buf), Buf);164BinaryIdLen = -1;165return 0;166}167168// Empty stubs to allow linking object files using the registration-based scheme169COMPILER_RT_VISIBILITY170void __llvm_profile_register_function(void *Data_) {}171172COMPILER_RT_VISIBILITY173void __llvm_profile_register_names_function(void *NamesStart,174uint64_t NamesSize) {}175176// The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in177// {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds",178// "__llvm_prf_vns", "__llvm_prf_vtab"})179// are always live when linking on AIX, regardless if the .o's being linked180// reference symbols from the profile library (for example when no files were181// compiled with -fprofile-generate). That's because these symbols are kept182// alive through references in constructor functions that are always live in the183// default linking model on AIX (-bcdtors:all). The __start_SECNAME and184// __stop_SECNAME symbols are only resolved by the linker when the SECNAME185// section exists. So for the scenario where the user objects have no such186// section (i.e. when they are compiled with -fno-profile-generate), we always187// define these zero length variables in each of the above 4 sections.188static int dummy_cnts[0] COMPILER_RT_SECTION(189COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);190static int dummy_bits[0] COMPILER_RT_SECTION(191COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);192static int dummy_data[0] COMPILER_RT_SECTION(193COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);194static const int dummy_name[0] COMPILER_RT_SECTION(195COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);196static int dummy_vnds[0] COMPILER_RT_SECTION(197COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);198static int dummy_orderfile[0] COMPILER_RT_SECTION(199COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME);200static int dummy_vname[0] COMPILER_RT_SECTION(201COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);202static int dummy_vtab[0] COMPILER_RT_SECTION(203COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);204205// To avoid GC'ing of the dummy variables by the linker, reference them in an206// array and reference the array in the runtime registration code207// (InstrProfilingRuntime.cpp)208#ifdef __GNUC__209#pragma GCC diagnostic push210#pragma GCC diagnostic ignored "-Wcast-qual"211#endif212COMPILER_RT_VISIBILITY213void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,214(void *)&dummy_data, (void *)&dummy_name,215(void *)&dummy_vnds, (void *)&dummy_orderfile,216(void *)&dummy_vname, (void *)&dummy_vtab};217#ifdef __GNUC__218#pragma GCC diagnostic pop219#endif220#endif221222223