xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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