diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/linux/crc32.cc | 70 | ||||
-rw-r--r-- | src/common/linux/crc32.h | 53 | ||||
-rw-r--r-- | src/common/linux/dump_symbols.cc | 75 |
3 files changed, 175 insertions, 23 deletions
diff --git a/src/common/linux/crc32.cc b/src/common/linux/crc32.cc new file mode 100644 index 00000000..8df636ce --- /dev/null +++ b/src/common/linux/crc32.cc @@ -0,0 +1,70 @@ +// Copyright 2014 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "common/linux/crc32.h" + +namespace google_breakpad { + +// This implementation is based on the sample implementation in RFC 1952. + +// CRC32 polynomial, in reversed form. +// See RFC 1952, or http://en.wikipedia.org/wiki/Cyclic_redundancy_check +static const uint32_t kCrc32Polynomial = 0xEDB88320; +static uint32_t kCrc32Table[256] = { 0 }; + +#define arraysize(f) (sizeof(f) / sizeof(*f)) + +static void EnsureCrc32TableInited() { + if (kCrc32Table[arraysize(kCrc32Table) - 1]) + return; // already inited + for (uint32_t i = 0; i < arraysize(kCrc32Table); ++i) { + uint32_t c = i; + for (size_t j = 0; j < 8; ++j) { + if (c & 1) { + c = kCrc32Polynomial ^ (c >> 1); + } else { + c >>= 1; + } + } + kCrc32Table[i] = c; + } +} + +uint32_t UpdateCrc32(uint32_t start, const void* buf, size_t len) { + EnsureCrc32TableInited(); + + uint32_t c = start ^ 0xFFFFFFFF; + const uint8_t* u = static_cast<const uint8_t*>(buf); + for (size_t i = 0; i < len; ++i) { + c = kCrc32Table[(c ^ u[i]) & 0xFF] ^ (c >> 8); + } + return c ^ 0xFFFFFFFF; +} + +} // namespace google_breakpad diff --git a/src/common/linux/crc32.h b/src/common/linux/crc32.h new file mode 100644 index 00000000..e3d9db92 --- /dev/null +++ b/src/common/linux/crc32.h @@ -0,0 +1,53 @@ +// Copyright 2014 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef COMMON_LINUX_CRC32_H_ +#define COMMON_LINUX_CRC32_H_ + +#include <stdint.h> + +#include <string> + +namespace google_breakpad { + +// Updates a CRC32 checksum with |len| bytes from |buf|. |initial| holds the +// checksum result from the previous update; for the first call, it should be 0. +uint32_t UpdateCrc32(uint32_t initial, const void* buf, size_t len); + +// Computes a CRC32 checksum using |len| bytes from |buf|. +inline uint32_t ComputeCrc32(const void* buf, size_t len) { + return UpdateCrc32(0, buf, len); +} +inline uint32_t ComputeCrc32(const std::string& str) { + return ComputeCrc32(str.c_str(), str.size()); +} + +} // namespace google_breakpad + +#endif // COMMON_LINUX_CRC32_H_ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index 75dcfd4c..b03bea87 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -57,6 +57,8 @@ #include "common/dwarf_cfi_to_module.h" #include "common/dwarf_cu_to_module.h" #include "common/dwarf_line_to_module.h" +#include "common/linux/crc32.h" +#include "common/linux/eintr_wrapper.h" #include "common/linux/elfutils.h" #include "common/linux/elfutils-inl.h" #include "common/linux/elf_symbols_to_module.h" @@ -141,7 +143,7 @@ class MmapWrapper { private: bool is_set_; - void *base_; + void* base_; size_t size_; }; @@ -204,8 +206,8 @@ class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler { void StartCompilationUnit(const string& compilation_dir) { compilation_dir_ = compilation_dir; } - void ReadProgram(const char *program, uint64 length, - Module *module, std::vector<Module::Line> *lines) { + void ReadProgram(const char* program, uint64 length, + Module* module, std::vector<Module::Line>* lines) { DwarfLineToModule handler(module, compilation_dir_, lines); dwarf2reader::LineInfo parser(program, length, byte_reader_, &handler); parser.Start(); @@ -369,7 +371,7 @@ bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper, obj_file.c_str(), strerror(errno)); return false; } - void *obj_base = mmap(NULL, st.st_size, + void* obj_base = mmap(NULL, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0); if (obj_base == MAP_FAILED) { fprintf(stderr, "Failed to mmap ELF file '%s': %s\n", @@ -405,19 +407,19 @@ bool ElfEndianness(const typename ElfClass::Ehdr* elf_header, // Read the .gnu_debuglink and get the debug file name. If anything goes // wrong, return an empty string. -template<typename ElfClass> string ReadDebugLink(const char* debuglink, - size_t debuglink_size, + const size_t debuglink_size, + const bool big_endian, const string& obj_file, const std::vector<string>& debug_dirs) { - size_t debuglink_len = strlen(debuglink) + 5; // '\0' + CRC32. - debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round to nearest 4 bytes. + size_t debuglink_len = strlen(debuglink) + 5; // Include '\0' + CRC32. + debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes. // Sanity check. if (debuglink_len != debuglink_size) { fprintf(stderr, "Mismatched .gnu_debuglink string / section size: " "%zx %zx\n", debuglink_len, debuglink_size); - return ""; + return string(); } bool found = false; @@ -428,10 +430,39 @@ string ReadDebugLink(const char* debuglink, const string& debug_dir = *it; debuglink_path = debug_dir + "/" + debuglink; debuglink_fd = open(debuglink_path.c_str(), O_RDONLY); - if (debuglink_fd >= 0) { - found = true; - break; + if (debuglink_fd < 0) + continue; + + FDWrapper debuglink_fd_wrapper(debuglink_fd); + + // The CRC is the last 4 bytes in |debuglink|. + const dwarf2reader::Endianness endianness = big_endian ? + dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE; + dwarf2reader::ByteReader byte_reader(endianness); + uint32_t expected_crc = + byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]); + + uint32_t actual_crc = 0; + while (true) { + const size_t kReadSize = 4096; + char buf[kReadSize]; + ssize_t bytes_read = HANDLE_EINTR(read(debuglink_fd, &buf, kReadSize)); + if (bytes_read < 0) { + fprintf(stderr, "Error reading debug ELF file %s.\n", + debuglink_path.c_str()); + return string(); + } + if (bytes_read == 0) + break; + actual_crc = google_breakpad::UpdateCrc32(actual_crc, buf, bytes_read); } + if (actual_crc != expected_crc) { + fprintf(stderr, "Error reading debug ELF file - CRC32 mismatch: %s\n", + debuglink_path.c_str()); + continue; + } + found = true; + break; } if (!found) { @@ -441,13 +472,9 @@ string ReadDebugLink(const char* debuglink, const string debug_dir = *it; fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink); } - return ""; + return string(); } - FDWrapper debuglink_fd_wrapper(debuglink_fd); - // TODO(thestig) check the CRC-32 at the end of the .gnu_debuglink - // section. - return debuglink_path; } @@ -545,7 +572,7 @@ bool LoadSymbols(const string& obj_file, module->SetLoadAddress(loading_addr); info->set_loading_addr(loading_addr, obj_file); - Word debug_section_type = + Word debug_section_type = elf_header->e_machine == EM_MIPS ? SHT_MIPS_DWARF : SHT_PROGBITS; const Shdr* sections = GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff); @@ -657,10 +684,12 @@ bool LoadSymbols(const string& obj_file, const char* debuglink_contents = GetOffset<ElfClass, char>(elf_header, gnu_debuglink_section->sh_offset); - string debuglink_file - = ReadDebugLink<ElfClass>(debuglink_contents, - gnu_debuglink_section->sh_size, - obj_file, info->debug_dirs()); + string debuglink_file = + ReadDebugLink(debuglink_contents, + gnu_debuglink_section->sh_size, + big_endian, + obj_file, + info->debug_dirs()); info->set_debuglink_file(debuglink_file); } else { fprintf(stderr, ".gnu_debuglink section found in '%s', " @@ -759,7 +788,7 @@ string FormatIdentifier(unsigned char identifier[16]) { // last slash, or the whole filename if there are no slashes. string BaseFileName(const string &filename) { // Lots of copies! basename's behavior is less than ideal. - char *c_filename = strdup(filename.c_str()); + char* c_filename = strdup(filename.c_str()); string base = basename(c_filename); free(c_filename); return base; |