1787fbad5SWael Yehia /*===- InstrProfilingPlatformAIX.c - Profile data AIX platform ------------===*\ 2787fbad5SWael Yehia |* 3787fbad5SWael Yehia |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4787fbad5SWael Yehia |* See https://llvm.org/LICENSE.txt for license information. 5787fbad5SWael Yehia |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6787fbad5SWael Yehia |* 7787fbad5SWael Yehia \*===----------------------------------------------------------------------===*/ 8787fbad5SWael Yehia 9787fbad5SWael Yehia #if defined(_AIX) 10787fbad5SWael Yehia 110e2ed905SWael Yehia #ifdef __64BIT__ 120e2ed905SWael Yehia #define __XCOFF64__ 130e2ed905SWael Yehia #endif 140e2ed905SWael Yehia #include <errno.h> 150e2ed905SWael Yehia #include <stdlib.h> 160e2ed905SWael Yehia #include <string.h> 170e2ed905SWael Yehia #include <sys/ldr.h> 180e2ed905SWael Yehia #include <xcoff.h> 190e2ed905SWael Yehia 20787fbad5SWael Yehia #include "InstrProfiling.h" 210e2ed905SWael Yehia #include "InstrProfilingInternal.h" 220e2ed905SWael Yehia 230e2ed905SWael Yehia #define BIN_ID_PREFIX "xcoff_binary_id:" 240e2ed905SWael Yehia 250e2ed905SWael Yehia // If found, write the build-id into the Result buffer. 260e2ed905SWael Yehia static size_t FindBinaryId(char *Result, size_t Size) { 270e2ed905SWael Yehia unsigned long EntryAddr = (unsigned long)__builtin_return_address(0); 280e2ed905SWael Yehia 290e2ed905SWael Yehia // Use loadquery to get information about loaded modules; loadquery writes 300e2ed905SWael Yehia // its result into a buffer of unknown size. 310e2ed905SWael Yehia char Buf[1024]; 320e2ed905SWael Yehia size_t BufSize = sizeof(Buf); 330e2ed905SWael Yehia char *BufPtr = Buf; 340e2ed905SWael Yehia int RC = -1; 350e2ed905SWael Yehia 360e2ed905SWael Yehia errno = 0; 370e2ed905SWael Yehia RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize); 380e2ed905SWael Yehia if (RC == -1 && errno == ENOMEM) { 390e2ed905SWael Yehia BufSize = 64000; // should be plenty for any program. 400e2ed905SWael Yehia BufPtr = malloc(BufSize); 4109ab1f33SWael Yehia if (BufPtr != 0) 420e2ed905SWael Yehia RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize); 430e2ed905SWael Yehia } 440e2ed905SWael Yehia 450e2ed905SWael Yehia if (RC == -1) 4609ab1f33SWael Yehia goto done; 470e2ed905SWael Yehia 480e2ed905SWael Yehia // Locate the ld_xinfo corresponding to this module. 490e2ed905SWael Yehia struct ld_xinfo *CurInfo = (struct ld_xinfo *)BufPtr; 500e2ed905SWael Yehia while (1) { 510e2ed905SWael Yehia unsigned long CurTextStart = (uint64_t)CurInfo->ldinfo_textorg; 520e2ed905SWael Yehia unsigned long CurTextEnd = CurTextStart + CurInfo->ldinfo_textsize; 530e2ed905SWael Yehia if (CurTextStart <= EntryAddr && EntryAddr < CurTextEnd) { 540e2ed905SWael Yehia // Found my slot. Now search for the build-id. 550e2ed905SWael Yehia char *p = (char *)CurInfo->ldinfo_textorg; 560e2ed905SWael Yehia 570e2ed905SWael Yehia FILHDR *f = (FILHDR *)p; 580e2ed905SWael Yehia AOUTHDR *a = (AOUTHDR *)(p + FILHSZ); 590e2ed905SWael Yehia SCNHDR *s = 600e2ed905SWael Yehia (SCNHDR *)(p + FILHSZ + f->f_opthdr + SCNHSZ * (a->o_snloader - 1)); 610e2ed905SWael Yehia LDHDR *ldhdr = (LDHDR *)(p + s->s_scnptr); 620e2ed905SWael Yehia // This is the loader string table 630e2ed905SWael Yehia char *lstr = (char *)ldhdr + ldhdr->l_stoff; 640e2ed905SWael Yehia 650e2ed905SWael Yehia // If the build-id exists, it's the first entry. 660e2ed905SWael Yehia // Each entry is comprised of a 2-byte size component, followed by the 670e2ed905SWael Yehia // data. 680e2ed905SWael Yehia size_t len = *(short *)lstr; 690e2ed905SWael Yehia char *str = (char *)(lstr + 2); 700e2ed905SWael Yehia size_t PrefixLen = sizeof(BIN_ID_PREFIX) - 1; 710e2ed905SWael Yehia if (len > PrefixLen && (len - PrefixLen) <= Size && 720e2ed905SWael Yehia strncmp(str, BIN_ID_PREFIX, PrefixLen) == 0) { 730e2ed905SWael Yehia memcpy(Result, str + PrefixLen, len - PrefixLen); 740e2ed905SWael Yehia RC = len - PrefixLen; 750e2ed905SWael Yehia goto done; 760e2ed905SWael Yehia } 770e2ed905SWael Yehia break; 780e2ed905SWael Yehia } 790e2ed905SWael Yehia if (CurInfo->ldinfo_next == 0u) 800e2ed905SWael Yehia break; 810e2ed905SWael Yehia CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next); 820e2ed905SWael Yehia } 830e2ed905SWael Yehia done: 840e2ed905SWael Yehia if (BufSize != sizeof(Buf) && BufPtr != 0) 850e2ed905SWael Yehia free(BufPtr); 860e2ed905SWael Yehia return RC; 870e2ed905SWael Yehia } 880e2ed905SWael Yehia 890e2ed905SWael Yehia static int StrToHexError = 0; 900e2ed905SWael Yehia static uint8_t StrToHex(char c) { 910e2ed905SWael Yehia if (c >= '0' && c <= '9') 920e2ed905SWael Yehia return c - '0'; 930e2ed905SWael Yehia if (c >= 'a' && c <= 'f') 940e2ed905SWael Yehia return c - 'a' + 0xa; 950e2ed905SWael Yehia if (c >= 'A' && c <= 'F') 960e2ed905SWael Yehia return c - 'A' + 0xa; 970e2ed905SWael Yehia StrToHexError = 1; 980e2ed905SWael Yehia return 0; 990e2ed905SWael Yehia } 1000e2ed905SWael Yehia 1010e2ed905SWael Yehia COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) { 1020e2ed905SWael Yehia // 200 bytes should be enough for the build-id hex string. 1030e2ed905SWael Yehia static char Buf[200]; 1040e2ed905SWael Yehia // Profile reading tools expect this to be 8-bytes long. 1050e2ed905SWael Yehia static int64_t BinaryIdLen = 0; 1060e2ed905SWael Yehia static uint8_t *BinaryIdData = 0; 1070e2ed905SWael Yehia 1080e2ed905SWael Yehia // -1 means we already checked for a BinaryId and didn't find one. 1090e2ed905SWael Yehia if (BinaryIdLen == -1) 1100e2ed905SWael Yehia return 0; 1110e2ed905SWael Yehia 1120e2ed905SWael Yehia // Are we being called for the first time? 1130e2ed905SWael Yehia if (BinaryIdLen == 0) { 1140e2ed905SWael Yehia if (getenv("LLVM_PROFILE_NO_BUILD_ID")) 1150e2ed905SWael Yehia goto fail; 1160e2ed905SWael Yehia 1170e2ed905SWael Yehia int BuildIdLen = FindBinaryId(Buf, sizeof(Buf)); 1180e2ed905SWael Yehia if (BuildIdLen <= 0) 1190e2ed905SWael Yehia goto fail; 1200e2ed905SWael Yehia 1210e2ed905SWael Yehia if (Buf[BuildIdLen - 1] == '\0') 1220e2ed905SWael Yehia BuildIdLen--; 1230e2ed905SWael Yehia 1240e2ed905SWael Yehia // assume even number of digits/chars, so 0xabc must be 0x0abc 1250e2ed905SWael Yehia if ((BuildIdLen % 2) != 0 || BuildIdLen == 0) 1260e2ed905SWael Yehia goto fail; 1270e2ed905SWael Yehia 1280e2ed905SWael Yehia // The numeric ID is represented as an ascii string in the loader section, 1290e2ed905SWael Yehia // so convert it to raw binary. 1300e2ed905SWael Yehia BinaryIdLen = BuildIdLen / 2; 1310e2ed905SWael Yehia BinaryIdData = (uint8_t *)Buf; 1320e2ed905SWael Yehia 1330e2ed905SWael Yehia // Skip "0x" prefix if it exists. 1340e2ed905SWael Yehia if (Buf[0] == '0' && Buf[1] == 'x') { 1350e2ed905SWael Yehia BinaryIdLen -= 1; 1360e2ed905SWael Yehia BinaryIdData += 2; 1370e2ed905SWael Yehia } 1380e2ed905SWael Yehia 1390e2ed905SWael Yehia StrToHexError = 0; 1400e2ed905SWael Yehia for (int i = 0; i < BinaryIdLen; i++) 1410e2ed905SWael Yehia BinaryIdData[i] = (StrToHex(BinaryIdData[2 * i]) << 4) + 1420e2ed905SWael Yehia StrToHex(BinaryIdData[2 * i + 1]); 1430e2ed905SWael Yehia 1440e2ed905SWael Yehia if (StrToHexError) 1450e2ed905SWael Yehia goto fail; 1460e2ed905SWael Yehia 1470e2ed905SWael Yehia if (getenv("LLVM_PROFILE_VERBOSE")) { 1480e2ed905SWael Yehia char *StrBuf = (char *)COMPILER_RT_ALLOCA(2 * BinaryIdLen + 1); 1490e2ed905SWael Yehia for (int i = 0; i < (int)BinaryIdLen; i++) 1500e2ed905SWael Yehia sprintf(&StrBuf[2 * i], "%02x", BinaryIdData[i]); 1510e2ed905SWael Yehia PROF_NOTE("Writing binary id: %s\n", StrBuf); 1520e2ed905SWael Yehia } 1530e2ed905SWael Yehia } 1540e2ed905SWael Yehia 1550e2ed905SWael Yehia uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen); 1560e2ed905SWael Yehia if (Writer && lprofWriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData, 1570e2ed905SWael Yehia BinaryIdPadding) == -1) 1580e2ed905SWael Yehia return -1; // Return -1 rather goto fail to match the NT_GNU_BUILD_ID path. 1590e2ed905SWael Yehia 1600e2ed905SWael Yehia return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding; 1610e2ed905SWael Yehia 1620e2ed905SWael Yehia fail: 1630e2ed905SWael Yehia if (getenv("LLVM_PROFILE_VERBOSE")) 1640e2ed905SWael Yehia fprintf(stderr, "no or invalid binary id: %.*s\n", (int)sizeof(Buf), Buf); 1650e2ed905SWael Yehia BinaryIdLen = -1; 1660e2ed905SWael Yehia return 0; 1670e2ed905SWael Yehia } 168787fbad5SWael Yehia 169787fbad5SWael Yehia // Empty stubs to allow linking object files using the registration-based scheme 170787fbad5SWael Yehia COMPILER_RT_VISIBILITY 171787fbad5SWael Yehia void __llvm_profile_register_function(void *Data_) {} 172787fbad5SWael Yehia 173787fbad5SWael Yehia COMPILER_RT_VISIBILITY 174787fbad5SWael Yehia void __llvm_profile_register_names_function(void *NamesStart, 175787fbad5SWael Yehia uint64_t NamesSize) {} 176787fbad5SWael Yehia 177787fbad5SWael Yehia // The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in 17816e74fd4SMingming Liu // {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds", 17916e74fd4SMingming Liu // "__llvm_prf_vns", "__llvm_prf_vtab"}) 180787fbad5SWael Yehia // are always live when linking on AIX, regardless if the .o's being linked 181787fbad5SWael Yehia // reference symbols from the profile library (for example when no files were 182787fbad5SWael Yehia // compiled with -fprofile-generate). That's because these symbols are kept 183787fbad5SWael Yehia // alive through references in constructor functions that are always live in the 184787fbad5SWael Yehia // default linking model on AIX (-bcdtors:all). The __start_SECNAME and 185787fbad5SWael Yehia // __stop_SECNAME symbols are only resolved by the linker when the SECNAME 186787fbad5SWael Yehia // section exists. So for the scenario where the user objects have no such 187787fbad5SWael Yehia // section (i.e. when they are compiled with -fno-profile-generate), we always 188787fbad5SWael Yehia // define these zero length variables in each of the above 4 sections. 189787fbad5SWael Yehia static int dummy_cnts[0] COMPILER_RT_SECTION( 190787fbad5SWael Yehia COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME); 191f95b2f1aSAlan Phipps static int dummy_bits[0] COMPILER_RT_SECTION( 192f95b2f1aSAlan Phipps COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME); 193787fbad5SWael Yehia static int dummy_data[0] COMPILER_RT_SECTION( 194787fbad5SWael Yehia COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME); 195787fbad5SWael Yehia static const int dummy_name[0] COMPILER_RT_SECTION( 196787fbad5SWael Yehia COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME); 197787fbad5SWael Yehia static int dummy_vnds[0] COMPILER_RT_SECTION( 198787fbad5SWael Yehia COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME); 19915cccc55SWael Yehia static int dummy_orderfile[0] COMPILER_RT_SECTION( 20015cccc55SWael Yehia COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME); 20116e74fd4SMingming Liu static int dummy_vname[0] COMPILER_RT_SECTION( 20216e74fd4SMingming Liu COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME); 20316e74fd4SMingming Liu static int dummy_vtab[0] COMPILER_RT_SECTION( 20416e74fd4SMingming Liu COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME); 205*f9d07890SQiongsi Wu static int dummy_covinit_funcs[0] COMPILER_RT_SECTION( 206*f9d07890SQiongsi Wu COMPILER_RT_SEG INSTR_PROF_COVINIT_SECT_NAME); 207787fbad5SWael Yehia 208787fbad5SWael Yehia // To avoid GC'ing of the dummy variables by the linker, reference them in an 209787fbad5SWael Yehia // array and reference the array in the runtime registration code 210787fbad5SWael Yehia // (InstrProfilingRuntime.cpp) 2110680ca7fSJake Egan #ifdef __GNUC__ 2120680ca7fSJake Egan #pragma GCC diagnostic push 2130680ca7fSJake Egan #pragma GCC diagnostic ignored "-Wcast-qual" 2140680ca7fSJake Egan #endif 215787fbad5SWael Yehia COMPILER_RT_VISIBILITY 216f95b2f1aSAlan Phipps void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits, 217f95b2f1aSAlan Phipps (void *)&dummy_data, (void *)&dummy_name, 21816e74fd4SMingming Liu (void *)&dummy_vnds, (void *)&dummy_orderfile, 219*f9d07890SQiongsi Wu (void *)&dummy_vname, (void *)&dummy_vtab, 220*f9d07890SQiongsi Wu (void *)&dummy_covinit_funcs}; 2210680ca7fSJake Egan #ifdef __GNUC__ 2220680ca7fSJake Egan #pragma GCC diagnostic pop 2230680ca7fSJake Egan #endif 224787fbad5SWael Yehia #endif 225