aboutsummaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/linux/dump_symbols.cc36
-rw-r--r--src/common/linux/file_id.cc70
-rw-r--r--src/common/linux/file_id.h31
-rw-r--r--src/common/linux/file_id_unittest.cc176
-rw-r--r--src/common/memory.h52
-rw-r--r--src/common/memory_unittest.cc27
6 files changed, 259 insertions, 133 deletions
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
index 5d2aac7e..d31e2c2d 100644
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -64,6 +64,7 @@
#include "common/linux/elfutils-inl.h"
#include "common/linux/elf_symbols_to_module.h"
#include "common/linux/file_id.h"
+#include "common/memory.h"
#include "common/module.h"
#include "common/scoped_ptr.h"
#ifndef NO_STABS_SUPPORT
@@ -82,14 +83,18 @@ using google_breakpad::DwarfLineToModule;
using google_breakpad::ElfClass;
using google_breakpad::ElfClass32;
using google_breakpad::ElfClass64;
+using google_breakpad::FileID;
using google_breakpad::FindElfSectionByName;
using google_breakpad::GetOffset;
using google_breakpad::IsValidElf;
+using google_breakpad::kDefaultBuildIdSize;
using google_breakpad::Module;
+using google_breakpad::PageAllocator;
#ifndef NO_STABS_SUPPORT
using google_breakpad::StabsToModule;
#endif
using google_breakpad::scoped_ptr;
+using google_breakpad::wasteful_vector;
// Define AARCH64 ELF architecture if host machine does not include this define.
#ifndef EM_AARCH64
@@ -854,25 +859,6 @@ const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
}
}
-// Format the Elf file identifier in IDENTIFIER as a UUID with the
-// dashes removed.
-string FormatIdentifier(unsigned char identifier[16]) {
- char identifier_str[40];
- google_breakpad::FileID::ConvertIdentifierToString(
- identifier,
- identifier_str,
- sizeof(identifier_str));
- string id_no_dash;
- for (int i = 0; identifier_str[i] != '\0'; ++i)
- if (identifier_str[i] != '-')
- id_no_dash += identifier_str[i];
- // Add an extra "0" by the end. PDB files on Windows have an 'age'
- // number appended to the end of the file identifier; this isn't
- // really used or necessary on other platforms, but be consistent.
- id_no_dash += '0';
- return id_no_dash;
-}
-
// Return the non-directory portion of FILENAME: the portion after the
// last slash, or the whole filename if there are no slashes.
string BaseFileName(const string &filename) {
@@ -924,9 +910,10 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
*out_module = NULL;
- unsigned char identifier[16];
- if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
- identifier)) {
+ PageAllocator allocator;
+ wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
+ if (!FileID::ElfFileIdentifierFromMappedFile(elf_header,
+ identifier)) {
fprintf(stderr, "%s: unable to generate file identifier\n",
obj_filename.c_str());
return false;
@@ -946,7 +933,10 @@ bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
string name = BaseFileName(obj_filename);
string os = "Linux";
- string id = FormatIdentifier(identifier);
+ // Add an extra "0" at the end. PDB files on Windows have an 'age'
+ // number appended to the end of the file identifier; this isn't
+ // really used or necessary on other platforms, but be consistent.
+ string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0";
LoadSymbolsInfo<ElfClass> info(debug_dirs);
scoped_ptr<Module> module(new Module(name, os, architecture, id));
diff --git a/src/common/linux/file_id.cc b/src/common/linux/file_id.cc
index 00b37313..e8dc528d 100644
--- a/src/common/linux/file_id.cc
+++ b/src/common/linux/file_id.cc
@@ -39,6 +39,7 @@
#include <string.h>
#include <algorithm>
+#include <string>
#include "common/linux/elf_gnu_compat.h"
#include "common/linux/elfutils.h"
@@ -46,8 +47,13 @@
#include "common/linux/memory_mapped_file.h"
#include "third_party/lss/linux_syscall_support.h"
+using std::string;
+
namespace google_breakpad {
+// Used in a few places for backwards-compatibility.
+const size_t kMDGUIDSize = sizeof(MDGUID);
+
FileID::FileID(const char* path) : path_(path) {}
// ELF note name and desc are 32-bits word padded.
@@ -58,7 +64,7 @@ FileID::FileID(const char* path) : path_(path) {}
template<typename ElfClass>
static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
- uint8_t identifier[kMDGUIDSize]) {
+ wasteful_vector<uint8_t>& identifier) {
typedef typename ElfClass::Nhdr Nhdr;
const void* section_end = reinterpret_cast<const char*>(section) + length;
@@ -76,21 +82,19 @@ static bool ElfClassBuildIDNoteIdentifier(const void *section, size_t length,
return false;
}
- const char* build_id = reinterpret_cast<const char*>(note_header) +
+ const uint8_t* build_id = reinterpret_cast<const uint8_t*>(note_header) +
sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz);
- // Copy as many bits of the build ID as will fit
- // into the GUID space.
- my_memset(identifier, 0, kMDGUIDSize);
- memcpy(identifier, build_id,
- std::min(kMDGUIDSize, (size_t)note_header->n_descsz));
+ identifier.insert(identifier.end(),
+ build_id,
+ build_id + note_header->n_descsz);
return true;
}
// Attempt to locate a .note.gnu.build-id section in an ELF binary
-// and copy as many bytes of it as will fit into |identifier|.
-static bool FindElfBuildIDNote(const void *elf_mapped_base,
- uint8_t identifier[kMDGUIDSize]) {
+// and copy it into |identifier|.
+static bool FindElfBuildIDNote(const void* elf_mapped_base,
+ wasteful_vector<uint8_t>& identifier) {
void* note_section;
size_t note_size;
int elfclass;
@@ -116,8 +120,10 @@ static bool FindElfBuildIDNote(const void *elf_mapped_base,
// Attempt to locate the .text section of an ELF binary and generate
// a simple hash by XORing the first page worth of bytes into |identifier|.
-static bool HashElfTextSection(const void *elf_mapped_base,
- uint8_t identifier[kMDGUIDSize]) {
+static bool HashElfTextSection(const void* elf_mapped_base,
+ wasteful_vector<uint8_t>& identifier) {
+ identifier.resize(kMDGUIDSize);
+
void* text_section;
size_t text_size;
if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
@@ -126,7 +132,9 @@ static bool HashElfTextSection(const void *elf_mapped_base,
return false;
}
- my_memset(identifier, 0, kMDGUIDSize);
+ // Only provide |kMDGUIDSize| bytes to keep identifiers produced by this
+ // function backwards-compatible.
+ my_memset(&identifier[0], 0, kMDGUIDSize);
const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
const uint8_t* ptr_end = ptr + std::min(text_size, static_cast<size_t>(4096));
while (ptr < ptr_end) {
@@ -139,7 +147,7 @@ static bool HashElfTextSection(const void *elf_mapped_base,
// static
bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
- uint8_t identifier[kMDGUIDSize]) {
+ wasteful_vector<uint8_t>& identifier) {
// Look for a build id note first.
if (FindElfBuildIDNote(base, identifier))
return true;
@@ -148,7 +156,7 @@ bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
return HashElfTextSection(base, identifier);
}
-bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
+bool FileID::ElfFileIdentifier(wasteful_vector<uint8_t>& identifier) {
MemoryMappedFile mapped_file(path_.c_str(), 0);
if (!mapped_file.data()) // Should probably check if size >= ElfW(Ehdr)?
return false;
@@ -156,13 +164,16 @@ bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
}
+// This function is not ever called in an unsafe context, so it's OK
+// to allocate memory and use libc.
// static
-void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
- char* buffer, int buffer_length) {
- uint8_t identifier_swapped[kMDGUIDSize];
+string FileID::ConvertIdentifierToUUIDString(
+ const wasteful_vector<uint8_t>& identifier) {
+ uint8_t identifier_swapped[kMDGUIDSize] = { 0 };
// Endian-ness swap to match dump processor expectation.
- memcpy(identifier_swapped, identifier, kMDGUIDSize);
+ memcpy(identifier_swapped, &identifier[0],
+ std::min(kMDGUIDSize, identifier.size()));
uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
*data1 = htonl(*data1);
uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
@@ -170,22 +181,13 @@ void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
*data3 = htons(*data3);
- int buffer_idx = 0;
- for (unsigned int idx = 0;
- (buffer_idx < buffer_length) && (idx < kMDGUIDSize);
- ++idx) {
- int hi = (identifier_swapped[idx] >> 4) & 0x0F;
- int lo = (identifier_swapped[idx]) & 0x0F;
-
- if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
- buffer[buffer_idx++] = '-';
-
- buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
- buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
+ string result;
+ for (unsigned int idx = 0; idx < kMDGUIDSize; ++idx) {
+ char buf[3];
+ snprintf(buf, sizeof(buf), "%02X", identifier_swapped[idx]);
+ result.append(buf);
}
-
- // NULL terminate
- buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
+ return result;
}
} // namespace google_breakpad
diff --git a/src/common/linux/file_id.h b/src/common/linux/file_id.h
index 2642722a..80e5a8e9 100644
--- a/src/common/linux/file_id.h
+++ b/src/common/linux/file_id.h
@@ -37,10 +37,15 @@
#include <string>
#include "common/linux/guid_creator.h"
+#include "common/memory.h"
namespace google_breakpad {
-static const size_t kMDGUIDSize = sizeof(MDGUID);
+// GNU binutils' ld defaults to 'sha1', which is 160 bits == 20 bytes,
+// so this is enough to fit that, which most binaries will use.
+// This is just a sensible default for auto_wasteful_vector so most
+// callers can get away with stack allocation.
+static const size_t kDefaultBuildIdSize = 20;
class FileID {
public:
@@ -48,25 +53,25 @@ class FileID {
~FileID() {}
// Load the identifier for the elf file path specified in the constructor into
- // |identifier|. Return false if the identifier could not be created for the
- // file.
+ // |identifier|.
+ //
// The current implementation will look for a .note.gnu.build-id
// section and use that as the file id, otherwise it falls back to
// XORing the first 4096 bytes of the .text section to generate an identifier.
- bool ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]);
+ bool ElfFileIdentifier(wasteful_vector<uint8_t>& identifier);
// Load the identifier for the elf file mapped into memory at |base| into
- // |identifier|. Return false if the identifier could not be created for the
+ // |identifier|. Return false if the identifier could not be created for this
// file.
- static bool ElfFileIdentifierFromMappedFile(const void* base,
- uint8_t identifier[kMDGUIDSize]);
+ static bool ElfFileIdentifierFromMappedFile(
+ const void* base,
+ wasteful_vector<uint8_t>& identifier);
- // Convert the |identifier| data to a NULL terminated string. The string will
- // be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
- // The |buffer| should be at least 37 bytes long to receive all of the data
- // and termination. Shorter buffers will contain truncated data.
- static void ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
- char* buffer, int buffer_length);
+ // Convert the |identifier| data to a string. The string will
+ // be formatted as a UUID in all uppercase without dashes.
+ // (e.g., 22F065BBFC9C49F780FE26A7CEBD7BCE).
+ static std::string ConvertIdentifierToUUIDString(
+ const wasteful_vector<uint8_t>& identifier);
private:
// Storage for the path specified
diff --git a/src/common/linux/file_id_unittest.cc b/src/common/linux/file_id_unittest.cc
index 760eae82..ec11bb25 100644
--- a/src/common/linux/file_id_unittest.cc
+++ b/src/common/linux/file_id_unittest.cc
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string>
+#include <vector>
#include "common/linux/elf_gnu_compat.h"
#include "common/linux/elfutils.h"
@@ -45,13 +46,11 @@
#include "breakpad_googletest_includes.h"
using namespace google_breakpad;
-using google_breakpad::ElfClass32;
-using google_breakpad::ElfClass64;
-using google_breakpad::SafeReadLink;
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::Notes;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
+using std::vector;
using ::testing::Types;
namespace {
@@ -64,6 +63,8 @@ void PopulateSection(Section* section, int size, int prime_number) {
section->Append(1, (i % prime_number) % 256);
}
+typedef wasteful_vector<uint8_t> id_vector;
+
} // namespace
#ifndef __ANDROID__
@@ -87,19 +88,20 @@ TEST(FileIDStripTest, StripSelf) {
sprintf(cmdline, "strip \"%s\"", templ.c_str());
ASSERT_EQ(0, system(cmdline)) << "Failed to execute: " << cmdline;
- uint8_t identifier1[sizeof(MDGUID)];
- uint8_t identifier2[sizeof(MDGUID)];
+ PageAllocator allocator;
+ id_vector identifier1(&allocator, kDefaultBuildIdSize);
+ id_vector identifier2(&allocator, kDefaultBuildIdSize);
+
FileID fileid1(exe_name);
EXPECT_TRUE(fileid1.ElfFileIdentifier(identifier1));
FileID fileid2(templ.c_str());
EXPECT_TRUE(fileid2.ElfFileIdentifier(identifier2));
- char identifier_string1[37];
- char identifier_string2[37];
- FileID::ConvertIdentifierToString(identifier1, identifier_string1,
- 37);
- FileID::ConvertIdentifierToString(identifier2, identifier_string2,
- 37);
- EXPECT_STREQ(identifier_string1, identifier_string2);
+
+ string identifier_string1 =
+ FileID::ConvertIdentifierToUUIDString(identifier1);
+ string identifier_string2 =
+ FileID::ConvertIdentifierToUUIDString(identifier2);
+ EXPECT_EQ(identifier_string1, identifier_string2);
}
#endif // !__ANDROID__
@@ -116,8 +118,22 @@ public:
elfdata = &elfdata_v[0];
}
+ id_vector make_vector() {
+ return id_vector(&allocator, kDefaultBuildIdSize);
+ }
+
+ template<size_t N>
+ string get_file_id(const uint8_t (&data)[N]) {
+ id_vector expected_identifier(make_vector());
+ expected_identifier.insert(expected_identifier.end(),
+ &data[0],
+ data + N);
+ return FileID::ConvertIdentifierToUUIDString(expected_identifier);
+ }
+
vector<uint8_t> elfdata_v;
uint8_t* elfdata;
+ PageAllocator allocator;
};
typedef Types<ElfClass32, ElfClass64> ElfClasses;
@@ -125,10 +141,8 @@ typedef Types<ElfClass32, ElfClass64> ElfClasses;
TYPED_TEST_CASE(FileIDTest, ElfClasses);
TYPED_TEST(FileIDTest, ElfClass) {
- uint8_t identifier[sizeof(MDGUID)];
const char expected_identifier_string[] =
- "80808080-8080-0000-0000-008080808080";
- char identifier_string[sizeof(expected_identifier_string)];
+ "80808080808000000000008080808080";
const size_t kTextSectionSize = 128;
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
@@ -140,58 +154,106 @@ TYPED_TEST(FileIDTest, ElfClass) {
elf.Finish();
this->GetElfContents(elf);
+ id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
- FileID::ConvertIdentifierToString(identifier, identifier_string,
- sizeof(identifier_string));
- EXPECT_STREQ(expected_identifier_string, identifier_string);
+ string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
+ EXPECT_EQ(expected_identifier_string, identifier_string);
}
TYPED_TEST(FileIDTest, BuildID) {
- const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
+ const uint8_t kExpectedIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
- char expected_identifier_string[] =
- "00000000-0000-0000-0000-000000000000";
- FileID::ConvertIdentifierToString(kExpectedIdentifier,
- expected_identifier_string,
- sizeof(expected_identifier_string));
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13};
+ const string expected_identifier_string =
+ this->get_file_id(kExpectedIdentifierBytes);
+
+ ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
+ Section text(kLittleEndian);
+ text.Append(4096, 0);
+ elf.AddSection(".text", text, SHT_PROGBITS);
+ Notes notes(kLittleEndian);
+ notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
+ sizeof(kExpectedIdentifierBytes));
+ elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
+ elf.Finish();
+ this->GetElfContents(elf);
- uint8_t identifier[sizeof(MDGUID)];
- char identifier_string[sizeof(expected_identifier_string)];
+ id_vector identifier(this->make_vector());
+ EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
+ identifier));
+ EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
+
+ string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
+ EXPECT_EQ(expected_identifier_string, identifier_string);
+}
+
+// Test that a build id note with fewer bytes than usual is handled.
+TYPED_TEST(FileIDTest, BuildIDShort) {
+ const uint8_t kExpectedIdentifierBytes[] =
+ {0x00, 0x01, 0x02, 0x03};
+ const string expected_identifier_string =
+ this->get_file_id(kExpectedIdentifierBytes);
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
text.Append(4096, 0);
elf.AddSection(".text", text, SHT_PROGBITS);
Notes notes(kLittleEndian);
- notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
- sizeof(kExpectedIdentifier));
+ notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
+ sizeof(kExpectedIdentifierBytes));
elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
elf.Finish();
this->GetElfContents(elf);
+ id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
+ EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
- FileID::ConvertIdentifierToString(identifier, identifier_string,
- sizeof(identifier_string));
- EXPECT_STREQ(expected_identifier_string, identifier_string);
+ string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
+ EXPECT_EQ(expected_identifier_string, identifier_string);
}
-TYPED_TEST(FileIDTest, BuildIDPH) {
- const uint8_t kExpectedIdentifier[sizeof(MDGUID)] =
+// Test that a build id note with more bytes than usual is handled.
+TYPED_TEST(FileIDTest, BuildIDLong) {
+ const uint8_t kExpectedIdentifierBytes[] =
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
- char expected_identifier_string[] =
- "00000000-0000-0000-0000-000000000000";
- FileID::ConvertIdentifierToString(kExpectedIdentifier,
- expected_identifier_string,
- sizeof(expected_identifier_string));
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
+ const string expected_identifier_string =
+ this->get_file_id(kExpectedIdentifierBytes);
- uint8_t identifier[sizeof(MDGUID)];
- char identifier_string[sizeof(expected_identifier_string)];
+ ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
+ Section text(kLittleEndian);
+ text.Append(4096, 0);
+ elf.AddSection(".text", text, SHT_PROGBITS);
+ Notes notes(kLittleEndian);
+ notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
+ sizeof(kExpectedIdentifierBytes));
+ elf.AddSection(".note.gnu.build-id", notes, SHT_NOTE);
+ elf.Finish();
+ this->GetElfContents(elf);
+
+ id_vector identifier(this->make_vector());
+ EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
+ identifier));
+ EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
+
+ string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
+ EXPECT_EQ(expected_identifier_string, identifier_string);
+}
+
+TYPED_TEST(FileIDTest, BuildIDPH) {
+ const uint8_t kExpectedIdentifierBytes[] =
+ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13};
+ const string expected_identifier_string =
+ this->get_file_id(kExpectedIdentifierBytes);
ELF elf(EM_386, TypeParam::kClass, kLittleEndian);
Section text(kLittleEndian);
@@ -200,31 +262,25 @@ TYPED_TEST(FileIDTest, BuildIDPH) {
Notes notes(kLittleEndian);
notes.AddNote(0, "Linux",
reinterpret_cast<const uint8_t *>("\0x42\0x02\0\0"), 4);
- notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifier,
- sizeof(kExpectedIdentifier));
+ notes.AddNote(NT_GNU_BUILD_ID, "GNU", kExpectedIdentifierBytes,
+ sizeof(kExpectedIdentifierBytes));
int note_idx = elf.AddSection(".note", notes, SHT_NOTE);
elf.AddSegment(note_idx, note_idx, PT_NOTE);
elf.Finish();
this->GetElfContents(elf);
+ id_vector identifier(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier));
+ EXPECT_EQ(sizeof(kExpectedIdentifierBytes), identifier.size());
- FileID::ConvertIdentifierToString(identifier, identifier_string,
- sizeof(identifier_string));
- EXPECT_STREQ(expected_identifier_string, identifier_string);
+ string identifier_string = FileID::ConvertIdentifierToUUIDString(identifier);
+ EXPECT_EQ(expected_identifier_string, identifier_string);
}
// Test to make sure two files with different text sections produce
// different hashes when not using a build id.
TYPED_TEST(FileIDTest, UniqueHashes) {
- char identifier_string_1[] =
- "00000000-0000-0000-0000-000000000000";
- char identifier_string_2[] =
- "00000000-0000-0000-0000-000000000000";
- uint8_t identifier_1[sizeof(MDGUID)];
- uint8_t identifier_2[sizeof(MDGUID)];
-
{
ELF elf1(EM_386, TypeParam::kClass, kLittleEndian);
Section foo_1(kLittleEndian);
@@ -237,10 +293,11 @@ TYPED_TEST(FileIDTest, UniqueHashes) {
this->GetElfContents(elf1);
}
+ id_vector identifier_1(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier_1));
- FileID::ConvertIdentifierToString(identifier_1, identifier_string_1,
- sizeof(identifier_string_1));
+ string identifier_string_1 =
+ FileID::ConvertIdentifierToUUIDString(identifier_1);
{
ELF elf2(EM_386, TypeParam::kClass, kLittleEndian);
@@ -254,10 +311,11 @@ TYPED_TEST(FileIDTest, UniqueHashes) {
this->GetElfContents(elf2);
}
+ id_vector identifier_2(this->make_vector());
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(this->elfdata,
identifier_2));
- FileID::ConvertIdentifierToString(identifier_2, identifier_string_2,
- sizeof(identifier_string_2));
+ string identifier_string_2 =
+ FileID::ConvertIdentifierToUUIDString(identifier_2);
- EXPECT_STRNE(identifier_string_1, identifier_string_2);
+ EXPECT_NE(identifier_string_1, identifier_string_2);
}
diff --git a/src/common/memory.h b/src/common/memory.h
index d6aa137d..16a612b8 100644
--- a/src/common/memory.h
+++ b/src/common/memory.h
@@ -64,7 +64,8 @@ class PageAllocator {
: page_size_(getpagesize()),
last_(NULL),
current_page_(NULL),
- page_offset_(0) {
+ page_offset_(0),
+ pages_allocated_(0) {
}
~PageAllocator() {
@@ -112,6 +113,8 @@ class PageAllocator {
return false;
}
+ unsigned long pages_allocated() { return pages_allocated_; }
+
private:
uint8_t *GetNPages(size_t num_pages) {
#if defined(__x86_64__) || defined(__aarch64__) || defined(__aarch64__) || \
@@ -136,6 +139,8 @@ class PageAllocator {
header->num_pages = num_pages;
last_ = header;
+ pages_allocated_ += num_pages;
+
return reinterpret_cast<uint8_t*>(a);
}
@@ -157,6 +162,7 @@ class PageAllocator {
PageHeader *last_;
uint8_t *current_page_;
size_t page_offset_;
+ unsigned long pages_allocated_;
};
// Wrapper to use with STL containers
@@ -165,12 +171,30 @@ struct PageStdAllocator : public std::allocator<T> {
typedef typename std::allocator<T>::pointer pointer;
typedef typename std::allocator<T>::size_type size_type;
- explicit PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {}
+ explicit PageStdAllocator(PageAllocator& allocator) : allocator_(allocator),
+ stackdata_(NULL),
+ stackdata_size_(0)
+ {}
+
template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other)
- : allocator_(other.allocator_) {}
+ : allocator_(other.allocator_),
+ stackdata_(nullptr),
+ stackdata_size_(0)
+ {}
+
+ explicit PageStdAllocator(PageAllocator& allocator,
+ pointer stackdata,
+ size_type stackdata_size) : allocator_(allocator),
+ stackdata_(stackdata),
+ stackdata_size_(stackdata_size)
+ {}
inline pointer allocate(size_type n, const void* = 0) {
- return static_cast<pointer>(allocator_.Alloc(sizeof(T) * n));
+ const size_type size = sizeof(T) * n;
+ if (size <= stackdata_size_) {
+ return stackdata_;
+ }
+ return static_cast<pointer>(allocator_.Alloc(size));
}
inline void deallocate(pointer, size_type) {
@@ -188,6 +212,8 @@ struct PageStdAllocator : public std::allocator<T> {
template<typename Other> friend struct PageStdAllocator;
PageAllocator& allocator_;
+ pointer stackdata_;
+ size_type stackdata_size_;
};
// A wasteful vector is a std::vector, except that it allocates memory from a
@@ -200,6 +226,24 @@ class wasteful_vector : public std::vector<T, PageStdAllocator<T> > {
: std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
}
+ protected:
+ wasteful_vector(PageStdAllocator<T> allocator)
+ : std::vector<T, PageStdAllocator<T> >(allocator) {}
+};
+
+// auto_wasteful_vector allocates space on the stack for N entries to avoid
+// using the PageAllocator for small data, while still allowing for larger data.
+template<class T, unsigned int N>
+class auto_wasteful_vector : public wasteful_vector<T> {
+ T stackdata_[N];
+ public:
+ auto_wasteful_vector(PageAllocator* allocator)
+ : wasteful_vector<T>(
+ PageStdAllocator<T>(*allocator,
+ &stackdata_[0],
+ sizeof(stackdata_))) {
+ std::vector<T, PageStdAllocator<T> >::reserve(N);
+ }
};
} // namespace google_breakpad
diff --git a/src/common/memory_unittest.cc b/src/common/memory_unittest.cc
index 1e511ca5..b271bc3c 100644
--- a/src/common/memory_unittest.cc
+++ b/src/common/memory_unittest.cc
@@ -38,11 +38,13 @@ typedef testing::Test PageAllocatorTest;
TEST(PageAllocatorTest, Setup) {
PageAllocator allocator;
+ EXPECT_EQ(0, allocator.pages_allocated());
}
TEST(PageAllocatorTest, SmallObjects) {
PageAllocator allocator;
+ EXPECT_EQ(0, allocator.pages_allocated());
for (unsigned i = 1; i < 1024; ++i) {
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
@@ -53,8 +55,10 @@ TEST(PageAllocatorTest, SmallObjects) {
TEST(PageAllocatorTest, LargeObject) {
PageAllocator allocator;
+ EXPECT_EQ(0, allocator.pages_allocated());
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(10000));
ASSERT_FALSE(p == NULL);
+ EXPECT_EQ(3, allocator.pages_allocated());
for (unsigned i = 1; i < 10; ++i) {
uint8_t *p = reinterpret_cast<uint8_t*>(allocator.Alloc(i));
ASSERT_FALSE(p == NULL);
@@ -75,6 +79,7 @@ TEST(WastefulVectorTest, Setup) {
TEST(WastefulVectorTest, Simple) {
PageAllocator allocator_;
+ EXPECT_EQ(0, allocator_.pages_allocated());
wasteful_vector<unsigned> v(&allocator_);
for (unsigned i = 0; i < 256; ++i) {
@@ -84,6 +89,7 @@ TEST(WastefulVectorTest, Simple) {
}
ASSERT_FALSE(v.empty());
ASSERT_EQ(v.size(), 256u);
+ EXPECT_EQ(1, allocator_.pages_allocated());
for (unsigned i = 0; i < 256; ++i)
ASSERT_EQ(v[i], i);
}
@@ -91,7 +97,28 @@ TEST(WastefulVectorTest, Simple) {
TEST(WastefulVectorTest, UsesPageAllocator) {
PageAllocator allocator_;
wasteful_vector<unsigned> v(&allocator_);
+ EXPECT_EQ(1, allocator_.pages_allocated());
v.push_back(1);
ASSERT_TRUE(allocator_.OwnsPointer(&v[0]));
}
+
+TEST(WastefulVectorTest, AutoWastefulVector) {
+ PageAllocator allocator_;
+ EXPECT_EQ(0, allocator_.pages_allocated());
+
+ auto_wasteful_vector<unsigned, 4> v(&allocator_);
+ EXPECT_EQ(0, allocator_.pages_allocated());
+
+ v.push_back(1);
+ EXPECT_EQ(0, allocator_.pages_allocated());
+ EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
+
+ v.resize(4);
+ EXPECT_EQ(0, allocator_.pages_allocated());
+ EXPECT_FALSE(allocator_.OwnsPointer(&v[0]));
+
+ v.resize(10);
+ EXPECT_EQ(1, allocator_.pages_allocated());
+ EXPECT_TRUE(allocator_.OwnsPointer(&v[0]));
+}