brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.7 KiB · 9cb313b Raw
222 lines · c
1/*===- InstrProfilingPlatformAIX.c - Profile data AIX platform ------------===*\2|*3|* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4|* See https://llvm.org/LICENSE.txt for license information.5|* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6|*7\*===----------------------------------------------------------------------===*/8 9#if defined(_AIX)10 11#ifdef __64BIT__12#define __XCOFF64__13#endif14#include <errno.h>15#include <stdlib.h>16#include <string.h>17#include <sys/ldr.h>18#include <xcoff.h>19 20#include "InstrProfiling.h"21#include "InstrProfilingInternal.h"22 23#define BIN_ID_PREFIX "xcoff_binary_id:"24 25// If found, write the build-id into the Result buffer.26static size_t FindBinaryId(char *Result, size_t Size) {27  unsigned long EntryAddr = (unsigned long)__builtin_return_address(0);28 29  // Use loadquery to get information about loaded modules; loadquery writes30  // its result into a buffer of unknown size.31  char Buf[1024];32  size_t BufSize = sizeof(Buf);33  char *BufPtr = Buf;34  int RC = -1;35 36  errno = 0;37  RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);38  if (RC == -1 && errno == ENOMEM) {39    BufSize = 64000; // should be plenty for any program.40    BufPtr = malloc(BufSize);41    if (BufPtr != 0)42      RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);43  }44 45  if (RC == -1)46    goto done;47 48  // Locate the ld_xinfo corresponding to this module.49  struct ld_xinfo *CurInfo = (struct ld_xinfo *)BufPtr;50  while (1) {51    unsigned long CurTextStart = (uint64_t)CurInfo->ldinfo_textorg;52    unsigned long CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize;53    if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd) {54      // Found my slot. Now search for the build-id.55      char *p = (char *)CurInfo->ldinfo_textorg;56 57      FILHDR *f = (FILHDR *)p;58      AOUTHDR *a = (AOUTHDR *)(p + FILHSZ);59      SCNHDR *s =60          (SCNHDR *)(p + FILHSZ + f->f_opthdr + SCNHSZ * (a->o_snloader - 1));61      LDHDR *ldhdr = (LDHDR *)(p + s->s_scnptr);62      // This is the loader string table63      char *lstr = (char *)ldhdr + ldhdr->l_stoff;64 65      // If the build-id exists, it's the first entry.66      // Each entry is comprised of a 2-byte size component, followed by the67      // data.68      size_t len = *(short *)lstr;69      char *str = (char *)(lstr + 2);70      size_t PrefixLen = sizeof(BIN_ID_PREFIX) - 1;71      if (len > PrefixLen && (len - PrefixLen) <= Size &&72          strncmp(str, BIN_ID_PREFIX, PrefixLen) == 0) {73        memcpy(Result, str + PrefixLen, len - PrefixLen);74        RC = len - PrefixLen;75        goto done;76      }77      break;78    }79    if (CurInfo->ldinfo_next == 0u)80      break;81    CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next);82  }83done:84  if (BufSize != sizeof(Buf) && BufPtr != 0)85    free(BufPtr);86  return RC;87}88 89static int StrToHexError = 0;90static uint8_t StrToHex(char c) {91  if (c >= '0' && c <= '9')92    return c - '0';93  if (c >= 'a' && c <= 'f')94    return c - 'a' + 0xa;95  if (c >= 'A' && c <= 'F')96    return c - 'A' + 0xa;97  StrToHexError = 1;98  return 0;99}100 101COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {102  // 200 bytes should be enough for the build-id hex string.103  static char Buf[200];104  // Profile reading tools expect this to be 8-bytes long.105  static int64_t BinaryIdLen = 0;106  static uint8_t *BinaryIdData = 0;107 108  // -1 means we already checked for a BinaryId and didn't find one.109  if (BinaryIdLen == -1)110    return 0;111 112  // Are we being called for the first time?113  if (BinaryIdLen == 0) {114    if (getenv("LLVM_PROFILE_NO_BUILD_ID"))115      goto fail;116 117    int BuildIdLen = FindBinaryId(Buf, sizeof(Buf));118    if (BuildIdLen <= 0)119      goto fail;120 121    if (Buf[BuildIdLen - 1] == '\0')122      BuildIdLen--;123 124    // assume even number of digits/chars, so 0xabc must be 0x0abc125    if ((BuildIdLen % 2) != 0 || BuildIdLen == 0)126      goto fail;127 128    // The numeric ID is represented as an ascii string in the loader section,129    // so convert it to raw binary.130    BinaryIdLen = BuildIdLen / 2;131    BinaryIdData = (uint8_t *)Buf;132 133    // Skip "0x" prefix if it exists.134    if (Buf[0] == '0' && Buf[1] == 'x') {135      BinaryIdLen -= 1;136      BinaryIdData += 2;137    }138 139    StrToHexError = 0;140    for (int i = 0; i < BinaryIdLen; i++)141      BinaryIdData[i] = (StrToHex(BinaryIdData[2 * i]) << 4) +142                        StrToHex(BinaryIdData[2 * i + 1]);143 144    if (StrToHexError)145      goto fail;146 147    if (getenv("LLVM_PROFILE_VERBOSE")) {148      char *StrBuf = (char *)COMPILER_RT_ALLOCA(2 * BinaryIdLen + 1);149      for (int i = 0; i < (int)BinaryIdLen; i++)150        sprintf(&StrBuf[2 * i], "%02x", BinaryIdData[i]);151      PROF_NOTE("Writing binary id: %s\n", StrBuf);152    }153  }154 155  uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen);156  if (Writer && lprofWriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,157                                      BinaryIdPadding) == -1)158    return -1; // Return -1 rather goto fail to match the NT_GNU_BUILD_ID path.159 160  return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;161 162fail:163  if (getenv("LLVM_PROFILE_VERBOSE"))164    fprintf(stderr, "no or invalid binary id: %.*s\n", (int)sizeof(Buf), Buf);165  BinaryIdLen = -1;166  return 0;167}168 169// Empty stubs to allow linking object files using the registration-based scheme170COMPILER_RT_VISIBILITY171void __llvm_profile_register_function(void *Data_) {}172 173COMPILER_RT_VISIBILITY174void __llvm_profile_register_names_function(void *NamesStart,175                                            uint64_t NamesSize) {}176 177// The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in178// {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds",179// "__llvm_prf_vns", "__llvm_prf_vtab"})180// are always live when linking on AIX, regardless if the .o's being linked181// reference symbols from the profile library (for example when no files were182// compiled with -fprofile-generate). That's because these symbols are kept183// alive through references in constructor functions that are always live in the184// default linking model on AIX (-bcdtors:all). The __start_SECNAME and185// __stop_SECNAME symbols are only resolved by the linker when the SECNAME186// section exists. So for the scenario where the user objects have no such187// section (i.e. when they are compiled with -fno-profile-generate), we always188// define these zero length variables in each of the above 4 sections.189static int dummy_cnts[0] COMPILER_RT_SECTION(190    COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);191static int dummy_bits[0] COMPILER_RT_SECTION(192    COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);193static int dummy_data[0] COMPILER_RT_SECTION(194    COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);195static const int dummy_name[0] COMPILER_RT_SECTION(196    COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);197static int dummy_vnds[0] COMPILER_RT_SECTION(198    COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);199static int dummy_vname[0] COMPILER_RT_SECTION(200    COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);201static int dummy_vtab[0] COMPILER_RT_SECTION(202    COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);203static int dummy_covinit_funcs[0] COMPILER_RT_SECTION(204    COMPILER_RT_SEG INSTR_PROF_COVINIT_SECT_NAME);205 206// To avoid GC'ing of the dummy variables by the linker, reference them in an207// array and reference the array in the runtime registration code208// (InstrProfilingRuntime.cpp)209#ifdef __GNUC__210#pragma GCC diagnostic push211#pragma GCC diagnostic ignored "-Wcast-qual"212#endif213COMPILER_RT_VISIBILITY214void *__llvm_profile_keep[] = {215    (void *)&dummy_cnts, (void *)&dummy_bits,         (void *)&dummy_data,216    (void *)&dummy_name, (void *)&dummy_vnds,         (void *)&dummy_vname,217    (void *)&dummy_vtab, (void *)&dummy_covinit_funcs};218#ifdef __GNUC__219#pragma GCC diagnostic pop220#endif221#endif222