Repository navigation
feat(hrr): strip build info from stored code objects, blank GPU identifiers #13701
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
andraghetti
merged 11 commits into
develop
from
users/andraghetti/hrr-strip-code-object-build-info
Oct 20, 2026
+1,084
−47
Merged
Changes from all commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
582005f
feat(hrr): strip build info from stored code objects, blank GPU ident…
andraghetti 6cb83d8
fix(hrr): verify allocated build-info sections and only registered fa…
andraghetti c1e2bff
fix(hrr): retype scrubbed code object sections SHT_NOBITS; bound the …
andraghetti b90e2f0
fix(hrr): skip unterminated section names; pick the fat binary id by …
andraghetti 33c8ea6
docs(hrr): finish the README sentence on symbol names
andraghetti b4d82a8
Merge branch 'develop' into users/andraghetti/hrr-strip-code-object-b…
andraghetti 4ef0b5a
fix(hrr): blank the GPU's UUID, LUID and PCI ids in hipChooseDevice r…
andraghetti 336c4dd
fix(hrr): report absolute paths left in loaded code; say what capture…
andraghetti f1d3fa2
Merge branch 'develop' into users/andraghetti/hrr-strip-code-object-b…
andraghetti 2aea59d
Merge commit '5b4535b7ba' into HEAD
andraghetti da99aff
fix(hrr): verify reads format v10 and paths with spaces or a drive le…
andraghetti File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| /* | ||
| * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| */ | ||
|
|
||
| #include "hip_capture_scrub.h" | ||
|
|
||
| #include <cstring> | ||
|
|
||
| // Field offsets are spelled out rather than taken from <elf.h>, which Windows | ||
| // does not have and whose Elf64_* typedefs collide with CLR's own ELF headers. | ||
| // The image is the application's memory, so every read is bounds-checked and | ||
| // copied out with memcpy, whatever its alignment. | ||
|
|
||
| namespace hrr_cap { | ||
| namespace scrub { | ||
|
|
||
| namespace { | ||
|
|
||
| constexpr size_t kElfHeaderSize = 64; | ||
| constexpr size_t kSectionHeaderSize = 64; | ||
| constexpr uint8_t kElfClass64 = 2; | ||
| constexpr uint8_t kElfDataLsb = 1; | ||
| constexpr uint32_t kShtNobits = 8; | ||
| constexpr uint64_t kShfAlloc = 0x2; | ||
|
|
||
| constexpr char kBundleMagic[] = "__CLANG_OFFLOAD_BUNDLE__"; | ||
| constexpr size_t kBundleMagicLen = sizeof(kBundleMagic) - 1; | ||
| constexpr size_t kBundleEntryHeaderSize = 3 * sizeof(uint64_t); | ||
|
|
||
| template <typename T> | ||
| T read(const uint8_t* p, size_t at) { | ||
| T v; | ||
| std::memcpy(&v, p + at, sizeof(v)); | ||
| return v; | ||
| } | ||
|
|
||
| // [offset, offset + size) lies inside [0, limit). | ||
| bool in_range(uint64_t offset, uint64_t size, size_t limit) { | ||
| return offset <= limit && size <= limit - offset; | ||
| } | ||
|
|
||
| bool has_prefix(const char* s, size_t len, const char* prefix) { | ||
| const size_t n = std::strlen(prefix); | ||
| return len >= n && std::memcmp(s, prefix, n) == 0; | ||
| } | ||
|
|
||
| bool is_scrubbed_section(const char* name, size_t len) { | ||
| return (len == 8 && std::memcmp(name, ".comment", 8) == 0) || has_prefix(name, len, ".debug"); | ||
| } | ||
|
|
||
| size_t scrub_elf(uint8_t* image, size_t size) { | ||
| if (size < kElfHeaderSize || std::memcmp(image, "\x7f" "ELF", 4) != 0 || | ||
| image[4] != kElfClass64 || image[5] != kElfDataLsb) | ||
| return 0; | ||
| const uint64_t shoff = read<uint64_t>(image, 0x28); | ||
| const uint16_t shentsize = read<uint16_t>(image, 0x3a); | ||
| const uint16_t shnum = read<uint16_t>(image, 0x3c); | ||
| const uint16_t shstrndx = read<uint16_t>(image, 0x3e); | ||
| // shnum == 0 also covers extended section numbering, which code objects never need. | ||
| if (shentsize != kSectionHeaderSize || shnum == 0 || shstrndx >= shnum || | ||
| !in_range(shoff, uint64_t{shnum} * kSectionHeaderSize, size)) | ||
| return 0; | ||
|
|
||
| const uint8_t* shstr_hdr = image + shoff + size_t{shstrndx} * kSectionHeaderSize; | ||
| const uint64_t names_off = read<uint64_t>(shstr_hdr, 24); | ||
| const uint64_t names_size = read<uint64_t>(shstr_hdr, 32); | ||
| if (!in_range(names_off, names_size, size)) return 0; | ||
| const char* names = reinterpret_cast<const char*>(image + names_off); | ||
|
|
||
| size_t zeroed = 0; | ||
| for (uint16_t i = 0; i < shnum; ++i) { | ||
| uint8_t* sh = image + shoff + size_t{i} * kSectionHeaderSize; | ||
| const uint32_t name = read<uint32_t>(sh, 0); | ||
| const uint32_t type = read<uint32_t>(sh, 4); | ||
| const uint64_t flags = read<uint64_t>(sh, 8); | ||
| const uint64_t offset = read<uint64_t>(sh, 24); | ||
| const uint64_t sec_size = read<uint64_t>(sh, 32); | ||
| if (name >= names_size || type == kShtNobits || (flags & kShfAlloc) != 0) continue; | ||
| const size_t name_len = strnlen(names + name, names_size - name); | ||
| if (name_len == names_size - name) continue; // no terminator inside the table | ||
| if (!is_scrubbed_section(names + name, name_len)) continue; | ||
| if (sec_size == 0 || !in_range(offset, sec_size, size)) continue; | ||
| std::memset(image + offset, 0, sec_size); | ||
| // SHT_NOBITS makes DWARF readers see the section as absent rather than as | ||
| // malformed zeros. It is not SHF_ALLOC, so the loader maps nothing from it. | ||
| std::memcpy(sh + 4, &kShtNobits, sizeof(kShtNobits)); | ||
| ++zeroed; | ||
| } | ||
| return zeroed; | ||
| } | ||
|
|
||
| size_t scrub_bundle(uint8_t* image, size_t size) { | ||
| size_t pos = kBundleMagicLen; | ||
| if (size < pos + sizeof(uint64_t)) return 0; | ||
| const uint64_t count = read<uint64_t>(image, pos); | ||
| pos += sizeof(uint64_t); | ||
| size_t zeroed = 0; | ||
| for (uint64_t i = 0; i < count; ++i) { | ||
| if (size - pos < kBundleEntryHeaderSize) break; | ||
| const uint64_t offset = read<uint64_t>(image, pos); | ||
| const uint64_t entry_size = read<uint64_t>(image, pos + 8); | ||
| const uint64_t id_size = read<uint64_t>(image, pos + 16); | ||
| pos += kBundleEntryHeaderSize; | ||
| if (id_size > size - pos) break; | ||
| pos += id_size; | ||
| if (in_range(offset, entry_size, size)) zeroed += scrub_elf(image + offset, entry_size); | ||
| } | ||
| return zeroed; | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| size_t scrub_code_object(uint8_t* image, size_t size) { | ||
| if (!image) return 0; | ||
| if (size >= kBundleMagicLen && std::memcmp(image, kBundleMagic, kBundleMagicLen) == 0) | ||
| return scrub_bundle(image, size); | ||
| return scrub_elf(image, size); | ||
| } | ||
|
|
||
| } // namespace scrub | ||
| } // namespace hrr_cap | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (c) Advanced Micro Devices, Inc., or its affiliates. | ||
| * | ||
| * SPDX-License-Identifier: MIT | ||
| */ | ||
| #pragma once | ||
|
|
||
| #include <cstddef> | ||
| #include <cstdint> | ||
|
|
||
| namespace hrr_cap { | ||
| namespace scrub { | ||
|
|
||
| // Zeroes, in place, the contents of the .comment and .debug* sections of a code | ||
| // object about to be stored: an ELF64 image, or every entry of an uncompressed | ||
| // clang offload bundle. Those sections carry the compiler build, absolute build | ||
| // paths and source file names; the GPU never loads them, so replay is unchanged. | ||
| // A string the GPU does load, such as the file name in a device assert(), stays. | ||
| // Each zeroed section is retyped SHT_NOBITS, so debuggers and profilers see it as | ||
| // absent. Sizes and offsets stay as they are, so a bundle's entry table stays valid. | ||
| // A compressed bundle, or anything that does not parse, is left as it is. | ||
| // Returns how many sections were zeroed. | ||
| size_t scrub_code_object(uint8_t* image, size_t size); | ||
|
|
||
| } // namespace scrub | ||
| } // namespace hrr_cap |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.