[clang][dataflow][NFC] Fix stale comments. (#71654)
[llvm-project.git] / compiler-rt / lib / profile / InstrProfilingPlatformAIX.c
blob9f46a98d78ac4ea071531a787b3788d99a4c795a
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 \*===----------------------------------------------------------------------===*/
9 #if defined(_AIX)
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>
20 #include "InstrProfiling.h"
21 #include "InstrProfilingInternal.h"
23 #define BIN_ID_PREFIX "xcoff_binary_id:"
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);
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;
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);
45 if (RC == -1)
46 goto done;
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;
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;
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;
77 break;
79 if (CurInfo->ldinfo_next == 0u)
80 break;
81 CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next);
83 done:
84 if (BufSize != sizeof(Buf) && BufPtr != 0)
85 free(BufPtr);
86 return RC;
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;
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;
108 // -1 means we already checked for a BinaryId and didn't find one.
109 if (BinaryIdLen == -1)
110 return 0;
112 // Are we being called for the first time?
113 if (BinaryIdLen == 0) {
114 if (getenv("LLVM_PROFILE_NO_BUILD_ID"))
115 goto fail;
117 int BuildIdLen = FindBinaryId(Buf, sizeof(Buf));
118 if (BuildIdLen <= 0)
119 goto fail;
121 if (Buf[BuildIdLen - 1] == '\0')
122 BuildIdLen--;
124 // assume even number of digits/chars, so 0xabc must be 0x0abc
125 if ((BuildIdLen % 2) != 0 || BuildIdLen == 0)
126 goto fail;
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;
133 // Skip "0x" prefix if it exists.
134 if (Buf[0] == '0' && Buf[1] == 'x') {
135 BinaryIdLen -= 1;
136 BinaryIdData += 2;
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]);
144 if (StrToHexError)
145 goto fail;
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);
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.
160 return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;
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;
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_) {}
173 COMPILER_RT_VISIBILITY
174 void __llvm_profile_register_names_function(void *NamesStart,
175 uint64_t NamesSize) {}
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_bits[0] COMPILER_RT_SECTION(
191 COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);
192 static int dummy_data[0] COMPILER_RT_SECTION(
193 COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
194 static const int dummy_name[0] COMPILER_RT_SECTION(
195 COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
196 static int dummy_vnds[0] COMPILER_RT_SECTION(
197 COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
199 // To avoid GC'ing of the dummy variables by the linker, reference them in an
200 // array and reference the array in the runtime registration code
201 // (InstrProfilingRuntime.cpp)
202 #ifdef __GNUC__
203 #pragma GCC diagnostic push
204 #pragma GCC diagnostic ignored "-Wcast-qual"
205 #endif
206 COMPILER_RT_VISIBILITY
207 void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
208 (void *)&dummy_data, (void *)&dummy_name,
209 (void *)&dummy_vnds};
210 #ifdef __GNUC__
211 #pragma GCC diagnostic pop
212 #endif
213 #endif