xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_machoread.c (revision 4d9fdb46b215739778ebc12079842c9905586999)
1 /*
2 Copyright (c) 2019, David Anderson
3 All rights reserved.
4 cc
5 Redistribution and use in source and binary forms, with
6 or without modification, are permitted provided that the
7 following conditions are met:
8 
9     Redistributions of source code must retain the above
10     copyright notice, this list of conditions and the following
11     disclaimer.
12 
13     Redistributions in binary form must reproduce the above
14     copyright notice, this list of conditions and the following
15     disclaimer in the documentation and/or other materials
16     provided with the distribution.
17 
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 /*  This file reads the parts of an Apple mach-o object
34     file appropriate to reading DWARF debugging data.
35     Overview:
36     _dwarf_macho_setup() Does all macho setup.
37         calls _dwarf_macho_access_init()
38             calls _dwarf_macho_object_access_internals_init()
39                 Creates internals record 'M',
40                     dwarf_macho_object_access_internals_t
41                 Sets flags/data in internals record
42                 Loads macho object data needed later.
43                 Sets methods struct to access macho object.
44         calls _dwarf_object_init_b() Creates Dwarf_Debug, independent
45             of any macho code.
46         Sets internals record into dbg.
47     ----------------------
48     _dwarf_destruct_macho_access(). This frees
49         the macho internals record created in
50         _dwarf_macho_object_access_internals_init()
51         in case of errors during setup or when
52         dwarf_finish() is called.  Works safely for
53         partially or fully set-up macho internals record.
54 
55     Other than in _dwarf_macho_setup() the macho code
56     knows nothing about Dwarf_Debug, and the rest of
57     libdwarf knows nothing about the content of the
58     macho internals record.
59 
60 */
61 
62 #ifdef _WIN32
63 #define _CRT_SECURE_NO_WARNINGS
64 #endif /* _WIN32 */
65 
66 #include "config.h"
67 #include <stdio.h>
68 #ifdef HAVE_STDLIB_H
69 #include <stdlib.h>
70 #endif /* HAVE_STDLIB_H */
71 #ifdef HAVE_MALLOC_H
72 /* Useful include for some Windows compilers. */
73 #include <malloc.h>
74 #endif /* HAVE_MALLOC_H */
75 #include <string.h>
76 #include <sys/types.h> /* open() */
77 #include <sys/stat.h> /* open() */
78 #include <fcntl.h> /* open() */
79 #include <time.h>
80 #ifdef HAVE_UNISTD_H
81 #include <unistd.h> /* lseek read close */
82 #elif defined(_WIN32) && defined(_MSC_VER)
83 #include <io.h>
84 #endif /* HAVE_UNISTD_H */
85 
86 /* Windows specific header files */
87 #if defined(_WIN32) && defined(HAVE_STDAFX_H)
88 #include "stdafx.h"
89 #endif /* HAVE_STDAFX_H */
90 
91 #include "libdwarf.h"
92 #include "libdwarfdefs.h"
93 #include "dwarf_base_types.h"
94 #include "dwarf_opaque.h"
95 #include "dwarf_error.h" /* for _dwarf_error() declaration */
96 #include "dwarf_reading.h"
97 #include "memcpy_swap.h"
98 #include "dwarf_object_read_common.h"
99 #include "dwarf_machoread.h"
100 #include "dwarf_object_detector.h"
101 #include "dwarf_macho_loader.h"
102 
103 #ifndef TYP
104 #define TYP(n,l) char n[l]
105 #endif /* TYPE */
106 
107 #ifdef WORDS_BIGENDIAN
108 #define ASNAR(func,t,s)                         \
109     do {                                        \
110         unsigned tbyte = sizeof(t) - sizeof(s); \
111         t = 0;                                  \
112         func(((char *)&t)+tbyte ,&s[0],sizeof(s));  \
113     } while (0)
114 #else /* LITTLE ENDIAN */
115 #define ASNAR(func,t,s)                         \
116     do {                                        \
117         t = 0;                                  \
118         func(&t,&s[0],sizeof(s));               \
119     } while (0)
120 #endif /* end LITTLE- BIG-ENDIAN */
121 
122 
123 /* MACH-O and dwarf section names */
124 static struct macho_sect_names_s {
125     char const *ms_moname;
126     char const *ms_dwname;
127 } const SectionNames [] = {
128     { "", "" },  /* ELF index-0 entry */
129     { "__debug_abbrev",         ".debug_abbrev" },
130     { "__debug_aranges",        ".debug_aranges" },
131     { "__debug_frame",          ".debug_frame" },
132     { "__debug_info",           ".debug_info" },
133     { "__debug_line",           ".debug_line" },
134     { "__debug_macinfo",        ".debug_macinfo" },
135     { "__debug_loc",            ".debug_loc" },
136     { "__debug_pubnames",       ".debug_pubnames" },
137     { "__debug_pubtypes",       ".debug_pubtypes" },
138     { "__debug_str",            ".debug_str" },
139     { "__debug_ranges",         ".debug_ranges" },
140     { "__debug_macro",          ".debug_macro" },
141     { "__debug_gdb_scri",       ".debug_gdb_scripts" }
142 };
143 
144 static int
145 _dwarf_macho_object_access_init(
146     int  fd,
147     unsigned ftype,
148     unsigned endian,
149     unsigned offsetsize,
150     size_t filesize,
151     Dwarf_Unsigned access,
152     Dwarf_Obj_Access_Interface **binary_interface,
153     int *localerrnum);
154 
155 
macho_get_byte_order(void * obj)156 static Dwarf_Endianness macho_get_byte_order (void *obj)
157 {
158     dwarf_macho_object_access_internals_t *macho =
159         (dwarf_macho_object_access_internals_t*)(obj);
160     return macho->mo_endian;
161 }
162 
163 
macho_get_length_size(void * obj)164 static Dwarf_Small macho_get_length_size (void *obj)
165 {
166     dwarf_macho_object_access_internals_t *macho =
167         (dwarf_macho_object_access_internals_t*)(obj);
168     return macho->mo_offsetsize/8;
169 }
170 
171 
macho_get_pointer_size(void * obj)172 static Dwarf_Small macho_get_pointer_size (void *obj)
173 {
174     dwarf_macho_object_access_internals_t *macho =
175         (dwarf_macho_object_access_internals_t*)(obj);
176     return macho->mo_pointersize/8;
177 }
178 
179 
macho_get_section_count(void * obj)180 static Dwarf_Unsigned macho_get_section_count (void *obj)
181 {
182     dwarf_macho_object_access_internals_t *macho =
183         (dwarf_macho_object_access_internals_t*)(obj);
184     return macho->mo_dwarf_sectioncount;
185 }
186 
macho_get_section_info(void * obj,Dwarf_Half section_index,Dwarf_Obj_Access_Section * return_section,UNUSEDARG int * error)187 static int macho_get_section_info (void *obj,
188     Dwarf_Half section_index,
189     Dwarf_Obj_Access_Section *return_section,
190     UNUSEDARG int *error)
191 {
192     dwarf_macho_object_access_internals_t *macho =
193         (dwarf_macho_object_access_internals_t*)(obj);
194 
195 
196     if (section_index < macho->mo_dwarf_sectioncount) {
197         struct generic_macho_section *sp = 0;
198 
199         sp = macho->mo_dwarf_sections + section_index;
200         return_section->addr = 0;
201         return_section->type = 0;
202         return_section->size = sp->size;
203         return_section->name = sp->dwarfsectname;
204         return_section->link = 0;
205         return_section->info = 0;
206         return_section->entrysize = 0;
207         return DW_DLV_OK;
208     }
209     return DW_DLV_NO_ENTRY;
210 }
211 
212 static int
macho_load_section(void * obj,Dwarf_Half section_index,Dwarf_Small ** return_data,int * error)213 macho_load_section (void *obj, Dwarf_Half section_index,
214     Dwarf_Small **return_data, int *error)
215 {
216     dwarf_macho_object_access_internals_t *macho =
217         (dwarf_macho_object_access_internals_t*)(obj);
218 
219     if (0 < section_index &&
220         section_index < macho->mo_dwarf_sectioncount) {
221         int res = 0;
222 
223         struct generic_macho_section *sp =
224             macho->mo_dwarf_sections + section_index;
225         if(sp->loaded_data) {
226             *return_data = sp->loaded_data;
227             return DW_DLV_OK;
228         }
229         if (!sp->size) {
230             return DW_DLV_NO_ENTRY;
231         }
232         if ((sp->size + sp->offset) >
233             macho->mo_filesize) {
234             *error = DW_DLE_FILE_TOO_SMALL;
235             return DW_DLV_ERROR;
236         }
237 
238         sp->loaded_data = malloc((size_t)sp->size);
239         if (!sp->loaded_data) {
240             *error = DW_DLE_ALLOC_FAIL;
241             return DW_DLV_ERROR;
242         }
243         res = RRMOA(macho->mo_fd,
244             sp->loaded_data, (off_t)sp->offset,
245             (size_t)sp->size, (off_t)macho->mo_filesize, error);
246         if (res != DW_DLV_OK) {
247             free(sp->loaded_data);
248             sp->loaded_data = 0;
249             return res;
250         }
251         *return_data = sp->loaded_data;
252         return DW_DLV_OK;
253     }
254     return DW_DLV_NO_ENTRY;
255 }
256 
257 void
_dwarf_destruct_macho_access(struct Dwarf_Obj_Access_Interface_s * aip)258 _dwarf_destruct_macho_access(
259     struct Dwarf_Obj_Access_Interface_s *aip)
260 {
261     dwarf_macho_object_access_internals_t *mp = 0;
262     Dwarf_Unsigned i = 0;
263 
264     if(!aip) {
265         return;
266     }
267     mp = (dwarf_macho_object_access_internals_t *)aip->object;
268     if (mp->mo_destruct_close_fd) {
269         close(mp->mo_fd);
270         mp->mo_fd = -1;
271     }
272     if (mp->mo_commands){
273         free(mp->mo_commands);
274         mp->mo_commands = 0;
275     }
276     if (mp->mo_segment_commands){
277         free(mp->mo_segment_commands);
278         mp->mo_segment_commands = 0;
279     }
280     free((char *)mp->mo_path);
281     if (mp->mo_dwarf_sections) {
282         struct generic_macho_section *sp = 0;
283 
284         sp = mp->mo_dwarf_sections;
285         for( i=0; i < mp->mo_dwarf_sectioncount; ++i,++sp) {
286             if (sp->loaded_data) {
287                 free(sp->loaded_data);
288                 sp->loaded_data = 0;
289             }
290         }
291         free(mp->mo_dwarf_sections);
292         mp->mo_dwarf_sections = 0;
293     }
294     free(mp);
295     free(aip);
296     return;
297 }
298 
299 /* load_macho_header32(dwarf_macho_object_access_internals_t *mfp)*/
300 static int
load_macho_header32(dwarf_macho_object_access_internals_t * mfp,int * errcode)301 load_macho_header32(dwarf_macho_object_access_internals_t *mfp, int *errcode)
302 {
303     struct mach_header mh32;
304     int res = 0;
305 
306     if (sizeof(mh32) > mfp->mo_filesize) {
307         *errcode = DW_DLE_FILE_TOO_SMALL;
308         return DW_DLV_ERROR;
309     }
310     res = RRMOA(mfp->mo_fd, &mh32, 0, sizeof(mh32),
311         (off_t)mfp->mo_filesize, errcode);
312     if (res != DW_DLV_OK) {
313         return res;
314     }
315     /* Do not adjust endianness of magic, leave as-is. */
316     ASNAR(memcpy,mfp->mo_header.magic,mh32.magic);
317     ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh32.cputype);
318     ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype,mh32.cpusubtype);
319     ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh32.filetype);
320     ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh32.ncmds);
321     ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds,mh32.sizeofcmds);
322     ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh32.flags);
323     mfp->mo_header.reserved = 0;
324     mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds;
325     mfp->mo_command_start_offset = sizeof(mh32);
326     return DW_DLV_OK;
327 }
328 
329 /* load_macho_header64(dwarf_macho_object_access_internals_t *mfp) */
330 static int
load_macho_header64(dwarf_macho_object_access_internals_t * mfp,int * errcode)331 load_macho_header64(dwarf_macho_object_access_internals_t *mfp,
332     int *errcode)
333 {
334     struct mach_header_64 mh64;
335     int res = 0;
336 
337     if (sizeof(mh64) > mfp->mo_filesize) {
338         *errcode = DW_DLE_FILE_TOO_SMALL;
339         return DW_DLV_ERROR;
340     }
341     res = RRMOA(mfp->mo_fd, &mh64, 0, sizeof(mh64),
342         (off_t)mfp->mo_filesize, errcode);
343     if (res != DW_DLV_OK) {
344         return res;
345     }
346     /* Do not adjust endianness of magic, leave as-is. */
347     ASNAR(memcpy,mfp->mo_header.magic,mh64.magic);
348     ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh64.cputype);
349     ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype,mh64.cpusubtype);
350     ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh64.filetype);
351     ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh64.ncmds);
352     ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds,mh64.sizeofcmds);
353     ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh64.flags);
354     ASNAR(mfp->mo_copy_word,mfp->mo_header.reserved,mh64.reserved);
355     mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds;
356     mfp->mo_command_start_offset = sizeof(mh64);
357     return DW_DLV_OK;
358 }
359 
360 int
dwarf_load_macho_header(dwarf_macho_object_access_internals_t * mfp,int * errcode)361 dwarf_load_macho_header(dwarf_macho_object_access_internals_t *mfp,
362     int *errcode)
363 {
364     int res = 0;
365 
366     if (mfp->mo_offsetsize == 32) {
367         res = load_macho_header32(mfp,errcode);
368     } else if (mfp->mo_offsetsize == 64) {
369         res = load_macho_header64(mfp,errcode);
370     } else {
371         *errcode = DW_DLE_OFFSET_SIZE;
372         return DW_DLV_ERROR;
373     }
374     return res;
375 }
376 
377 
378 static int
load_segment_command_content32(dwarf_macho_object_access_internals_t * mfp,struct generic_macho_command * mmp,struct generic_macho_segment_command * msp,Dwarf_Unsigned mmpindex,int * errcode)379 load_segment_command_content32(
380     dwarf_macho_object_access_internals_t *mfp,
381     struct generic_macho_command *mmp,
382     struct generic_macho_segment_command *msp,
383     Dwarf_Unsigned mmpindex,
384     int *errcode)
385 {
386     struct segment_command sc;
387     int res = 0;
388     Dwarf_Unsigned filesize = mfp->mo_filesize;
389     Dwarf_Unsigned segoffset = mmp->offset_this_command;
390     Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc);
391 
392     if (mmp->offset_this_command > filesize ||
393         mmp->cmdsize > filesize ||
394         (mmp->cmdsize + mmp->offset_this_command) > filesize ) {
395         *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD;
396         return DW_DLV_ERROR;
397     }
398     res = RRMOA(mfp->mo_fd, &sc, (off_t)mmp->offset_this_command, sizeof(sc),
399         (off_t)filesize, errcode);
400     if (res != DW_DLV_OK) {
401         return res;
402     }
403     ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd);
404     ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize);
405     strncpy(msp->segname,sc.segname,16);
406     msp->segname[15] =0;
407     ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr);
408     ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize);
409     ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff);
410     ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize);
411     if (msp->fileoff > mfp->mo_filesize ||
412         msp->filesize > mfp->mo_filesize) {
413         /* corrupt */
414         *errcode = DW_DLE_FILE_OFFSET_BAD;
415         return DW_DLV_ERROR;
416     }
417     if ((msp->fileoff+msp->filesize ) > filesize) {
418         /* corrupt */
419         *errcode = DW_DLE_FILE_OFFSET_BAD;
420         return DW_DLV_ERROR;
421     }
422     ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot);
423     ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot);
424     ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects);
425     ASNAR(mfp->mo_copy_word,msp->flags,sc.flags);
426     msp->macho_command_index = mmpindex;
427     msp->sectionsoffset = afterseghdr;
428     return DW_DLV_OK;
429 }
430 static int
load_segment_command_content64(dwarf_macho_object_access_internals_t * mfp,struct generic_macho_command * mmp,struct generic_macho_segment_command * msp,Dwarf_Unsigned mmpindex,int * errcode)431 load_segment_command_content64(
432     dwarf_macho_object_access_internals_t *mfp,
433     struct generic_macho_command *mmp,
434     struct generic_macho_segment_command *msp,
435     Dwarf_Unsigned mmpindex,int *errcode)
436 {
437     struct segment_command_64 sc;
438     int res = 0;
439     Dwarf_Unsigned filesize = mfp->mo_filesize;
440     Dwarf_Unsigned segoffset = mmp->offset_this_command;
441     Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc);
442 
443     if (mmp->offset_this_command > filesize ||
444         mmp->cmdsize > filesize ||
445         (mmp->cmdsize + mmp->offset_this_command) > filesize ) {
446         *errcode = DW_DLE_FILE_OFFSET_BAD;
447         return DW_DLV_ERROR;
448     }
449     res = RRMOA(mfp->mo_fd, &sc, (off_t)mmp->offset_this_command, sizeof(sc),
450         (off_t)filesize, errcode);
451     if (res != DW_DLV_OK) {
452         return res;
453     }
454     ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd);
455     ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize);
456     strncpy(msp->segname,sc.segname,16);
457     msp->segname[16] =0;
458     ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr);
459     ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize);
460     ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff);
461     ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize);
462     if (msp->fileoff > filesize ||
463         msp->filesize > filesize) {
464         /* corrupt */
465         *errcode = DW_DLE_FILE_OFFSET_BAD;
466         return DW_DLV_ERROR;
467     }
468     if ((msp->fileoff+msp->filesize ) > filesize) {
469         /* corrupt */
470         *errcode = DW_DLE_FILE_OFFSET_BAD;
471         return DW_DLV_ERROR;
472     }
473     ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot);
474     ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot);
475     ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects);
476     ASNAR(mfp->mo_copy_word,msp->flags,sc.flags);
477     msp->macho_command_index = mmpindex;
478     msp->sectionsoffset = afterseghdr;
479     return DW_DLV_OK;
480 }
481 
482 static int
dwarf_macho_load_segment_commands(dwarf_macho_object_access_internals_t * mfp,int * errcode)483 dwarf_macho_load_segment_commands(
484     dwarf_macho_object_access_internals_t *mfp,int *errcode)
485 {
486     Dwarf_Unsigned i = 0;
487     struct generic_macho_command *mmp = 0;
488     struct generic_macho_segment_command *msp = 0;
489 
490     if (mfp->mo_segment_count < 1) {
491         return DW_DLV_OK;
492     }
493     mfp->mo_segment_commands =
494         (struct generic_macho_segment_command *)
495         calloc(sizeof(struct generic_macho_segment_command),
496         (size_t)mfp->mo_segment_count);
497     if (!mfp->mo_segment_commands) {
498         *errcode = DW_DLE_ALLOC_FAIL;
499         return DW_DLV_ERROR;
500     }
501 
502     mmp = mfp->mo_commands;
503     msp = mfp->mo_segment_commands;
504     for (i = 0 ; i < mfp->mo_command_count; ++i,++mmp) {
505         unsigned cmd = (unsigned)mmp->cmd;
506         int res = 0;
507 
508         if (cmd == LC_SEGMENT) {
509             res = load_segment_command_content32(mfp,mmp,msp,i,errcode);
510             ++msp;
511         } else if (cmd == LC_SEGMENT_64) {
512             res = load_segment_command_content64(mfp,mmp,msp,i,errcode);
513             ++msp;
514         }
515         if (res != DW_DLV_OK) {
516             return res;
517         }
518     }
519     return DW_DLV_OK;
520 }
521 
522 static int
dwarf_macho_load_dwarf_section_details32(dwarf_macho_object_access_internals_t * mfp,struct generic_macho_segment_command * segp,Dwarf_Unsigned segi,int * errcode)523 dwarf_macho_load_dwarf_section_details32(
524     dwarf_macho_object_access_internals_t *mfp,
525     struct generic_macho_segment_command *segp,
526     Dwarf_Unsigned segi, int *errcode)
527 {
528     Dwarf_Unsigned seci = 0;
529     Dwarf_Unsigned seccount = segp->nsects;
530     Dwarf_Unsigned secalloc = seccount+1;
531     Dwarf_Unsigned curoff = segp->sectionsoffset;
532     Dwarf_Unsigned shdrlen = sizeof(struct section);
533 
534     struct generic_macho_section *secs = 0;
535 
536     secs = (struct generic_macho_section *)calloc(
537         sizeof(struct generic_macho_section),
538         (size_t)secalloc);
539     if (!secs) {
540         *errcode = DW_DLE_ALLOC_FAIL;
541         return DW_DLV_OK;
542     }
543     mfp->mo_dwarf_sections = secs;
544     mfp->mo_dwarf_sectioncount = secalloc;
545     if ((curoff  > mfp->mo_filesize) ||
546         (seccount > mfp->mo_filesize) ||
547         (curoff+(seccount*sizeof(struct section)) >
548             mfp->mo_filesize)) {
549         *errcode = DW_DLE_FILE_TOO_SMALL;
550         return DW_DLV_ERROR;
551     }
552     secs->offset_of_sec_rec = curoff;
553     /*  Leave 0 section all zeros except our offset,
554         elf-like in a sense */
555     secs->dwarfsectname = "";
556     ++secs;
557     seci = 1;
558     for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) {
559         struct section mosec;
560         int res = 0;
561 
562         res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec),
563             (off_t)mfp->mo_filesize, errcode);
564         if (res != DW_DLV_OK) {
565             return res;
566         }
567         strncpy(secs->sectname,mosec.sectname,16);
568         secs->sectname[16] = 0;
569         strncpy(secs->segname,mosec.segname,16);
570         secs->segname[16] = 0;
571         ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr);
572         ASNAR(mfp->mo_copy_word,secs->size,mosec.size);
573         ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset);
574         ASNAR(mfp->mo_copy_word,secs->align,mosec.align);
575         ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff);
576         ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc);
577         ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags);
578         if (secs->offset > mfp->mo_filesize ||
579             secs->size > mfp->mo_filesize ||
580             (secs->offset+secs->size) > mfp->mo_filesize) {
581             *errcode = DW_DLE_FILE_OFFSET_BAD;
582             return DW_DLV_ERROR;
583         }
584         secs->reserved1 = 0;
585         secs->reserved2 = 0;
586         secs->reserved3 = 0;
587         secs->generic_segment_num  = segi;
588         secs->offset_of_sec_rec = curoff;
589     }
590     return DW_DLV_OK;
591 }
592 static int
dwarf_macho_load_dwarf_section_details64(dwarf_macho_object_access_internals_t * mfp,struct generic_macho_segment_command * segp,Dwarf_Unsigned segi,int * errcode)593 dwarf_macho_load_dwarf_section_details64(
594     dwarf_macho_object_access_internals_t *mfp,
595     struct generic_macho_segment_command *segp,
596     Dwarf_Unsigned segi,
597     int *errcode)
598 {
599     Dwarf_Unsigned seci = 0;
600     Dwarf_Unsigned seccount = segp->nsects;
601     Dwarf_Unsigned secalloc = seccount+1;
602     Dwarf_Unsigned curoff = segp->sectionsoffset;
603     Dwarf_Unsigned shdrlen = sizeof(struct section_64);
604     struct generic_macho_section *secs = 0;
605 
606     secs = (struct generic_macho_section *)calloc(
607         sizeof(struct generic_macho_section),
608         (size_t)secalloc);
609     if (!secs) {
610         *errcode = DW_DLE_ALLOC_FAIL;
611         return DW_DLV_ERROR;
612     }
613     mfp->mo_dwarf_sections = secs;
614     mfp->mo_dwarf_sectioncount = secalloc;
615     secs->offset_of_sec_rec = curoff;
616     /*  Leave 0 section all zeros except our offset,
617         elf-like in a sense */
618     secs->dwarfsectname = "";
619     ++secs;
620     if ((curoff  > mfp->mo_filesize) ||
621         (seccount > mfp->mo_filesize) ||
622         (curoff+(seccount*sizeof(struct section_64)) >
623             mfp->mo_filesize)) {
624         *errcode = DW_DLE_FILE_TOO_SMALL;
625         return DW_DLV_ERROR;
626     }
627     seci = 1;
628     for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) {
629         int res = 0;
630         struct section_64 mosec;
631 
632         res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec),
633             (off_t)mfp->mo_filesize, errcode);
634         if (res != DW_DLV_OK) {
635             return res;
636         }
637         strncpy(secs->sectname,mosec.sectname,16);
638         secs->sectname[16] = 0;
639         strncpy(secs->segname,mosec.segname,16);
640         secs->segname[16] = 0;
641         ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr);
642         ASNAR(mfp->mo_copy_word,secs->size,mosec.size);
643         ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset);
644         ASNAR(mfp->mo_copy_word,secs->align,mosec.align);
645         ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff);
646         ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc);
647         ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags);
648         if (secs->offset > mfp->mo_filesize ||
649             secs->size > mfp->mo_filesize ||
650             (secs->offset+secs->size) > mfp->mo_filesize) {
651             *errcode = DW_DLE_FILE_OFFSET_BAD;
652             return DW_DLV_OK;
653         }
654         secs->reserved1 = 0;
655         secs->reserved2 = 0;
656         secs->reserved3 = 0;
657         secs->offset_of_sec_rec = curoff;
658         secs->generic_segment_num  = segi;
659     }
660     return DW_DLV_OK;
661 }
662 
663 static int
dwarf_macho_load_dwarf_section_details(dwarf_macho_object_access_internals_t * mfp,struct generic_macho_segment_command * segp,Dwarf_Unsigned segi,int * errcode)664 dwarf_macho_load_dwarf_section_details(
665     dwarf_macho_object_access_internals_t *mfp,
666     struct generic_macho_segment_command *segp,
667     Dwarf_Unsigned segi,int *errcode)
668 {
669     int res = 0;
670 
671     if (mfp->mo_offsetsize == 32) {
672         res = dwarf_macho_load_dwarf_section_details32(mfp,
673             segp,segi,errcode);
674     } else if (mfp->mo_offsetsize == 64) {
675         res = dwarf_macho_load_dwarf_section_details64(mfp,
676             segp,segi,errcode);
677     } else {
678         *errcode = DW_DLE_OFFSET_SIZE;
679         return DW_DLV_ERROR;
680     }
681     return res;
682 }
683 
684 static int
dwarf_macho_load_dwarf_sections(dwarf_macho_object_access_internals_t * mfp,int * errcode)685 dwarf_macho_load_dwarf_sections(
686     dwarf_macho_object_access_internals_t *mfp,int *errcode)
687 {
688     Dwarf_Unsigned segi = 0;
689 
690     struct generic_macho_segment_command *segp =
691         mfp->mo_segment_commands;
692     for ( ; segi < mfp->mo_segment_count; ++segi,++segp) {
693         int res = 0;
694 
695         if (strcmp(segp->segname,"__DWARF")) {
696             continue;
697         }
698         /* Found DWARF, for now assume only one such. */
699         res = dwarf_macho_load_dwarf_section_details(mfp,segp,segi,errcode);
700         return res;
701     }
702     return DW_DLV_OK;
703 }
704 
705 /* Works the same, 32 or 64 bit */
706 int
dwarf_load_macho_commands(dwarf_macho_object_access_internals_t * mfp,int * errcode)707 dwarf_load_macho_commands(
708     dwarf_macho_object_access_internals_t *mfp,int *errcode)
709 {
710     Dwarf_Unsigned cmdi = 0;
711     Dwarf_Unsigned curoff = mfp->mo_command_start_offset;
712     Dwarf_Unsigned cmdspace = 0;
713     struct load_command mc;
714     struct generic_macho_command *mcp = 0;
715     unsigned segment_command_count = 0;
716     int res = 0;
717 
718     if (mfp->mo_command_count >= mfp->mo_filesize) {
719         /* corrupt object. */
720         *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD;
721         return DW_DLV_ERROR;
722     }
723     if ((curoff + mfp->mo_command_count * sizeof(mc)) >=
724         mfp->mo_filesize) {
725         /* corrupt object. */
726         *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD;
727         return DW_DLV_ERROR;
728     }
729 
730     mfp->mo_commands = (struct generic_macho_command *) calloc(
731         mfp->mo_command_count,sizeof(struct generic_macho_command));
732     if( !mfp->mo_commands) {
733         /* out of memory */
734         *errcode = DW_DLE_ALLOC_FAIL;
735         return DW_DLV_ERROR;
736     }
737     mcp = mfp->mo_commands;
738     for ( ; cmdi < mfp->mo_header.ncmds; ++cmdi,++mcp ) {
739         res = RRMOA(mfp->mo_fd, &mc, (off_t)curoff, sizeof(mc),
740             (off_t)mfp->mo_filesize, errcode);
741         if (res != DW_DLV_OK) {
742             return res;
743         }
744         ASNAR(mfp->mo_copy_word,mcp->cmd,mc.cmd);
745         ASNAR(mfp->mo_copy_word,mcp->cmdsize,mc.cmdsize);
746         mcp->offset_this_command = curoff;
747         curoff += mcp->cmdsize;
748         cmdspace += mcp->cmdsize;
749         if (mcp->cmdsize > mfp->mo_filesize ||
750             curoff > mfp->mo_filesize) {
751             /* corrupt object */
752             *errcode = DW_DLE_FILE_OFFSET_BAD;
753             return DW_DLV_ERROR;
754         }
755         if (mcp->cmd == LC_SEGMENT || mcp->cmd == LC_SEGMENT_64) {
756             segment_command_count++;
757         }
758     }
759     mfp->mo_segment_count = segment_command_count;
760     res = dwarf_macho_load_segment_commands(mfp,errcode);
761     if (res != DW_DLV_OK) {
762         return res;
763     }
764     res = dwarf_macho_load_dwarf_sections(mfp,errcode);
765     return res;
766 }
767 int
_dwarf_macho_setup(int fd,char * true_path,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,Dwarf_Unsigned access,unsigned groupnumber,Dwarf_Handler errhand,Dwarf_Ptr errarg,Dwarf_Debug * dbg,Dwarf_Error * error)768 _dwarf_macho_setup(int fd,
769     char *true_path,
770     unsigned ftype,
771     unsigned endian,
772     unsigned offsetsize,
773     size_t filesize,
774     Dwarf_Unsigned access,
775     unsigned groupnumber,
776     Dwarf_Handler errhand,
777     Dwarf_Ptr errarg,
778     Dwarf_Debug *dbg,Dwarf_Error *error)
779 {
780     Dwarf_Obj_Access_Interface *binary_interface = 0;
781     dwarf_macho_object_access_internals_t *intfc = 0;
782     int res = DW_DLV_OK;
783     int localerrnum = 0;
784 
785     res = _dwarf_macho_object_access_init(
786         fd,
787         ftype,endian,offsetsize,filesize,access,
788         &binary_interface,
789         &localerrnum);
790     if (res != DW_DLV_OK) {
791         if (res == DW_DLV_NO_ENTRY) {
792             return res;
793         }
794         _dwarf_error(NULL, error, localerrnum);
795         return DW_DLV_ERROR;
796     }
797     /*  allocates and initializes Dwarf_Debug,
798         generic code */
799     res = dwarf_object_init_b(binary_interface, errhand, errarg,
800         groupnumber, dbg, error);
801     if (res != DW_DLV_OK){
802         _dwarf_destruct_macho_access(binary_interface);
803         return res;
804     }
805     intfc = binary_interface->object;
806     intfc->mo_path = strdup(true_path);
807     return res;
808 }
809 
810 
811 static Dwarf_Obj_Access_Methods const macho_methods = {
812     macho_get_section_info,
813     macho_get_byte_order,
814     macho_get_length_size,
815     macho_get_pointer_size,
816     macho_get_section_count,
817     macho_load_section,
818     /*  We do not do macho relocations. dsym files do not require it. */
819     NULL
820 };
821 
822 /*  On any error this frees internals argument. */
823 static int
_dwarf_macho_object_access_internals_init(dwarf_macho_object_access_internals_t * internals,int fd,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,UNUSEDARG Dwarf_Unsigned access,int * errcode)824 _dwarf_macho_object_access_internals_init(
825     dwarf_macho_object_access_internals_t * internals,
826     int  fd,
827     unsigned ftype,
828     unsigned endian,
829     unsigned offsetsize,
830     size_t filesize,
831     UNUSEDARG Dwarf_Unsigned access,
832     int *errcode)
833 {
834     dwarf_macho_object_access_internals_t * intfc = internals;
835     Dwarf_Unsigned i  = 0;
836     struct generic_macho_section *sp = 0;
837     struct Dwarf_Obj_Access_Interface_s *localdoas;
838     int res = 0;
839 
840     /*  Must malloc as _dwarf_destruct_macho_access()
841         forces that due to other uses. */
842     localdoas = (struct Dwarf_Obj_Access_Interface_s *)
843         malloc(sizeof(struct Dwarf_Obj_Access_Interface_s));
844     if (!localdoas) {
845         free(internals);
846         *errcode = DW_DLE_ALLOC_FAIL;
847         return DW_DLV_ERROR;
848     }
849     memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_s));
850     intfc->mo_ident[0]    = 'M';
851     intfc->mo_ident[1]    = '1';
852     intfc->mo_fd          = fd;
853     intfc->mo_is_64bit    = ((offsetsize==64)?TRUE:FALSE);
854     intfc->mo_offsetsize  = offsetsize;
855     intfc->mo_pointersize = offsetsize;
856     intfc->mo_filesize    = filesize;
857     intfc->mo_ftype       = ftype;
858 
859 #ifdef WORDS_BIGENDIAN
860     if (endian == DW_ENDIAN_LITTLE ) {
861         intfc->mo_copy_word = _dwarf_memcpy_swap_bytes;
862         intfc->mo_endian = DW_OBJECT_LSB;
863     } else {
864         intfc->mo_copy_word = _dwarf_memcpy_noswap_bytes;
865         intfc->mo_endian = DW_OBJECT_MSB;
866     }
867 #else  /* LITTLE ENDIAN */
868     if (endian == DW_ENDIAN_LITTLE ) {
869         intfc->mo_copy_word = _dwarf_memcpy_noswap_bytes;
870         intfc->mo_endian = DW_OBJECT_LSB;
871     } else {
872         intfc->mo_copy_word = _dwarf_memcpy_swap_bytes;
873         intfc->mo_endian = DW_OBJECT_MSB;
874     }
875 #endif /* LITTLE- BIG-ENDIAN */
876     res = dwarf_load_macho_header(intfc,errcode);
877     if (res != DW_DLV_OK) {
878         localdoas->object = intfc;
879         localdoas->methods = 0;
880         _dwarf_destruct_macho_access(localdoas);
881         return res;
882     }
883     /* Load sections */
884     res = dwarf_load_macho_commands(intfc,errcode);
885     if (res != DW_DLV_OK) {
886         localdoas->methods = 0;
887         localdoas->object = intfc;
888         _dwarf_destruct_macho_access(localdoas);
889         return res;
890     }
891     sp = intfc->mo_dwarf_sections+1;
892     for(i = 1; i < intfc->mo_dwarf_sectioncount ; ++i,++sp) {
893         int j = 1;
894         int lim = sizeof(SectionNames)/sizeof(SectionNames[0]);
895         sp->dwarfsectname = "";
896         for( ; j < lim; ++j) {
897             if(!strcmp(sp->sectname,SectionNames[j].ms_moname)) {
898                 sp->dwarfsectname = SectionNames[j].ms_dwname;
899                 break;
900             }
901         }
902     }
903     free(localdoas);
904     return DW_DLV_OK;
905 }
906 
907 
908 static int
_dwarf_macho_object_access_init(int fd,unsigned ftype,unsigned endian,unsigned offsetsize,size_t filesize,Dwarf_Unsigned access,Dwarf_Obj_Access_Interface ** binary_interface,int * localerrnum)909 _dwarf_macho_object_access_init(
910     int  fd,
911     unsigned ftype,
912     unsigned endian,
913     unsigned offsetsize,
914     size_t filesize,
915     Dwarf_Unsigned access,
916     Dwarf_Obj_Access_Interface **binary_interface,
917     int *localerrnum)
918 {
919 
920     int res = 0;
921     dwarf_macho_object_access_internals_t *internals = 0;
922     Dwarf_Obj_Access_Interface *intfc = 0;
923 
924     internals = malloc(sizeof(dwarf_macho_object_access_internals_t));
925     if (!internals) {
926         *localerrnum = DW_DLE_ALLOC_FAIL;
927         /* Impossible case, we hope. Give up. */
928         return DW_DLV_ERROR;
929     }
930     memset(internals,0,sizeof(*internals));
931     res = _dwarf_macho_object_access_internals_init(internals,
932         fd,
933         ftype, endian, offsetsize, filesize,
934         access,
935         localerrnum);
936     if (res != DW_DLV_OK){
937         /* *err is already set and the call freed internals. */
938         return DW_DLV_ERROR;
939     }
940 
941     intfc = malloc(sizeof(Dwarf_Obj_Access_Interface));
942     if (!intfc) {
943         /* Impossible case, we hope. Give up. */
944         free(internals);
945         *localerrnum = DW_DLE_ALLOC_FAIL;
946         return DW_DLV_ERROR;
947     }
948     /* Initialize the interface struct */
949     intfc->object = internals;
950     intfc->methods = &macho_methods;
951     *binary_interface = intfc;
952     return DW_DLV_OK;
953 }
954