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