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