Support generic Elf notes, with unit tests

A=Mike Hommey <mh@glandium.org>
R=ted at https://breakpad.appspot.com/546002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1142 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek@gmail.com 2013-04-04 16:24:44 +00:00
parent 3a8617eb8c
commit 6dc56cca44
4 changed files with 63 additions and 27 deletions

View File

@ -47,8 +47,8 @@ using namespace google_breakpad;
using google_breakpad::ElfClass32; using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64; using google_breakpad::ElfClass64;
using google_breakpad::SafeReadLink; using google_breakpad::SafeReadLink;
using google_breakpad::synth_elf::BuildIDNote;
using google_breakpad::synth_elf::ELF; using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::test_assembler::kLittleEndian; using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section; using google_breakpad::test_assembler::Section;
using ::testing::Types; using ::testing::Types;
@ -160,9 +160,10 @@ TYPED_TEST(FileIDTest, BuildID) {
Section text(kLittleEndian); Section text(kLittleEndian);
text.Append(4096, 0); text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS); elf.AddSection(".text", text, SHT_PROGBITS);
BuildIDNote::AppendSection(elf, Notes notes(kLittleEndian);
kExpectedIdentifier, notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
sizeof(kExpectedIdentifier)); sizeof(kExpectedIdentifier));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
elf.Finish(); elf.Finish();
this->GetElfContents(elf); this->GetElfContents(elf);

View File

@ -243,30 +243,21 @@ void SymbolTable::AddSymbol(const string& name, uint64_t value,
D64(size); D64(size);
} }
BuildIDNote::BuildIDNote(const uint8_t* id_bytes, void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes,
size_t id_size, size_t desc_size) {
Endianness endianness) : Section(endianness) {
const char kNoteName[] = "GNU";
// Elf32_Nhdr and Elf64_Nhdr are exactly the same. // Elf32_Nhdr and Elf64_Nhdr are exactly the same.
Elf32_Nhdr note_header; Elf32_Nhdr note_header;
memset(&note_header, 0, sizeof(note_header)); memset(&note_header, 0, sizeof(note_header));
note_header.n_namesz = sizeof(kNoteName); note_header.n_namesz = name.length() + 1;
note_header.n_descsz = id_size; note_header.n_descsz = desc_size;
note_header.n_type = NT_GNU_BUILD_ID; note_header.n_type = type;
Append(reinterpret_cast<const uint8_t*>(&note_header), Append(reinterpret_cast<const uint8_t*>(&note_header),
sizeof(note_header)); sizeof(note_header));
AppendCString(kNoteName); AppendCString(name);
Append(id_bytes, id_size); Align(4);
} Append(desc_bytes, desc_size);
Align(4);
// static
void BuildIDNote::AppendSection(ELF& elf,
const uint8_t* id_bytes,
size_t id_size) {
const char kBuildIDSectionName[] = ".note.gnu.build-id";
BuildIDNote note(id_bytes, id_size, elf.endianness());
elf.AddSection(kBuildIDSectionName, note, SHT_NOTE);
} }
} // namespace synth_elf } // namespace synth_elf

View File

@ -177,13 +177,16 @@ class SymbolTable : public Section {
StringTable& table_; StringTable& table_;
}; };
// A class to build GNU Build ID note sections // A class for note sections
class BuildIDNote : public Section { class Notes : public Section {
public: public:
BuildIDNote(const uint8_t* id_bytes, size_t id_size, Endianness endianness); Notes(Endianness endianness)
: Section(endianness) {
}
// Append a new Build ID note section to |elf|. // Add a note.
static void AppendSection(ELF& elf, const uint8_t* id_bytes, size_t id_size); void AddNote(int type, const string &name, const uint8_t* desc_bytes,
size_t desc_size);
}; };
} // namespace synth_elf } // namespace synth_elf

View File

@ -42,6 +42,7 @@
using google_breakpad::ElfClass32; using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64; using google_breakpad::ElfClass64;
using google_breakpad::synth_elf::ELF; using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::synth_elf::Section; using google_breakpad::synth_elf::Section;
using google_breakpad::synth_elf::StringTable; using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable; using google_breakpad::synth_elf::SymbolTable;
@ -369,4 +370,44 @@ TYPED_TEST(BasicElf, BasicLE) {
EXPECT_EQ(0U, phdr->p_align); EXPECT_EQ(0U, phdr->p_align);
} }
class ElfNotesTest : public Test {};
TEST_F(ElfNotesTest, Empty) {
Notes notes(kLittleEndian);
string contents;
ASSERT_TRUE(notes.GetContents(&contents));
EXPECT_EQ(0U, contents.size());
}
TEST_F(ElfNotesTest, Notes) {
Notes notes(kLittleEndian);
notes.AddNote(1, "Linux", reinterpret_cast<const uint8_t *>("\x42\x02\0\0"),
4);
notes.AddNote(2, "a", reinterpret_cast<const uint8_t *>("foobar"),
sizeof("foobar") - 1);
const uint8_t kExpectedNotesContents[] = {
// Note 1
0x06, 0x00, 0x00, 0x00, // name size, including terminating zero
0x04, 0x00, 0x00, 0x00, // desc size
0x01, 0x00, 0x00, 0x00, // type
'L', 'i', 'n', 'u', 'x', 0x00, 0x00, 0x00, // padded "Linux"
0x42, 0x02, 0x00, 0x00, // desc
// Note 2
0x02, 0x00, 0x00, 0x00, // name size
0x06, 0x00, 0x00, 0x00, // desc size
0x02, 0x00, 0x00, 0x00, // type
'a', 0x00, 0x00, 0x00, // padded "a"
'f', 'o', 'o', 'b', 'a', 'r', 0x00, 0x00, // padded "foobar"
};
const size_t kExpectedNotesSize = sizeof(kExpectedNotesContents);
EXPECT_EQ(kExpectedNotesSize, notes.Size());
string notes_contents;
ASSERT_TRUE(notes.GetContents(&notes_contents));
EXPECT_EQ(0, memcmp(kExpectedNotesContents,
notes_contents.data(),
notes_contents.size()));
}
#endif // defined(__i386__) || defined(__x86_64__) #endif // defined(__i386__) || defined(__x86_64__)