InstrProfilingPlatformAIX.c 7.4 KB

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