macho_id.cc revision 4ac61acb3a7dad6ce722fe07564be8ec92713228
1fd98b2af3773437487af0df22c428f3db630949awaylonis// Copyright (c) 2006, Google Inc.
2fd98b2af3773437487af0df22c428f3db630949awaylonis// All rights reserved.
3fd98b2af3773437487af0df22c428f3db630949awaylonis//
4fd98b2af3773437487af0df22c428f3db630949awaylonis// Redistribution and use in source and binary forms, with or without
5fd98b2af3773437487af0df22c428f3db630949awaylonis// modification, are permitted provided that the following conditions are
6fd98b2af3773437487af0df22c428f3db630949awaylonis// met:
7fd98b2af3773437487af0df22c428f3db630949awaylonis//
8fd98b2af3773437487af0df22c428f3db630949awaylonis//     * Redistributions of source code must retain the above copyright
9fd98b2af3773437487af0df22c428f3db630949awaylonis// notice, this list of conditions and the following disclaimer.
10fd98b2af3773437487af0df22c428f3db630949awaylonis//     * Redistributions in binary form must reproduce the above
11fd98b2af3773437487af0df22c428f3db630949awaylonis// copyright notice, this list of conditions and the following disclaimer
12fd98b2af3773437487af0df22c428f3db630949awaylonis// in the documentation and/or other materials provided with the
13fd98b2af3773437487af0df22c428f3db630949awaylonis// distribution.
14fd98b2af3773437487af0df22c428f3db630949awaylonis//     * Neither the name of Google Inc. nor the names of its
15fd98b2af3773437487af0df22c428f3db630949awaylonis// contributors may be used to endorse or promote products derived from
16fd98b2af3773437487af0df22c428f3db630949awaylonis// this software without specific prior written permission.
17fd98b2af3773437487af0df22c428f3db630949awaylonis//
18fd98b2af3773437487af0df22c428f3db630949awaylonis// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19fd98b2af3773437487af0df22c428f3db630949awaylonis// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20fd98b2af3773437487af0df22c428f3db630949awaylonis// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21fd98b2af3773437487af0df22c428f3db630949awaylonis// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22fd98b2af3773437487af0df22c428f3db630949awaylonis// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23fd98b2af3773437487af0df22c428f3db630949awaylonis// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24fd98b2af3773437487af0df22c428f3db630949awaylonis// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25fd98b2af3773437487af0df22c428f3db630949awaylonis// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26fd98b2af3773437487af0df22c428f3db630949awaylonis// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27fd98b2af3773437487af0df22c428f3db630949awaylonis// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28fd98b2af3773437487af0df22c428f3db630949awaylonis// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29e5dc60822e5938fea2ae892ccddb906641ba174emmentovai
30fd98b2af3773437487af0df22c428f3db630949awaylonis// macho_id.cc: Functions to gather identifying information from a macho file
31fd98b2af3773437487af0df22c428f3db630949awaylonis//
32fd98b2af3773437487af0df22c428f3db630949awaylonis// See macho_id.h for documentation
33fd98b2af3773437487af0df22c428f3db630949awaylonis//
34fd98b2af3773437487af0df22c428f3db630949awaylonis// Author: Dan Waylonis
35fd98b2af3773437487af0df22c428f3db630949awaylonis
368aef89f021c687e96c66cb99b5dac312324e785cladderbreakerextern "C" {  // necessary for Leopard
378aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <fcntl.h>
388aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <mach-o/loader.h>
398aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <mach-o/swap.h>
408aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <openssl/md5.h>
418aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <openssl/sha.h>
428aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <stdio.h>
438aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <stdlib.h>
448aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <string.h>
458aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <sys/time.h>
468aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <sys/types.h>
478aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <unistd.h>
488aef89f021c687e96c66cb99b5dac312324e785cladderbreaker}
49fd98b2af3773437487af0df22c428f3db630949awaylonis
50fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_id.h"
51fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_walker.h"
52255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek#include "common/mac/macho_utilities.h"
53fd98b2af3773437487af0df22c428f3db630949awaylonis
54fd98b2af3773437487af0df22c428f3db630949awaylonisnamespace MacFileUtilities {
55fd98b2af3773437487af0df22c428f3db630949awaylonis
564ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachMachoID::MachoID(const char *path)
574ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach   : file_(0),
584ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     crc_(0),
594ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     md5_context_(),
604ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     sha1_context_(),
614ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     update_function_(NULL) {
62fd98b2af3773437487af0df22c428f3db630949awaylonis  strlcpy(path_, path, sizeof(path_));
63fd98b2af3773437487af0df22c428f3db630949awaylonis  file_ = open(path, O_RDONLY);
64fd98b2af3773437487af0df22c428f3db630949awaylonis}
65fd98b2af3773437487af0df22c428f3db630949awaylonis
66fd98b2af3773437487af0df22c428f3db630949awaylonisMachoID::~MachoID() {
67fd98b2af3773437487af0df22c428f3db630949awaylonis  if (file_ != -1)
68fd98b2af3773437487af0df22c428f3db630949awaylonis    close(file_);
69fd98b2af3773437487af0df22c428f3db630949awaylonis}
70fd98b2af3773437487af0df22c428f3db630949awaylonis
71fd98b2af3773437487af0df22c428f3db630949awaylonis// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
72fd98b2af3773437487af0df22c428f3db630949awaylonis// With optimizations from http://www.zlib.net/
73fd98b2af3773437487af0df22c428f3db630949awaylonis
74fd98b2af3773437487af0df22c428f3db630949awaylonis// The largest prime smaller than 65536
75fd98b2af3773437487af0df22c428f3db630949awaylonis#define MOD_ADLER 65521
76fd98b2af3773437487af0df22c428f3db630949awaylonis// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
77fd98b2af3773437487af0df22c428f3db630949awaylonis#define MAX_BLOCK 5552
78fd98b2af3773437487af0df22c428f3db630949awaylonis
79fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
80fd98b2af3773437487af0df22c428f3db630949awaylonis// Unrolled loops for summing
81fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO1(buf,i)  {sum1 += (buf)[i]; sum2 += sum1;}
82fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
83fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
84fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
85fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO16(buf)   DO8(buf,0); DO8(buf,8);
86fd98b2af3773437487af0df22c428f3db630949awaylonis  // Split up the crc
87fd98b2af3773437487af0df22c428f3db630949awaylonis  uint32_t sum1 = crc_ & 0xFFFF;
88fd98b2af3773437487af0df22c428f3db630949awaylonis  uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
89fd98b2af3773437487af0df22c428f3db630949awaylonis
90fd98b2af3773437487af0df22c428f3db630949awaylonis  // Do large blocks
91fd98b2af3773437487af0df22c428f3db630949awaylonis  while (size >= MAX_BLOCK) {
92fd98b2af3773437487af0df22c428f3db630949awaylonis    size -= MAX_BLOCK;
93fd98b2af3773437487af0df22c428f3db630949awaylonis    int block_count = MAX_BLOCK / 16;
94fd98b2af3773437487af0df22c428f3db630949awaylonis    do {
95fd98b2af3773437487af0df22c428f3db630949awaylonis      DO16(bytes);
96fd98b2af3773437487af0df22c428f3db630949awaylonis      bytes += 16;
97fd98b2af3773437487af0df22c428f3db630949awaylonis    } while (--block_count);
98fd98b2af3773437487af0df22c428f3db630949awaylonis    sum1 %= MOD_ADLER;
99fd98b2af3773437487af0df22c428f3db630949awaylonis    sum2 %= MOD_ADLER;
100fd98b2af3773437487af0df22c428f3db630949awaylonis  }
101fd98b2af3773437487af0df22c428f3db630949awaylonis
102fd98b2af3773437487af0df22c428f3db630949awaylonis  // Do remaining bytes
103fd98b2af3773437487af0df22c428f3db630949awaylonis  if (size) {
104fd98b2af3773437487af0df22c428f3db630949awaylonis    while (size >= 16) {
105fd98b2af3773437487af0df22c428f3db630949awaylonis      size -= 16;
106fd98b2af3773437487af0df22c428f3db630949awaylonis      DO16(bytes);
107fd98b2af3773437487af0df22c428f3db630949awaylonis      bytes += 16;
108fd98b2af3773437487af0df22c428f3db630949awaylonis    }
109fd98b2af3773437487af0df22c428f3db630949awaylonis    while (size--) {
110fd98b2af3773437487af0df22c428f3db630949awaylonis      sum1 += *bytes++;
111fd98b2af3773437487af0df22c428f3db630949awaylonis      sum2 += sum1;
112fd98b2af3773437487af0df22c428f3db630949awaylonis    }
113fd98b2af3773437487af0df22c428f3db630949awaylonis    sum1 %= MOD_ADLER;
114fd98b2af3773437487af0df22c428f3db630949awaylonis    sum2 %= MOD_ADLER;
115fd98b2af3773437487af0df22c428f3db630949awaylonis    crc_ = (sum2 << 16) | sum1;
116fd98b2af3773437487af0df22c428f3db630949awaylonis  }
117fd98b2af3773437487af0df22c428f3db630949awaylonis}
118fd98b2af3773437487af0df22c428f3db630949awaylonis
119fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
120fd98b2af3773437487af0df22c428f3db630949awaylonis  MD5_Update(&md5_context_, bytes, size);
121fd98b2af3773437487af0df22c428f3db630949awaylonis}
122fd98b2af3773437487af0df22c428f3db630949awaylonis
123fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateSHA1(unsigned char *bytes, size_t size) {
124fd98b2af3773437487af0df22c428f3db630949awaylonis  SHA_Update(&sha1_context_, bytes, size);
125fd98b2af3773437487af0df22c428f3db630949awaylonis}
126fd98b2af3773437487af0df22c428f3db630949awaylonis
1274ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachvoid MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
12887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  if (!update_function_ || !size)
12987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    return;
13087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
13187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  // Read up to 4k bytes at a time
13287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  unsigned char buffer[4096];
13387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  size_t buffer_size;
13487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  off_t file_offset = offset;
13587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  while (size > 0) {
13687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    if (size > sizeof(buffer)) {
13787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      buffer_size = sizeof(buffer);
13887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      size -= buffer_size;
13987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    } else {
14087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      buffer_size = size;
14187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      size = 0;
14287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    }
14387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
14487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    if (!walker->ReadBytes(buffer, buffer_size, file_offset))
14587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      return;
14687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
14787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    (this->*update_function_)(buffer, buffer_size);
14887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    file_offset += buffer_size;
14987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  }
150fd98b2af3773437487af0df22c428f3db630949awaylonis}
151fd98b2af3773437487af0df22c428f3db630949awaylonis
152fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
153255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek  struct breakpad_uuid_command uuid_cmd;
154fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd);
155fd98b2af3773437487af0df22c428f3db630949awaylonis
156fd98b2af3773437487af0df22c428f3db630949awaylonis  uuid_cmd.cmd = 0;
157fd98b2af3773437487af0df22c428f3db630949awaylonis  if (!walker.WalkHeader(cpu_type))
158fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
159fd98b2af3773437487af0df22c428f3db630949awaylonis
160fd98b2af3773437487af0df22c428f3db630949awaylonis  // If we found the command, we'll have initialized the uuid_command
161fd98b2af3773437487af0df22c428f3db630949awaylonis  // structure
162fd98b2af3773437487af0df22c428f3db630949awaylonis  if (uuid_cmd.cmd == LC_UUID) {
163fd98b2af3773437487af0df22c428f3db630949awaylonis    memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
164fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
165fd98b2af3773437487af0df22c428f3db630949awaylonis  }
166fd98b2af3773437487af0df22c428f3db630949awaylonis
167fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
168fd98b2af3773437487af0df22c428f3db630949awaylonis}
169fd98b2af3773437487af0df22c428f3db630949awaylonis
170fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
171fd98b2af3773437487af0df22c428f3db630949awaylonis  struct dylib_command dylib_cmd;
172fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoWalker walker(path_, IDWalkerCB, &dylib_cmd);
173fd98b2af3773437487af0df22c428f3db630949awaylonis
174fd98b2af3773437487af0df22c428f3db630949awaylonis  dylib_cmd.cmd = 0;
175fd98b2af3773437487af0df22c428f3db630949awaylonis  if (!walker.WalkHeader(cpu_type))
176fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
177fd98b2af3773437487af0df22c428f3db630949awaylonis
178fd98b2af3773437487af0df22c428f3db630949awaylonis  // If we found the command, we'll have initialized the dylib_command
179fd98b2af3773437487af0df22c428f3db630949awaylonis  // structure
180fd98b2af3773437487af0df22c428f3db630949awaylonis  if (dylib_cmd.cmd == LC_ID_DYLIB) {
1811a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // Take the hashed filename, version, and compatability version bytes
1821a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // to form the first 12 bytes, pad the rest with zeros
1831a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
1841a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // create a crude hash of the filename to generate the first 4 bytes
1851a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[0] = 0;
1861a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[1] = 0;
1871a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[2] = 0;
1881a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[3] = 0;
1891a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
1904ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach    for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
1911a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker      identifier[j%4] += path_[i];
1921a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    }
1931a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
194fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
195fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
196fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
197fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
198fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
199fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
200fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
201fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
202baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[12] = (cpu_type >> 24) & 0xFF;
203baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[13] = (cpu_type >> 16) & 0xFF;
204baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[14] = (cpu_type >> 8) & 0xFF;
205baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[15] = cpu_type & 0xFF;
206fd98b2af3773437487af0df22c428f3db630949awaylonis
207fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
208fd98b2af3773437487af0df22c428f3db630949awaylonis  }
209fd98b2af3773437487af0df22c428f3db630949awaylonis
210fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
211fd98b2af3773437487af0df22c428f3db630949awaylonis}
212fd98b2af3773437487af0df22c428f3db630949awaylonis
213fd98b2af3773437487af0df22c428f3db630949awaylonisuint32_t MachoID::Adler32(int cpu_type) {
214fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoWalker walker(path_, WalkerCB, this);
215fd98b2af3773437487af0df22c428f3db630949awaylonis  update_function_ = &MachoID::UpdateCRC;
216fd98b2af3773437487af0df22c428f3db630949awaylonis  crc_ = 0;
217fd98b2af3773437487af0df22c428f3db630949awaylonis
218fd98b2af3773437487af0df22c428f3db630949awaylonis  if (!walker.WalkHeader(cpu_type))
219fd98b2af3773437487af0df22c428f3db630949awaylonis    return 0;
220fd98b2af3773437487af0df22c428f3db630949awaylonis
221fd98b2af3773437487af0df22c428f3db630949awaylonis  return crc_;
222fd98b2af3773437487af0df22c428f3db630949awaylonis}
223fd98b2af3773437487af0df22c428f3db630949awaylonis
224fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
225fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoWalker walker(path_, WalkerCB, this);
226fd98b2af3773437487af0df22c428f3db630949awaylonis  update_function_ = &MachoID::UpdateMD5;
227fd98b2af3773437487af0df22c428f3db630949awaylonis
228fd98b2af3773437487af0df22c428f3db630949awaylonis  if (MD5_Init(&md5_context_)) {
229fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker.WalkHeader(cpu_type))
230fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
231fd98b2af3773437487af0df22c428f3db630949awaylonis
232fd98b2af3773437487af0df22c428f3db630949awaylonis    MD5_Final(identifier, &md5_context_);
233fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
234fd98b2af3773437487af0df22c428f3db630949awaylonis  }
235fd98b2af3773437487af0df22c428f3db630949awaylonis
236fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
237fd98b2af3773437487af0df22c428f3db630949awaylonis}
238fd98b2af3773437487af0df22c428f3db630949awaylonis
239fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::SHA1(int cpu_type, unsigned char identifier[16]) {
240fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoWalker walker(path_, WalkerCB, this);
241fd98b2af3773437487af0df22c428f3db630949awaylonis  update_function_ = &MachoID::UpdateSHA1;
242fd98b2af3773437487af0df22c428f3db630949awaylonis
243fd98b2af3773437487af0df22c428f3db630949awaylonis  if (SHA_Init(&sha1_context_)) {
244fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker.WalkHeader(cpu_type))
245fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
246fd98b2af3773437487af0df22c428f3db630949awaylonis
247fd98b2af3773437487af0df22c428f3db630949awaylonis    SHA_Final(identifier, &sha1_context_);
248fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
249fd98b2af3773437487af0df22c428f3db630949awaylonis  }
250fd98b2af3773437487af0df22c428f3db630949awaylonis
251fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
252fd98b2af3773437487af0df22c428f3db630949awaylonis}
253fd98b2af3773437487af0df22c428f3db630949awaylonis
254fd98b2af3773437487af0df22c428f3db630949awaylonis// static
255fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
256fd98b2af3773437487af0df22c428f3db630949awaylonis                       bool swap, void *context) {
257fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoID *macho_id = (MachoID *)context;
258fd98b2af3773437487af0df22c428f3db630949awaylonis
259fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_SEGMENT) {
260fd98b2af3773437487af0df22c428f3db630949awaylonis    struct segment_command seg;
261fd98b2af3773437487af0df22c428f3db630949awaylonis
262fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(&seg, sizeof(seg), offset))
263fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
264fd98b2af3773437487af0df22c428f3db630949awaylonis
265fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
266fd98b2af3773437487af0df22c428f3db630949awaylonis      swap_segment_command(&seg, NXHostByteOrder());
267fd98b2af3773437487af0df22c428f3db630949awaylonis
268983264848d5372d8e64d62eb67f672c71e4b6470waylonis    struct mach_header_64 header;
269983264848d5372d8e64d62eb67f672c71e4b6470waylonis    off_t header_offset;
270983264848d5372d8e64d62eb67f672c71e4b6470waylonis
271983264848d5372d8e64d62eb67f672c71e4b6470waylonis    if (!walker->CurrentHeader(&header, &header_offset))
272983264848d5372d8e64d62eb67f672c71e4b6470waylonis      return false;
273983264848d5372d8e64d62eb67f672c71e4b6470waylonis
27487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // Process segments that have sections:
27587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
27687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    offset += sizeof(struct segment_command);
27787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    struct section sec;
27887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    for (unsigned long i = 0; i < seg.nsects; ++i) {
27987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (!walker->ReadBytes(&sec, sizeof(sec), offset))
28087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis        return false;
28187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
28287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (swap)
28387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis        swap_section(&sec, 1, NXHostByteOrder());
28487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
2852e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // sections of type S_ZEROFILL are "virtual" and contain no data
2862e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // in the file itself
2872e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
2882e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker        macho_id->Update(walker, header_offset + sec.offset, sec.size);
2892e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker
29087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      offset += sizeof(struct section);
29187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    }
292fd98b2af3773437487af0df22c428f3db630949awaylonis  } else if (cmd->cmd == LC_SEGMENT_64) {
293fd98b2af3773437487af0df22c428f3db630949awaylonis    struct segment_command_64 seg64;
294fd98b2af3773437487af0df22c428f3db630949awaylonis
295fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
296fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
297fd98b2af3773437487af0df22c428f3db630949awaylonis
298fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
299255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
300fd98b2af3773437487af0df22c428f3db630949awaylonis
301983264848d5372d8e64d62eb67f672c71e4b6470waylonis    struct mach_header_64 header;
302983264848d5372d8e64d62eb67f672c71e4b6470waylonis    off_t header_offset;
303983264848d5372d8e64d62eb67f672c71e4b6470waylonis
304983264848d5372d8e64d62eb67f672c71e4b6470waylonis    if (!walker->CurrentHeader(&header, &header_offset))
305983264848d5372d8e64d62eb67f672c71e4b6470waylonis      return false;
306983264848d5372d8e64d62eb67f672c71e4b6470waylonis
30787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // Process segments that have sections:
30887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
30987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    offset += sizeof(struct segment_command_64);
31087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    struct section_64 sec64;
31187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    for (unsigned long i = 0; i < seg64.nsects; ++i) {
31287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
313fd98b2af3773437487af0df22c428f3db630949awaylonis        return false;
314fd98b2af3773437487af0df22c428f3db630949awaylonis
31587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (swap)
316255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek        breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
31787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
3182e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // sections of type S_ZEROFILL are "virtual" and contain no data
3192e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // in the file itself
3202e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
3214ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach        macho_id->Update(walker,
3224ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach                         header_offset + sec64.offset,
3234ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach                         (size_t)sec64.size);
3242e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker
32587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      offset += sizeof(struct section_64);
326fd98b2af3773437487af0df22c428f3db630949awaylonis    }
327fd98b2af3773437487af0df22c428f3db630949awaylonis  }
328fd98b2af3773437487af0df22c428f3db630949awaylonis
329fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
330fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
331fd98b2af3773437487af0df22c428f3db630949awaylonis}
332fd98b2af3773437487af0df22c428f3db630949awaylonis
333fd98b2af3773437487af0df22c428f3db630949awaylonis// static
334fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
335fd98b2af3773437487af0df22c428f3db630949awaylonis                           bool swap, void *context) {
336fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_UUID) {
337255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek    struct breakpad_uuid_command *uuid_cmd =
338255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      (struct breakpad_uuid_command *)context;
339fd98b2af3773437487af0df22c428f3db630949awaylonis
340255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek    if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
341255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek                           offset))
342fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
343fd98b2af3773437487af0df22c428f3db630949awaylonis
344fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
345255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
346fd98b2af3773437487af0df22c428f3db630949awaylonis
347fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
348fd98b2af3773437487af0df22c428f3db630949awaylonis  }
349fd98b2af3773437487af0df22c428f3db630949awaylonis
350fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
351fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
352fd98b2af3773437487af0df22c428f3db630949awaylonis}
353fd98b2af3773437487af0df22c428f3db630949awaylonis
354fd98b2af3773437487af0df22c428f3db630949awaylonis// static
355fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
356fd98b2af3773437487af0df22c428f3db630949awaylonis                         bool swap, void *context) {
357fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_ID_DYLIB) {
358fd98b2af3773437487af0df22c428f3db630949awaylonis    struct dylib_command *dylib_cmd = (struct dylib_command *)context;
359fd98b2af3773437487af0df22c428f3db630949awaylonis
360fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
361fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
362fd98b2af3773437487af0df22c428f3db630949awaylonis
363fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
364fd98b2af3773437487af0df22c428f3db630949awaylonis      swap_dylib_command(dylib_cmd, NXHostByteOrder());
365fd98b2af3773437487af0df22c428f3db630949awaylonis
366fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
367fd98b2af3773437487af0df22c428f3db630949awaylonis  }
368fd98b2af3773437487af0df22c428f3db630949awaylonis
369fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
370fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
371fd98b2af3773437487af0df22c428f3db630949awaylonis}
372fd98b2af3773437487af0df22c428f3db630949awaylonis
373fd98b2af3773437487af0df22c428f3db630949awaylonis}  // namespace MacFileUtilities
374