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_walker.cc: Iterate over the load commands in a mach-o file
30*9712c20fSFrederick Mayle //
31*9712c20fSFrederick Mayle // See macho_walker.h for documentation
32*9712c20fSFrederick Mayle //
33*9712c20fSFrederick Mayle // Author: Dan Waylonis
34*9712c20fSFrederick Mayle
35*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
36*9712c20fSFrederick Mayle #include <config.h> // Must come first
37*9712c20fSFrederick Mayle #endif
38*9712c20fSFrederick Mayle
39*9712c20fSFrederick Mayle #include <assert.h>
40*9712c20fSFrederick Mayle #include <fcntl.h>
41*9712c20fSFrederick Mayle #include <mach-o/fat.h>
42*9712c20fSFrederick Mayle #include <mach-o/loader.h>
43*9712c20fSFrederick Mayle #include <string.h>
44*9712c20fSFrederick Mayle #include <unistd.h>
45*9712c20fSFrederick Mayle
46*9712c20fSFrederick Mayle #include "common/mac/arch_utilities.h"
47*9712c20fSFrederick Mayle #include "common/mac/byteswap.h"
48*9712c20fSFrederick Mayle #include "common/mac/macho_utilities.h"
49*9712c20fSFrederick Mayle #include "common/mac/macho_walker.h"
50*9712c20fSFrederick Mayle
51*9712c20fSFrederick Mayle namespace MacFileUtilities {
52*9712c20fSFrederick Mayle
MachoWalker(const char * path,LoadCommandCallback callback,void * context)53*9712c20fSFrederick Mayle MachoWalker::MachoWalker(const char* path, LoadCommandCallback callback,
54*9712c20fSFrederick Mayle void* context)
55*9712c20fSFrederick Mayle : file_(-1),
56*9712c20fSFrederick Mayle memory_(NULL),
57*9712c20fSFrederick Mayle memory_size_(0),
58*9712c20fSFrederick Mayle callback_(callback),
59*9712c20fSFrederick Mayle callback_context_(context),
60*9712c20fSFrederick Mayle current_header_(NULL),
61*9712c20fSFrederick Mayle current_header_size_(0),
62*9712c20fSFrederick Mayle current_header_offset_(0) {
63*9712c20fSFrederick Mayle file_ = open(path, O_RDONLY);
64*9712c20fSFrederick Mayle }
65*9712c20fSFrederick Mayle
MachoWalker(void * memory,size_t size,LoadCommandCallback callback,void * context)66*9712c20fSFrederick Mayle MachoWalker::MachoWalker(void* memory, size_t size,
67*9712c20fSFrederick Mayle LoadCommandCallback callback, void* context)
68*9712c20fSFrederick Mayle : file_(-1),
69*9712c20fSFrederick Mayle memory_(memory),
70*9712c20fSFrederick Mayle memory_size_(size),
71*9712c20fSFrederick Mayle callback_(callback),
72*9712c20fSFrederick Mayle callback_context_(context),
73*9712c20fSFrederick Mayle current_header_(NULL),
74*9712c20fSFrederick Mayle current_header_size_(0),
75*9712c20fSFrederick Mayle current_header_offset_(0) {
76*9712c20fSFrederick Mayle }
77*9712c20fSFrederick Mayle
~MachoWalker()78*9712c20fSFrederick Mayle MachoWalker::~MachoWalker() {
79*9712c20fSFrederick Mayle if (file_ != -1)
80*9712c20fSFrederick Mayle close(file_);
81*9712c20fSFrederick Mayle }
82*9712c20fSFrederick Mayle
WalkHeader(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype)83*9712c20fSFrederick Mayle bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
84*9712c20fSFrederick Mayle cpu_type_t valid_cpu_type = cpu_type;
85*9712c20fSFrederick Mayle cpu_subtype_t valid_cpu_subtype = cpu_subtype;
86*9712c20fSFrederick Mayle // if |cpu_type| is 0, use the native cpu type.
87*9712c20fSFrederick Mayle if (cpu_type == 0) {
88*9712c20fSFrederick Mayle ArchInfo arch = GetLocalArchInfo();
89*9712c20fSFrederick Mayle valid_cpu_type = arch.cputype;
90*9712c20fSFrederick Mayle valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
91*9712c20fSFrederick Mayle }
92*9712c20fSFrederick Mayle off_t offset;
93*9712c20fSFrederick Mayle if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) {
94*9712c20fSFrederick Mayle if (cpu_type & CPU_ARCH_ABI64)
95*9712c20fSFrederick Mayle return WalkHeader64AtOffset(offset);
96*9712c20fSFrederick Mayle
97*9712c20fSFrederick Mayle return WalkHeaderAtOffset(offset);
98*9712c20fSFrederick Mayle }
99*9712c20fSFrederick Mayle
100*9712c20fSFrederick Mayle return false;
101*9712c20fSFrederick Mayle }
102*9712c20fSFrederick Mayle
ReadBytes(void * buffer,size_t size,off_t offset)103*9712c20fSFrederick Mayle bool MachoWalker::ReadBytes(void* buffer, size_t size, off_t offset) {
104*9712c20fSFrederick Mayle if (memory_) {
105*9712c20fSFrederick Mayle if (offset < 0)
106*9712c20fSFrederick Mayle return false;
107*9712c20fSFrederick Mayle bool result = true;
108*9712c20fSFrederick Mayle if (offset + size > memory_size_) {
109*9712c20fSFrederick Mayle if (static_cast<size_t>(offset) >= memory_size_)
110*9712c20fSFrederick Mayle return false;
111*9712c20fSFrederick Mayle size = memory_size_ - static_cast<size_t>(offset);
112*9712c20fSFrederick Mayle result = false;
113*9712c20fSFrederick Mayle }
114*9712c20fSFrederick Mayle memcpy(buffer, static_cast<char*>(memory_) + offset, size);
115*9712c20fSFrederick Mayle return result;
116*9712c20fSFrederick Mayle } else {
117*9712c20fSFrederick Mayle return pread(file_, buffer, size, offset) == (ssize_t)size;
118*9712c20fSFrederick Mayle }
119*9712c20fSFrederick Mayle }
120*9712c20fSFrederick Mayle
CurrentHeader(struct mach_header_64 * header,off_t * offset)121*9712c20fSFrederick Mayle bool MachoWalker::CurrentHeader(struct mach_header_64* header, off_t* offset) {
122*9712c20fSFrederick Mayle if (current_header_) {
123*9712c20fSFrederick Mayle memcpy(header, current_header_, sizeof(mach_header_64));
124*9712c20fSFrederick Mayle *offset = current_header_offset_;
125*9712c20fSFrederick Mayle return true;
126*9712c20fSFrederick Mayle }
127*9712c20fSFrederick Mayle
128*9712c20fSFrederick Mayle return false;
129*9712c20fSFrederick Mayle }
130*9712c20fSFrederick Mayle
FindHeader(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype,off_t & offset)131*9712c20fSFrederick Mayle bool MachoWalker::FindHeader(cpu_type_t cpu_type,
132*9712c20fSFrederick Mayle cpu_subtype_t cpu_subtype,
133*9712c20fSFrederick Mayle off_t& offset) {
134*9712c20fSFrederick Mayle // Read the magic bytes that's common amongst all mach-o files
135*9712c20fSFrederick Mayle uint32_t magic;
136*9712c20fSFrederick Mayle if (!ReadBytes(&magic, sizeof(magic), 0))
137*9712c20fSFrederick Mayle return false;
138*9712c20fSFrederick Mayle
139*9712c20fSFrederick Mayle offset = sizeof(magic);
140*9712c20fSFrederick Mayle
141*9712c20fSFrederick Mayle // Figure out what type of file we've got
142*9712c20fSFrederick Mayle bool is_fat = false;
143*9712c20fSFrederick Mayle if (magic == FAT_MAGIC || magic == FAT_CIGAM) {
144*9712c20fSFrederick Mayle is_fat = true;
145*9712c20fSFrederick Mayle }
146*9712c20fSFrederick Mayle else if (magic != MH_MAGIC && magic != MH_CIGAM && magic != MH_MAGIC_64 &&
147*9712c20fSFrederick Mayle magic != MH_CIGAM_64) {
148*9712c20fSFrederick Mayle return false;
149*9712c20fSFrederick Mayle }
150*9712c20fSFrederick Mayle
151*9712c20fSFrederick Mayle if (!is_fat) {
152*9712c20fSFrederick Mayle // If we don't have a fat header, check if the cpu type matches the single
153*9712c20fSFrederick Mayle // header
154*9712c20fSFrederick Mayle struct mach_header header;
155*9712c20fSFrederick Mayle if (!ReadBytes(&header, sizeof(header), 0))
156*9712c20fSFrederick Mayle return false;
157*9712c20fSFrederick Mayle
158*9712c20fSFrederick Mayle if (magic == MH_CIGAM || magic == MH_CIGAM_64)
159*9712c20fSFrederick Mayle breakpad_swap_mach_header(&header);
160*9712c20fSFrederick Mayle
161*9712c20fSFrederick Mayle if (cpu_type != header.cputype ||
162*9712c20fSFrederick Mayle (cpu_subtype != CPU_SUBTYPE_MULTIPLE &&
163*9712c20fSFrederick Mayle cpu_subtype != header.cpusubtype)) {
164*9712c20fSFrederick Mayle return false;
165*9712c20fSFrederick Mayle }
166*9712c20fSFrederick Mayle
167*9712c20fSFrederick Mayle offset = 0;
168*9712c20fSFrederick Mayle return true;
169*9712c20fSFrederick Mayle } else {
170*9712c20fSFrederick Mayle // Read the fat header and find an appropriate architecture
171*9712c20fSFrederick Mayle offset = 0;
172*9712c20fSFrederick Mayle struct fat_header fat;
173*9712c20fSFrederick Mayle if (!ReadBytes(&fat, sizeof(fat), offset))
174*9712c20fSFrederick Mayle return false;
175*9712c20fSFrederick Mayle
176*9712c20fSFrederick Mayle if (NXHostByteOrder() != NX_BigEndian)
177*9712c20fSFrederick Mayle breakpad_swap_fat_header(&fat);
178*9712c20fSFrederick Mayle
179*9712c20fSFrederick Mayle offset += sizeof(fat);
180*9712c20fSFrederick Mayle
181*9712c20fSFrederick Mayle // Search each architecture for the desired one
182*9712c20fSFrederick Mayle struct fat_arch arch;
183*9712c20fSFrederick Mayle for (uint32_t i = 0; i < fat.nfat_arch; ++i) {
184*9712c20fSFrederick Mayle if (!ReadBytes(&arch, sizeof(arch), offset))
185*9712c20fSFrederick Mayle return false;
186*9712c20fSFrederick Mayle
187*9712c20fSFrederick Mayle if (NXHostByteOrder() != NX_BigEndian)
188*9712c20fSFrederick Mayle breakpad_swap_fat_arch(&arch, 1);
189*9712c20fSFrederick Mayle
190*9712c20fSFrederick Mayle if (arch.cputype == cpu_type &&
191*9712c20fSFrederick Mayle (cpu_subtype == CPU_SUBTYPE_MULTIPLE ||
192*9712c20fSFrederick Mayle arch.cpusubtype == cpu_subtype)) {
193*9712c20fSFrederick Mayle offset = arch.offset;
194*9712c20fSFrederick Mayle return true;
195*9712c20fSFrederick Mayle }
196*9712c20fSFrederick Mayle
197*9712c20fSFrederick Mayle offset += sizeof(arch);
198*9712c20fSFrederick Mayle }
199*9712c20fSFrederick Mayle }
200*9712c20fSFrederick Mayle
201*9712c20fSFrederick Mayle return false;
202*9712c20fSFrederick Mayle }
203*9712c20fSFrederick Mayle
WalkHeaderAtOffset(off_t offset)204*9712c20fSFrederick Mayle bool MachoWalker::WalkHeaderAtOffset(off_t offset) {
205*9712c20fSFrederick Mayle struct mach_header header;
206*9712c20fSFrederick Mayle if (!ReadBytes(&header, sizeof(header), offset))
207*9712c20fSFrederick Mayle return false;
208*9712c20fSFrederick Mayle
209*9712c20fSFrederick Mayle bool swap = (header.magic == MH_CIGAM);
210*9712c20fSFrederick Mayle if (swap)
211*9712c20fSFrederick Mayle breakpad_swap_mach_header(&header);
212*9712c20fSFrederick Mayle
213*9712c20fSFrederick Mayle // Copy the data into the mach_header_64 structure. Since the 32-bit and
214*9712c20fSFrederick Mayle // 64-bit only differ in the last field (reserved), this is safe to do.
215*9712c20fSFrederick Mayle struct mach_header_64 header64;
216*9712c20fSFrederick Mayle memcpy((void*)&header64, (const void*)&header, sizeof(header));
217*9712c20fSFrederick Mayle header64.reserved = 0;
218*9712c20fSFrederick Mayle
219*9712c20fSFrederick Mayle current_header_ = &header64;
220*9712c20fSFrederick Mayle current_header_size_ = sizeof(header); // 32-bit, not 64-bit
221*9712c20fSFrederick Mayle current_header_offset_ = offset;
222*9712c20fSFrederick Mayle offset += current_header_size_;
223*9712c20fSFrederick Mayle bool result = WalkHeaderCore(offset, header.ncmds, swap);
224*9712c20fSFrederick Mayle current_header_ = NULL;
225*9712c20fSFrederick Mayle current_header_size_ = 0;
226*9712c20fSFrederick Mayle current_header_offset_ = 0;
227*9712c20fSFrederick Mayle return result;
228*9712c20fSFrederick Mayle }
229*9712c20fSFrederick Mayle
WalkHeader64AtOffset(off_t offset)230*9712c20fSFrederick Mayle bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
231*9712c20fSFrederick Mayle struct mach_header_64 header;
232*9712c20fSFrederick Mayle if (!ReadBytes(&header, sizeof(header), offset))
233*9712c20fSFrederick Mayle return false;
234*9712c20fSFrederick Mayle
235*9712c20fSFrederick Mayle bool swap = (header.magic == MH_CIGAM_64);
236*9712c20fSFrederick Mayle if (swap)
237*9712c20fSFrederick Mayle breakpad_swap_mach_header_64(&header);
238*9712c20fSFrederick Mayle
239*9712c20fSFrederick Mayle current_header_ = &header;
240*9712c20fSFrederick Mayle current_header_size_ = sizeof(header);
241*9712c20fSFrederick Mayle current_header_offset_ = offset;
242*9712c20fSFrederick Mayle offset += current_header_size_;
243*9712c20fSFrederick Mayle bool result = WalkHeaderCore(offset, header.ncmds, swap);
244*9712c20fSFrederick Mayle current_header_ = NULL;
245*9712c20fSFrederick Mayle current_header_size_ = 0;
246*9712c20fSFrederick Mayle current_header_offset_ = 0;
247*9712c20fSFrederick Mayle return result;
248*9712c20fSFrederick Mayle }
249*9712c20fSFrederick Mayle
WalkHeaderCore(off_t offset,uint32_t number_of_commands,bool swap)250*9712c20fSFrederick Mayle bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands,
251*9712c20fSFrederick Mayle bool swap) {
252*9712c20fSFrederick Mayle for (uint32_t i = 0; i < number_of_commands; ++i) {
253*9712c20fSFrederick Mayle struct load_command cmd;
254*9712c20fSFrederick Mayle if (!ReadBytes(&cmd, sizeof(cmd), offset))
255*9712c20fSFrederick Mayle return false;
256*9712c20fSFrederick Mayle
257*9712c20fSFrederick Mayle if (swap)
258*9712c20fSFrederick Mayle breakpad_swap_load_command(&cmd);
259*9712c20fSFrederick Mayle
260*9712c20fSFrederick Mayle // Call the user callback
261*9712c20fSFrederick Mayle if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_))
262*9712c20fSFrederick Mayle break;
263*9712c20fSFrederick Mayle
264*9712c20fSFrederick Mayle offset += cmd.cmdsize;
265*9712c20fSFrederick Mayle }
266*9712c20fSFrederick Mayle
267*9712c20fSFrederick Mayle return true;
268*9712c20fSFrederick Mayle }
269*9712c20fSFrederick Mayle
270*9712c20fSFrederick Mayle } // namespace MacFileUtilities
271