Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/profile/InstrProfilingPlatformAIX.c
35233 views
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
9
#if defined(_AIX)
10
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>
19
20
#include "InstrProfiling.h"
21
#include "InstrProfilingInternal.h"
22
23
#define BIN_ID_PREFIX "xcoff_binary_id:"
24
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);
28
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;
35
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);
43
}
44
45
if (RC == -1)
46
goto done;
47
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;
56
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;
64
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;
76
}
77
break;
78
}
79
if (CurInfo->ldinfo_next == 0u)
80
break;
81
CurInfo = (struct ld_xinfo *)((char *)CurInfo + CurInfo->ldinfo_next);
82
}
83
done:
84
if (BufSize != sizeof(Buf) && BufPtr != 0)
85
free(BufPtr);
86
return RC;
87
}
88
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;
99
}
100
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;
107
108
// -1 means we already checked for a BinaryId and didn't find one.
109
if (BinaryIdLen == -1)
110
return 0;
111
112
// Are we being called for the first time?
113
if (BinaryIdLen == 0) {
114
if (getenv("LLVM_PROFILE_NO_BUILD_ID"))
115
goto fail;
116
117
int BuildIdLen = FindBinaryId(Buf, sizeof(Buf));
118
if (BuildIdLen <= 0)
119
goto fail;
120
121
if (Buf[BuildIdLen - 1] == '\0')
122
BuildIdLen--;
123
124
// assume even number of digits/chars, so 0xabc must be 0x0abc
125
if ((BuildIdLen % 2) != 0 || BuildIdLen == 0)
126
goto fail;
127
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;
132
133
// Skip "0x" prefix if it exists.
134
if (Buf[0] == '0' && Buf[1] == 'x') {
135
BinaryIdLen -= 1;
136
BinaryIdData += 2;
137
}
138
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]);
143
144
if (StrToHexError)
145
goto fail;
146
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);
152
}
153
}
154
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.
159
160
return sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;
161
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;
167
}
168
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_) {}
172
173
COMPILER_RT_VISIBILITY
174
void __llvm_profile_register_names_function(void *NamesStart,
175
uint64_t NamesSize) {}
176
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
// "__llvm_prf_vns", "__llvm_prf_vtab"})
180
// are always live when linking on AIX, regardless if the .o's being linked
181
// reference symbols from the profile library (for example when no files were
182
// compiled with -fprofile-generate). That's because these symbols are kept
183
// alive through references in constructor functions that are always live in the
184
// default linking model on AIX (-bcdtors:all). The __start_SECNAME and
185
// __stop_SECNAME symbols are only resolved by the linker when the SECNAME
186
// section exists. So for the scenario where the user objects have no such
187
// section (i.e. when they are compiled with -fno-profile-generate), we always
188
// define these zero length variables in each of the above 4 sections.
189
static int dummy_cnts[0] COMPILER_RT_SECTION(
190
COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
191
static int dummy_bits[0] COMPILER_RT_SECTION(
192
COMPILER_RT_SEG INSTR_PROF_BITS_SECT_NAME);
193
static int dummy_data[0] COMPILER_RT_SECTION(
194
COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
195
static const int dummy_name[0] COMPILER_RT_SECTION(
196
COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
197
static int dummy_vnds[0] COMPILER_RT_SECTION(
198
COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
199
static int dummy_orderfile[0] COMPILER_RT_SECTION(
200
COMPILER_RT_SEG INSTR_PROF_ORDERFILE_SECT_NAME);
201
static int dummy_vname[0] COMPILER_RT_SECTION(
202
COMPILER_RT_SEG INSTR_PROF_VNAME_SECT_NAME);
203
static int dummy_vtab[0] COMPILER_RT_SECTION(
204
COMPILER_RT_SEG INSTR_PROF_VTAB_SECT_NAME);
205
206
// To avoid GC'ing of the dummy variables by the linker, reference them in an
207
// array and reference the array in the runtime registration code
208
// (InstrProfilingRuntime.cpp)
209
#ifdef __GNUC__
210
#pragma GCC diagnostic push
211
#pragma GCC diagnostic ignored "-Wcast-qual"
212
#endif
213
COMPILER_RT_VISIBILITY
214
void *__llvm_profile_keep[] = {(void *)&dummy_cnts, (void *)&dummy_bits,
215
(void *)&dummy_data, (void *)&dummy_name,
216
(void *)&dummy_vnds, (void *)&dummy_orderfile,
217
(void *)&dummy_vname, (void *)&dummy_vtab};
218
#ifdef __GNUC__
219
#pragma GCC diagnostic pop
220
#endif
221
#endif
222
223