~ubuntu-branches/ubuntu/trusty/tomahawk/trusty-proposed

« back to all changes in this revision

Viewing changes to thirdparty/breakpad/common/linux/file_id.cc

  • Committer: Package Import Robot
  • Author(s): Harald Sitter
  • Date: 2013-03-07 21:50:13 UTC
  • Revision ID: package-import@ubuntu.com-20130307215013-6gdjkdds7i9uenvs
Tags: upstream-0.6.0+dfsg
ImportĀ upstreamĀ versionĀ 0.6.0+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
//
 
34
 
 
35
#include "common/linux/file_id.h"
 
36
 
 
37
#include <arpa/inet.h>
 
38
#include <assert.h>
 
39
#if defined(__ANDROID__)
 
40
#include <linux/elf.h>
 
41
#include "client/linux/android_link.h"
 
42
#else
 
43
#include <elf.h>
 
44
#include <link.h>
 
45
#endif
 
46
#include <string.h>
 
47
 
 
48
#include <algorithm>
 
49
 
 
50
#include "common/linux/linux_libc_support.h"
 
51
#include "common/linux/memory_mapped_file.h"
 
52
#include "third_party/lss/linux_syscall_support.h"
 
53
 
 
54
namespace google_breakpad {
 
55
 
 
56
#ifndef NT_GNU_BUILD_ID
 
57
#define NT_GNU_BUILD_ID 3
 
58
#endif
 
59
 
 
60
FileID::FileID(const char* path) {
 
61
  strncpy(path_, path, sizeof(path_));
 
62
}
 
63
 
 
64
struct ElfClass32 {
 
65
  typedef Elf32_Ehdr Ehdr;
 
66
  typedef Elf32_Nhdr Nhdr;
 
67
  typedef Elf32_Shdr Shdr;
 
68
  static const int kClass = ELFCLASS32;
 
69
};
 
70
 
 
71
struct ElfClass64 {
 
72
  typedef Elf64_Ehdr Ehdr;
 
73
  typedef Elf64_Nhdr Nhdr;
 
74
  typedef Elf64_Shdr Shdr;
 
75
  static const int kClass = ELFCLASS64;
 
76
};
 
77
 
 
78
// These six functions are also used inside the crashed process, so be safe
 
79
// and use the syscall/libc wrappers instead of direct syscalls or libc.
 
80
template<typename ElfClass>
 
81
static void FindElfClassSection(const char *elf_base,
 
82
                                const char *section_name,
 
83
                                uint32_t section_type,
 
84
                                const void **section_start,
 
85
                                int *section_size) {
 
86
  typedef typename ElfClass::Ehdr Ehdr;
 
87
  typedef typename ElfClass::Shdr Shdr;
 
88
 
 
89
  assert(elf_base);
 
90
  assert(section_start);
 
91
  assert(section_size);
 
92
 
 
93
  assert(my_strncmp(elf_base, ELFMAG, SELFMAG) == 0);
 
94
 
 
95
  int name_len = my_strlen(section_name);
 
96
 
 
97
  const Ehdr* elf_header = reinterpret_cast<const Ehdr*>(elf_base);
 
98
  assert(elf_header->e_ident[EI_CLASS] == ElfClass::kClass);
 
99
 
 
100
  const Shdr* sections =
 
101
      reinterpret_cast<const Shdr*>(elf_base + elf_header->e_shoff);
 
102
  const Shdr* string_section = sections + elf_header->e_shstrndx;
 
103
 
 
104
  const Shdr* section = NULL;
 
105
  for (int i = 0; i < elf_header->e_shnum; ++i) {
 
106
    if (sections[i].sh_type == section_type) {
 
107
      const char* current_section_name = (char*)(elf_base +
 
108
                                                 string_section->sh_offset +
 
109
                                                 sections[i].sh_name);
 
110
      if (!my_strncmp(current_section_name, section_name, name_len)) {
 
111
        section = &sections[i];
 
112
        break;
 
113
      }
 
114
    }
 
115
  }
 
116
  if (section != NULL && section->sh_size > 0) {
 
117
    *section_start = elf_base + section->sh_offset;
 
118
    *section_size = section->sh_size;
 
119
  }
 
120
}
 
121
 
 
122
// Attempt to find a section named |section_name| of type |section_type|
 
123
// in the ELF binary data at |elf_mapped_base|. On success, returns true
 
124
// and sets |*section_start| to point to the start of the section data,
 
125
// and |*section_size| to the size of the section's data. If |elfclass|
 
126
// is not NULL, set |*elfclass| to the ELF file class.
 
127
static bool FindElfSection(const void *elf_mapped_base,
 
128
                           const char *section_name,
 
129
                           uint32_t section_type,
 
130
                           const void **section_start,
 
131
                           int *section_size,
 
132
                           int *elfclass) {
 
133
  assert(elf_mapped_base);
 
134
  assert(section_start);
 
135
  assert(section_size);
 
136
 
 
137
  *section_start = NULL;
 
138
  *section_size = 0;
 
139
 
 
140
  const char* elf_base =
 
141
    static_cast<const char*>(elf_mapped_base);
 
142
  const ElfW(Ehdr)* elf_header =
 
143
    reinterpret_cast<const ElfW(Ehdr)*>(elf_base);
 
144
  if (my_strncmp(elf_base, ELFMAG, SELFMAG) != 0)
 
145
    return false;
 
146
 
 
147
  if (elfclass) {
 
148
    *elfclass = elf_header->e_ident[EI_CLASS];
 
149
  }
 
150
 
 
151
  if (elf_header->e_ident[EI_CLASS] == ELFCLASS32) {
 
152
    FindElfClassSection<ElfClass32>(elf_base, section_name, section_type,
 
153
                                    section_start, section_size);
 
154
    return *section_start != NULL;
 
155
  } else if (elf_header->e_ident[EI_CLASS] == ELFCLASS64) {
 
156
    FindElfClassSection<ElfClass64>(elf_base, section_name, section_type,
 
157
                                    section_start, section_size);
 
158
    return *section_start != NULL;
 
159
  }
 
160
 
 
161
  return false;
 
162
}
 
163
 
 
164
template<typename ElfClass>
 
165
static bool ElfClassBuildIDNoteIdentifier(const void *section,
 
166
                                          uint8_t identifier[kMDGUIDSize]) {
 
167
  typedef typename ElfClass::Nhdr Nhdr;
 
168
 
 
169
  const Nhdr* note_header = reinterpret_cast<const Nhdr*>(section);
 
170
  if (note_header->n_type != NT_GNU_BUILD_ID ||
 
171
      note_header->n_descsz == 0) {
 
172
    return false;
 
173
  }
 
174
 
 
175
  const char* build_id = reinterpret_cast<const char*>(section) +
 
176
    sizeof(Nhdr) + note_header->n_namesz;
 
177
  // Copy as many bits of the build ID as will fit
 
178
  // into the GUID space.
 
179
  my_memset(identifier, 0, kMDGUIDSize);
 
180
  memcpy(identifier, build_id,
 
181
         std::min(kMDGUIDSize, (size_t)note_header->n_descsz));
 
182
 
 
183
  return true;
 
184
}
 
185
 
 
186
// Attempt to locate a .note.gnu.build-id section in an ELF binary
 
187
// and copy as many bytes of it as will fit into |identifier|.
 
188
static bool FindElfBuildIDNote(const void *elf_mapped_base,
 
189
                               uint8_t identifier[kMDGUIDSize]) {
 
190
  void* note_section;
 
191
  int note_size, elfclass;
 
192
  if (!FindElfSection(elf_mapped_base, ".note.gnu.build-id", SHT_NOTE,
 
193
                      (const void**)&note_section, &note_size, &elfclass) ||
 
194
      note_size == 0) {
 
195
    return false;
 
196
  }
 
197
 
 
198
  if (elfclass == ELFCLASS32) {
 
199
    return ElfClassBuildIDNoteIdentifier<ElfClass32>(note_section, identifier);
 
200
  } else if (elfclass == ELFCLASS64) {
 
201
    return ElfClassBuildIDNoteIdentifier<ElfClass64>(note_section, identifier);
 
202
  }
 
203
 
 
204
  return false;
 
205
}
 
206
 
 
207
// Attempt to locate the .text section of an ELF binary and generate
 
208
// a simple hash by XORing the first page worth of bytes into |identifier|.
 
209
static bool HashElfTextSection(const void *elf_mapped_base,
 
210
                               uint8_t identifier[kMDGUIDSize]) {
 
211
  void* text_section;
 
212
  int text_size;
 
213
  if (!FindElfSection(elf_mapped_base, ".text", SHT_PROGBITS,
 
214
                      (const void**)&text_section, &text_size, NULL) ||
 
215
      text_size == 0) {
 
216
    return false;
 
217
  }
 
218
 
 
219
  my_memset(identifier, 0, kMDGUIDSize);
 
220
  const uint8_t* ptr = reinterpret_cast<const uint8_t*>(text_section);
 
221
  const uint8_t* ptr_end = ptr + std::min(text_size, 4096);
 
222
  while (ptr < ptr_end) {
 
223
    for (unsigned i = 0; i < kMDGUIDSize; i++)
 
224
      identifier[i] ^= ptr[i];
 
225
    ptr += kMDGUIDSize;
 
226
  }
 
227
  return true;
 
228
}
 
229
 
 
230
// static
 
231
bool FileID::ElfFileIdentifierFromMappedFile(const void* base,
 
232
                                             uint8_t identifier[kMDGUIDSize]) {
 
233
  // Look for a build id note first.
 
234
  if (FindElfBuildIDNote(base, identifier))
 
235
    return true;
 
236
 
 
237
  // Fall back on hashing the first page of the text section.
 
238
  return HashElfTextSection(base, identifier);
 
239
}
 
240
 
 
241
bool FileID::ElfFileIdentifier(uint8_t identifier[kMDGUIDSize]) {
 
242
  MemoryMappedFile mapped_file(path_);
 
243
  if (!mapped_file.data())  // Should probably check if size >= ElfW(Ehdr)?
 
244
    return false;
 
245
 
 
246
  return ElfFileIdentifierFromMappedFile(mapped_file.data(), identifier);
 
247
}
 
248
 
 
249
// static
 
250
void FileID::ConvertIdentifierToString(const uint8_t identifier[kMDGUIDSize],
 
251
                                       char* buffer, int buffer_length) {
 
252
  uint8_t identifier_swapped[kMDGUIDSize];
 
253
 
 
254
  // Endian-ness swap to match dump processor expectation.
 
255
  memcpy(identifier_swapped, identifier, kMDGUIDSize);
 
256
  uint32_t* data1 = reinterpret_cast<uint32_t*>(identifier_swapped);
 
257
  *data1 = htonl(*data1);
 
258
  uint16_t* data2 = reinterpret_cast<uint16_t*>(identifier_swapped + 4);
 
259
  *data2 = htons(*data2);
 
260
  uint16_t* data3 = reinterpret_cast<uint16_t*>(identifier_swapped + 6);
 
261
  *data3 = htons(*data3);
 
262
 
 
263
  int buffer_idx = 0;
 
264
  for (unsigned int idx = 0;
 
265
       (buffer_idx < buffer_length) && (idx < kMDGUIDSize);
 
266
       ++idx) {
 
267
    int hi = (identifier_swapped[idx] >> 4) & 0x0F;
 
268
    int lo = (identifier_swapped[idx]) & 0x0F;
 
269
 
 
270
    if (idx == 4 || idx == 6 || idx == 8 || idx == 10)
 
271
      buffer[buffer_idx++] = '-';
 
272
 
 
273
    buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
 
274
    buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
 
275
  }
 
276
 
 
277
  // NULL terminate
 
278
  buffer[(buffer_idx < buffer_length) ? buffer_idx : buffer_idx - 1] = 0;
 
279
}
 
280
 
 
281
}  // namespace google_breakpad