bug 603592 - make a file_id host binary that can spit out a Breakpad file id. r=mwu a=blocking-fennec

This commit is contained in:
Ted Mielczarek 2010-10-14 20:38:19 -04:00
Родитель ed569a9c92
Коммит 0c493a18d8
5 изменённых файлов: 279 добавлений и 27 удалений

Просмотреть файл

@ -98,6 +98,10 @@ DIRS += \
$(NULL)
endif
ifeq ($(OS_TARGET),Android)
DIRS += fileid
endif
DIRS += client
LOCAL_INCLUDES = -I$(srcdir)/google-breakpad/src

Просмотреть файл

@ -0,0 +1,68 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla Breakpad integration
#
# The Initial Developer of the Original Code is
# Ted Mielczarek <ted.mielczarek@gmail.com>
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
HOST_PROGRAM = file_id
LOCAL_INCLUDES = \
-I$(srcdir)/../google-breakpad/src \
-I$(srcdir)/../google-breakpad/src/common/linux \
$(NULL)
HOST_CPPSRCS = \
file_id.cc \
$(NULL)
HOST_LIBS += \
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/linux/$(LIB_PREFIX)host_breakpad_linux_common_s.$(LIB_SUFFIX) \
$(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/$(LIB_PREFIX)host_breakpad_common_s.$(LIB_SUFFIX) \
$(NULL)
# force C++ linking
CPP_PROG_LINK = 1
FORCE_USE_PIC = 1
#XXX: bug 554854 causes us to be unable to run binaries on the build slaves
# due to them having an older libstdc++
HOST_LDFLAGS += -static
include $(topsrcdir)/config/rules.mk

Просмотреть файл

@ -0,0 +1,82 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Breakpad integration
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ted Mielczarek <ted.mielczarek@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include <string>
#include <stdio.h>
#include "common/linux/file_id.h"
//TODO: move this somewhere common, this is copied from dump_symbols.cc
// Format the Elf file identifier in IDENTIFIER as a UUID with the
// dashes removed.
std::string FormatIdentifier(unsigned char identifier[16]) {
char identifier_str[40];
google_breakpad::FileID::ConvertIdentifierToString(
identifier,
identifier_str,
sizeof(identifier_str));
std::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 let's preserve
// the pattern.
id_no_dash += '0';
return id_no_dash;
}
int main(int argc, char** argv)
{
if (argc != 2) {
fprintf(stderr, "usage: file_id <elf file>\n");
return 1;
}
unsigned char identifier[google_breakpad::kMDGUIDSize];
google_breakpad::FileID file_id(argv[1]);
if (!file_id.ElfFileIdentifier(identifier)) {
fprintf(stderr, "%s: unable to generate file identifier\n",
argv[1]);
return 1;
}
printf("%s\n", FormatIdentifier(identifier).c_str());
return 0;
}

Просмотреть файл

@ -60,37 +60,44 @@ FileID::FileID(const char* path) {
strncpy(path_, path, sizeof(path_));
}
// These two functions are also used inside the crashed process, so be safe
struct ElfClass32 {
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Shdr Shdr;
static const int kClass = ELFCLASS32;
};
struct ElfClass64 {
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Shdr Shdr;
static const int kClass = ELFCLASS64;
};
// These three functions are also used inside the crashed process, so be safe
// and use the syscall/libc wrappers instead of direct syscalls or libc.
static bool FindElfTextSection(const void *elf_mapped_base,
const void **text_start,
int *text_size) {
assert(elf_mapped_base);
template<typename ElfClass>
static void FindElfClassTextSection(const char *elf_base,
const void **text_start,
int *text_size) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
assert(elf_base);
assert(text_start);
assert(text_size);
const char* elf_base =
static_cast<const char*>(elf_mapped_base);
const ElfW(Ehdr)* elf_header =
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
return false;
#if __ELF_NATIVE_CLASS == 32 || ELFSIZE == 32
#define ELFCLASS ELFCLASS32
#else
#define ELFCLASS ELFCLASS64
#endif
//TODO: support dumping 32-bit binaries from a 64-bit dump_syms?
if (elf_header->e_ident[EI_CLASS] != ELFCLASS)
return false;
*text_start = NULL;
*text_size = 0;
const ElfW(Shdr)* sections =
reinterpret_cast<const ElfW(Shdr)*>(elf_base + elf_header->e_shoff);
assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
const char* text_section_name = ".text";
int name_len = my_strlen(text_section_name);
const ElfW(Shdr)* string_section = sections + elf_header->e_shstrndx;
const ElfW(Shdr)* text_section = NULL;
const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
const Shdr* sections =
reinterpret_cast<const Shdr*>(elf_base + elf_header->e_shoff);
const Shdr* string_section = sections + elf_header->e_shstrndx;
const Shdr* text_section = NULL;
for (int i = 0; i < elf_header->e_shnum; ++i) {
if (sections[i].sh_type == SHT_PROGBITS) {
const char* section_name = (char*)(elf_base +
@ -106,6 +113,30 @@ FileID::FileID(const char* path) {
*text_start = elf_base + text_section->sh_offset;
*text_size = text_section->sh_size;
}
}
static bool FindElfTextSection(const void *elf_mapped_base,
const void **text_start,
int *text_size) {
assert(elf_mapped_base);
assert(text_start);
assert(text_size);
const char* elf_base =
static_cast<const char*>(elf_mapped_base);
const ElfW(Ehdr)* elf_header =
reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
return false;
if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) {
FindElfClassTextSection<ElfClass32>(elf_base, text_start, text_size);
} else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) {
FindElfClassTextSection<ElfClass64>(elf_base, text_start, text_size);
} else {
return false;
}
return true;
}

Просмотреть файл

@ -1,4 +1,4 @@
// Copyright (c) 2009, Google Inc.
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -29,6 +29,7 @@
// Unit tests for FileID
#include <elf.h>
#include <stdlib.h>
#include "common/linux/file_id.h"
@ -36,7 +37,6 @@
using namespace google_breakpad;
namespace {
typedef testing::Test FileIDTest;
}
@ -74,3 +74,70 @@ TEST(FileIDTest, FileIDStrip) {
EXPECT_STREQ(identifier_string1, identifier_string2);
unlink(templ);
}
struct ElfClass32 {
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Shdr Shdr;
static const int kClass = ELFCLASS32;
};
struct ElfClass64 {
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Shdr Shdr;
static const int kClass = ELFCLASS64;
};
template<typename ElfClass>
struct ElfishElf {
static const size_t kTextSectionSize = 128;
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
Ehdr elf_header;
Shdr text_header;
Shdr string_header;
char text_section[kTextSectionSize];
char string_section[8];
static void Populate(ElfishElf* elf) {
memset(elf, 0, sizeof(ElfishElf));
memcpy(elf, ELFMAG, SELFMAG);
elf->elf_header.e_ident[EI_CLASS] = ElfClass::kClass;
elf->elf_header.e_shoff = offsetof(ElfishElf, text_header);
elf->elf_header.e_shnum = 2;
elf->elf_header.e_shstrndx = 1;
elf->text_header.sh_name = 0;
elf->text_header.sh_type = SHT_PROGBITS;
elf->text_header.sh_offset = offsetof(ElfishElf, text_section);
elf->text_header.sh_size = kTextSectionSize;
for (size_t i = 0; i < kTextSectionSize; ++i) {
elf->text_section[i] = i * 3;
}
elf->string_header.sh_offset = offsetof(ElfishElf, string_section);
strcpy(elf->string_section, ".text");
}
};
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)];
ElfishElf<ElfClass32> elf32;
ElfishElf<ElfClass32>::Populate(&elf32);
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf32, identifier));
FileID::ConvertIdentifierToString(identifier, identifier_string,
sizeof(identifier_string));
EXPECT_STREQ(expected_identifier_string, identifier_string);
memset(identifier, 0, sizeof(identifier));
memset(identifier_string, 0, sizeof(identifier_string));
ElfishElf<ElfClass64> elf64;
ElfishElf<ElfClass64>::Populate(&elf64);
EXPECT_TRUE(FileID::ElfFileIdentifierFromMappedFile(&elf64, identifier));
FileID::ConvertIdentifierToString(identifier, identifier_string,
sizeof(identifier_string));
EXPECT_STREQ(expected_identifier_string, identifier_string);
}