xref: /aosp_15_r20/external/google-breakpad/src/common/mac/macho_reader.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1*9712c20fSFrederick Mayle // Copyright 2010 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 // Original author: Jim Blandy <[email protected]> <[email protected]>
30*9712c20fSFrederick Mayle 
31*9712c20fSFrederick Mayle // macho_reader.cc: Implementation of google_breakpad::Mach_O::FatReader and
32*9712c20fSFrederick Mayle // google_breakpad::Mach_O::Reader. See macho_reader.h for details.
33*9712c20fSFrederick Mayle 
34*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
35*9712c20fSFrederick Mayle #include <config.h>  // Must come first
36*9712c20fSFrederick Mayle #endif
37*9712c20fSFrederick Mayle 
38*9712c20fSFrederick Mayle #include "common/mac/macho_reader.h"
39*9712c20fSFrederick Mayle 
40*9712c20fSFrederick Mayle #include <assert.h>
41*9712c20fSFrederick Mayle #include <stdio.h>
42*9712c20fSFrederick Mayle #include <stdlib.h>
43*9712c20fSFrederick Mayle 
44*9712c20fSFrederick Mayle #include <limits>
45*9712c20fSFrederick Mayle 
46*9712c20fSFrederick Mayle // Unfortunately, CPU_TYPE_ARM is not define for 10.4.
47*9712c20fSFrederick Mayle #if !defined(CPU_TYPE_ARM)
48*9712c20fSFrederick Mayle #define CPU_TYPE_ARM 12
49*9712c20fSFrederick Mayle #endif
50*9712c20fSFrederick Mayle 
51*9712c20fSFrederick Mayle #if !defined(CPU_TYPE_ARM_64)
52*9712c20fSFrederick Mayle #define CPU_TYPE_ARM_64 16777228
53*9712c20fSFrederick Mayle #endif
54*9712c20fSFrederick Mayle 
55*9712c20fSFrederick Mayle namespace google_breakpad {
56*9712c20fSFrederick Mayle namespace mach_o {
57*9712c20fSFrederick Mayle 
58*9712c20fSFrederick Mayle // If NDEBUG is #defined, then the 'assert' macro doesn't evaluate its
59*9712c20fSFrederick Mayle // arguments, so you can't place expressions that do necessary work in
60*9712c20fSFrederick Mayle // the argument of an assert. Nor can you assign the result of the
61*9712c20fSFrederick Mayle // expression to a variable and assert that the variable's value is
62*9712c20fSFrederick Mayle // true: you'll get unused variable warnings when NDEBUG is #defined.
63*9712c20fSFrederick Mayle //
64*9712c20fSFrederick Mayle // ASSERT_ALWAYS_EVAL always evaluates its argument, and asserts that
65*9712c20fSFrederick Mayle // the result is true if NDEBUG is not #defined.
66*9712c20fSFrederick Mayle #if defined(NDEBUG)
67*9712c20fSFrederick Mayle #define ASSERT_ALWAYS_EVAL(x) (x)
68*9712c20fSFrederick Mayle #else
69*9712c20fSFrederick Mayle #define ASSERT_ALWAYS_EVAL(x) assert(x)
70*9712c20fSFrederick Mayle #endif
71*9712c20fSFrederick Mayle 
BadHeader()72*9712c20fSFrederick Mayle void FatReader::Reporter::BadHeader() {
73*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file is neither a fat binary file"
74*9712c20fSFrederick Mayle           " nor a Mach-O object file\n", filename_.c_str());
75*9712c20fSFrederick Mayle }
76*9712c20fSFrederick Mayle 
TooShort()77*9712c20fSFrederick Mayle void FatReader::Reporter::TooShort() {
78*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file too short for the data it claims to contain\n",
79*9712c20fSFrederick Mayle           filename_.c_str());
80*9712c20fSFrederick Mayle }
81*9712c20fSFrederick Mayle 
MisplacedObjectFile()82*9712c20fSFrederick Mayle void FatReader::Reporter::MisplacedObjectFile() {
83*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file too short for the object files it claims"
84*9712c20fSFrederick Mayle           " to contain\n", filename_.c_str());
85*9712c20fSFrederick Mayle }
86*9712c20fSFrederick Mayle 
Read(const uint8_t * buffer,size_t size)87*9712c20fSFrederick Mayle bool FatReader::Read(const uint8_t* buffer, size_t size) {
88*9712c20fSFrederick Mayle   buffer_.start = buffer;
89*9712c20fSFrederick Mayle   buffer_.end = buffer + size;
90*9712c20fSFrederick Mayle   ByteCursor cursor(&buffer_);
91*9712c20fSFrederick Mayle 
92*9712c20fSFrederick Mayle   // Fat binaries always use big-endian, so read the magic number in
93*9712c20fSFrederick Mayle   // that endianness. To recognize Mach-O magic numbers, which can use
94*9712c20fSFrederick Mayle   // either endianness, check for both the proper and reversed forms
95*9712c20fSFrederick Mayle   // of the magic numbers.
96*9712c20fSFrederick Mayle   cursor.set_big_endian(true);
97*9712c20fSFrederick Mayle   if (cursor >> magic_) {
98*9712c20fSFrederick Mayle     if (magic_ == FAT_MAGIC) {
99*9712c20fSFrederick Mayle       // How many object files does this fat binary contain?
100*9712c20fSFrederick Mayle       uint32_t object_files_count;
101*9712c20fSFrederick Mayle       if (!(cursor >> object_files_count)) {  // nfat_arch
102*9712c20fSFrederick Mayle         reporter_->TooShort();
103*9712c20fSFrederick Mayle         return false;
104*9712c20fSFrederick Mayle       }
105*9712c20fSFrederick Mayle 
106*9712c20fSFrederick Mayle       // Read the list of object files.
107*9712c20fSFrederick Mayle       object_files_.resize(object_files_count);
108*9712c20fSFrederick Mayle       for (size_t i = 0; i < object_files_count; i++) {
109*9712c20fSFrederick Mayle         struct fat_arch objfile;
110*9712c20fSFrederick Mayle 
111*9712c20fSFrederick Mayle         // Read this object file entry, byte-swapping as appropriate.
112*9712c20fSFrederick Mayle         cursor >> objfile.cputype
113*9712c20fSFrederick Mayle                >> objfile.cpusubtype
114*9712c20fSFrederick Mayle                >> objfile.offset
115*9712c20fSFrederick Mayle                >> objfile.size
116*9712c20fSFrederick Mayle                >> objfile.align;
117*9712c20fSFrederick Mayle 
118*9712c20fSFrederick Mayle         SuperFatArch super_fat_arch(objfile);
119*9712c20fSFrederick Mayle         object_files_[i] = super_fat_arch;
120*9712c20fSFrederick Mayle 
121*9712c20fSFrederick Mayle         if (!cursor) {
122*9712c20fSFrederick Mayle           reporter_->TooShort();
123*9712c20fSFrederick Mayle           return false;
124*9712c20fSFrederick Mayle         }
125*9712c20fSFrederick Mayle         // Does the file actually have the bytes this entry refers to?
126*9712c20fSFrederick Mayle         size_t fat_size = buffer_.Size();
127*9712c20fSFrederick Mayle         if (objfile.offset > fat_size ||
128*9712c20fSFrederick Mayle             objfile.size > fat_size - objfile.offset) {
129*9712c20fSFrederick Mayle           reporter_->MisplacedObjectFile();
130*9712c20fSFrederick Mayle           return false;
131*9712c20fSFrederick Mayle         }
132*9712c20fSFrederick Mayle       }
133*9712c20fSFrederick Mayle 
134*9712c20fSFrederick Mayle       return true;
135*9712c20fSFrederick Mayle     } else if (magic_ == MH_MAGIC || magic_ == MH_MAGIC_64 ||
136*9712c20fSFrederick Mayle                magic_ == MH_CIGAM || magic_ == MH_CIGAM_64) {
137*9712c20fSFrederick Mayle       // If this is a little-endian Mach-O file, fix the cursor's endianness.
138*9712c20fSFrederick Mayle       if (magic_ == MH_CIGAM || magic_ == MH_CIGAM_64)
139*9712c20fSFrederick Mayle         cursor.set_big_endian(false);
140*9712c20fSFrederick Mayle       // Record the entire file as a single entry in the object file list.
141*9712c20fSFrederick Mayle       object_files_.resize(1);
142*9712c20fSFrederick Mayle 
143*9712c20fSFrederick Mayle       // Get the cpu type and subtype from the Mach-O header.
144*9712c20fSFrederick Mayle       if (!(cursor >> object_files_[0].cputype
145*9712c20fSFrederick Mayle                    >> object_files_[0].cpusubtype)) {
146*9712c20fSFrederick Mayle         reporter_->TooShort();
147*9712c20fSFrederick Mayle         return false;
148*9712c20fSFrederick Mayle       }
149*9712c20fSFrederick Mayle 
150*9712c20fSFrederick Mayle       object_files_[0].offset = 0;
151*9712c20fSFrederick Mayle       object_files_[0].size = static_cast<uint64_t>(buffer_.Size());
152*9712c20fSFrederick Mayle       // This alignment is correct for 32 and 64-bit x86 and ppc.
153*9712c20fSFrederick Mayle       // See get_align in the lipo source for other architectures:
154*9712c20fSFrederick Mayle       // http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
155*9712c20fSFrederick Mayle       object_files_[0].align = 12;  // 2^12 == 4096
156*9712c20fSFrederick Mayle       return true;
157*9712c20fSFrederick Mayle     }
158*9712c20fSFrederick Mayle   }
159*9712c20fSFrederick Mayle   reporter_->BadHeader();
160*9712c20fSFrederick Mayle   return false;
161*9712c20fSFrederick Mayle }
162*9712c20fSFrederick Mayle 
BadHeader()163*9712c20fSFrederick Mayle void Reader::Reporter::BadHeader() {
164*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file is not a Mach-O object file\n", filename_.c_str());
165*9712c20fSFrederick Mayle }
166*9712c20fSFrederick Mayle 
CPUTypeMismatch(cpu_type_t cpu_type,cpu_subtype_t cpu_subtype,cpu_type_t expected_cpu_type,cpu_subtype_t expected_cpu_subtype)167*9712c20fSFrederick Mayle void Reader::Reporter::CPUTypeMismatch(cpu_type_t cpu_type,
168*9712c20fSFrederick Mayle                                        cpu_subtype_t cpu_subtype,
169*9712c20fSFrederick Mayle                                        cpu_type_t expected_cpu_type,
170*9712c20fSFrederick Mayle                                        cpu_subtype_t expected_cpu_subtype) {
171*9712c20fSFrederick Mayle   fprintf(stderr, "%s: CPU type %d, subtype %d does not match expected"
172*9712c20fSFrederick Mayle           " type %d, subtype %d\n",
173*9712c20fSFrederick Mayle           filename_.c_str(), cpu_type, cpu_subtype,
174*9712c20fSFrederick Mayle           expected_cpu_type, expected_cpu_subtype);
175*9712c20fSFrederick Mayle }
176*9712c20fSFrederick Mayle 
HeaderTruncated()177*9712c20fSFrederick Mayle void Reader::Reporter::HeaderTruncated() {
178*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file does not contain a complete Mach-O header\n",
179*9712c20fSFrederick Mayle           filename_.c_str());
180*9712c20fSFrederick Mayle }
181*9712c20fSFrederick Mayle 
LoadCommandRegionTruncated()182*9712c20fSFrederick Mayle void Reader::Reporter::LoadCommandRegionTruncated() {
183*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file too short to hold load command region"
184*9712c20fSFrederick Mayle           " given in Mach-O header\n", filename_.c_str());
185*9712c20fSFrederick Mayle }
186*9712c20fSFrederick Mayle 
LoadCommandsOverrun(size_t claimed,size_t i,LoadCommandType type)187*9712c20fSFrederick Mayle void Reader::Reporter::LoadCommandsOverrun(size_t claimed, size_t i,
188*9712c20fSFrederick Mayle                                            LoadCommandType type) {
189*9712c20fSFrederick Mayle   fprintf(stderr, "%s: file's header claims there are %zu"
190*9712c20fSFrederick Mayle           " load commands, but load command #%zu",
191*9712c20fSFrederick Mayle           filename_.c_str(), claimed, i);
192*9712c20fSFrederick Mayle   if (type) fprintf(stderr, ", of type %d,", type);
193*9712c20fSFrederick Mayle   fprintf(stderr, " extends beyond the end of the load command region\n");
194*9712c20fSFrederick Mayle }
195*9712c20fSFrederick Mayle 
LoadCommandTooShort(size_t i,LoadCommandType type)196*9712c20fSFrederick Mayle void Reader::Reporter::LoadCommandTooShort(size_t i, LoadCommandType type) {
197*9712c20fSFrederick Mayle   fprintf(stderr, "%s: the contents of load command #%zu, of type %d,"
198*9712c20fSFrederick Mayle           " extend beyond the size given in the load command's header\n",
199*9712c20fSFrederick Mayle           filename_.c_str(), i, type);
200*9712c20fSFrederick Mayle }
201*9712c20fSFrederick Mayle 
SectionsMissing(const string & name)202*9712c20fSFrederick Mayle void Reader::Reporter::SectionsMissing(const string& name) {
203*9712c20fSFrederick Mayle   fprintf(stderr, "%s: the load command for segment '%s'"
204*9712c20fSFrederick Mayle           " is too short to hold the section headers it claims to have\n",
205*9712c20fSFrederick Mayle           filename_.c_str(), name.c_str());
206*9712c20fSFrederick Mayle }
207*9712c20fSFrederick Mayle 
MisplacedSegmentData(const string & name)208*9712c20fSFrederick Mayle void Reader::Reporter::MisplacedSegmentData(const string& name) {
209*9712c20fSFrederick Mayle   fprintf(stderr, "%s: the segment '%s' claims its contents lie beyond"
210*9712c20fSFrederick Mayle           " the end of the file\n", filename_.c_str(), name.c_str());
211*9712c20fSFrederick Mayle }
212*9712c20fSFrederick Mayle 
MisplacedSectionData(const string & section,const string & segment)213*9712c20fSFrederick Mayle void Reader::Reporter::MisplacedSectionData(const string& section,
214*9712c20fSFrederick Mayle                                             const string& segment) {
215*9712c20fSFrederick Mayle   fprintf(stderr, "%s: the section '%s' in segment '%s'"
216*9712c20fSFrederick Mayle           " claims its contents lie outside the segment's contents\n",
217*9712c20fSFrederick Mayle           filename_.c_str(), section.c_str(), segment.c_str());
218*9712c20fSFrederick Mayle }
219*9712c20fSFrederick Mayle 
MisplacedSymbolTable()220*9712c20fSFrederick Mayle void Reader::Reporter::MisplacedSymbolTable() {
221*9712c20fSFrederick Mayle   fprintf(stderr, "%s: the LC_SYMTAB load command claims that the symbol"
222*9712c20fSFrederick Mayle           " table's contents are located beyond the end of the file\n",
223*9712c20fSFrederick Mayle           filename_.c_str());
224*9712c20fSFrederick Mayle }
225*9712c20fSFrederick Mayle 
UnsupportedCPUType(cpu_type_t cpu_type)226*9712c20fSFrederick Mayle void Reader::Reporter::UnsupportedCPUType(cpu_type_t cpu_type) {
227*9712c20fSFrederick Mayle   fprintf(stderr, "%s: CPU type %d is not supported\n",
228*9712c20fSFrederick Mayle           filename_.c_str(), cpu_type);
229*9712c20fSFrederick Mayle }
230*9712c20fSFrederick Mayle 
Read(const uint8_t * buffer,size_t size,cpu_type_t expected_cpu_type,cpu_subtype_t expected_cpu_subtype)231*9712c20fSFrederick Mayle bool Reader::Read(const uint8_t* buffer,
232*9712c20fSFrederick Mayle                   size_t size,
233*9712c20fSFrederick Mayle                   cpu_type_t expected_cpu_type,
234*9712c20fSFrederick Mayle                   cpu_subtype_t expected_cpu_subtype) {
235*9712c20fSFrederick Mayle   assert(!buffer_.start);
236*9712c20fSFrederick Mayle   buffer_.start = buffer;
237*9712c20fSFrederick Mayle   buffer_.end = buffer + size;
238*9712c20fSFrederick Mayle   ByteCursor cursor(&buffer_, true);
239*9712c20fSFrederick Mayle   uint32_t magic;
240*9712c20fSFrederick Mayle   if (!(cursor >> magic)) {
241*9712c20fSFrederick Mayle     reporter_->HeaderTruncated();
242*9712c20fSFrederick Mayle     return false;
243*9712c20fSFrederick Mayle   }
244*9712c20fSFrederick Mayle 
245*9712c20fSFrederick Mayle   if (expected_cpu_type != CPU_TYPE_ANY) {
246*9712c20fSFrederick Mayle     uint32_t expected_magic;
247*9712c20fSFrederick Mayle     // validate that magic matches the expected cpu type
248*9712c20fSFrederick Mayle     switch (expected_cpu_type) {
249*9712c20fSFrederick Mayle       case CPU_TYPE_ARM:
250*9712c20fSFrederick Mayle       case CPU_TYPE_I386:
251*9712c20fSFrederick Mayle         expected_magic = MH_CIGAM;
252*9712c20fSFrederick Mayle         break;
253*9712c20fSFrederick Mayle       case CPU_TYPE_POWERPC:
254*9712c20fSFrederick Mayle         expected_magic = MH_MAGIC;
255*9712c20fSFrederick Mayle         break;
256*9712c20fSFrederick Mayle       case CPU_TYPE_ARM_64:
257*9712c20fSFrederick Mayle       case CPU_TYPE_X86_64:
258*9712c20fSFrederick Mayle         expected_magic = MH_CIGAM_64;
259*9712c20fSFrederick Mayle         break;
260*9712c20fSFrederick Mayle       case CPU_TYPE_POWERPC64:
261*9712c20fSFrederick Mayle         expected_magic = MH_MAGIC_64;
262*9712c20fSFrederick Mayle         break;
263*9712c20fSFrederick Mayle       default:
264*9712c20fSFrederick Mayle         reporter_->UnsupportedCPUType(expected_cpu_type);
265*9712c20fSFrederick Mayle         return false;
266*9712c20fSFrederick Mayle     }
267*9712c20fSFrederick Mayle 
268*9712c20fSFrederick Mayle     if (expected_magic != magic) {
269*9712c20fSFrederick Mayle       reporter_->BadHeader();
270*9712c20fSFrederick Mayle       return false;
271*9712c20fSFrederick Mayle     }
272*9712c20fSFrederick Mayle   }
273*9712c20fSFrederick Mayle 
274*9712c20fSFrederick Mayle   // Since the byte cursor is in big-endian mode, a reversed magic number
275*9712c20fSFrederick Mayle   // always indicates a little-endian file, regardless of our own endianness.
276*9712c20fSFrederick Mayle   switch (magic) {
277*9712c20fSFrederick Mayle     case MH_MAGIC:    big_endian_ = true;  bits_64_ = false; break;
278*9712c20fSFrederick Mayle     case MH_CIGAM:    big_endian_ = false; bits_64_ = false; break;
279*9712c20fSFrederick Mayle     case MH_MAGIC_64: big_endian_ = true;  bits_64_ = true;  break;
280*9712c20fSFrederick Mayle     case MH_CIGAM_64: big_endian_ = false; bits_64_ = true;  break;
281*9712c20fSFrederick Mayle     default:
282*9712c20fSFrederick Mayle       reporter_->BadHeader();
283*9712c20fSFrederick Mayle       return false;
284*9712c20fSFrederick Mayle   }
285*9712c20fSFrederick Mayle   cursor.set_big_endian(big_endian_);
286*9712c20fSFrederick Mayle   uint32_t commands_size, reserved;
287*9712c20fSFrederick Mayle   cursor >> cpu_type_ >> cpu_subtype_ >> file_type_ >> load_command_count_
288*9712c20fSFrederick Mayle          >> commands_size >> flags_;
289*9712c20fSFrederick Mayle   if (bits_64_)
290*9712c20fSFrederick Mayle     cursor >> reserved;
291*9712c20fSFrederick Mayle   if (!cursor) {
292*9712c20fSFrederick Mayle     reporter_->HeaderTruncated();
293*9712c20fSFrederick Mayle     return false;
294*9712c20fSFrederick Mayle   }
295*9712c20fSFrederick Mayle 
296*9712c20fSFrederick Mayle   if (expected_cpu_type != CPU_TYPE_ANY &&
297*9712c20fSFrederick Mayle       (expected_cpu_type != cpu_type_ ||
298*9712c20fSFrederick Mayle        expected_cpu_subtype != cpu_subtype_)) {
299*9712c20fSFrederick Mayle     reporter_->CPUTypeMismatch(cpu_type_, cpu_subtype_,
300*9712c20fSFrederick Mayle                               expected_cpu_type, expected_cpu_subtype);
301*9712c20fSFrederick Mayle     return false;
302*9712c20fSFrederick Mayle   }
303*9712c20fSFrederick Mayle 
304*9712c20fSFrederick Mayle   cursor
305*9712c20fSFrederick Mayle       .PointTo(&load_commands_.start, commands_size)
306*9712c20fSFrederick Mayle       .PointTo(&load_commands_.end, 0);
307*9712c20fSFrederick Mayle   if (!cursor) {
308*9712c20fSFrederick Mayle     reporter_->LoadCommandRegionTruncated();
309*9712c20fSFrederick Mayle     return false;
310*9712c20fSFrederick Mayle   }
311*9712c20fSFrederick Mayle 
312*9712c20fSFrederick Mayle   return true;
313*9712c20fSFrederick Mayle }
314*9712c20fSFrederick Mayle 
WalkLoadCommands(Reader::LoadCommandHandler * handler) const315*9712c20fSFrederick Mayle bool Reader::WalkLoadCommands(Reader::LoadCommandHandler* handler) const {
316*9712c20fSFrederick Mayle   ByteCursor list_cursor(&load_commands_, big_endian_);
317*9712c20fSFrederick Mayle 
318*9712c20fSFrederick Mayle   for (size_t index = 0; index < load_command_count_; ++index) {
319*9712c20fSFrederick Mayle     // command refers to this load command alone, so that cursor will
320*9712c20fSFrederick Mayle     // refuse to read past the load command's end. But since we haven't
321*9712c20fSFrederick Mayle     // read the size yet, let command initially refer to the entire
322*9712c20fSFrederick Mayle     // remainder of the load command series.
323*9712c20fSFrederick Mayle     ByteBuffer command(list_cursor.here(), list_cursor.Available());
324*9712c20fSFrederick Mayle     ByteCursor cursor(&command, big_endian_);
325*9712c20fSFrederick Mayle 
326*9712c20fSFrederick Mayle     // Read the command type and size --- fields common to all commands.
327*9712c20fSFrederick Mayle     uint32_t type, size;
328*9712c20fSFrederick Mayle     if (!(cursor >> type)) {
329*9712c20fSFrederick Mayle       reporter_->LoadCommandsOverrun(load_command_count_, index, 0);
330*9712c20fSFrederick Mayle       return false;
331*9712c20fSFrederick Mayle     }
332*9712c20fSFrederick Mayle     if (!(cursor >> size) || size > command.Size()) {
333*9712c20fSFrederick Mayle       reporter_->LoadCommandsOverrun(load_command_count_, index, type);
334*9712c20fSFrederick Mayle       return false;
335*9712c20fSFrederick Mayle     }
336*9712c20fSFrederick Mayle 
337*9712c20fSFrederick Mayle     // Now that we've read the length, restrict command's range to this
338*9712c20fSFrederick Mayle     // load command only.
339*9712c20fSFrederick Mayle     command.end = command.start + size;
340*9712c20fSFrederick Mayle 
341*9712c20fSFrederick Mayle     switch (type) {
342*9712c20fSFrederick Mayle       case LC_SEGMENT:
343*9712c20fSFrederick Mayle       case LC_SEGMENT_64: {
344*9712c20fSFrederick Mayle         Segment segment;
345*9712c20fSFrederick Mayle         segment.bits_64 = (type == LC_SEGMENT_64);
346*9712c20fSFrederick Mayle         size_t word_size = segment.bits_64 ? 8 : 4;
347*9712c20fSFrederick Mayle         cursor.CString(&segment.name, 16);
348*9712c20fSFrederick Mayle         cursor
349*9712c20fSFrederick Mayle             .Read(word_size, false, &segment.vmaddr)
350*9712c20fSFrederick Mayle             .Read(word_size, false, &segment.vmsize)
351*9712c20fSFrederick Mayle             .Read(word_size, false, &segment.fileoff)
352*9712c20fSFrederick Mayle             .Read(word_size, false, &segment.filesize);
353*9712c20fSFrederick Mayle         cursor >> segment.maxprot
354*9712c20fSFrederick Mayle                >> segment.initprot
355*9712c20fSFrederick Mayle                >> segment.nsects
356*9712c20fSFrederick Mayle                >> segment.flags;
357*9712c20fSFrederick Mayle         if (!cursor) {
358*9712c20fSFrederick Mayle           reporter_->LoadCommandTooShort(index, type);
359*9712c20fSFrederick Mayle           return false;
360*9712c20fSFrederick Mayle         }
361*9712c20fSFrederick Mayle         if (segment.fileoff > buffer_.Size() ||
362*9712c20fSFrederick Mayle             segment.filesize > buffer_.Size() - segment.fileoff) {
363*9712c20fSFrederick Mayle           reporter_->MisplacedSegmentData(segment.name);
364*9712c20fSFrederick Mayle           return false;
365*9712c20fSFrederick Mayle         }
366*9712c20fSFrederick Mayle         // Mach-O files in .dSYM bundles have the contents of the loaded
367*9712c20fSFrederick Mayle         // segments removed, and their file offsets and file sizes zeroed
368*9712c20fSFrederick Mayle         // out. To help us handle this special case properly, give such
369*9712c20fSFrederick Mayle         // segments' contents NULL starting and ending pointers.
370*9712c20fSFrederick Mayle         if (segment.fileoff == 0 && segment.filesize == 0) {
371*9712c20fSFrederick Mayle           segment.contents.start = segment.contents.end = NULL;
372*9712c20fSFrederick Mayle         } else {
373*9712c20fSFrederick Mayle           segment.contents.start = buffer_.start + segment.fileoff;
374*9712c20fSFrederick Mayle           segment.contents.end = segment.contents.start + segment.filesize;
375*9712c20fSFrederick Mayle         }
376*9712c20fSFrederick Mayle         // The section list occupies the remainder of this load command's space.
377*9712c20fSFrederick Mayle         segment.section_list.start = cursor.here();
378*9712c20fSFrederick Mayle         segment.section_list.end = command.end;
379*9712c20fSFrederick Mayle 
380*9712c20fSFrederick Mayle         if (!handler->SegmentCommand(segment))
381*9712c20fSFrederick Mayle           return false;
382*9712c20fSFrederick Mayle         break;
383*9712c20fSFrederick Mayle       }
384*9712c20fSFrederick Mayle 
385*9712c20fSFrederick Mayle       case LC_SYMTAB: {
386*9712c20fSFrederick Mayle         uint32_t symoff, nsyms, stroff, strsize;
387*9712c20fSFrederick Mayle         cursor >> symoff >> nsyms >> stroff >> strsize;
388*9712c20fSFrederick Mayle         if (!cursor) {
389*9712c20fSFrederick Mayle           reporter_->LoadCommandTooShort(index, type);
390*9712c20fSFrederick Mayle           return false;
391*9712c20fSFrederick Mayle         }
392*9712c20fSFrederick Mayle         // How big are the entries in the symbol table?
393*9712c20fSFrederick Mayle         // sizeof(struct nlist_64) : sizeof(struct nlist),
394*9712c20fSFrederick Mayle         // but be paranoid about alignment vs. target architecture.
395*9712c20fSFrederick Mayle         size_t symbol_size = bits_64_ ? 16 : 12;
396*9712c20fSFrederick Mayle         // How big is the entire symbol array?
397*9712c20fSFrederick Mayle         size_t symbols_size = nsyms * symbol_size;
398*9712c20fSFrederick Mayle         if (symoff > buffer_.Size() || symbols_size > buffer_.Size() - symoff ||
399*9712c20fSFrederick Mayle             stroff > buffer_.Size() || strsize > buffer_.Size() - stroff) {
400*9712c20fSFrederick Mayle           reporter_->MisplacedSymbolTable();
401*9712c20fSFrederick Mayle           return false;
402*9712c20fSFrederick Mayle         }
403*9712c20fSFrederick Mayle         ByteBuffer entries(buffer_.start + symoff, symbols_size);
404*9712c20fSFrederick Mayle         ByteBuffer names(buffer_.start + stroff, strsize);
405*9712c20fSFrederick Mayle         if (!handler->SymtabCommand(entries, names))
406*9712c20fSFrederick Mayle           return false;
407*9712c20fSFrederick Mayle         break;
408*9712c20fSFrederick Mayle       }
409*9712c20fSFrederick Mayle 
410*9712c20fSFrederick Mayle       default: {
411*9712c20fSFrederick Mayle         if (!handler->UnknownCommand(type, command))
412*9712c20fSFrederick Mayle           return false;
413*9712c20fSFrederick Mayle         break;
414*9712c20fSFrederick Mayle       }
415*9712c20fSFrederick Mayle     }
416*9712c20fSFrederick Mayle 
417*9712c20fSFrederick Mayle     list_cursor.set_here(command.end);
418*9712c20fSFrederick Mayle   }
419*9712c20fSFrederick Mayle 
420*9712c20fSFrederick Mayle   return true;
421*9712c20fSFrederick Mayle }
422*9712c20fSFrederick Mayle 
423*9712c20fSFrederick Mayle // A load command handler that looks for a segment of a given name.
424*9712c20fSFrederick Mayle class Reader::SegmentFinder : public LoadCommandHandler {
425*9712c20fSFrederick Mayle  public:
426*9712c20fSFrederick Mayle   // Create a load command handler that looks for a segment named NAME,
427*9712c20fSFrederick Mayle   // and sets SEGMENT to describe it if found.
SegmentFinder(const string & name,Segment * segment)428*9712c20fSFrederick Mayle   SegmentFinder(const string& name, Segment* segment)
429*9712c20fSFrederick Mayle       : name_(name), segment_(segment), found_() { }
430*9712c20fSFrederick Mayle 
431*9712c20fSFrederick Mayle   // Return true if the traversal found the segment, false otherwise.
found() const432*9712c20fSFrederick Mayle   bool found() const { return found_; }
433*9712c20fSFrederick Mayle 
SegmentCommand(const Segment & segment)434*9712c20fSFrederick Mayle   bool SegmentCommand(const Segment& segment) {
435*9712c20fSFrederick Mayle     if (segment.name == name_) {
436*9712c20fSFrederick Mayle       *segment_ = segment;
437*9712c20fSFrederick Mayle       found_ = true;
438*9712c20fSFrederick Mayle       return false;
439*9712c20fSFrederick Mayle     }
440*9712c20fSFrederick Mayle     return true;
441*9712c20fSFrederick Mayle   }
442*9712c20fSFrederick Mayle 
443*9712c20fSFrederick Mayle  private:
444*9712c20fSFrederick Mayle   // The name of the segment our creator is looking for.
445*9712c20fSFrederick Mayle   const string& name_;
446*9712c20fSFrederick Mayle 
447*9712c20fSFrederick Mayle   // Where we should store the segment if found. (WEAK)
448*9712c20fSFrederick Mayle   Segment* segment_;
449*9712c20fSFrederick Mayle 
450*9712c20fSFrederick Mayle   // True if we found the segment.
451*9712c20fSFrederick Mayle   bool found_;
452*9712c20fSFrederick Mayle };
453*9712c20fSFrederick Mayle 
FindSegment(const string & name,Segment * segment) const454*9712c20fSFrederick Mayle bool Reader::FindSegment(const string& name, Segment* segment) const {
455*9712c20fSFrederick Mayle   SegmentFinder finder(name, segment);
456*9712c20fSFrederick Mayle   WalkLoadCommands(&finder);
457*9712c20fSFrederick Mayle   return finder.found();
458*9712c20fSFrederick Mayle }
459*9712c20fSFrederick Mayle 
WalkSegmentSections(const Segment & segment,SectionHandler * handler) const460*9712c20fSFrederick Mayle bool Reader::WalkSegmentSections(const Segment& segment,
461*9712c20fSFrederick Mayle                                  SectionHandler* handler) const {
462*9712c20fSFrederick Mayle   size_t word_size = segment.bits_64 ? 8 : 4;
463*9712c20fSFrederick Mayle   ByteCursor cursor(&segment.section_list, big_endian_);
464*9712c20fSFrederick Mayle 
465*9712c20fSFrederick Mayle   for (size_t i = 0; i < segment.nsects; i++) {
466*9712c20fSFrederick Mayle     Section section;
467*9712c20fSFrederick Mayle     section.bits_64 = segment.bits_64;
468*9712c20fSFrederick Mayle     uint64_t size, offset;
469*9712c20fSFrederick Mayle     uint32_t dummy32;
470*9712c20fSFrederick Mayle     cursor
471*9712c20fSFrederick Mayle         .CString(&section.section_name, 16)
472*9712c20fSFrederick Mayle         .CString(&section.segment_name, 16)
473*9712c20fSFrederick Mayle         .Read(word_size, false, &section.address)
474*9712c20fSFrederick Mayle         .Read(word_size, false, &size)
475*9712c20fSFrederick Mayle         .Read(sizeof(uint32_t), false, &offset)  // clears high bits of |offset|
476*9712c20fSFrederick Mayle         >> section.align
477*9712c20fSFrederick Mayle         >> dummy32
478*9712c20fSFrederick Mayle         >> dummy32
479*9712c20fSFrederick Mayle         >> section.flags
480*9712c20fSFrederick Mayle         >> dummy32
481*9712c20fSFrederick Mayle         >> dummy32;
482*9712c20fSFrederick Mayle     if (section.bits_64)
483*9712c20fSFrederick Mayle       cursor >> dummy32;
484*9712c20fSFrederick Mayle     if (!cursor) {
485*9712c20fSFrederick Mayle       reporter_->SectionsMissing(segment.name);
486*9712c20fSFrederick Mayle       return false;
487*9712c20fSFrederick Mayle     }
488*9712c20fSFrederick Mayle 
489*9712c20fSFrederick Mayle     // Even 64-bit Mach-O isn’t a true 64-bit format in that it doesn’t handle
490*9712c20fSFrederick Mayle     // 64-bit file offsets gracefully. Segment load commands do contain 64-bit
491*9712c20fSFrederick Mayle     // file offsets, but sections within do not. Because segments load
492*9712c20fSFrederick Mayle     // contiguously, recompute each section’s file offset on the basis of its
493*9712c20fSFrederick Mayle     // containing segment’s file offset and the difference between the section’s
494*9712c20fSFrederick Mayle     // and segment’s load addresses. If truncation is detected, honor the
495*9712c20fSFrederick Mayle     // recomputed offset.
496*9712c20fSFrederick Mayle     if (segment.bits_64 &&
497*9712c20fSFrederick Mayle         segment.fileoff + segment.filesize >
498*9712c20fSFrederick Mayle             std::numeric_limits<uint32_t>::max()) {
499*9712c20fSFrederick Mayle       const uint64_t section_offset_recomputed =
500*9712c20fSFrederick Mayle           segment.fileoff + section.address - segment.vmaddr;
501*9712c20fSFrederick Mayle       if (offset == static_cast<uint32_t>(section_offset_recomputed)) {
502*9712c20fSFrederick Mayle         offset = section_offset_recomputed;
503*9712c20fSFrederick Mayle       }
504*9712c20fSFrederick Mayle     }
505*9712c20fSFrederick Mayle 
506*9712c20fSFrederick Mayle     const uint32_t section_type = section.flags & SECTION_TYPE;
507*9712c20fSFrederick Mayle     if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL ||
508*9712c20fSFrederick Mayle             section_type == S_GB_ZEROFILL) {
509*9712c20fSFrederick Mayle       // Zero-fill sections have a size, but no contents.
510*9712c20fSFrederick Mayle       section.contents.start = section.contents.end = NULL;
511*9712c20fSFrederick Mayle     } else if (segment.contents.start == NULL &&
512*9712c20fSFrederick Mayle                segment.contents.end == NULL) {
513*9712c20fSFrederick Mayle       // Mach-O files in .dSYM bundles have the contents of the loaded
514*9712c20fSFrederick Mayle       // segments removed, and their file offsets and file sizes zeroed
515*9712c20fSFrederick Mayle       // out.  However, the sections within those segments still have
516*9712c20fSFrederick Mayle       // non-zero sizes.  There's no reason to call MisplacedSectionData in
517*9712c20fSFrederick Mayle       // this case; the caller may just need the section's load
518*9712c20fSFrederick Mayle       // address. But do set the contents' limits to NULL, for safety.
519*9712c20fSFrederick Mayle       section.contents.start = section.contents.end = NULL;
520*9712c20fSFrederick Mayle     } else {
521*9712c20fSFrederick Mayle       if (offset < size_t(segment.contents.start - buffer_.start) ||
522*9712c20fSFrederick Mayle           offset > size_t(segment.contents.end - buffer_.start) ||
523*9712c20fSFrederick Mayle           size > size_t(segment.contents.end - buffer_.start - offset)) {
524*9712c20fSFrederick Mayle         if (offset > 0) {
525*9712c20fSFrederick Mayle           reporter_->MisplacedSectionData(section.section_name,
526*9712c20fSFrederick Mayle                                           section.segment_name);
527*9712c20fSFrederick Mayle           return false;
528*9712c20fSFrederick Mayle         } else {
529*9712c20fSFrederick Mayle           // Mach-O files in .dSYM bundles have the contents of the loaded
530*9712c20fSFrederick Mayle           // segments partially removed. The removed sections will have zero as
531*9712c20fSFrederick Mayle           // their offset. MisplacedSectionData should not be called in this
532*9712c20fSFrederick Mayle           // case.
533*9712c20fSFrederick Mayle           section.contents.start = section.contents.end = NULL;
534*9712c20fSFrederick Mayle         }
535*9712c20fSFrederick Mayle       } else {
536*9712c20fSFrederick Mayle         section.contents.start = buffer_.start + offset;
537*9712c20fSFrederick Mayle         section.contents.end = section.contents.start + size;
538*9712c20fSFrederick Mayle       }
539*9712c20fSFrederick Mayle     }
540*9712c20fSFrederick Mayle     if (!handler->HandleSection(section))
541*9712c20fSFrederick Mayle       return false;
542*9712c20fSFrederick Mayle   }
543*9712c20fSFrederick Mayle   return true;
544*9712c20fSFrederick Mayle }
545*9712c20fSFrederick Mayle 
546*9712c20fSFrederick Mayle // A SectionHandler that builds a SectionMap for the sections within a
547*9712c20fSFrederick Mayle // given segment.
548*9712c20fSFrederick Mayle class Reader::SectionMapper: public SectionHandler {
549*9712c20fSFrederick Mayle  public:
550*9712c20fSFrederick Mayle   // Create a SectionHandler that populates MAP with an entry for
551*9712c20fSFrederick Mayle   // each section it is given.
SectionMapper(SectionMap * map)552*9712c20fSFrederick Mayle   SectionMapper(SectionMap* map) : map_(map) { }
HandleSection(const Section & section)553*9712c20fSFrederick Mayle   bool HandleSection(const Section& section) {
554*9712c20fSFrederick Mayle     (*map_)[section.section_name] = section;
555*9712c20fSFrederick Mayle     return true;
556*9712c20fSFrederick Mayle   }
557*9712c20fSFrederick Mayle  private:
558*9712c20fSFrederick Mayle   // The map under construction. (WEAK)
559*9712c20fSFrederick Mayle   SectionMap* map_;
560*9712c20fSFrederick Mayle };
561*9712c20fSFrederick Mayle 
MapSegmentSections(const Segment & segment,SectionMap * section_map) const562*9712c20fSFrederick Mayle bool Reader::MapSegmentSections(const Segment& segment,
563*9712c20fSFrederick Mayle                                 SectionMap* section_map) const {
564*9712c20fSFrederick Mayle   section_map->clear();
565*9712c20fSFrederick Mayle   SectionMapper mapper(section_map);
566*9712c20fSFrederick Mayle   return WalkSegmentSections(segment, &mapper);
567*9712c20fSFrederick Mayle }
568*9712c20fSFrederick Mayle 
569*9712c20fSFrederick Mayle }  // namespace mach_o
570*9712c20fSFrederick Mayle }  // namespace google_breakpad
571