1*9712c20fSFrederick Mayle // Copyright 2006 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle // * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle // * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle // * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle
29*9712c20fSFrederick Mayle // macho_id.cc: Functions to gather identifying information from a macho file
30*9712c20fSFrederick Mayle //
31*9712c20fSFrederick Mayle // See macho_id.h for documentation
32*9712c20fSFrederick Mayle //
33*9712c20fSFrederick Mayle // Author: Dan Waylonis
34*9712c20fSFrederick Mayle
35*9712c20fSFrederick Mayle
36*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
37*9712c20fSFrederick Mayle #include <config.h> // Must come first
38*9712c20fSFrederick Mayle #endif
39*9712c20fSFrederick Mayle
40*9712c20fSFrederick Mayle #include <fcntl.h>
41*9712c20fSFrederick Mayle #include <mach-o/loader.h>
42*9712c20fSFrederick Mayle #include <stdio.h>
43*9712c20fSFrederick Mayle #include <string.h>
44*9712c20fSFrederick Mayle
45*9712c20fSFrederick Mayle #include "common/mac/macho_id.h"
46*9712c20fSFrederick Mayle #include "common/mac/macho_walker.h"
47*9712c20fSFrederick Mayle #include "common/mac/macho_utilities.h"
48*9712c20fSFrederick Mayle
49*9712c20fSFrederick Mayle namespace MacFileUtilities {
50*9712c20fSFrederick Mayle
51*9712c20fSFrederick Mayle using google_breakpad::MD5Init;
52*9712c20fSFrederick Mayle using google_breakpad::MD5Update;
53*9712c20fSFrederick Mayle using google_breakpad::MD5Final;
54*9712c20fSFrederick Mayle
MachoID(const char * path)55*9712c20fSFrederick Mayle MachoID::MachoID(const char* path)
56*9712c20fSFrederick Mayle : memory_(0), memory_size_(0), md5_context_(), update_function_(NULL) {
57*9712c20fSFrederick Mayle snprintf(path_, sizeof(path_), "%s", path);
58*9712c20fSFrederick Mayle }
59*9712c20fSFrederick Mayle
MachoID(void * memory,size_t size)60*9712c20fSFrederick Mayle MachoID::MachoID(void* memory, size_t size)
61*9712c20fSFrederick Mayle : path_(),
62*9712c20fSFrederick Mayle memory_(memory),
63*9712c20fSFrederick Mayle memory_size_(size),
64*9712c20fSFrederick Mayle md5_context_(),
65*9712c20fSFrederick Mayle update_function_(NULL) {}
66*9712c20fSFrederick Mayle
~MachoID()67*9712c20fSFrederick Mayle MachoID::~MachoID() {}
68*9712c20fSFrederick Mayle
UpdateMD5(unsigned char * bytes,size_t size)69*9712c20fSFrederick Mayle void MachoID::UpdateMD5(unsigned char* bytes, size_t size) {
70*9712c20fSFrederick Mayle MD5Update(&md5_context_, bytes, static_cast<unsigned>(size));
71*9712c20fSFrederick Mayle }
72*9712c20fSFrederick Mayle
Update(MachoWalker * walker,off_t offset,size_t size)73*9712c20fSFrederick Mayle void MachoID::Update(MachoWalker* walker, off_t offset, size_t size) {
74*9712c20fSFrederick Mayle if (!update_function_ || !size)
75*9712c20fSFrederick Mayle return;
76*9712c20fSFrederick Mayle
77*9712c20fSFrederick Mayle // Read up to 4k bytes at a time
78*9712c20fSFrederick Mayle unsigned char buffer[4096];
79*9712c20fSFrederick Mayle size_t buffer_size;
80*9712c20fSFrederick Mayle off_t file_offset = offset;
81*9712c20fSFrederick Mayle while (size > 0) {
82*9712c20fSFrederick Mayle if (size > sizeof(buffer)) {
83*9712c20fSFrederick Mayle buffer_size = sizeof(buffer);
84*9712c20fSFrederick Mayle size -= buffer_size;
85*9712c20fSFrederick Mayle } else {
86*9712c20fSFrederick Mayle buffer_size = size;
87*9712c20fSFrederick Mayle size = 0;
88*9712c20fSFrederick Mayle }
89*9712c20fSFrederick Mayle
90*9712c20fSFrederick Mayle if (!walker->ReadBytes(buffer, buffer_size, file_offset))
91*9712c20fSFrederick Mayle return;
92*9712c20fSFrederick Mayle
93*9712c20fSFrederick Mayle (this->*update_function_)(buffer, buffer_size);
94*9712c20fSFrederick Mayle file_offset += buffer_size;
95*9712c20fSFrederick Mayle }
96*9712c20fSFrederick Mayle }
97*9712c20fSFrederick Mayle
UUIDCommand(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype,unsigned char bytes[16])98*9712c20fSFrederick Mayle bool MachoID::UUIDCommand(cpu_type_t cpu_type,
99*9712c20fSFrederick Mayle cpu_subtype_t cpu_subtype,
100*9712c20fSFrederick Mayle unsigned char bytes[16]) {
101*9712c20fSFrederick Mayle struct breakpad_uuid_command uuid_cmd;
102*9712c20fSFrederick Mayle uuid_cmd.cmd = 0;
103*9712c20fSFrederick Mayle if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
104*9712c20fSFrederick Mayle return false;
105*9712c20fSFrederick Mayle
106*9712c20fSFrederick Mayle // If we found the command, we'll have initialized the uuid_command
107*9712c20fSFrederick Mayle // structure
108*9712c20fSFrederick Mayle if (uuid_cmd.cmd == LC_UUID) {
109*9712c20fSFrederick Mayle memcpy(bytes, uuid_cmd.uuid, sizeof(uuid_cmd.uuid));
110*9712c20fSFrederick Mayle return true;
111*9712c20fSFrederick Mayle }
112*9712c20fSFrederick Mayle
113*9712c20fSFrederick Mayle return false;
114*9712c20fSFrederick Mayle }
115*9712c20fSFrederick Mayle
MD5(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype,unsigned char identifier[16])116*9712c20fSFrederick Mayle bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
117*9712c20fSFrederick Mayle update_function_ = &MachoID::UpdateMD5;
118*9712c20fSFrederick Mayle
119*9712c20fSFrederick Mayle MD5Init(&md5_context_);
120*9712c20fSFrederick Mayle
121*9712c20fSFrederick Mayle if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
122*9712c20fSFrederick Mayle return false;
123*9712c20fSFrederick Mayle
124*9712c20fSFrederick Mayle MD5Final(identifier, &md5_context_);
125*9712c20fSFrederick Mayle return true;
126*9712c20fSFrederick Mayle }
127*9712c20fSFrederick Mayle
WalkHeader(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype,MachoWalker::LoadCommandCallback callback,void * context)128*9712c20fSFrederick Mayle bool MachoID::WalkHeader(cpu_type_t cpu_type,
129*9712c20fSFrederick Mayle cpu_subtype_t cpu_subtype,
130*9712c20fSFrederick Mayle MachoWalker::LoadCommandCallback callback,
131*9712c20fSFrederick Mayle void* context) {
132*9712c20fSFrederick Mayle if (memory_) {
133*9712c20fSFrederick Mayle MachoWalker walker(memory_, memory_size_, callback, context);
134*9712c20fSFrederick Mayle return walker.WalkHeader(cpu_type, cpu_subtype);
135*9712c20fSFrederick Mayle } else {
136*9712c20fSFrederick Mayle MachoWalker walker(path_, callback, context);
137*9712c20fSFrederick Mayle return walker.WalkHeader(cpu_type, cpu_subtype);
138*9712c20fSFrederick Mayle }
139*9712c20fSFrederick Mayle }
140*9712c20fSFrederick Mayle
141*9712c20fSFrederick Mayle // static
WalkerCB(MachoWalker * walker,load_command * cmd,off_t offset,bool swap,void * context)142*9712c20fSFrederick Mayle bool MachoID::WalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
143*9712c20fSFrederick Mayle bool swap, void* context) {
144*9712c20fSFrederick Mayle MachoID* macho_id = (MachoID*)context;
145*9712c20fSFrederick Mayle
146*9712c20fSFrederick Mayle if (cmd->cmd == LC_SEGMENT) {
147*9712c20fSFrederick Mayle struct segment_command seg;
148*9712c20fSFrederick Mayle
149*9712c20fSFrederick Mayle if (!walker->ReadBytes(&seg, sizeof(seg), offset))
150*9712c20fSFrederick Mayle return false;
151*9712c20fSFrederick Mayle
152*9712c20fSFrederick Mayle if (swap)
153*9712c20fSFrederick Mayle breakpad_swap_segment_command(&seg);
154*9712c20fSFrederick Mayle
155*9712c20fSFrederick Mayle struct mach_header_64 header;
156*9712c20fSFrederick Mayle off_t header_offset;
157*9712c20fSFrederick Mayle
158*9712c20fSFrederick Mayle if (!walker->CurrentHeader(&header, &header_offset))
159*9712c20fSFrederick Mayle return false;
160*9712c20fSFrederick Mayle
161*9712c20fSFrederick Mayle // Process segments that have sections:
162*9712c20fSFrederick Mayle // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
163*9712c20fSFrederick Mayle offset += sizeof(struct segment_command);
164*9712c20fSFrederick Mayle struct section sec;
165*9712c20fSFrederick Mayle for (unsigned long i = 0; i < seg.nsects; ++i) {
166*9712c20fSFrederick Mayle if (!walker->ReadBytes(&sec, sizeof(sec), offset))
167*9712c20fSFrederick Mayle return false;
168*9712c20fSFrederick Mayle
169*9712c20fSFrederick Mayle if (swap)
170*9712c20fSFrederick Mayle breakpad_swap_section(&sec, 1);
171*9712c20fSFrederick Mayle
172*9712c20fSFrederick Mayle // sections of type S_ZEROFILL are "virtual" and contain no data
173*9712c20fSFrederick Mayle // in the file itself
174*9712c20fSFrederick Mayle if ((sec.flags & SECTION_TYPE) != S_ZEROFILL && sec.offset != 0)
175*9712c20fSFrederick Mayle macho_id->Update(walker, header_offset + sec.offset, sec.size);
176*9712c20fSFrederick Mayle
177*9712c20fSFrederick Mayle offset += sizeof(struct section);
178*9712c20fSFrederick Mayle }
179*9712c20fSFrederick Mayle } else if (cmd->cmd == LC_SEGMENT_64) {
180*9712c20fSFrederick Mayle struct segment_command_64 seg64;
181*9712c20fSFrederick Mayle
182*9712c20fSFrederick Mayle if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
183*9712c20fSFrederick Mayle return false;
184*9712c20fSFrederick Mayle
185*9712c20fSFrederick Mayle if (swap)
186*9712c20fSFrederick Mayle breakpad_swap_segment_command_64(&seg64);
187*9712c20fSFrederick Mayle
188*9712c20fSFrederick Mayle struct mach_header_64 header;
189*9712c20fSFrederick Mayle off_t header_offset;
190*9712c20fSFrederick Mayle
191*9712c20fSFrederick Mayle if (!walker->CurrentHeader(&header, &header_offset))
192*9712c20fSFrederick Mayle return false;
193*9712c20fSFrederick Mayle
194*9712c20fSFrederick Mayle // Process segments that have sections:
195*9712c20fSFrederick Mayle // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
196*9712c20fSFrederick Mayle offset += sizeof(struct segment_command_64);
197*9712c20fSFrederick Mayle struct section_64 sec64;
198*9712c20fSFrederick Mayle for (unsigned long i = 0; i < seg64.nsects; ++i) {
199*9712c20fSFrederick Mayle if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
200*9712c20fSFrederick Mayle return false;
201*9712c20fSFrederick Mayle
202*9712c20fSFrederick Mayle if (swap)
203*9712c20fSFrederick Mayle breakpad_swap_section_64(&sec64, 1);
204*9712c20fSFrederick Mayle
205*9712c20fSFrederick Mayle // sections of type S_ZEROFILL are "virtual" and contain no data
206*9712c20fSFrederick Mayle // in the file itself
207*9712c20fSFrederick Mayle if ((sec64.flags & SECTION_TYPE) != S_ZEROFILL && sec64.offset != 0)
208*9712c20fSFrederick Mayle macho_id->Update(walker,
209*9712c20fSFrederick Mayle header_offset + sec64.offset,
210*9712c20fSFrederick Mayle (size_t)sec64.size);
211*9712c20fSFrederick Mayle
212*9712c20fSFrederick Mayle offset += sizeof(struct section_64);
213*9712c20fSFrederick Mayle }
214*9712c20fSFrederick Mayle }
215*9712c20fSFrederick Mayle
216*9712c20fSFrederick Mayle // Continue processing
217*9712c20fSFrederick Mayle return true;
218*9712c20fSFrederick Mayle }
219*9712c20fSFrederick Mayle
220*9712c20fSFrederick Mayle // static
UUIDWalkerCB(MachoWalker * walker,load_command * cmd,off_t offset,bool swap,void * context)221*9712c20fSFrederick Mayle bool MachoID::UUIDWalkerCB(MachoWalker* walker, load_command* cmd, off_t offset,
222*9712c20fSFrederick Mayle bool swap, void* context) {
223*9712c20fSFrederick Mayle if (cmd->cmd == LC_UUID) {
224*9712c20fSFrederick Mayle struct breakpad_uuid_command* uuid_cmd =
225*9712c20fSFrederick Mayle (struct breakpad_uuid_command*)context;
226*9712c20fSFrederick Mayle
227*9712c20fSFrederick Mayle if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
228*9712c20fSFrederick Mayle offset))
229*9712c20fSFrederick Mayle return false;
230*9712c20fSFrederick Mayle
231*9712c20fSFrederick Mayle if (swap)
232*9712c20fSFrederick Mayle breakpad_swap_uuid_command(uuid_cmd);
233*9712c20fSFrederick Mayle
234*9712c20fSFrederick Mayle return false;
235*9712c20fSFrederick Mayle }
236*9712c20fSFrederick Mayle
237*9712c20fSFrederick Mayle // Continue processing
238*9712c20fSFrederick Mayle return true;
239*9712c20fSFrederick Mayle }
240*9712c20fSFrederick Mayle } // namespace MacFileUtilities
241