*/
int __llvm_write_binary_ids(ProfDataWriter *Writer);
+/*
+ * Write binary id length and then its data, because binary id does not
+ * have a fixed length.
+ */
+int lprofWriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen,
+ const uint8_t *BinaryIdData,
+ uint64_t BinaryIdPadding);
+
#endif
#if defined(_AIX)
+#ifdef __64BIT__
+#define __XCOFF64__
+#endif
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ldr.h>
+#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);
+ RC = loadquery(L_GETXINFO | L_IGNOREUNLOAD, BufPtr, (unsigned int)BufSize);
+ }
+
+ if (RC == -1)
+ return RC;
+
+ // 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
}
/*
- * Write binary id length and then its data, because binary id does not
- * have a fixed length.
- */
-static int WriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen,
- const uint8_t *BinaryIdData,
- uint64_t BinaryIdPadding) {
- ProfDataIOVec BinaryIdIOVec[] = {
- {&BinaryIdLen, sizeof(uint64_t), 1, 0},
- {BinaryIdData, sizeof(uint8_t), BinaryIdLen, 0},
- {NULL, sizeof(uint8_t), BinaryIdPadding, 1},
- };
- if (Writer->Write(Writer, BinaryIdIOVec,
- sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec)))
- return -1;
-
- /* Successfully wrote binary id, report success. */
- return 0;
-}
-
-/*
* Look for the note that has the name "GNU\0" and type NT_GNU_BUILD_ID
* that contains build id. If build id exists, write binary id.
*
const uint8_t *BinaryIdData =
(const uint8_t *)(NoteName + RoundUp(Note->n_namesz, 4));
uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen);
- if (Writer != NULL && WriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,
- BinaryIdPadding) == -1)
+ if (Writer != NULL &&
+ lprofWriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,
+ BinaryIdPadding) == -1)
return -1;
BinaryIdSize = sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;
return TotalBinaryIdsSize;
}
-#else /* !NT_GNU_BUILD_ID */
+#elif !defined(_AIX) /* !NT_GNU_BUILD_ID */
/*
* Fallback implementation for targets that don't support the GNU
* extensions NT_GNU_BUILD_ID and __ehdr_start.
return writeValueProfData(Writer, VPDataReader, DataBegin, DataEnd);
}
+
+/*
+ * Write binary id length and then its data, because binary id does not
+ * have a fixed length.
+ */
+COMPILER_RT_VISIBILITY
+int lprofWriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen,
+ const uint8_t *BinaryIdData,
+ uint64_t BinaryIdPadding) {
+ ProfDataIOVec BinaryIdIOVec[] = {
+ {&BinaryIdLen, sizeof(uint64_t), 1, 0},
+ {BinaryIdData, sizeof(uint8_t), BinaryIdLen, 0},
+ {NULL, sizeof(uint8_t), BinaryIdPadding, 1},
+ };
+ if (Writer->Write(Writer, BinaryIdIOVec,
+ sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec)))
+ return -1;
+
+ /* Successfully wrote binary id, report success. */
+ return 0;
+}
--- /dev/null
+// RUN: split-file %s %t
+// RUN: cd %t
+// RUN: %clang_pgogen -c shr1.c -o shr1.o -Xclang -fprofile-instrument-path=default_1.profraw
+// RUN: %clang_pgogen -shared shr1.o -o shr1.so -mxcoff-build-id=0x01
+//
+// RUN: %clangxx_pgogen -c shr2.cpp -o shr2.o -Xclang -fprofile-instrument-path=default_2.profraw
+// RUN: %clangxx_pgogen -shared shr2.o -o shr2.so -mxcoff-build-id=0x02
+//
+// RUN: %clang_pgogen -c main.c -o main.o -Xclang -fprofile-instrument-path=default_main.profraw
+// RUN: %clang_pgogen main.o -L%t shr1.so shr2.so -o a.out -mxcoff-build-id=0xFFFFFFFFFFFFFFFF
+//
+// RUN: %run ./a.out
+//
+// RUN: llvm-profdata show --binary-ids default_1.profraw | FileCheck %s --check-prefix=SHARED1
+// RUN: llvm-profdata show --binary-ids default_2.profraw | FileCheck %s --check-prefix=SHARED2
+// RUN: llvm-profdata show --binary-ids default_main.profraw | FileCheck %s --check-prefix=MAIN
+
+// SHARED1: Binary IDs:
+// SHARED1-NEXT: {{^}}01{{$}}
+// SHARED2: Binary IDs:
+// SHARED2-NEXT: {{^}}02{{$}}
+// MAIN: Binary IDs:
+// MAIN-NEXT: {{^}}ffffffffffffffff{{$}}
+
+//--- shr1.c
+int shr1() { return 1; }
+
+//--- shr2.cpp
+int helper() { return 3; }
+extern "C" int shr2() { return helper(); }
+
+//--- main.c
+int shr1();
+int shr2();
+int main() { return 4 - shr1() - shr2(); }
--- /dev/null
+// RUN: %clang_pgogen -c -o %t.o %s
+//
+// Test valid IDs:
+// (20-byte, ends with 2 zeroes, upper case)
+// RUN: %clang_pgogen -mxcoff-build-id=0x8d7AEC8b900dce6c14afe557dc8889230518be00 -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=LONG
+
+// (all zeroes)
+// RUN: %clang_pgogen -mxcoff-build-id=0x00 -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=00
+
+// (starts with one zero)
+// RUN: %clang_pgogen -mxcoff-build-id=0x0120 -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=0120
+
+// (starts with 8 zeroes == 4 bytes)
+// RUN: %clang_pgogen -mxcoff-build-id=0x0000000012 -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=0000000012
+
+// (starts with 16 zeroes == 8 bytes)
+// RUN: %clang_pgogen -mxcoff-build-id=0x0000000000000000ff -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=0000000000000000ff
+
+// (starts with 17 zeroes)
+// RUN: %clang_pgogen -mxcoff-build-id=0x00000000000000000f -o %t %t.o
+// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
+// RUN: llvm-profdata show --binary-ids %t.profraw | FileCheck %s --check-prefix=00000000000000000f
+
+// LONG: Binary IDs:
+// LONG-NEXT: 8d7aec8b900dce6c14afe557dc8889230518be00
+// 00: Binary IDs:
+// 00-NEXT: {{^}}00{{$}}
+// 0120: Binary IDs:
+// 0120-NEXT: {{^}}0120{{$}}
+// 0000000012: Binary IDs:
+// 0000000012-NEXT: {{^}}0000000012{{$}}
+// 0000000000000000ff: Binary IDs:
+// 0000000000000000ff-NEXT: {{^}}0000000000000000ff{{$}}
+// 00000000000000000f: Binary IDs:
+// 00000000000000000f-NEXT: {{^}}00000000000000000f{{$}}
+
+int main() { return 0; }