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-exception 6 |* 7 \*===----------------------------------------------------------------------===*/ 8 9 #if defined(_AIX) 10 11 #ifdef __64BIT__ 12 #define __XCOFF64__ 13 #endif 14 #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. 26 static 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 writes 30 // 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 table 63 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 the 67 // 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 } 83 done: 84 if (BufSize != sizeof(Buf) && BufPtr != 0) 85 free(BufPtr); 86 return RC; 87 } 88 89 static int StrToHexError = 0; 90 static 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 101 COMPILER_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 0x0abc 125 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 162 fail: 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 scheme 170 COMPILER_RT_VISIBILITY 171 void __llvm_profile_register_function(void *Data_) {} 172 173 COMPILER_RT_VISIBILITY 174 void __llvm_profile_register_names_function(void *NamesStart, 175 uint64_t NamesSize) {} 176 177 // The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in 178 // {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds"}) 179 // are always live when linking on AIX, regardless if the .o's being linked 180 // reference symbols from the profile library (for example when no files were 181 // compiled with -fprofile-generate). That's because these symbols are kept 182 // alive through references in constructor functions that are always live in the 183 // default linking model on AIX (-bcdtors:all). The __start_SECNAME and 184 // __stop_SECNAME symbols are only resolved by the linker when the SECNAME 185 // section exists. So for the scenario where the user objects have no such 186 // section (i.e. when they are compiled with -fno-profile-generate), we always 187 // define these zero length variables in each of the above 4 sections. 188 static int dummy_cnts[0] COMPILER_RT_SECTION( 189 COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME); 190 static int dummy_data[0] COMPILER_RT_SECTION( 191 COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME); 192 static const int dummy_name[0] COMPILER_RT_SECTION( 193 COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME); 194 static int dummy_vnds[0] COMPILER_RT_SECTION( 195 COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME); 196 197 // To avoid GC'ing of the dummy variables by the linker, reference them in an 198 // array and reference the array in the runtime registration code 199 // (InstrProfilingRuntime.cpp) 200 #ifdef __GNUC__ 201 #pragma GCC diagnostic push 202 #pragma GCC diagnostic ignored "-Wcast-qual" 203 #endif 204 COMPILER_RT_VISIBILITY 205 void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_data, 206 (void *)&dummy_name, (void *)&dummy_vnds}; 207 #ifdef __GNUC__ 208 #pragma GCC diagnostic pop 209 #endif 210 #endif 211