Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
24308b2
[llvm-objcopy][ELF] Add an option to remove notes
igorkudrin Nov 28, 2024
6533806
Merge branch 'main' into llvm-objcopy-remove-note
igorkudrin Dec 14, 2024
3550f3a
fixup: update parsing the argument
igorkudrin Dec 14, 2024
51b05f2
fixup: update tests
igorkudrin Dec 14, 2024
1bad501
fixup: add the option to the command guide
igorkudrin Dec 14, 2024
3b17fdb
fixup: fix updating offsets
igorkudrin Dec 20, 2024
1c84760
fixup: split 'removeNote()'
igorkudrin Dec 20, 2024
f6d4330
fixup: do not allow '--remove-note' with '--(remove|add|update)-section'
igorkudrin Dec 20, 2024
fd72505
fixup: change ELF type of the test file ET_CORE -> ET_EXEC
igorkudrin Dec 21, 2024
e730cfd
fixup: also run the test for ELF32 and BE
igorkudrin Dec 21, 2024
de67454
fixup: handle SHT_NOTE sections outside of segments
igorkudrin Dec 21, 2024
95b6b94
Remove handling for segments
igorkudrin Dec 23, 2024
9baf37a
Remove DeletedRange.NewPos
igorkudrin Jan 16, 2025
1432460
"auto &RemRange" -> "const DeletedRange &RemRange"
igorkudrin Jan 16, 2025
a4c8edb
Remove a blank line at the end of an namespace
igorkudrin Jan 16, 2025
5695096
Print a warning for note segments and note sections in segments
igorkudrin Jan 16, 2025
17a3c77
Extend the test
igorkudrin Jan 17, 2025
08f7f23
Revert "Print a warning for note segments and note sections in segments"
igorkudrin Jan 18, 2025
1ee4850
removeNote() -> removeNotes()
igorkudrin Jan 18, 2025
2860c31
Print a warning for note segments and note sections in segments v2
igorkudrin Jan 18, 2025
b1957e7
std::vector<SecPtr>::iterator -> SecPtr&
igorkudrin Jan 18, 2025
9110b2c
Move tests from 'remove-note-unsupported.test' to 'remove-note.test'
igorkudrin Jan 23, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions llvm/include/llvm/ObjCopy/CommonConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,11 @@ struct CommonConfig {

SmallVector<std::pair<NameMatcher, llvm::DebugCompressionType>, 0>
compressSections;

// ErrorCallback is used to handle recoverable errors. An Error returned
// by the callback aborts the execution and is then returned to the caller.
// If the callback is not set, the errors are not issued.
std::function<Error(Error)> ErrorCallback;
};

} // namespace objcopy
Expand Down
42 changes: 29 additions & 13 deletions llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,6 @@ struct RemoveNoteDetail {
struct DeletedRange {
uint64_t OldFrom;
uint64_t OldTo;
uint64_t NewPos;
};

template <class ELFT>
Expand All @@ -624,7 +623,6 @@ struct RemoveNoteDetail {
static std::vector<uint8_t> updateData(ArrayRef<uint8_t> OldData,
ArrayRef<DeletedRange> ToRemove);
};

} // namespace

template <class ELFT>
Expand All @@ -634,7 +632,6 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT);
std::vector<DeletedRange> ToRemove;
uint64_t CurPos = 0;
uint64_t NewPos = 0;
while (CurPos + sizeof(Elf_Nhdr) <= Data.size()) {
auto Nhdr = reinterpret_cast<const Elf_Nhdr *>(Data.data() + CurPos);
size_t FullSize = Nhdr->getSize(Align);
Expand All @@ -647,9 +644,7 @@ RemoveNoteDetail::findNotesToRemove(ArrayRef<uint8_t> Data, size_t Align,
(NoteInfo.Name.empty() || NoteInfo.Name == Note.getName());
});
if (ShouldRemove)
ToRemove.push_back({CurPos, CurPos + FullSize, NewPos});
else
NewPos += FullSize;
ToRemove.push_back({CurPos, CurPos + FullSize});
CurPos += FullSize;
}
return ToRemove;
Expand All @@ -661,12 +656,11 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
std::vector<uint8_t> NewData;
NewData.reserve(OldData.size());
uint64_t CurPos = 0;
for (auto &RemRange : ToRemove) {
for (const DeletedRange &RemRange : ToRemove) {
if (CurPos < RemRange.OldFrom) {
auto Slice = OldData.slice(CurPos, RemRange.OldFrom - CurPos);
NewData.insert(NewData.end(), Slice.begin(), Slice.end());
}
assert(RemRange.NewPos == NewData.size());
CurPos = RemRange.OldTo;
}
if (CurPos < OldData.size()) {
Expand All @@ -676,12 +670,33 @@ RemoveNoteDetail::updateData(ArrayRef<uint8_t> OldData,
return NewData;
}

static Error removeNote(Object &Obj, endianness Endianness,
ArrayRef<RemoveNoteInfo> NotesToRemove) {
static Error removeNotes(Object &Obj, endianness Endianness,
ArrayRef<RemoveNoteInfo> NotesToRemove,
function_ref<Error(Error)> ErrorCallback) {
// TODO: Support note segments.
if (ErrorCallback) {
for (Segment &Seg : Obj.segments()) {
if (Seg.Type == PT_NOTE) {
if (Error E = ErrorCallback(createStringError(
errc::not_supported, "note segments are not supported")))
return E;
break;
}
}
}
for (auto &Sec : Obj.sections()) {
// TODO: Support note sections in segments
if (Sec.Type != SHT_NOTE || Sec.ParentSegment || !Sec.hasContents())
if (Sec.Type != SHT_NOTE || !Sec.hasContents())
continue;
// TODO: Support note sections in segments.
if (Sec.ParentSegment) {
if (ErrorCallback)
if (Error E = ErrorCallback(createStringError(
errc::not_supported,
"cannot remove note(s) from " + Sec.Name +
": sections in segments are not supported")))
return E;
continue;
}
ArrayRef<uint8_t> OldData = Sec.getContents();
size_t Align = std::max<size_t>(4, Sec.Align);
// Note: notes for both 32-bit and 64-bit ELF files use 4-byte words in the
Expand Down Expand Up @@ -891,7 +906,8 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
: endianness::big;

if (!ELFConfig.NotesToRemove.empty()) {
if (Error Err = removeNote(Obj, E, ELFConfig.NotesToRemove))
if (Error Err =
removeNotes(Obj, E, ELFConfig.NotesToRemove, Config.ErrorCallback))
return Err;
}

Expand Down
24 changes: 11 additions & 13 deletions llvm/lib/ObjCopy/ELF/ELFObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2154,27 +2154,25 @@ ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
: Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
OnlyKeepDebug(OnlyKeepDebug) {}

Error Object::updateSectionData(std::vector<SecPtr>::iterator It,
ArrayRef<uint8_t> Data) {
auto *OldSec = It->get();
if (!OldSec->hasContents())
Error Object::updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data) {
if (!Sec->hasContents())
return createStringError(
errc::invalid_argument,
"section '%s' cannot be updated because it does not have contents",
OldSec->Name.c_str());
Sec->Name.c_str());

if (Data.size() > OldSec->Size && OldSec->ParentSegment)
if (Data.size() > Sec->Size && Sec->ParentSegment)
return createStringError(errc::invalid_argument,
"cannot fit data of size %zu into section '%s' "
"with size %" PRIu64 " that is part of a segment",
Data.size(), OldSec->Name.c_str(), OldSec->Size);
Data.size(), Sec->Name.c_str(), Sec->Size);

if (!OldSec->ParentSegment) {
*It = std::make_unique<OwnedDataSection>(*OldSec, Data);
if (!Sec->ParentSegment) {
Sec = std::make_unique<OwnedDataSection>(*Sec, Data);
} else {
// The segment writer will be in charge of updating these contents.
OldSec->Size = Data.size();
UpdatedSections[OldSec] = Data;
Sec->Size = Data.size();
UpdatedSections[Sec.get()] = Data;
}

return Error::success();
Expand All @@ -2186,14 +2184,14 @@ Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) {
if (It == Sections.end())
return createStringError(errc::invalid_argument, "section '%s' not found",
Name.str().c_str());
return updateSectionData(It, Data);
return updateSectionData(*It, Data);
}

Error Object::updateSectionData(SectionBase &S, ArrayRef<uint8_t> Data) {
auto It = llvm::find_if(Sections,
[&](const SecPtr &Sec) { return Sec.get() == &S; });
assert(It != Sections.end() && "The section should belong to the object");
return updateSectionData(It, Data);
return updateSectionData(*It, Data);
}

Error Object::removeSections(
Expand Down
3 changes: 1 addition & 2 deletions llvm/lib/ObjCopy/ELF/ELFObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -1168,8 +1168,7 @@ class Object {
return Sec.Flags & ELF::SHF_ALLOC;
};

Error updateSectionData(std::vector<SecPtr>::iterator SecIt,
ArrayRef<uint8_t> Data);
Error updateSectionData(SecPtr &Sec, ArrayRef<uint8_t> Data);

public:
template <class T>
Expand Down
47 changes: 47 additions & 0 deletions llvm/test/tools/llvm-objcopy/ELF/remove-note-unsupported.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# RUN: yaml2obj --docnum=1 %s -o %t1
# RUN: llvm-objcopy --remove-note=1 %t1 %t1o 2>&1 | FileCheck %s --check-prefix=NOTE_SEGMENT
# NOTE_SEGMENT: warning: note segments are not supported
# NOTE_SEGMENT-NOT: note segments are not supported

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_NOTE
FirstSec: .data0
LastSec: .data0
- Type: PT_NOTE
FirstSec: .data1
LastSec: .data1
Sections:
- Name: .data0
Type: SHT_PROGBITS
AddressAlign: 4
Content: "1122334455"
- Name: .data1
Type: SHT_PROGBITS
AddressAlign: 4
Content: "1122334455"

# RUN: yaml2obj --docnum=2 %s -o %t2
# RUN: llvm-objcopy --remove-note=1 %t2 %t2o 2>&1 | FileCheck %s --check-prefix=NOTE_SECTION
# NOTE_SECTION: warning: cannot remove note(s) from .note: sections in segments are not supported

--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
ProgramHeaders:
- Type: PT_LOAD
FirstSec: .note
LastSec: .note
Sections:
- Name: .note
Type: SHT_NOTE
AddressAlign: 4
Content: "1122334455"
37 changes: 26 additions & 11 deletions llvm/test/tools/llvm-objcopy/ELF/remove-note.test
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Check incompatible options
## Check incompatible options.
# RUN: not llvm-objcopy --remove-note=1 --remove-section=.test - 2>&1 | FileCheck %s --check-prefix=ERR-REMSEC
# RUN: not llvm-objcopy --remove-note=1 --add-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-ADDSEC
# RUN: not llvm-objcopy --remove-note=1 --update-section=.test=%s - 2>&1 | FileCheck %s --check-prefix=ERR-UPDSEC
Expand All @@ -7,7 +7,7 @@
# ERR-ADDSEC: error: cannot specify both --remove-note and --add-section
# ERR-UPDSEC: error: cannot specify both --remove-note and --update-section

## Check invalid argument formats
## Check invalid argument formats.
# RUN: not llvm-objcopy --remove-note= - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
# RUN: not llvm-objcopy --remove-note=CORE/ - 2>&1 | FileCheck %s --check-prefix=ERR-NOTYPEID
# RUN: not llvm-objcopy --remove-note=/1 - 2>&1 | FileCheck %s --check-prefix=ERR-EMPTYNAME
Expand All @@ -20,20 +20,24 @@
# ERR-INVNUM1: error: bad note type_id for --remove-note: '1/2'
# ERR-INVNUM2: error: bad note type_id for --remove-note: 'Notanumber'

## Check deleting notes:
## * --remove-note=1 will remove note "CORE/1" and "LINUX/1",
## * --remove-note=DUMMY/2 will not remove any notes because there are no notes with this owner,
## * --remove-note=CORE/3 will remove "CORE/3" but preserve "LINUX/3".
# RUN: yaml2obj -D ALIGN=8 -D ELFCLASS=64 -D ENDIANNESS=LSB %s -o %t8.64.lsb
# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/2 --remove-note=CORE/0x03 %t8.64.lsb %t8.64.lsb.o
# RUN: llvm-readobj --segments --sections --notes %t8.64.lsb.o | \
# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=32
# RUN: FileCheck %s -D#SIZE0=32 -D#SIZE1=64

# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=64 -D ENDIANNESS=MSB %s -o %t4.64.msb
# RUN: llvm-objcopy --remove-note=0x01 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.64.msb %t4.64.msb.o
# RUN: llvm-readobj --segments --sections --notes %t4.64.msb.o | \
# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24
# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48

# RUN: yaml2obj -D ALIGN=4 -D ELFCLASS=32 -D ENDIANNESS=LSB %s -o %t4.32.lsb
# RUN: llvm-objcopy --remove-note=1 --remove-note=DUMMY/0x02 --remove-note=CORE/3 %t4.32.lsb %t4.32.lsb.o
# RUN: llvm-readobj --segments --sections --notes %t4.32.lsb.o | \
# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=24
# RUN: FileCheck %s -D#SIZE0=24 -D#SIZE1=48

# CHECK: Sections [
# CHECK: Section {
Expand Down Expand Up @@ -70,7 +74,7 @@
# CHECK-NEXT: Data size: 0x2
# CHECK-NEXT: Type: NT_ARCH
# CHECK-NEXT: Description data (
# CHECK-NEXT: 0000: 0202
# CHECK-NEXT: 0000: 0201
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: ]
Expand All @@ -81,11 +85,19 @@
# CHECK-NEXT: Size: 0x[[#%X,SIZE1]]
# CHECK-NEXT: Notes [
# CHECK-NEXT: {
# CHECK-NEXT: Owner: LINUX
# CHECK-NEXT: Data size: 0x2
# CHECK-NEXT: Type: Unknown (0x00000003)
# CHECK-NEXT: Description data (
# CHECK-NEXT: 0000: 0301
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: {
# CHECK-NEXT: Owner: CORE
# CHECK-NEXT: Data size: 0x2
# CHECK-NEXT: Type: Unknown (0x00000004)
# CHECK-NEXT: Description data (
# CHECK-NEXT: 0000: 0404
# CHECK-NEXT: 0000: 0401
# CHECK-NEXT: )
# CHECK-NEXT: }
# CHECK-NEXT: ]
Expand Down Expand Up @@ -114,22 +126,25 @@ Sections:
Desc: 0101
- Name: CORE
Type: 0x02
Desc: 0202
Desc: 0201
- Name: .note1
Type: SHT_NOTE
AddressAlign: [[ALIGN]]
Notes:
- Name: LINUX
Type: 0x03
Desc: 0301
- Name: CORE
Type: 0x03
Desc: 0303
Desc: 0302
- Name: CORE
Type: 0x04
Desc: 0404
Desc: 0401
- Name: .note2
Type: SHT_NOTE
AddressAlign: [[ALIGN]]
Notes:
- Name: LINUX
Type: 0x01
Desc: 0505
Desc: 0102
...
2 changes: 2 additions & 0 deletions llvm/tools/llvm-objcopy/llvm-objcopy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,8 @@ int llvm_objcopy_main(int argc, char **argv, const llvm::ToolContext &) {
return 1;
}
for (ConfigManager &ConfigMgr : DriverConfig->CopyConfigs) {
assert(!ConfigMgr.Common.ErrorCallback);
ConfigMgr.Common.ErrorCallback = reportWarning;
if (Error E = executeObjcopy(ConfigMgr)) {
logAllUnhandledErrors(std::move(E), WithColor::error(errs(), ToolName));
return 1;
Expand Down
Loading