19abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// Copyright (c) 2007, Google Inc.
29abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// All rights reserved.
39abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//
49abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// Redistribution and use in source and binary forms, with or without
59abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// modification, are permitted provided that the following conditions are
69abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// met:
79abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//
89abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//     * Redistributions of source code must retain the above copyright
99abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// notice, this list of conditions and the following disclaimer.
109abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//     * Redistributions in binary form must reproduce the above
119abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// copyright notice, this list of conditions and the following disclaimer
129abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// in the documentation and/or other materials provided with the
139abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// distribution.
149abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//     * Neither the name of Google Inc. nor the names of its
159abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// contributors may be used to endorse or promote products derived from
169abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// this software without specific prior written permission.
179abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//
189abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
199abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
209abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
219abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
229abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
239abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
249abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
259abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
269abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
279abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
289abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
299abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
309abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// file_id.cc: Return a unique identifier for a file
319abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//
329abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// See file_id.h for documentation
339abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai//
349abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// Author: Alfred Peng
359abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
369abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <elf.h>
379abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <fcntl.h>
389abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <gelf.h>
399abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <sys/mman.h>
409abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <sys/ksyms.h>
419abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <stdio.h>
429abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <string.h>
439abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <unistd.h>
449abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
459abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <cassert>
469abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include <cstdio>
479abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
4868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include "common/md5.h"
499abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include "common/solaris/file_id.h"
509abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include "common/solaris/message_output.h"
519abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai#include "google_breakpad/common/minidump_format.h"
529abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
539abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovainamespace google_breakpad {
549abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
559abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaiclass AutoElfEnder {
569abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai public:
579abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  AutoElfEnder(Elf *elf) : elf_(elf) {}
589abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  ~AutoElfEnder() { if (elf_) elf_end(elf_); }
599abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai private:
609abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  Elf *elf_;
619abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai};
629abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
639abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// Find the text section in elf object file.
649abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// Return the section start address and the size.
659abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaistatic bool FindElfTextSection(int fd, const void *elf_base,
669abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai                               const void **text_start,
679abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai                               int *text_size) {
689abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  assert(text_start);
699abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  assert(text_size);
709abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
719abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  *text_start = NULL;
729abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  *text_size = 0;
739abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
749abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (elf_version(EV_CURRENT) == EV_NONE) {
759abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    print_message2(2, "elf_version() failed: %s\n", elf_errmsg(0));
769abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
779abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
789abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
799abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  GElf_Ehdr elf_header;
809abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  lseek(fd, 0L, 0);
819abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  Elf *elf = elf_begin(fd, ELF_C_READ, NULL);
829abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  AutoElfEnder elfEnder(elf);
839abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
849abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) {
859abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1));
869abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
879abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
889abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
899abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (elf_header.e_ident[EI_MAG0] != ELFMAG0 ||
909abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      elf_header.e_ident[EI_MAG1] != ELFMAG1 ||
919abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      elf_header.e_ident[EI_MAG2] != ELFMAG2 ||
929abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      elf_header.e_ident[EI_MAG3] != ELFMAG3) {
939abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    print_message1(2, "header magic doesn't match\n");
949abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
959abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
969abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
979abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  static const char kTextSectionName[] = ".text";
989abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  const GElf_Shdr *text_section = NULL;
999abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  Elf_Scn *scn = NULL;
1009abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  GElf_Shdr shdr;
1019abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1029abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  while ((scn = elf_nextscn(elf, scn)) != NULL) {
1039abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) {
1049abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      print_message2(2, "failed to read section header: %s\n", elf_errmsg(0));
1059abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      return false;
1069abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    }
1079abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1089abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    if (shdr.sh_type == SHT_PROGBITS) {
1099abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      const char *section_name = elf_strptr(elf, elf_header.e_shstrndx,
1109abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai                                            shdr.sh_name);
1119abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      if (!section_name) {
1129abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai        print_message2(2, "Section name error: %s\n", elf_errmsg(-1));
1139abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai        continue;
1149abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      }
1159abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1169abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      if (strcmp(section_name, kTextSectionName) == 0) {
1179abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai        text_section = &shdr;
1189abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai        break;
1199abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai      }
1209abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    }
1219abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
1229abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (text_section != NULL && text_section->sh_size > 0) {
1239abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    *text_start = (char *)elf_base + text_section->sh_offset;
1249abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    *text_size = text_section->sh_size;
1259abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return true;
1269abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
1279abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1289abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  return false;
1299abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai}
1309abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1319abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaiFileID::FileID(const char *path) {
13268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  strcpy(path_, path);
1339abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai}
1349abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1359abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaiclass AutoCloser {
1369abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai public:
1379abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  AutoCloser(int fd) : fd_(fd) {}
1389abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  ~AutoCloser() { if (fd_) close(fd_); }
1399abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai private:
1409abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  int fd_;
1419abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai};
1429abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1439abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaibool FileID::ElfFileIdentifier(unsigned char identifier[16]) {
1449abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  int fd = 0;
1459abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if ((fd = open(path_, O_RDONLY)) < 0)
1469abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
1479abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1489abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  AutoCloser autocloser(fd);
1499abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  struct stat st;
1509abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (fstat(fd, &st) != 0 || st.st_size <= 0)
1519abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
1529abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1539abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
154cadc8ddde91cd82aa74375abb45417c75662e9b7nealsid  if (base == MAP_FAILED)
1559abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
1569abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1579abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  bool success = false;
1589abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  const void *text_section = NULL;
1599abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  int text_size = 0;
1609abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1619abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (FindElfTextSection(fd, base, &text_section, &text_size)) {
16268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    MD5Context md5;
16368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    MD5Init(&md5);
16468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    MD5Update(&md5, (const unsigned char *)text_section, text_size);
16568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    MD5Final(identifier, &md5);
1669abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    success = true;
1679abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
1689abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1699abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  munmap((char *)base, st.st_size);
1709abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  return success;
1719abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai}
1729abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1739abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai// static
1749abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovaibool FileID::ConvertIdentifierToString(const unsigned char identifier[16],
1759abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai                                       char *buffer, int buffer_length) {
1769abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  if (buffer_length < 34)
1779abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    return false;
1789abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1799abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  int buffer_idx = 0;
1809abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  for (int idx = 0; idx < 16; ++idx) {
1819abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    int hi = (identifier[idx] >> 4) & 0x0F;
1829abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    int lo = (identifier[idx]) & 0x0F;
1839abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1849abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi;
1859abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai    buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo;
1869abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  }
1879abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1889abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  // Add an extra "0" by the end.
1899abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  buffer[buffer_idx++] = '0';
1909abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1919abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  // NULL terminate
1929abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  buffer[buffer_idx] = 0;
1939abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1949abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai  return true;
1959abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai}
1969abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai
1979abfe3d0a5bbefd85c54feda0dac2d030cbb5635mmentovai}  // namespace google_breakpad
198