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