1 /*===- InstrProfilingPlatformAIX.c - Profile data AIX platform ------------===*\
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
7 \*===----------------------------------------------------------------------===*/
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.
32 size_t BufSize
= sizeof(Buf
);
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
);
42 RC
= loadquery(L_GETXINFO
| L_IGNOREUNLOAD
, BufPtr
, (unsigned int)BufSize
);
48 // Locate the ld_xinfo corresponding to this module.
49 struct ld_xinfo
*CurInfo
= (struct ld_xinfo
*)BufPtr
;
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
);
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
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
);
79 if (CurInfo
->ldinfo_next
== 0u)
81 CurInfo
= (struct ld_xinfo
*)((char *)CurInfo
+ CurInfo
->ldinfo_next
);
84 if (BufSize
!= sizeof(Buf
) && BufPtr
!= 0)
89 static int StrToHexError
= 0;
90 static uint8_t StrToHex(char c
) {
91 if (c
>= '0' && c
<= '9')
93 if (c
>= 'a' && c
<= 'f')
95 if (c
>= 'A' && c
<= 'F')
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)
112 // Are we being called for the first time?
113 if (BinaryIdLen
== 0) {
114 if (getenv("LLVM_PROFILE_NO_BUILD_ID"))
117 int BuildIdLen
= FindBinaryId(Buf
, sizeof(Buf
));
121 if (Buf
[BuildIdLen
- 1] == '\0')
124 // assume even number of digits/chars, so 0xabc must be 0x0abc
125 if ((BuildIdLen
% 2) != 0 || BuildIdLen
== 0)
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') {
140 for (int i
= 0; i
< BinaryIdLen
; i
++)
141 BinaryIdData
[i
] = (StrToHex(BinaryIdData
[2 * i
]) << 4) +
142 StrToHex(BinaryIdData
[2 * i
+ 1]);
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
;
163 if (getenv("LLVM_PROFILE_VERBOSE"))
164 fprintf(stderr
, "no or invalid binary id: %.*s\n", (int)sizeof(Buf
), Buf
);
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)
203 #pragma GCC diagnostic push
204 #pragma GCC diagnostic ignored "-Wcast-qual"
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
};
211 #pragma GCC diagnostic pop