toolkit/crashreporter/google-breakpad/src/common/linux/file_id.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2006, Google Inc.
     2 // All rights reserved.
     3 //
     4 // Redistribution and use in source and binary forms, with or without
     5 // modification, are permitted provided that the following conditions are
     6 // met:
     7 //
     8 //     * Redistributions of source code must retain the above copyright
     9 // notice, this list of conditions and the following disclaimer.
    10 //     * Redistributions in binary form must reproduce the above
    11 // copyright notice, this list of conditions and the following disclaimer
    12 // in the documentation and/or other materials provided with the
    13 // distribution.
    14 //     * Neither the name of Google Inc. nor the names of its
    15 // contributors may be used to endorse or promote products derived from
    16 // this software without specific prior written permission.
    17 //
    18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29 //
    30 // file_id.cc: Return a unique identifier for a file
    31 //
    32 // See file_id.h for documentation
    33 //
    35 #include "common/linux/file_id.h"
    37 #include <arpa/inet.h>
    38 #include <assert.h>
    39 #include <string.h>
    41 #include <algorithm>
    43 #include "common/linux/elfutils.h"
    44 #include "common/linux/linux_libc_support.h"
    45 #include "common/linux/memory_mapped_file.h"
    46 #include "third_party/lss/linux_syscall_support.h"
    48 namespace google_breakpad {
    50 #ifndef NT_GNU_BUILD_ID
    51 #define NT_GNU_BUILD_ID 3
    52 #endif
    54 FileID::FileID(const char* path) {
    55   strncpy(path_, path, sizeof(path_));
    56 }
    58 // ELF note name and desc are 32-bits word padded.
    59 #define NOTE_PADDING(a) ((a + 3) & ~3)
    61 // These functions are also used inside the crashed process, so be safe
    62 // and use the syscall/libc wrappers instead of direct syscalls or libc.
    64 template<typename ElfClass>
    65 static bool ElfClassBuildIDNoteIdentifier(const void *section, int length,
    66                                           uint8_t identifier[kMDGUIDSize]) {
    67   typedef typename ElfClass::Nhdr Nhdr;
    69   const void* section_end = reinterpret_cast<const char*>(section) + length;
    70   const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
    71   while (reinterpret_cast<const void *>(note_header) < section_end) {
    72     if (note_header->n_type == NT_GNU_BUILD_ID)
    73       break;
    74     note_header = reinterpret_cast<const Nhdr*>(
    75                   reinterpret_cast<const char*>(note_header) + sizeof(Nhdr) +
    76                   NOTE_PADDING(note_header->n_namesz) +
    77                   NOTE_PADDING(note_header->n_descsz));
    78   }
    79   if (reinterpret_cast<const void *>(note_header) >= section_end ||
    80       note_header->n_descsz == 0) {
    81     return false;
    82   }
    84   const char* build_id = reinterpret_cast<const char*>(note_header) +
    85     sizeof(Nhdr) + NOTE_PADDING(note_header->n_namesz);
    86   // Copy as many bits of the build ID as will fit
    87   // into the GUID space.
    88   my_memset(identifier, 0, kMDGUIDSize);
    89   memcpy(identifier, build_id,
    90          std::min(kMDGUIDSize, (size_t)note_header->n_descsz));
    92   return true;
    93 }
    95 // Attempt to locate a .note.gnu.build-id section in an ELF binary
    96 // and copy as many bytes of it as will fit into |identifier|.
    97 static bool FindElfBuildIDNote(const void *elf_mapped_base,
    98                                uint8_t identifier[kMDGUIDSize]) {
    99   void* note_section;
   100   int note_size, elfclass;
   101   if ((!FindElfSegment(elf_mapped_base, PT_NOTE,
   102                        (const void**)&note_section, &note_size, &elfclass) ||
   103       note_size == 0)  &&
   104       (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
   105                        (const void**)&note_section, &note_size, &elfclass) ||
   106       note_size == 0)) {
   107     return false;
   108   }
   110   if (elfclass == ELFCLASS32) {
   111     return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, note_size,
   112                                                      identifier);
   113   } else if (elfclass == ELFCLASS64) {
   114     return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, note_size,
   115                                                      identifier);
   116   }
   118   return false;
   119 }
   121 // Attempt to locate the .text section of an ELF binary and generate
   122 // a simple hash by XORing the first page worth of bytes into |identifier|.
   123 static bool HashElfTextSection(const void *elf_mapped_base,
   124                                uint8_t identifier[kMDGUIDSize]) {
   125   void* text_section;
   126   int text_size;
   127   if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
   128                       (const void**)&text_section, &text_size, NULL) ||
   129       text_size == 0) {
   130     return false;
   131   }
   133   my_memset(identifier, 0, kMDGUIDSize);
   134   const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
   135   const uint8_t* ptr_end = ptr + std::min(text_size, 4096);
   136   while (ptr < ptr_end) {
   137     for (unsigned i = 0; i < kMDGUIDSize; i++)
   138       identifier[i] ^= ptr[i];
   139     ptr += kMDGUIDSize;
   140   }
   141   return true;
   142 }
   144 // static
   145 bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
   146                                              uint8_t identifier[kMDGUIDSize]) {
   147   // Look for a build id note first.
   148   if (FindElfBuildIDNote(base, identifier))
   149     return true;
   151   // Fall back on hashing the first page of the text section.
   152   return HashElfTextSection(base, identifier);
   153 }
   155 bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
   156   MemoryMappedFile mapped_file(path_);
   157   if (!mapped_file.data())  // Should probably check if size >= ElfW(Ehdr)?
   158     return false;
   160   return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
   161 }
   163 // static
   164 void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
   165                                        char* buffer, int buffer_length) {
   166   uint8_t identifier_swapped[kMDGUIDSize];
   168   // Endian-ness swap to match dump processor expectation.
   169   memcpy(identifier_swapped, identifier, kMDGUIDSize);
   170   uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
   171   *data1 = htonl(*data1);
   172   uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
   173   *data2 = htons(*data2);
   174   uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
   175   *data3 = htons(*data3);
   177   int buffer_idx = 0;
   178   for (unsigned int idx = 0;
   179        (buffer_idx < buffer_length) && (idx < kMDGUIDSize);
   180        ++idx) {
   181     int hi = (identifier_swapped[idx] >> 4) & 0x0F;
   182     int lo = (identifier_swapped[idx]) & 0x0F;
   184     if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
   185       buffer[buffer_idx++] = '-';
   187     buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
   188     buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
   189   }
   191   // NULL terminate
   192   buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
   193 }
   195 }  // namespace google_breakpad

mercurial