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 <stdio.h>
418aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <stdlib.h>
428aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <string.h>
438aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <sys/time.h>
448aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <sys/types.h>
458aef89f021c687e96c66cb99b5dac312324e785cladderbreaker  #include <unistd.h>
468aef89f021c687e96c66cb99b5dac312324e785cladderbreaker}
47fd98b2af3773437487af0df22c428f3db630949awaylonis
48fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_id.h"
49fd98b2af3773437487af0df22c428f3db630949awaylonis#include "common/mac/macho_walker.h"
50255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek#include "common/mac/macho_utilities.h"
51fd98b2af3773437487af0df22c428f3db630949awaylonis
52fd98b2af3773437487af0df22c428f3db630949awaylonisnamespace MacFileUtilities {
53fd98b2af3773437487af0df22c428f3db630949awaylonis
5497bed584e322953bad9eee43c49955aa4684b19eted.mielczarekusing google_breakpad::MD5Init;
5597bed584e322953bad9eee43c49955aa4684b19eted.mielczarekusing google_breakpad::MD5Update;
5697bed584e322953bad9eee43c49955aa4684b19eted.mielczarekusing google_breakpad::MD5Final;
5797bed584e322953bad9eee43c49955aa4684b19eted.mielczarek
584ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachMachoID::MachoID(const char *path)
598fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org   : memory_(0),
608fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org     memory_size_(0),
618fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org     crc_(0),
628fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org     md5_context_(),
638fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org     update_function_(NULL) {
648fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org  strlcpy(path_, path, sizeof(path_));
658fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org}
668fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org
678fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.orgMachoID::MachoID(const char *path, void *memory, size_t size)
688fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org   : memory_(memory),
698fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org     memory_size_(size),
704ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     crc_(0),
714ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     md5_context_(),
724ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach     update_function_(NULL) {
73fd98b2af3773437487af0df22c428f3db630949awaylonis  strlcpy(path_, path, sizeof(path_));
74fd98b2af3773437487af0df22c428f3db630949awaylonis}
75fd98b2af3773437487af0df22c428f3db630949awaylonis
76fd98b2af3773437487af0df22c428f3db630949awaylonisMachoID::~MachoID() {
77fd98b2af3773437487af0df22c428f3db630949awaylonis}
78fd98b2af3773437487af0df22c428f3db630949awaylonis
79fd98b2af3773437487af0df22c428f3db630949awaylonis// The CRC info is from http://en.wikipedia.org/wiki/Adler-32
80fd98b2af3773437487af0df22c428f3db630949awaylonis// With optimizations from http://www.zlib.net/
81fd98b2af3773437487af0df22c428f3db630949awaylonis
82fd98b2af3773437487af0df22c428f3db630949awaylonis// The largest prime smaller than 65536
83fd98b2af3773437487af0df22c428f3db630949awaylonis#define MOD_ADLER 65521
84fd98b2af3773437487af0df22c428f3db630949awaylonis// MAX_BLOCK is the largest n such that 255n(n+1)/2 + (n+1)(MAX_BLOCK-1) <= 2^32-1
85fd98b2af3773437487af0df22c428f3db630949awaylonis#define MAX_BLOCK 5552
86fd98b2af3773437487af0df22c428f3db630949awaylonis
87fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateCRC(unsigned char *bytes, size_t size) {
88fd98b2af3773437487af0df22c428f3db630949awaylonis// Unrolled loops for summing
89fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO1(buf,i)  {sum1 += (buf)[i]; sum2 += sum1;}
90fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
91fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
92fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
93fd98b2af3773437487af0df22c428f3db630949awaylonis#define DO16(buf)   DO8(buf,0); DO8(buf,8);
94fd98b2af3773437487af0df22c428f3db630949awaylonis  // Split up the crc
95fd98b2af3773437487af0df22c428f3db630949awaylonis  uint32_t sum1 = crc_ & 0xFFFF;
96fd98b2af3773437487af0df22c428f3db630949awaylonis  uint32_t sum2 = (crc_ >> 16) & 0xFFFF;
97fd98b2af3773437487af0df22c428f3db630949awaylonis
98fd98b2af3773437487af0df22c428f3db630949awaylonis  // Do large blocks
99fd98b2af3773437487af0df22c428f3db630949awaylonis  while (size >= MAX_BLOCK) {
100fd98b2af3773437487af0df22c428f3db630949awaylonis    size -= MAX_BLOCK;
101fd98b2af3773437487af0df22c428f3db630949awaylonis    int block_count = MAX_BLOCK / 16;
102fd98b2af3773437487af0df22c428f3db630949awaylonis    do {
103fd98b2af3773437487af0df22c428f3db630949awaylonis      DO16(bytes);
104fd98b2af3773437487af0df22c428f3db630949awaylonis      bytes += 16;
105fd98b2af3773437487af0df22c428f3db630949awaylonis    } while (--block_count);
106fd98b2af3773437487af0df22c428f3db630949awaylonis    sum1 %= MOD_ADLER;
107fd98b2af3773437487af0df22c428f3db630949awaylonis    sum2 %= MOD_ADLER;
108fd98b2af3773437487af0df22c428f3db630949awaylonis  }
109fd98b2af3773437487af0df22c428f3db630949awaylonis
110fd98b2af3773437487af0df22c428f3db630949awaylonis  // Do remaining bytes
111fd98b2af3773437487af0df22c428f3db630949awaylonis  if (size) {
112fd98b2af3773437487af0df22c428f3db630949awaylonis    while (size >= 16) {
113fd98b2af3773437487af0df22c428f3db630949awaylonis      size -= 16;
114fd98b2af3773437487af0df22c428f3db630949awaylonis      DO16(bytes);
115fd98b2af3773437487af0df22c428f3db630949awaylonis      bytes += 16;
116fd98b2af3773437487af0df22c428f3db630949awaylonis    }
117fd98b2af3773437487af0df22c428f3db630949awaylonis    while (size--) {
118fd98b2af3773437487af0df22c428f3db630949awaylonis      sum1 += *bytes++;
119fd98b2af3773437487af0df22c428f3db630949awaylonis      sum2 += sum1;
120fd98b2af3773437487af0df22c428f3db630949awaylonis    }
121fd98b2af3773437487af0df22c428f3db630949awaylonis    sum1 %= MOD_ADLER;
122fd98b2af3773437487af0df22c428f3db630949awaylonis    sum2 %= MOD_ADLER;
123fd98b2af3773437487af0df22c428f3db630949awaylonis    crc_ = (sum2 << 16) | sum1;
124fd98b2af3773437487af0df22c428f3db630949awaylonis  }
125fd98b2af3773437487af0df22c428f3db630949awaylonis}
126fd98b2af3773437487af0df22c428f3db630949awaylonis
127fd98b2af3773437487af0df22c428f3db630949awaylonisvoid MachoID::UpdateMD5(unsigned char *bytes, size_t size) {
128360347fe279b42eb00cef7863f3d44e7eb0d236civan.penkov@gmail.com  MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
129fd98b2af3773437487af0df22c428f3db630949awaylonis}
130fd98b2af3773437487af0df22c428f3db630949awaylonis
1314ac61acb3a7dad6ce722fe07564be8ec92713228dmaclachvoid MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
13287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  if (!update_function_ || !size)
13387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    return;
13487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
13587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  // Read up to 4k bytes at a time
13687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  unsigned char buffer[4096];
13787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  size_t buffer_size;
13887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  off_t file_offset = offset;
13987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  while (size > 0) {
14087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    if (size > sizeof(buffer)) {
14187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      buffer_size = sizeof(buffer);
14287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      size -= buffer_size;
14387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    } else {
14487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      buffer_size = size;
14587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      size = 0;
14687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    }
14787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
14887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    if (!walker->ReadBytes(buffer, buffer_size, file_offset))
14987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      return;
15087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
15187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    (this->*update_function_)(buffer, buffer_size);
15287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    file_offset += buffer_size;
15387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis  }
154fd98b2af3773437487af0df22c428f3db630949awaylonis}
155fd98b2af3773437487af0df22c428f3db630949awaylonis
156b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.orgbool MachoID::UUIDCommand(cpu_type_t cpu_type,
157b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org                          cpu_subtype_t cpu_subtype,
158b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org                          unsigned char bytes[16]) {
159255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek  struct breakpad_uuid_command uuid_cmd;
160fd98b2af3773437487af0df22c428f3db630949awaylonis  uuid_cmd.cmd = 0;
161b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org  if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
162fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
163fd98b2af3773437487af0df22c428f3db630949awaylonis
164fd98b2af3773437487af0df22c428f3db630949awaylonis  // If we found the command, we'll have initialized the uuid_command
165fd98b2af3773437487af0df22c428f3db630949awaylonis  // structure
166fd98b2af3773437487af0df22c428f3db630949awaylonis  if (uuid_cmd.cmd == LC_UUID) {
167fd98b2af3773437487af0df22c428f3db630949awaylonis    memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
168fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
169fd98b2af3773437487af0df22c428f3db630949awaylonis  }
170fd98b2af3773437487af0df22c428f3db630949awaylonis
171fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
172fd98b2af3773437487af0df22c428f3db630949awaylonis}
173fd98b2af3773437487af0df22c428f3db630949awaylonis
174b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.orgbool MachoID::IDCommand(cpu_type_t cpu_type,
175b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org                        cpu_subtype_t cpu_subtype,
176b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org                        unsigned char identifier[16]) {
177fd98b2af3773437487af0df22c428f3db630949awaylonis  struct dylib_command dylib_cmd;
178fd98b2af3773437487af0df22c428f3db630949awaylonis  dylib_cmd.cmd = 0;
179b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org  if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
180fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
181fd98b2af3773437487af0df22c428f3db630949awaylonis
182fd98b2af3773437487af0df22c428f3db630949awaylonis  // If we found the command, we'll have initialized the dylib_command
183fd98b2af3773437487af0df22c428f3db630949awaylonis  // structure
184fd98b2af3773437487af0df22c428f3db630949awaylonis  if (dylib_cmd.cmd == LC_ID_DYLIB) {
1851a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // Take the hashed filename, version, and compatability version bytes
1861a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // to form the first 12 bytes, pad the rest with zeros
1871a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
1881a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    // create a crude hash of the filename to generate the first 4 bytes
1891a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[0] = 0;
1901a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[1] = 0;
1911a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[2] = 0;
1921a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    identifier[3] = 0;
1931a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
1944ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach    for (int j = 0, i = (int)strlen(path_)-1; i>=0 && path_[i]!='/'; ++j, --i) {
1951a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker      identifier[j%4] += path_[i];
1961a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker    }
1971a4310017ec3af237399ccbc4ff096de4c08cf6dladderbreaker
198fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[4] = (dylib_cmd.dylib.current_version >> 24) & 0xFF;
199fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[5] = (dylib_cmd.dylib.current_version >> 16) & 0xFF;
200fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[6] = (dylib_cmd.dylib.current_version >> 8) & 0xFF;
201fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[7] = dylib_cmd.dylib.current_version & 0xFF;
202fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[8] = (dylib_cmd.dylib.compatibility_version >> 24) & 0xFF;
203fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[9] = (dylib_cmd.dylib.compatibility_version >> 16) & 0xFF;
204fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[10] = (dylib_cmd.dylib.compatibility_version >> 8) & 0xFF;
205fd98b2af3773437487af0df22c428f3db630949awaylonis    identifier[11] = dylib_cmd.dylib.compatibility_version & 0xFF;
206baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[12] = (cpu_type >> 24) & 0xFF;
207baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[13] = (cpu_type >> 16) & 0xFF;
208baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[14] = (cpu_type >> 8) & 0xFF;
209baaeb5af7149f9a4ced95331a6c577f6c0c96e34ladderbreaker    identifier[15] = cpu_type & 0xFF;
210fd98b2af3773437487af0df22c428f3db630949awaylonis
211fd98b2af3773437487af0df22c428f3db630949awaylonis    return true;
212fd98b2af3773437487af0df22c428f3db630949awaylonis  }
213fd98b2af3773437487af0df22c428f3db630949awaylonis
214fd98b2af3773437487af0df22c428f3db630949awaylonis  return false;
215fd98b2af3773437487af0df22c428f3db630949awaylonis}
216fd98b2af3773437487af0df22c428f3db630949awaylonis
217b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.orguint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
218fd98b2af3773437487af0df22c428f3db630949awaylonis  update_function_ = &MachoID::UpdateCRC;
219fd98b2af3773437487af0df22c428f3db630949awaylonis  crc_ = 0;
220fd98b2af3773437487af0df22c428f3db630949awaylonis
221b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org  if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
222fd98b2af3773437487af0df22c428f3db630949awaylonis    return 0;
223fd98b2af3773437487af0df22c428f3db630949awaylonis
224fd98b2af3773437487af0df22c428f3db630949awaylonis  return crc_;
225fd98b2af3773437487af0df22c428f3db630949awaylonis}
226fd98b2af3773437487af0df22c428f3db630949awaylonis
227b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.orgbool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
228fd98b2af3773437487af0df22c428f3db630949awaylonis  update_function_ = &MachoID::UpdateMD5;
229fd98b2af3773437487af0df22c428f3db630949awaylonis
230e919fdd63b4550a3261422ffde3c8d631007f75bmark@chromium.org  MD5Init(&md5_context_);
231fd98b2af3773437487af0df22c428f3db630949awaylonis
232b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org  if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
233e919fdd63b4550a3261422ffde3c8d631007f75bmark@chromium.org    return false;
234fd98b2af3773437487af0df22c428f3db630949awaylonis
235e919fdd63b4550a3261422ffde3c8d631007f75bmark@chromium.org  MD5Final(identifier, &md5_context_);
236e919fdd63b4550a3261422ffde3c8d631007f75bmark@chromium.org  return true;
237fd98b2af3773437487af0df22c428f3db630949awaylonis}
238fd98b2af3773437487af0df22c428f3db630949awaylonis
239b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.orgbool MachoID::WalkHeader(cpu_type_t cpu_type,
240b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org                         cpu_subtype_t cpu_subtype,
2418fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org                         MachoWalker::LoadCommandCallback callback,
2428fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org                         void *context) {
2438fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org  if (memory_) {
2448fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org    MachoWalker walker(memory_, memory_size_, callback, context);
245b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org    return walker.WalkHeader(cpu_type, cpu_subtype);
2468fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org  } else {
2478fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org    MachoWalker walker(path_, callback, context);
248b2cb7ad7bc83205d23f77b660438bf8e8d16fcb5qsr@chromium.org    return walker.WalkHeader(cpu_type, cpu_subtype);
2498fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org  }
2508fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org}
2518fac6df2a0dfbfe7512c3f6616cda4cbac4f0d9dqsr@chromium.org
252fd98b2af3773437487af0df22c428f3db630949awaylonis// static
253fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
254fd98b2af3773437487af0df22c428f3db630949awaylonis                       bool swap, void *context) {
255fd98b2af3773437487af0df22c428f3db630949awaylonis  MachoID *macho_id = (MachoID *)context;
256fd98b2af3773437487af0df22c428f3db630949awaylonis
257fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_SEGMENT) {
258fd98b2af3773437487af0df22c428f3db630949awaylonis    struct segment_command seg;
259fd98b2af3773437487af0df22c428f3db630949awaylonis
260fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(&seg, sizeof(seg), offset))
261fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
262fd98b2af3773437487af0df22c428f3db630949awaylonis
263fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
264fd98b2af3773437487af0df22c428f3db630949awaylonis      swap_segment_command(&seg, NXHostByteOrder());
265fd98b2af3773437487af0df22c428f3db630949awaylonis
266983264848d5372d8e64d62eb67f672c71e4b6470waylonis    struct mach_header_64 header;
267983264848d5372d8e64d62eb67f672c71e4b6470waylonis    off_t header_offset;
268983264848d5372d8e64d62eb67f672c71e4b6470waylonis
269983264848d5372d8e64d62eb67f672c71e4b6470waylonis    if (!walker->CurrentHeader(&header, &header_offset))
270983264848d5372d8e64d62eb67f672c71e4b6470waylonis      return false;
271983264848d5372d8e64d62eb67f672c71e4b6470waylonis
27287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // Process segments that have sections:
27387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
27487d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    offset += sizeof(struct segment_command);
27587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    struct section sec;
27687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    for (unsigned long i = 0; i < seg.nsects; ++i) {
27787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (!walker->ReadBytes(&sec, sizeof(sec), offset))
27887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis        return false;
27987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
28087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (swap)
28187d965538b4f9306a4c6e59fcb741b5a11a95963waylonis        swap_section(&sec, 1, NXHostByteOrder());
28287d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
2832e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // sections of type S_ZEROFILL are "virtual" and contain no data
2842e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // in the file itself
2852e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
2862e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker        macho_id->Update(walker, header_offset + sec.offset, sec.size);
2872e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker
28887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      offset += sizeof(struct section);
28987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    }
290fd98b2af3773437487af0df22c428f3db630949awaylonis  } else if (cmd->cmd == LC_SEGMENT_64) {
291fd98b2af3773437487af0df22c428f3db630949awaylonis    struct segment_command_64 seg64;
292fd98b2af3773437487af0df22c428f3db630949awaylonis
293fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
294fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
295fd98b2af3773437487af0df22c428f3db630949awaylonis
296fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
297255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
298fd98b2af3773437487af0df22c428f3db630949awaylonis
299983264848d5372d8e64d62eb67f672c71e4b6470waylonis    struct mach_header_64 header;
300983264848d5372d8e64d62eb67f672c71e4b6470waylonis    off_t header_offset;
301983264848d5372d8e64d62eb67f672c71e4b6470waylonis
302983264848d5372d8e64d62eb67f672c71e4b6470waylonis    if (!walker->CurrentHeader(&header, &header_offset))
303983264848d5372d8e64d62eb67f672c71e4b6470waylonis      return false;
304983264848d5372d8e64d62eb67f672c71e4b6470waylonis
30587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // Process segments that have sections:
30687d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
30787d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    offset += sizeof(struct segment_command_64);
30887d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    struct section_64 sec64;
30987d965538b4f9306a4c6e59fcb741b5a11a95963waylonis    for (unsigned long i = 0; i < seg64.nsects; ++i) {
31087d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
311fd98b2af3773437487af0df22c428f3db630949awaylonis        return false;
312fd98b2af3773437487af0df22c428f3db630949awaylonis
31387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      if (swap)
314255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek        breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
31587d965538b4f9306a4c6e59fcb741b5a11a95963waylonis
3162e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // sections of type S_ZEROFILL are "virtual" and contain no data
3172e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      // in the file itself
3182e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker      if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
3194ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach        macho_id->Update(walker,
3204ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach                         header_offset + sec64.offset,
3214ac61acb3a7dad6ce722fe07564be8ec92713228dmaclach                         (size_t)sec64.size);
3222e86dfe70513091a0fb8f5725a4c81c476f993e8ladderbreaker
32387d965538b4f9306a4c6e59fcb741b5a11a95963waylonis      offset += sizeof(struct section_64);
324fd98b2af3773437487af0df22c428f3db630949awaylonis    }
325fd98b2af3773437487af0df22c428f3db630949awaylonis  }
326fd98b2af3773437487af0df22c428f3db630949awaylonis
327fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
328fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
329fd98b2af3773437487af0df22c428f3db630949awaylonis}
330fd98b2af3773437487af0df22c428f3db630949awaylonis
331fd98b2af3773437487af0df22c428f3db630949awaylonis// static
332fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
333fd98b2af3773437487af0df22c428f3db630949awaylonis                           bool swap, void *context) {
334fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_UUID) {
335255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek    struct breakpad_uuid_command *uuid_cmd =
336255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      (struct breakpad_uuid_command *)context;
337fd98b2af3773437487af0df22c428f3db630949awaylonis
338255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek    if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
339255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek                           offset))
340fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
341fd98b2af3773437487af0df22c428f3db630949awaylonis
342fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
343255bbe93ed7aef5418000339b6cdb5677bf9e4d6ted.mielczarek      breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
344fd98b2af3773437487af0df22c428f3db630949awaylonis
345fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
346fd98b2af3773437487af0df22c428f3db630949awaylonis  }
347fd98b2af3773437487af0df22c428f3db630949awaylonis
348fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
349fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
350fd98b2af3773437487af0df22c428f3db630949awaylonis}
351fd98b2af3773437487af0df22c428f3db630949awaylonis
352fd98b2af3773437487af0df22c428f3db630949awaylonis// static
353fd98b2af3773437487af0df22c428f3db630949awaylonisbool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
354fd98b2af3773437487af0df22c428f3db630949awaylonis                         bool swap, void *context) {
355fd98b2af3773437487af0df22c428f3db630949awaylonis  if (cmd->cmd == LC_ID_DYLIB) {
356fd98b2af3773437487af0df22c428f3db630949awaylonis    struct dylib_command *dylib_cmd = (struct dylib_command *)context;
357fd98b2af3773437487af0df22c428f3db630949awaylonis
358fd98b2af3773437487af0df22c428f3db630949awaylonis    if (!walker->ReadBytes(dylib_cmd, sizeof(struct dylib_command), offset))
359fd98b2af3773437487af0df22c428f3db630949awaylonis      return false;
360fd98b2af3773437487af0df22c428f3db630949awaylonis
361fd98b2af3773437487af0df22c428f3db630949awaylonis    if (swap)
362fd98b2af3773437487af0df22c428f3db630949awaylonis      swap_dylib_command(dylib_cmd, NXHostByteOrder());
363fd98b2af3773437487af0df22c428f3db630949awaylonis
364fd98b2af3773437487af0df22c428f3db630949awaylonis    return false;
365fd98b2af3773437487af0df22c428f3db630949awaylonis  }
366fd98b2af3773437487af0df22c428f3db630949awaylonis
367fd98b2af3773437487af0df22c428f3db630949awaylonis  // Continue processing
368fd98b2af3773437487af0df22c428f3db630949awaylonis  return true;
369fd98b2af3773437487af0df22c428f3db630949awaylonis}
370fd98b2af3773437487af0df22c428f3db630949awaylonis
371fd98b2af3773437487af0df22c428f3db630949awaylonis}  // namespace MacFileUtilities
372