mirror of
https://git.suyu.dev/suyu/breakpad.git
synced 2026-03-25 10:32:59 +00:00
Add some unit tests for Linux WriteSymbolFile
This patch adds synth_elf::{StringTable,SymbolTable,ELF} classes to
produce in-memory ELF files to properly test the Linux symbol dumping
code. It also uses those classes to add some basic tests for
the WriteSymbolFile function.
R=jimb at http://breakpad.appspot.com/277001/show
git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@794 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
@@ -44,53 +45,10 @@
|
||||
|
||||
using google_breakpad::Module;
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
using std::vector;
|
||||
using testing::ContainerEq;
|
||||
|
||||
// Return a FILE * referring to a temporary file that will be deleted
|
||||
// automatically when the stream is closed or the program exits.
|
||||
static FILE *checked_tmpfile() {
|
||||
FILE *f = tmpfile();
|
||||
if (!f) {
|
||||
fprintf(stderr, "error creating temporary file: %s\n", strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
// Read from STREAM until end of file, and return the contents as a
|
||||
// string.
|
||||
static string checked_read(FILE *stream) {
|
||||
string contents;
|
||||
int c;
|
||||
while ((c = getc(stream)) != EOF)
|
||||
contents.push_back(c);
|
||||
if (ferror(stream)) {
|
||||
fprintf(stderr, "error reading temporary file contents: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
// Apply 'fflush' to STREAM, and check for errors.
|
||||
static void checked_fflush(FILE *stream) {
|
||||
if (fflush(stream) == EOF) {
|
||||
fprintf(stderr, "error flushing temporary file stream: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Apply 'fclose' to STREAM, and check for errors.
|
||||
static void checked_fclose(FILE *stream) {
|
||||
if (fclose(stream) == EOF) {
|
||||
fprintf(stderr, "error closing temporary file stream: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static Module::Function *generate_duplicate_function(const string &name) {
|
||||
const Module::Address DUP_ADDRESS = 0xd35402aac7a7ad5cLL;
|
||||
const Module::Address DUP_SIZE = 0x200b26e605f99071LL;
|
||||
@@ -110,19 +68,16 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
||||
#define MODULE_ID "id-string"
|
||||
|
||||
TEST(Write, Header) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
||||
TEST(Write, OneLineFunc) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
Module::File *file = m.FindFile("file_name.cc");
|
||||
@@ -136,11 +91,8 @@ TEST(Write, OneLineFunc) {
|
||||
function->lines.push_back(line);
|
||||
m.AddFunction(function);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 file_name.cc\n"
|
||||
"FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a"
|
||||
@@ -150,7 +102,7 @@ TEST(Write, OneLineFunc) {
|
||||
}
|
||||
|
||||
TEST(Write, RelativeLoadAddress) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Some source files. We will expect to see them in lexicographic order.
|
||||
@@ -189,11 +141,8 @@ TEST(Write, RelativeLoadAddress) {
|
||||
// the module must work fine.
|
||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 filename-a.cc\n"
|
||||
"FILE 1 filename-b.cc\n"
|
||||
@@ -247,12 +196,9 @@ TEST(Write, OmitUnusedFiles) {
|
||||
EXPECT_STREQ("filename3", vec[2]->name.c_str());
|
||||
EXPECT_NE(-1, vec[2]->source_id);
|
||||
|
||||
FILE *f = checked_tmpfile();
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
stringstream s;
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FILE 0 filename1\n"
|
||||
"FILE 1 filename3\n"
|
||||
@@ -264,7 +210,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||
}
|
||||
|
||||
TEST(Construct, AddFunctions) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two functions.
|
||||
@@ -287,11 +233,8 @@ TEST(Construct, AddFunctions) {
|
||||
|
||||
m.AddFunctions(vec.begin(), vec.end());
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
||||
" _and_void\n"
|
||||
@@ -308,7 +251,7 @@ TEST(Construct, AddFunctions) {
|
||||
}
|
||||
|
||||
TEST(Construct, AddFrames) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// First STACK CFI entry, with no initial rules or deltas.
|
||||
@@ -342,11 +285,8 @@ TEST(Construct, AddFrames) {
|
||||
m.AddStackFrameEntry(entry3);
|
||||
|
||||
// Check that Write writes STACK CFI records properly.
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
||||
"STACK CFI INIT 8064f3af5e067e38 de2a5ee55509407"
|
||||
@@ -411,7 +351,7 @@ TEST(Construct, UniqueFiles) {
|
||||
}
|
||||
|
||||
TEST(Construct, DuplicateFunctions) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two functions.
|
||||
@@ -421,11 +361,8 @@ TEST(Construct, DuplicateFunctions) {
|
||||
m.AddFunction(function1);
|
||||
m.AddFunction(function2);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||
" _without_form\n",
|
||||
@@ -433,7 +370,7 @@ TEST(Construct, DuplicateFunctions) {
|
||||
}
|
||||
|
||||
TEST(Construct, FunctionsWithSameAddress) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two functions.
|
||||
@@ -443,11 +380,8 @@ TEST(Construct, FunctionsWithSameAddress) {
|
||||
m.AddFunction(function1);
|
||||
m.AddFunction(function2);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||
" _and_void\n"
|
||||
@@ -459,7 +393,7 @@ TEST(Construct, FunctionsWithSameAddress) {
|
||||
// Externs should be written out as PUBLIC records, sorted by
|
||||
// address.
|
||||
TEST(Construct, Externs) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two externs.
|
||||
@@ -473,11 +407,8 @@ TEST(Construct, Externs) {
|
||||
m.AddExtern(extern1);
|
||||
m.AddExtern(extern2);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
MODULE_ID " " MODULE_NAME "\n"
|
||||
@@ -489,7 +420,7 @@ TEST(Construct, Externs) {
|
||||
// Externs with the same address should only keep the first entry
|
||||
// added.
|
||||
TEST(Construct, DuplicateExterns) {
|
||||
FILE *f = checked_tmpfile();
|
||||
stringstream s;
|
||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||
|
||||
// Two externs.
|
||||
@@ -503,11 +434,8 @@ TEST(Construct, DuplicateExterns) {
|
||||
m.AddExtern(extern1);
|
||||
m.AddExtern(extern2);
|
||||
|
||||
m.Write(f);
|
||||
checked_fflush(f);
|
||||
rewind(f);
|
||||
string contents = checked_read(f);
|
||||
checked_fclose(f);
|
||||
m.Write(s);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
MODULE_ID " " MODULE_NAME "\n"
|
||||
|
||||
Reference in New Issue
Block a user