Provide a ReadSymbolData function to get symbol data in a Module instead of just serializing it

R=thestig at https://breakpad.appspot.com/510002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1099 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek@gmail.com 2013-01-18 20:24:16 +00:00
parent e086f8a9c8
commit 7e72c6677a
3 changed files with 72 additions and 38 deletions

View file

@ -62,6 +62,7 @@
#include "common/linux/elf_symbols_to_module.h" #include "common/linux/elf_symbols_to_module.h"
#include "common/linux/file_id.h" #include "common/linux/file_id.h"
#include "common/module.h" #include "common/module.h"
#include "common/scoped_ptr.h"
#include "common/stabs_reader.h" #include "common/stabs_reader.h"
#include "common/stabs_to_module.h" #include "common/stabs_to_module.h"
#include "common/using_std_string.h" #include "common/using_std_string.h"
@ -80,6 +81,7 @@ using google_breakpad::GetOffset;
using google_breakpad::IsValidElf; using google_breakpad::IsValidElf;
using google_breakpad::Module; using google_breakpad::Module;
using google_breakpad::StabsToModule; using google_breakpad::StabsToModule;
using google_breakpad::scoped_ptr;
// //
// FDWrapper // FDWrapper
@ -708,14 +710,16 @@ string BaseFileName(const string &filename) {
} }
template<typename ElfClass> template<typename ElfClass>
bool WriteSymbolFileElfClass(const typename ElfClass::Ehdr* elf_header, bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
const string& obj_filename, const string& obj_filename,
const string& debug_dir, const string& debug_dir,
bool cfi, bool cfi,
std::ostream& sym_stream) { Module** out_module) {
typedef typename ElfClass::Ehdr Ehdr; typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr; typedef typename ElfClass::Shdr Shdr;
*out_module = NULL;
unsigned char identifier[16]; unsigned char identifier[16];
if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header, if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
identifier)) { identifier)) {
@ -741,9 +745,9 @@ bool WriteSymbolFileElfClass(const typename ElfClass::Ehdr* elf_header,
string id = FormatIdentifier(identifier); string id = FormatIdentifier(identifier);
LoadSymbolsInfo<ElfClass> info(debug_dir); LoadSymbolsInfo<ElfClass> info(debug_dir);
Module module(name, os, architecture, id); scoped_ptr<Module> module(new Module(name, os, architecture, id));
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header, if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
!debug_dir.empty(), &info, &module)) { !debug_dir.empty(), &info, module.get())) {
const string debuglink_file = info.debuglink_file(); const string debuglink_file = info.debuglink_file();
if (debuglink_file.empty()) if (debuglink_file.empty())
return false; return false;
@ -781,13 +785,12 @@ bool WriteSymbolFileElfClass(const typename ElfClass::Ehdr* elf_header,
} }
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian, if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
debug_elf_header, false, &info, &module)) { debug_elf_header, false, &info, module.get())) {
return false; return false;
} }
} }
if (!module.Write(sym_stream, cfi))
return false;
*out_module = module.release();
return true; return true;
} }
@ -796,11 +799,11 @@ bool WriteSymbolFileElfClass(const typename ElfClass::Ehdr* elf_header,
namespace google_breakpad { namespace google_breakpad {
// Not explicitly exported, but not static so it can be used in unit tests. // Not explicitly exported, but not static so it can be used in unit tests.
bool WriteSymbolFileInternal(const uint8_t* obj_file, bool ReadSymbolDataInternal(const uint8_t* obj_file,
const string& obj_filename, const string& obj_filename,
const string& debug_dir, const string& debug_dir,
bool cfi, bool cfi,
std::ostream& sym_stream) { Module** module) {
if (!IsValidElf(obj_file)) { if (!IsValidElf(obj_file)) {
fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str()); fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
@ -809,14 +812,14 @@ bool WriteSymbolFileInternal(const uint8_t* obj_file,
int elfclass = ElfClass(obj_file); int elfclass = ElfClass(obj_file);
if (elfclass == ELFCLASS32) { if (elfclass == ELFCLASS32) {
return WriteSymbolFileElfClass<ElfClass32>( return ReadSymbolDataElfClass<ElfClass32>(
reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dir, reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dir,
cfi, sym_stream); cfi, module);
} }
if (elfclass == ELFCLASS64) { if (elfclass == ELFCLASS64) {
return WriteSymbolFileElfClass<ElfClass64>( return ReadSymbolDataElfClass<ElfClass64>(
reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dir, reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, debug_dir,
cfi, sym_stream); cfi, module);
} }
return false; return false;
@ -826,13 +829,26 @@ bool WriteSymbolFile(const string &obj_file,
const string &debug_dir, const string &debug_dir,
bool cfi, bool cfi,
std::ostream &sym_stream) { std::ostream &sym_stream) {
Module* module;
if (!ReadSymbolData(obj_file, debug_dir, cfi, &module))
return false;
bool result = module->Write(sym_stream, cfi);
delete module;
return result;
}
bool ReadSymbolData(const string& obj_file,
const string& debug_dir,
bool cfi,
Module** module) {
MmapWrapper map_wrapper; MmapWrapper map_wrapper;
void* elf_header = NULL; void* elf_header = NULL;
if (!LoadELF(obj_file, &map_wrapper, &elf_header)) if (!LoadELF(obj_file, &map_wrapper, &elf_header))
return false; return false;
return WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(elf_header), return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
obj_file, debug_dir, cfi, sym_stream); obj_file, debug_dir, cfi, module);
} }
} // namespace google_breakpad } // namespace google_breakpad

View file

@ -42,6 +42,8 @@
namespace google_breakpad { namespace google_breakpad {
class Module;
// Find all the debugging information in OBJ_FILE, an ELF executable // Find all the debugging information in OBJ_FILE, an ELF executable
// or shared library, and write it to SYM_STREAM in the Breakpad symbol // or shared library, and write it to SYM_STREAM in the Breakpad symbol
// file format. // file format.
@ -53,6 +55,14 @@ bool WriteSymbolFile(const string &obj_file,
bool cfi, bool cfi,
std::ostream &sym_stream); std::ostream &sym_stream);
// As above, but simply return the debugging information in MODULE
// instead of writing it to a stream. The caller owns the resulting
// Module object and must delete it when finished.
bool ReadSymbolData(const string& obj_file,
const string& debug_dir,
bool cfi,
Module** module);
} // namespace google_breakpad } // namespace google_breakpad
#endif // COMMON_LINUX_DUMP_SYMBOLS_H__ #endif // COMMON_LINUX_DUMP_SYMBOLS_H__

View file

@ -37,19 +37,19 @@
#include <stdio.h> #include <stdio.h>
#include <sstream> #include <sstream>
#include <string>
#include <vector> #include <vector>
#include "breakpad_googletest_includes.h" #include "breakpad_googletest_includes.h"
#include "common/linux/synth_elf.h" #include "common/linux/synth_elf.h"
#include "common/module.h"
#include "common/using_std_string.h" #include "common/using_std_string.h"
namespace google_breakpad { namespace google_breakpad {
bool WriteSymbolFileInternal(const uint8_t* obj_file, bool ReadSymbolDataInternal(const uint8_t* obj_file,
const string &obj_filename, const string &obj_filename,
const string &debug_dir, const string &debug_dir,
bool cfi, bool cfi,
std::ostream &sym_stream); Module** module);
} }
using google_breakpad::synth_elf::ELF; using google_breakpad::synth_elf::ELF;
@ -57,7 +57,8 @@ using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable; using google_breakpad::synth_elf::SymbolTable;
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 google_breakpad::WriteSymbolFileInternal; using google_breakpad::Module;
using google_breakpad::ReadSymbolDataInternal;
using std::stringstream; using std::stringstream;
using std::vector; using std::vector;
using ::testing::Test; using ::testing::Test;
@ -81,12 +82,12 @@ class DumpSymbols : public Test {
TEST_F(DumpSymbols, Invalid) { TEST_F(DumpSymbols, Invalid) {
Elf32_Ehdr header; Elf32_Ehdr header;
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
stringstream s; Module* module;
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header), EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
"foo", "foo",
"", "",
true, true,
s)); &module));
} }
TEST_F(DumpSymbols, SimplePublic32) { TEST_F(DumpSymbols, SimplePublic32) {
@ -113,15 +114,19 @@ TEST_F(DumpSymbols, SimplePublic32) {
elf.Finish(); elf.Finish();
GetElfContents(elf); GetElfContents(elf);
Module* module;
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
"",
true,
&module));
stringstream s; stringstream s;
ASSERT_TRUE(WriteSymbolFileInternal(elfdata, module->Write(s, true);
"foo",
"",
true,
s));
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n" EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n", "PUBLIC 1000 0 superfunc\n",
s.str()); s.str());
delete module;
} }
TEST_F(DumpSymbols, SimplePublic64) { TEST_F(DumpSymbols, SimplePublic64) {
@ -148,12 +153,15 @@ TEST_F(DumpSymbols, SimplePublic64) {
elf.Finish(); elf.Finish();
GetElfContents(elf); GetElfContents(elf);
Module* module;
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
"",
true,
&module));
stringstream s; stringstream s;
ASSERT_TRUE(WriteSymbolFileInternal(elfdata, module->Write(s, true);
"foo",
"",
true,
s));
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n" EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n", "PUBLIC 1000 0 superfunc\n",
s.str()); s.str());