1 /* macho.c -- Get debug data from an Mach-O file for backtraces.
2    Copyright (C) 2012-2016 Free Software Foundation, Inc.
3    Written by John Colanduoni.
4 
5    Pending upstream pull request:
6    https://github.com/ianlancetaylor/libbacktrace/pull/2
7 
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11 
12     (1) Redistributions of source code must retain the above copyright
13     notice, this list of conditions and the following disclaimer.
14 
15     (2) Redistributions in binary form must reproduce the above copyright
16     notice, this list of conditions and the following disclaimer in
17     the documentation and/or other materials provided with the
18     distribution.
19 
20     (3) The name of the author may not be used to
21     endorse or promote products derived from this software without
22     specific prior written permission.
23 
24 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
33 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.  */
35 
36 #include "config.h"
37 
38 /* We can't use autotools to detect the pointer width of our program because
39    we may be building a fat Mach-O file containing both 32-bit and 64-bit
40    variants. However Mach-O runs a limited set of platforms so detection
41    via preprocessor is not difficult.  */
42 
43 #if defined(__MACH__)
44 #if defined(__LP64__)
45 #define BACKTRACE_BITS 64
46 #else
47 #define BACKTRACE_BITS 32
48 #endif
49 #else
50 #error Attempting to build Mach-O support on incorrect platform
51 #endif
52 
53 #if defined(__x86_64__)
54 #define NATIVE_CPU_TYPE CPU_TYPE_X86_64
55 #elif defined(__i386__)
56 #define NATIVE_CPU_TYPE CPU_TYPE_X86
57 #elif defined(__aarch64__)
58 #define NATIVE_CPU_TYPE CPU_TYPE_ARM64
59 #elif defined(__arm__)
60 #define NATIVE_CPU_TYPE CPU_TYPE_ARM
61 #else
62 #error Could not detect native Mach-O cpu_type_t
63 #endif
64 
65 #include <sys/types.h>
66 #include <sys/syslimits.h>
67 #include <string.h>
68 #include <mach-o/loader.h>
69 #include <mach-o/nlist.h>
70 #include <mach-o/fat.h>
71 #include <mach-o/dyld.h>
72 #include <uuid/uuid.h>
73 #include <dirent.h>
74 #include <stdlib.h>
75 
76 #include "backtrace.h"
77 #include "internal.h"
78 
79 struct macho_commands_view
80 {
81     struct backtrace_view view;
82     uint32_t commands_count;
83     uint32_t commands_total_size;
84     int bytes_swapped;
85     size_t base_offset;
86 };
87 
88 enum debug_section
89 {
90     DEBUG_INFO,
91     DEBUG_LINE,
92     DEBUG_ABBREV,
93     DEBUG_RANGES,
94     DEBUG_STR,
95     DEBUG_MAX
96 };
97 
98 static const char *const debug_section_names[DEBUG_MAX] =
99     {
100         "__debug_info",
101         "__debug_line",
102         "__debug_abbrev",
103         "__debug_ranges",
104         "__debug_str"
105     };
106 
107 struct found_dwarf_section
108 {
109     uint32_t file_offset;
110     uintptr_t file_size;
111     const unsigned char *data;
112 };
113 
114 /* Mach-O symbols don't have a length. As a result we have to infer it
115    by sorting the symbol addresses for each image and recording the
116    memory range attributed to each image.  */
117 struct macho_symbol
118 {
119     uintptr_t addr;
120     size_t size;
121     const char *name;
122 };
123 
124 struct macho_syminfo_data
125 {
126     struct macho_syminfo_data *next;
127     struct macho_symbol *symbols;
128     size_t symbol_count;
129     uintptr_t min_addr;
130     uintptr_t max_addr;
131 };
132 
133 uint16_t
macho_file_to_host_u16(int file_bytes_swapped,uint16_t input)134 macho_file_to_host_u16 (int file_bytes_swapped, uint16_t input)
135 {
136   if (file_bytes_swapped)
137     return (input >> 8) | (input << 8);
138   else
139     return input;
140 }
141 
142 uint32_t
macho_file_to_host_u32(int file_bytes_swapped,uint32_t input)143 macho_file_to_host_u32 (int file_bytes_swapped, uint32_t input)
144 {
145   if (file_bytes_swapped)
146     {
147       return ((input >> 24) & 0x000000FF)
148              | ((input >> 8) & 0x0000FF00)
149              | ((input << 8) & 0x00FF0000)
150              | ((input << 24) & 0xFF000000);
151     }
152   else
153     {
154       return input;
155     }
156 }
157 
158 uint64_t
macho_file_to_host_u64(int file_bytes_swapped,uint64_t input)159 macho_file_to_host_u64 (int file_bytes_swapped, uint64_t input)
160 {
161   if (file_bytes_swapped)
162     {
163       return macho_file_to_host_u32 (file_bytes_swapped,
164                                      (uint32_t) (input >> 32))
165              | (((uint64_t) macho_file_to_host_u32 (file_bytes_swapped,
166                                                     (uint32_t) input)) << 32);
167     }
168   else
169     {
170       return input;
171     }
172 }
173 
174 #if BACKTRACE_BITS == 64
175 #define macho_file_to_host_usize macho_file_to_host_u64
176 typedef struct mach_header_64 mach_header_native_t;
177 #define LC_SEGMENT_NATIVE LC_SEGMENT_64
178 typedef struct segment_command_64 segment_command_native_t;
179 typedef struct nlist_64 nlist_native_t;
180 typedef struct section_64 section_native_t;
181 #else /* BACKTRACE_BITS == 32 */
182 #define macho_file_to_host_usize macho_file_to_host_u32
183 typedef struct mach_header mach_header_native_t;
184 #define LC_SEGMENT_NATIVE LC_SEGMENT
185 typedef struct segment_command segment_command_native_t;
186 typedef struct nlist nlist_native_t;
187 typedef struct section section_native_t;
188 #endif
189 
190 // Gets a view into a Mach-O image, taking any slice offset into account
191 int
macho_get_view(struct backtrace_state * state,int descriptor,off_t offset,size_t size,backtrace_error_callback error_callback,void * data,struct macho_commands_view * commands_view,struct backtrace_view * view)192 macho_get_view (struct backtrace_state *state, int descriptor,
193                 off_t offset, size_t size,
194                 backtrace_error_callback error_callback,
195                 void *data, struct macho_commands_view *commands_view,
196                 struct backtrace_view *view)
197 {
198   return backtrace_get_view (state, descriptor,
199                              commands_view->base_offset + offset, size,
200                              error_callback, data, view);
201 }
202 
203 int
macho_get_commands(struct backtrace_state * state,int descriptor,backtrace_error_callback error_callback,void * data,struct macho_commands_view * commands_view,int * incompatible)204 macho_get_commands (struct backtrace_state *state, int descriptor,
205                     backtrace_error_callback error_callback,
206                     void *data, struct macho_commands_view *commands_view,
207                     int *incompatible)
208 {
209   int ret = 0;
210   int is_fat = 0;
211   struct backtrace_view file_header_view;
212   int file_header_view_valid = 0;
213   struct backtrace_view fat_archs_view;
214   int fat_archs_view_valid = 0;
215   const mach_header_native_t *file_header;
216   uint64_t commands_offset;
217 
218   *incompatible = 0;
219 
220   if (!backtrace_get_view (state, descriptor, 0, sizeof (mach_header_native_t),
221                            error_callback, data, &file_header_view))
222     goto end;
223   file_header_view_valid = 1;
224 
225   switch (*(uint32_t *) file_header_view.data)
226     {
227       case MH_MAGIC:
228         if (BACKTRACE_BITS == 32)
229           commands_view->bytes_swapped = 0;
230         else
231           {
232             *incompatible = 1;
233             goto end;
234           }
235       break;
236       case MH_CIGAM:
237         if (BACKTRACE_BITS == 32)
238           commands_view->bytes_swapped = 1;
239         else
240           {
241             *incompatible = 1;
242             goto end;
243           }
244       break;
245       case MH_MAGIC_64:
246         if (BACKTRACE_BITS == 64)
247           commands_view->bytes_swapped = 0;
248         else
249           {
250             *incompatible = 1;
251             goto end;
252           }
253       break;
254       case MH_CIGAM_64:
255         if (BACKTRACE_BITS == 64)
256           commands_view->bytes_swapped = 1;
257         else
258           {
259             *incompatible = 1;
260             goto end;
261           }
262       break;
263       case FAT_MAGIC:
264         is_fat = 1;
265         commands_view->bytes_swapped = 0;
266       break;
267       case FAT_CIGAM:
268         is_fat = 1;
269         commands_view->bytes_swapped = 1;
270       break;
271       default:
272         goto end;
273     }
274 
275   if (is_fat)
276     {
277       uint32_t native_slice_offset;
278       size_t archs_total_size;
279       uint32_t arch_count;
280       const struct fat_header *fat_header;
281       const struct fat_arch *archs;
282       uint32_t i;
283 
284       fat_header = file_header_view.data;
285       arch_count =
286           macho_file_to_host_u32 (commands_view->bytes_swapped,
287                                   fat_header->nfat_arch);
288 
289       archs_total_size = arch_count * sizeof (struct fat_arch);
290 
291       if (!backtrace_get_view (state, descriptor, sizeof (struct fat_header),
292                                archs_total_size, error_callback,
293                                data, &fat_archs_view))
294         goto end;
295       fat_archs_view_valid = 1;
296 
297       native_slice_offset = 0;
298       archs = fat_archs_view.data;
299       for (i = 0; i < arch_count; i++)
300         {
301           const struct fat_arch *raw_arch = archs + i;
302           int cpu_type =
303               (int) macho_file_to_host_u32 (commands_view->bytes_swapped,
304                                             (uint32_t) raw_arch->cputype);
305 
306           if (cpu_type == NATIVE_CPU_TYPE)
307             {
308               native_slice_offset =
309                   macho_file_to_host_u32 (commands_view->bytes_swapped,
310                                           raw_arch->offset);
311 
312               break;
313             }
314         }
315 
316       if (native_slice_offset == 0)
317         {
318           *incompatible = 1;
319           goto end;
320         }
321 
322       backtrace_release_view (state, &file_header_view, error_callback, data);
323       file_header_view_valid = 0;
324       if (!backtrace_get_view (state, descriptor, native_slice_offset,
325                                sizeof (mach_header_native_t), error_callback,
326                                data, &file_header_view))
327         goto end;
328       file_header_view_valid = 1;
329 
330       // The endianess of the slice may be different than the fat image
331       switch (*(uint32_t *) file_header_view.data)
332         {
333           case MH_MAGIC:
334             if (BACKTRACE_BITS == 32)
335               commands_view->bytes_swapped = 0;
336             else
337               goto end;
338           break;
339           case MH_CIGAM:
340             if (BACKTRACE_BITS == 32)
341               commands_view->bytes_swapped = 1;
342             else
343               goto end;
344           break;
345           case MH_MAGIC_64:
346             if (BACKTRACE_BITS == 64)
347               commands_view->bytes_swapped = 0;
348             else
349               goto end;
350           break;
351           case MH_CIGAM_64:
352             if (BACKTRACE_BITS == 64)
353               commands_view->bytes_swapped = 1;
354             else
355               goto end;
356           break;
357           default:
358             goto end;
359         }
360 
361       commands_view->base_offset = native_slice_offset;
362     }
363   else
364     commands_view->base_offset = 0;
365 
366   file_header = file_header_view.data;
367   commands_view->commands_count =
368       macho_file_to_host_u32 (commands_view->bytes_swapped,
369                               file_header->ncmds);
370   commands_view->commands_total_size =
371       macho_file_to_host_u32 (commands_view->bytes_swapped,
372                               file_header->sizeofcmds);
373   commands_offset =
374       commands_view->base_offset + sizeof (mach_header_native_t);
375 
376   if (!backtrace_get_view (state, descriptor, commands_offset,
377                            commands_view->commands_total_size, error_callback,
378                            data, &commands_view->view))
379     goto end;
380 
381   ret = 1;
382 
383 end:
384   if (file_header_view_valid)
385     backtrace_release_view (state, &file_header_view, error_callback, data);
386   if (fat_archs_view_valid)
387     backtrace_release_view (state, &fat_archs_view, error_callback, data);
388   return ret;
389 }
390 
391 int
macho_get_uuid(struct backtrace_state * state ATTRIBUTE_UNUSED,int descriptor ATTRIBUTE_UNUSED,backtrace_error_callback error_callback,void * data,struct macho_commands_view * commands_view,uuid_t * uuid)392 macho_get_uuid (struct backtrace_state *state ATTRIBUTE_UNUSED,
393                 int descriptor ATTRIBUTE_UNUSED,
394                 backtrace_error_callback error_callback,
395                 void *data, struct macho_commands_view *commands_view,
396                 uuid_t *uuid)
397 {
398   size_t offset = 0;
399   uint32_t i = 0;
400 
401   for (i = 0; i < commands_view->commands_count; i++)
402     {
403       const struct load_command *raw_command;
404       struct load_command command;
405 
406       if (offset + sizeof (struct load_command)
407           > commands_view->commands_total_size)
408         {
409           error_callback (data,
410                           "executable file contains out of range command offset",
411                           0);
412           return 0;
413         }
414 
415       raw_command =
416           commands_view->view.data + offset;
417       command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
418                                             raw_command->cmd);
419       command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
420                                                 raw_command->cmdsize);
421 
422       if (command.cmd == LC_UUID)
423         {
424           const struct uuid_command *uuid_command;
425 
426           if (offset + sizeof (struct uuid_command)
427               > commands_view->commands_total_size)
428             {
429               error_callback (data,
430                               "executable file contains out of range command offset",
431                               0);
432               return 0;
433             }
434 
435           uuid_command =
436               (struct uuid_command *) raw_command;
437           memcpy (uuid, uuid_command->uuid, sizeof (uuid_t));
438           return 1;
439         }
440 
441       offset += command.cmdsize;
442     }
443 
444   error_callback (data, "executable file is missing an identifying UUID", 0);
445   return 0;
446 }
447 
448 /* Returns the base address of a Mach-O image, as encoded in the file header.
449  * WARNING: This does not take ASLR into account, which is ubiquitous on recent
450  * Darwin platforms.
451  */
452 int
macho_get_addr_range(struct backtrace_state * state ATTRIBUTE_UNUSED,int descriptor ATTRIBUTE_UNUSED,backtrace_error_callback error_callback,void * data,struct macho_commands_view * commands_view,uintptr_t * base_address,uintptr_t * max_address)453 macho_get_addr_range (struct backtrace_state *state ATTRIBUTE_UNUSED,
454                       int descriptor ATTRIBUTE_UNUSED,
455                       backtrace_error_callback error_callback,
456                       void *data, struct macho_commands_view *commands_view,
457                       uintptr_t *base_address, uintptr_t *max_address)
458 {
459   size_t offset = 0;
460   int found_text = 0;
461   uint32_t i = 0;
462 
463   *max_address = 0;
464 
465   for (i = 0; i < commands_view->commands_count; i++)
466     {
467       const struct load_command *raw_command;
468       struct load_command command;
469 
470       if (offset + sizeof (struct load_command)
471           > commands_view->commands_total_size)
472         {
473           error_callback (data,
474                           "executable file contains out of range command offset",
475                           0);
476           return 0;
477         }
478 
479       raw_command = commands_view->view.data + offset;
480       command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
481                                             raw_command->cmd);
482       command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
483                                                 raw_command->cmdsize);
484 
485       if (command.cmd == LC_SEGMENT_NATIVE)
486         {
487           const segment_command_native_t *raw_segment;
488           uintptr_t segment_vmaddr;
489           uintptr_t segment_vmsize;
490           uintptr_t segment_maxaddr;
491           uintptr_t text_fileoff;
492 
493           if (offset + sizeof (segment_command_native_t)
494               > commands_view->commands_total_size)
495             {
496               error_callback (data,
497                               "executable file contains out of range command offset",
498                               0);
499               return 0;
500             }
501 
502           raw_segment = (segment_command_native_t *) raw_command;
503 
504           segment_vmaddr = macho_file_to_host_usize (
505               commands_view->bytes_swapped, raw_segment->vmaddr);
506           segment_vmsize = macho_file_to_host_usize (
507               commands_view->bytes_swapped, raw_segment->vmsize);
508           segment_maxaddr = segment_vmaddr + segment_vmsize;
509 
510           if (strncmp (raw_segment->segname, "__TEXT",
511                        sizeof (raw_segment->segname)) == 0)
512             {
513               text_fileoff = macho_file_to_host_usize (
514                   commands_view->bytes_swapped, raw_segment->fileoff);
515               *base_address = segment_vmaddr - text_fileoff;
516 
517               found_text = 1;
518             }
519 
520           if (segment_maxaddr > *max_address)
521             *max_address = segment_maxaddr;
522         }
523 
524       offset += command.cmdsize;
525     }
526 
527   if (found_text)
528     return 1;
529   else
530     {
531       error_callback (data, "executable is missing __TEXT segment", 0);
532       return 0;
533     }
534 }
535 
536 static int
macho_symbol_compare_addr(const void * left_raw,const void * right_raw)537 macho_symbol_compare_addr (const void *left_raw, const void *right_raw)
538 {
539   const struct macho_symbol *left = left_raw;
540   const struct macho_symbol *right = right_raw;
541 
542   if (left->addr > right->addr)
543     return 1;
544   else if (left->addr < right->addr)
545     return -1;
546   else
547     return 0;
548 }
549 
550 int
macho_symbol_type_relevant(uint8_t type)551 macho_symbol_type_relevant (uint8_t type)
552 {
553   uint8_t type_field = (uint8_t) (type & N_TYPE);
554 
555   return !(type & N_EXT) &&
556          (type_field == N_ABS || type_field == N_SECT);
557 }
558 
559 int
macho_add_symtab(struct backtrace_state * state,backtrace_error_callback error_callback,void * data,int descriptor,struct macho_commands_view * commands_view,uintptr_t base_address,uintptr_t max_image_address,intptr_t vmslide,int * found_sym)560 macho_add_symtab (struct backtrace_state *state,
561                   backtrace_error_callback error_callback,
562                   void *data, int descriptor,
563                   struct macho_commands_view *commands_view,
564                   uintptr_t base_address, uintptr_t max_image_address,
565                   intptr_t vmslide, int *found_sym)
566 {
567   struct macho_syminfo_data *syminfo_data;
568 
569   int ret = 0;
570   size_t offset = 0;
571   struct backtrace_view symtab_view;
572   int symtab_view_valid = 0;
573   struct backtrace_view strtab_view;
574   int strtab_view_valid = 0;
575   size_t syminfo_index = 0;
576   size_t function_count = 0;
577   uint32_t i = 0;
578   uint32_t j = 0;
579   uint32_t symtab_index = 0;
580 
581   *found_sym = 0;
582 
583   for (i = 0; i < commands_view->commands_count; i++)
584     {
585       const struct load_command *raw_command;
586       struct load_command command;
587 
588       if (offset + sizeof (struct load_command)
589           > commands_view->commands_total_size)
590         {
591           error_callback (data,
592                           "executable file contains out of range command offset",
593                           0);
594           return 0;
595         }
596 
597       raw_command = commands_view->view.data + offset;
598       command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
599                                             raw_command->cmd);
600       command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
601                                                 raw_command->cmdsize);
602 
603       if (command.cmd == LC_SYMTAB)
604         {
605           const struct symtab_command *symtab_command;
606           uint32_t symbol_table_offset;
607           uint32_t symbol_count;
608           uint32_t string_table_offset;
609           uint32_t string_table_size;
610 
611           if (offset + sizeof (struct symtab_command)
612               > commands_view->commands_total_size)
613             {
614               error_callback (data,
615                               "executable file contains out of range command offset",
616                               0);
617               return 0;
618             }
619 
620           symtab_command = (struct symtab_command *) raw_command;
621 
622           symbol_table_offset = macho_file_to_host_u32 (
623               commands_view->bytes_swapped, symtab_command->symoff);
624           symbol_count = macho_file_to_host_u32 (
625               commands_view->bytes_swapped, symtab_command->nsyms);
626           string_table_offset = macho_file_to_host_u32 (
627               commands_view->bytes_swapped, symtab_command->stroff);
628           string_table_size = macho_file_to_host_u32 (
629               commands_view->bytes_swapped, symtab_command->strsize);
630 
631 
632           if (!macho_get_view (state, descriptor, symbol_table_offset,
633                                symbol_count * sizeof (nlist_native_t),
634                                error_callback, data, commands_view,
635                                &symtab_view))
636             goto end;
637           symtab_view_valid = 1;
638 
639           if (!macho_get_view (state, descriptor, string_table_offset,
640                                string_table_size, error_callback, data,
641                                commands_view, &strtab_view))
642             goto end;
643           strtab_view_valid = 1;
644 
645           // Count functions first
646           for (j = 0; j < symbol_count; j++)
647             {
648               const nlist_native_t *raw_sym =
649                   ((const nlist_native_t *) symtab_view.data) + j;
650 
651               if (macho_symbol_type_relevant (raw_sym->n_type))
652                 {
653                   function_count += 1;
654                 }
655             }
656 
657           // Allocate space for the:
658           //  (a) macho_syminfo_data for this image
659           //  (b) macho_symbol entries
660           syminfo_data =
661               backtrace_alloc (state,
662                                sizeof (struct macho_syminfo_data),
663                                error_callback, data);
664           if (syminfo_data == NULL)
665             goto end;
666 
667           syminfo_data->symbols = backtrace_alloc (
668               state, function_count * sizeof (struct macho_symbol),
669               error_callback, data);
670           if (syminfo_data->symbols == NULL)
671             goto end;
672 
673           syminfo_data->symbol_count = function_count;
674           syminfo_data->next = NULL;
675           syminfo_data->min_addr = base_address;
676           syminfo_data->max_addr = max_image_address;
677 
678           for (symtab_index = 0;
679                symtab_index < symbol_count; symtab_index++)
680             {
681               const nlist_native_t *raw_sym =
682                   ((const nlist_native_t *) symtab_view.data) +
683                   symtab_index;
684 
685               if (macho_symbol_type_relevant (raw_sym->n_type))
686                 {
687                   size_t strtab_index;
688                   const char *name;
689                   size_t max_len_plus_one;
690 
691                   syminfo_data->symbols[syminfo_index].addr =
692                       macho_file_to_host_usize (commands_view->bytes_swapped,
693                                                 raw_sym->n_value) + vmslide;
694 
695                   strtab_index = macho_file_to_host_u32 (
696                       commands_view->bytes_swapped,
697                       raw_sym->n_un.n_strx);
698 
699                   // Check the range of the supposed "string" we've been
700                   // given
701                   if (strtab_index >= string_table_size)
702                     {
703                       error_callback (
704                           data,
705                           "dSYM file contains out of range string table index",
706                           0);
707                       goto end;
708                     }
709 
710                   name = strtab_view.data + strtab_index;
711                   max_len_plus_one = string_table_size - strtab_index;
712 
713                   if (strnlen (name, max_len_plus_one) >= max_len_plus_one)
714                     {
715                       error_callback (
716                           data,
717                           "dSYM file contains unterminated string",
718                           0);
719                       goto end;
720                     }
721 
722                   // Remove underscore prefixes
723                   if (name[0] == '_')
724                     {
725                       name = name + 1;
726                     }
727 
728                   syminfo_data->symbols[syminfo_index].name = name;
729 
730                   syminfo_index += 1;
731                 }
732             }
733 
734           backtrace_qsort (syminfo_data->symbols,
735                            syminfo_data->symbol_count,
736                            sizeof (struct macho_symbol),
737                            macho_symbol_compare_addr);
738 
739           // Calculate symbol sizes
740           for (syminfo_index = 0;
741                syminfo_index < syminfo_data->symbol_count; syminfo_index++)
742             {
743               if (syminfo_index + 1 < syminfo_data->symbol_count)
744                 {
745                   syminfo_data->symbols[syminfo_index].size =
746                       syminfo_data->symbols[syminfo_index + 1].addr -
747                       syminfo_data->symbols[syminfo_index].addr;
748                 }
749               else
750                 {
751                   syminfo_data->symbols[syminfo_index].size =
752                       max_image_address -
753                       syminfo_data->symbols[syminfo_index].addr;
754                 }
755             }
756 
757           if (!state->threaded)
758             {
759               struct macho_syminfo_data **pp;
760 
761               for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
762                    *pp != NULL;
763                    pp = &(*pp)->next);
764               *pp = syminfo_data;
765             }
766           else
767             {
768               while (1)
769                 {
770                   struct macho_syminfo_data **pp;
771 
772                   pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
773 
774                   while (1)
775                     {
776                       struct macho_syminfo_data *p;
777 
778                       p = backtrace_atomic_load_pointer (pp);
779 
780                       if (p == NULL)
781                         break;
782 
783                       pp = &p->next;
784                     }
785 
786                   if (__sync_bool_compare_and_swap (pp, NULL, syminfo_data))
787                     break;
788                 }
789             }
790 
791           strtab_view_valid = 0; // We need to keep string table around
792           *found_sym = 1;
793           ret = 1;
794           goto end;
795         }
796 
797       offset += command.cmdsize;
798     }
799 
800   // No symbol table here
801   ret = 1;
802   goto end;
803 
804 end:
805   if (symtab_view_valid)
806     backtrace_release_view (state, &symtab_view, error_callback, data);
807   if (strtab_view_valid)
808     backtrace_release_view (state, &strtab_view, error_callback, data);
809   return ret;
810 }
811 
812 int
macho_try_dwarf(struct backtrace_state * state,backtrace_error_callback error_callback,void * data,fileline * fileline_fn,uuid_t * executable_uuid,uintptr_t base_address,uintptr_t max_image_address,intptr_t vmslide,char * dwarf_filename,int * matched,int * found_sym,int * found_dwarf)813 macho_try_dwarf (struct backtrace_state *state,
814                  backtrace_error_callback error_callback,
815                  void *data, fileline *fileline_fn, uuid_t *executable_uuid,
816                  uintptr_t base_address, uintptr_t max_image_address,
817                  intptr_t vmslide, char *dwarf_filename, int *matched,
818                  int *found_sym, int *found_dwarf)
819 {
820   uuid_t dwarf_uuid;
821 
822   int ret = 0;
823   int dwarf_descriptor;
824   int dwarf_descriptor_valid = 0;
825   struct macho_commands_view commands_view;
826   int commands_view_valid = 0;
827   struct backtrace_view dwarf_view;
828   int dwarf_view_valid = 0;
829   size_t offset = 0;
830   struct found_dwarf_section dwarf_sections[DEBUG_MAX];
831   uintptr_t min_dwarf_offset = 0;
832   uintptr_t max_dwarf_offset = 0;
833   uint32_t i = 0;
834   uint32_t j = 0;
835   int k = 0;
836 
837   *matched = 0;
838   *found_sym = 0;
839   *found_dwarf = 0;
840 
841   if ((dwarf_descriptor = backtrace_open (dwarf_filename, error_callback,
842                                           data, NULL)) == 0)
843     goto end;
844   dwarf_descriptor_valid = 1;
845 
846   int incompatible;
847   if (!macho_get_commands (state, dwarf_descriptor, error_callback, data,
848                            &commands_view, &incompatible))
849     {
850       // Failing to read the header here is fine, because this dSYM may be
851       // for a different architecture
852       if (incompatible)
853         {
854           ret = 1;
855         }
856       goto end;
857     }
858   commands_view_valid = 1;
859 
860   // Get dSYM UUID and compare
861   if (!macho_get_uuid (state, dwarf_descriptor, error_callback, data,
862                        &commands_view, &dwarf_uuid))
863     {
864       error_callback (data, "dSYM file is missing an identifying uuid", 0);
865       goto end;
866     }
867   if (memcmp (executable_uuid, &dwarf_uuid, sizeof (uuid_t)) != 0)
868     {
869       // DWARF doesn't belong to desired executable
870       ret = 1;
871       goto end;
872     }
873 
874   *matched = 1;
875 
876   // Read symbol table
877   if (!macho_add_symtab (state, error_callback, data, dwarf_descriptor,
878                          &commands_view, base_address, max_image_address,
879                          vmslide, found_sym))
880     goto end;
881 
882   // Get DWARF sections
883 
884   memset (dwarf_sections, 0, sizeof (dwarf_sections));
885   offset = 0;
886   for (i = 0; i < commands_view.commands_count; i++)
887     {
888       const struct load_command *raw_command;
889       struct load_command command;
890 
891       if (offset + sizeof (struct load_command)
892           > commands_view.commands_total_size)
893         {
894           error_callback (data,
895                           "dSYM file contains out of range command offset", 0);
896           goto end;
897         }
898 
899       raw_command = commands_view.view.data + offset;
900       command.cmd = macho_file_to_host_u32 (commands_view.bytes_swapped,
901                                             raw_command->cmd);
902       command.cmdsize = macho_file_to_host_u32 (commands_view.bytes_swapped,
903                                                 raw_command->cmdsize);
904 
905       if (command.cmd == LC_SEGMENT_NATIVE)
906         {
907           uint32_t section_count;
908           size_t section_offset;
909           const segment_command_native_t *raw_segment;
910 
911           if (offset + sizeof (segment_command_native_t)
912               > commands_view.commands_total_size)
913             {
914               error_callback (data,
915                               "dSYM file contains out of range command offset",
916                               0);
917               goto end;
918             }
919 
920           raw_segment = (const segment_command_native_t *) raw_command;
921 
922           if (strncmp (raw_segment->segname, "__DWARF",
923                        sizeof (raw_segment->segname)) == 0)
924             {
925               section_count = macho_file_to_host_u32 (
926                   commands_view.bytes_swapped,
927                   raw_segment->nsects);
928 
929               section_offset = offset + sizeof (segment_command_native_t);
930 
931               // Search sections for relevant DWARF section names
932               for (j = 0; j < section_count; j++)
933                 {
934                   const section_native_t *raw_section;
935 
936                   if (section_offset + sizeof (section_native_t) >
937                       commands_view.commands_total_size)
938                     {
939                       error_callback (data,
940                                       "dSYM file contains out of range command offset",
941                                       0);
942                       goto end;
943                     }
944 
945                   raw_section = commands_view.view.data + section_offset;
946 
947                   for (k = 0; k < DEBUG_MAX; k++)
948                     {
949                       uintptr_t dwarf_section_end;
950 
951                       if (strncmp (raw_section->sectname,
952                                    debug_section_names[k],
953                                    sizeof (raw_section->sectname)) == 0)
954                         {
955                           *found_dwarf = 1;
956 
957                           dwarf_sections[k].file_offset =
958                               macho_file_to_host_u32 (
959                                   commands_view.bytes_swapped,
960                                   raw_section->offset);
961                           dwarf_sections[k].file_size =
962                               macho_file_to_host_usize (
963                                   commands_view.bytes_swapped,
964                                   raw_section->size);
965 
966                           if (min_dwarf_offset == 0 ||
967                               dwarf_sections[k].file_offset <
968                               min_dwarf_offset)
969                             min_dwarf_offset = dwarf_sections[k].file_offset;
970 
971                           dwarf_section_end =
972                               dwarf_sections[k].file_offset +
973                               dwarf_sections[k].file_size;
974                           if (dwarf_section_end > max_dwarf_offset)
975                             max_dwarf_offset = dwarf_section_end;
976 
977                           break;
978                         }
979                     }
980 
981                   section_offset += sizeof (section_native_t);
982                 }
983 
984               break;
985             }
986         }
987 
988       offset += command.cmdsize;
989     }
990 
991   if (!*found_dwarf)
992     {
993       // No DWARF in this file
994       ret = 1;
995       goto end;
996     }
997 
998   if (!macho_get_view (state, dwarf_descriptor, (off_t) min_dwarf_offset,
999                        max_dwarf_offset - min_dwarf_offset, error_callback,
1000                        data, &commands_view, &dwarf_view))
1001     goto end;
1002   dwarf_view_valid = 1;
1003 
1004   for (i = 0; i < DEBUG_MAX; i++)
1005     {
1006       if (dwarf_sections[i].file_offset == 0)
1007         dwarf_sections[i].data = NULL;
1008       else
1009         dwarf_sections[i].data =
1010             dwarf_view.data + dwarf_sections[i].file_offset - min_dwarf_offset;
1011     }
1012 
1013   if (!backtrace_dwarf_add (state, vmslide,
1014                             dwarf_sections[DEBUG_INFO].data,
1015                             dwarf_sections[DEBUG_INFO].file_size,
1016                             dwarf_sections[DEBUG_LINE].data,
1017                             dwarf_sections[DEBUG_LINE].file_size,
1018                             dwarf_sections[DEBUG_ABBREV].data,
1019                             dwarf_sections[DEBUG_ABBREV].file_size,
1020                             dwarf_sections[DEBUG_RANGES].data,
1021                             dwarf_sections[DEBUG_RANGES].file_size,
1022                             dwarf_sections[DEBUG_STR].data,
1023                             dwarf_sections[DEBUG_STR].file_size,
1024                             ((__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN)
1025                             ^ commands_view.bytes_swapped),
1026                             error_callback, data, fileline_fn))
1027     goto end;
1028 
1029   // Don't release the DWARF view because it is still in use
1030   dwarf_descriptor_valid = 0;
1031   dwarf_view_valid = 0;
1032   ret = 1;
1033 
1034 end:
1035   if (dwarf_descriptor_valid)
1036     backtrace_close (dwarf_descriptor, error_callback, data);
1037   if (commands_view_valid)
1038     backtrace_release_view (state, &commands_view.view, error_callback, data);
1039   if (dwarf_view_valid)
1040     backtrace_release_view (state, &dwarf_view, error_callback, data);
1041   return ret;
1042 }
1043 
1044 int
macho_try_dsym(struct backtrace_state * state,backtrace_error_callback error_callback,void * data,fileline * fileline_fn,uuid_t * executable_uuid,uintptr_t base_address,uintptr_t max_image_address,intptr_t vmslide,char * dsym_filename,int * matched,int * found_sym,int * found_dwarf)1045 macho_try_dsym (struct backtrace_state *state,
1046                 backtrace_error_callback error_callback,
1047                 void *data, fileline *fileline_fn, uuid_t *executable_uuid,
1048                 uintptr_t base_address, uintptr_t max_image_address,
1049                 intptr_t vmslide, char *dsym_filename, int *matched,
1050                 int *found_sym, int *found_dwarf)
1051 {
1052   int ret = 0;
1053   char dwarf_image_dir_path[PATH_MAX];
1054   DIR *dwarf_image_dir;
1055   int dwarf_image_dir_valid = 0;
1056   struct dirent *directory_entry;
1057   char dwarf_filename[PATH_MAX];
1058   int dwarf_matched;
1059   int dwarf_had_sym;
1060   int dwarf_had_dwarf;
1061 
1062   *matched = 0;
1063   *found_sym = 0;
1064   *found_dwarf = 0;
1065 
1066   strncpy (dwarf_image_dir_path, dsym_filename, PATH_MAX);
1067   strncat (dwarf_image_dir_path, "/Contents/Resources/DWARF", PATH_MAX);
1068 
1069   if (!(dwarf_image_dir = opendir (dwarf_image_dir_path)))
1070     {
1071       error_callback (data, "could not open DWARF directory in dSYM",
1072                       0);
1073       goto end;
1074     }
1075   dwarf_image_dir_valid = 1;
1076 
1077   while ((directory_entry = readdir (dwarf_image_dir)))
1078     {
1079       if (directory_entry->d_type != DT_REG)
1080         continue;
1081 
1082       strncpy (dwarf_filename, dwarf_image_dir_path, PATH_MAX);
1083       strncat (dwarf_filename, "/", PATH_MAX);
1084       strncat (dwarf_filename, directory_entry->d_name, PATH_MAX);
1085 
1086       if (!macho_try_dwarf (state, error_callback, data, fileline_fn,
1087                             executable_uuid, base_address, max_image_address,
1088                             vmslide, dwarf_filename,
1089                             &dwarf_matched, &dwarf_had_sym, &dwarf_had_dwarf))
1090         goto end;
1091 
1092       if (dwarf_matched)
1093         {
1094           *matched = 1;
1095           *found_sym = dwarf_had_sym;
1096           *found_dwarf = dwarf_had_dwarf;
1097           ret = 1;
1098           goto end;
1099         }
1100     }
1101 
1102   // No matching DWARF in this dSYM
1103   ret = 1;
1104   goto end;
1105 
1106 end:
1107   if (dwarf_image_dir_valid)
1108     closedir (dwarf_image_dir);
1109   return ret;
1110 }
1111 
1112 int
macho_add(struct backtrace_state * state,backtrace_error_callback error_callback,void * data,int descriptor,const char * filename,fileline * fileline_fn,intptr_t vmslide,int * found_sym,int * found_dwarf)1113 macho_add (struct backtrace_state *state,
1114            backtrace_error_callback error_callback, void *data, int descriptor,
1115            const char *filename, fileline *fileline_fn, intptr_t vmslide,
1116            int *found_sym, int *found_dwarf)
1117 {
1118   uuid_t image_uuid;
1119   uintptr_t image_file_base_address;
1120   uintptr_t image_file_max_address;
1121   uintptr_t image_actual_base_address = 0;
1122   uintptr_t image_actual_max_address = 0;
1123 
1124   int ret = 0;
1125   struct macho_commands_view commands_view;
1126   int commands_view_valid = 0;
1127   char executable_dirname[PATH_MAX];
1128   size_t filename_len;
1129   DIR *executable_dir = NULL;
1130   int executable_dir_valid = 0;
1131   struct dirent *directory_entry;
1132   char dsym_full_path[PATH_MAX];
1133   static const char *extension;
1134   size_t extension_len;
1135   ssize_t i;
1136 
1137   *found_sym = 0;
1138   *found_dwarf = 0;
1139 
1140   // Find Mach-O commands list
1141   int incompatible;
1142   if (!macho_get_commands (state, descriptor, error_callback, data,
1143                            &commands_view, &incompatible))
1144     goto end;
1145   commands_view_valid = 1;
1146 
1147   // First we need to get the uuid of our file so we can hunt down the correct
1148   // dSYM
1149   if (!macho_get_uuid (state, descriptor, error_callback, data, &commands_view,
1150                        &image_uuid))
1151     goto end;
1152 
1153   // Now we need to find the in memory base address. Step one is to find out
1154   // what the executable thinks the base address is
1155   if (!macho_get_addr_range (state, descriptor, error_callback, data,
1156                              &commands_view,
1157                              &image_file_base_address,
1158                              &image_file_max_address))
1159     goto end;
1160 
1161   image_actual_base_address =
1162       image_file_base_address + vmslide;
1163   image_actual_max_address =
1164       image_file_max_address + vmslide;
1165 
1166   if (image_actual_base_address == 0)
1167     {
1168       error_callback (data, "executable file is not loaded", 0);
1169       goto end;
1170     }
1171 
1172   // Look for dSYM in our executable's directory
1173   strncpy (executable_dirname, filename, PATH_MAX);
1174   filename_len = strlen (executable_dirname);
1175   for (i = filename_len - 1; i >= 0; i--)
1176     {
1177       if (executable_dirname[i] == '/')
1178         {
1179           executable_dirname[i] = '\0';
1180           break;
1181         }
1182       else if (i == 0)
1183         {
1184           executable_dirname[0] = '.';
1185           executable_dirname[1] = '\0';
1186           break;
1187         }
1188     }
1189 
1190   if (!(executable_dir = opendir (executable_dirname)))
1191     {
1192       error_callback (data, "could not open directory containing executable",
1193                       0);
1194       goto end;
1195     }
1196   executable_dir_valid = 1;
1197 
1198   extension = ".dSYM";
1199   extension_len = strlen (extension);
1200   while ((directory_entry = readdir (executable_dir)))
1201     {
1202       if (directory_entry->d_namlen < extension_len)
1203         continue;
1204       if (strncasecmp (directory_entry->d_name + directory_entry->d_namlen
1205                        - extension_len, extension, extension_len) == 0)
1206         {
1207           int matched;
1208           int dsym_had_sym;
1209           int dsym_had_dwarf;
1210 
1211           // Found a dSYM
1212           strncpy (dsym_full_path, executable_dirname, PATH_MAX);
1213           strncat (dsym_full_path, "/", PATH_MAX);
1214           strncat (dsym_full_path, directory_entry->d_name, PATH_MAX);
1215 
1216           if (!macho_try_dsym (state, error_callback, data,
1217                                fileline_fn, &image_uuid,
1218                                image_actual_base_address,
1219                                image_actual_max_address, vmslide,
1220                                dsym_full_path,
1221                                &matched, &dsym_had_sym, &dsym_had_dwarf))
1222             goto end;
1223 
1224           if (matched)
1225             {
1226               *found_sym = dsym_had_sym;
1227               *found_dwarf = dsym_had_dwarf;
1228               ret = 1;
1229               goto end;
1230             }
1231         }
1232     }
1233 
1234   // No matching dSYM
1235   ret = 1;
1236   goto end;
1237 
1238 end:
1239   if (commands_view_valid)
1240     backtrace_release_view (state, &commands_view.view, error_callback,
1241                             data);
1242   if (executable_dir_valid)
1243     closedir (executable_dir);
1244   return ret;
1245 }
1246 
1247 static int
macho_symbol_search(const void * vkey,const void * ventry)1248 macho_symbol_search (const void *vkey, const void *ventry)
1249 {
1250   const uintptr_t *key = (const uintptr_t *) vkey;
1251   const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
1252   uintptr_t addr;
1253 
1254   addr = *key;
1255   if (addr < entry->addr)
1256     return -1;
1257   else if (addr >= entry->addr + entry->size)
1258     return 1;
1259   else
1260     return 0;
1261 }
1262 
1263 static void
macho_syminfo(struct backtrace_state * state,uintptr_t addr,backtrace_syminfo_callback callback,backtrace_error_callback error_callback ATTRIBUTE_UNUSED,void * data)1264 macho_syminfo (struct backtrace_state *state,
1265                uintptr_t addr,
1266                backtrace_syminfo_callback callback,
1267                backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
1268                void *data)
1269 {
1270   struct macho_syminfo_data *edata;
1271   struct macho_symbol *sym = NULL;
1272 
1273   if (!state->threaded)
1274     {
1275       for (edata = (struct macho_syminfo_data *) state->syminfo_data;
1276            edata != NULL;
1277            edata = edata->next)
1278         {
1279           if (addr >= edata->min_addr && addr <= edata->max_addr)
1280             {
1281               sym = ((struct macho_symbol *)
1282                   bsearch (&addr, edata->symbols, edata->symbol_count,
1283                            sizeof (struct macho_symbol), macho_symbol_search));
1284               if (sym != NULL)
1285                 break;
1286             }
1287         }
1288     }
1289   else
1290     {
1291       struct macho_syminfo_data **pp;
1292 
1293       pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
1294       while (1)
1295         {
1296           edata = backtrace_atomic_load_pointer (pp);
1297           if (edata == NULL)
1298             break;
1299 
1300           if (addr >= edata->min_addr && addr <= edata->max_addr)
1301             {
1302               sym = ((struct macho_symbol *)
1303                   bsearch (&addr, edata->symbols, edata->symbol_count,
1304                            sizeof (struct macho_symbol), macho_symbol_search));
1305               if (sym != NULL)
1306                 break;
1307             }
1308 
1309           pp = &edata->next;
1310         }
1311     }
1312 
1313   if (sym == NULL)
1314     callback (data, addr, NULL, 0, 0);
1315   else
1316     callback (data, addr, sym->name, sym->addr, sym->size);
1317 }
1318 
1319 
1320 static int
macho_nodebug(struct backtrace_state * state ATTRIBUTE_UNUSED,uintptr_t pc ATTRIBUTE_UNUSED,backtrace_full_callback callback ATTRIBUTE_UNUSED,backtrace_error_callback error_callback,void * data)1321 macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
1322                uintptr_t pc ATTRIBUTE_UNUSED,
1323                backtrace_full_callback callback ATTRIBUTE_UNUSED,
1324                backtrace_error_callback error_callback, void *data)
1325 {
1326   error_callback (data, "no debug info in Mach-O executable", -1);
1327   return 0;
1328 }
1329 
1330 static void
macho_nosyms(struct backtrace_state * state ATTRIBUTE_UNUSED,uintptr_t addr ATTRIBUTE_UNUSED,backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,backtrace_error_callback error_callback,void * data)1331 macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
1332               uintptr_t addr ATTRIBUTE_UNUSED,
1333               backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
1334               backtrace_error_callback error_callback, void *data)
1335 {
1336   error_callback (data, "no symbol table in Mach-O executable", -1);
1337 }
1338 
1339 int
backtrace_initialize(struct backtrace_state * state,const char * filename,int descriptor,backtrace_error_callback error_callback,void * data,fileline * fileline_fn)1340 backtrace_initialize (struct backtrace_state *state,
1341                       const char *filename,
1342                       int descriptor,
1343                       backtrace_error_callback error_callback,
1344                       void *data, fileline *fileline_fn)
1345 {
1346   int ret;
1347   fileline macho_fileline_fn = macho_nodebug;
1348   int found_sym = 0;
1349   int found_dwarf = 0;
1350   uint32_t i = 0;
1351   uint32_t loaded_image_count;
1352 
1353   // Add all loaded images
1354   loaded_image_count = _dyld_image_count ();
1355   for (i = 0; i < loaded_image_count; i++)
1356     {
1357       int current_found_sym;
1358       int current_found_dwarf;
1359       int current_descriptor;
1360       intptr_t current_vmslide;
1361       const char *current_name;
1362 
1363       current_vmslide = _dyld_get_image_vmaddr_slide (i);
1364       current_name = _dyld_get_image_name (i);
1365 
1366       if (current_name == NULL || (i != 0 && current_vmslide == 0))
1367         continue;
1368 
1369       if (!(current_descriptor =
1370                 backtrace_open (current_name, error_callback, data, NULL)))
1371         {
1372           continue;
1373         }
1374 
1375       if (macho_add (state, error_callback, data, current_descriptor,
1376                       current_name, &macho_fileline_fn, current_vmslide,
1377                       &current_found_sym, &current_found_dwarf))
1378         {
1379           found_sym = found_sym || current_found_sym;
1380           found_dwarf = found_dwarf || current_found_dwarf;
1381         }
1382 
1383       backtrace_close (current_descriptor, error_callback, data);
1384     }
1385 
1386   if (!state->threaded)
1387     {
1388       if (found_sym)
1389         state->syminfo_fn = macho_syminfo;
1390       else if (state->syminfo_fn == NULL)
1391         state->syminfo_fn = macho_nosyms;
1392     }
1393   else
1394     {
1395       if (found_sym)
1396         backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
1397       else
1398         (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
1399                                              macho_nosyms);
1400     }
1401 
1402   if (!state->threaded)
1403     {
1404       if (state->fileline_fn == NULL || state->fileline_fn == macho_nodebug)
1405         *fileline_fn = macho_fileline_fn;
1406     }
1407   else
1408     {
1409       fileline current_fn;
1410 
1411       current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
1412       if (current_fn == NULL || current_fn == macho_nodebug)
1413         *fileline_fn = macho_fileline_fn;
1414     }
1415 
1416   return 1;
1417 }
1418 
1419