libbacktrace: add Mach-O 64-bit FAT support
authorIan Lance Taylor <iant@golang.org>
Mon, 24 Aug 2020 20:06:52 +0000 (13:06 -0700)
committerIan Lance Taylor <iant@golang.org>
Mon, 24 Aug 2020 20:10:26 +0000 (13:10 -0700)
libbacktrace/:
* macho.c (MACH_O_MH_MAGIC_FAT_64): Define.
(MACH_O_MH_CIGAM_FAT_64): Define.
(struct macho_fat_arch_64): Define.
(macho_add_fat): Add and use is_64 parameter.
(macho_add): Recognize 64-bit fat files.

libbacktrace/macho.c

index 3aea70cdbbe9cde5306444b036bedd1336eea3a6..bd737226ca62fe829341d90a69ecd64ce62b5c04 100644 (file)
@@ -75,7 +75,7 @@ struct macho_header_64
 
 struct macho_header_fat
 {
-  uint32_t magic;      /* Magic number (MACH_O_MH_MAGIC_FAT) */
+  uint32_t magic;      /* Magic number (MACH_O_MH_(MAGIC|CIGAM)_FAT(_64)?) */
   uint32_t nfat_arch;   /* Number of components */
 };
 
@@ -85,6 +85,8 @@ struct macho_header_fat
 #define MACH_O_MH_MAGIC_64     0xfeedfacf
 #define MACH_O_MH_MAGIC_FAT    0xcafebabe
 #define MACH_O_MH_CIGAM_FAT    0xbebafeca
+#define MACH_O_MH_MAGIC_FAT_64 0xcafebabf
+#define MACH_O_MH_CIGAM_FAT_64 0xbfbafeca
 
 /* Value for the header filetype field.  */
 
@@ -105,6 +107,20 @@ struct macho_fat_arch
   uint32_t align;      /* Alignment of this entry */
 };
 
+/* A component of a 64-bit fat file.  This is used if the magic field
+   is MAGIC_FAT_64.  This is only used when some file size or file
+   offset is too large to represent in the 32-bit format.  */
+
+struct macho_fat_arch_64
+{
+  uint32_t cputype;    /* CPU type */
+  uint32_t cpusubtype; /* CPU subtype */
+  uint64_t offset;     /* File offset of this entry */
+  uint64_t size;       /* Size of this entry */
+  uint32_t align;      /* Alignment of this entry */
+  uint32_t reserved;   /* Reserved */
+};
+
 /* Values for the fat_arch cputype field (and the header cputype
    field).  */
 
@@ -740,14 +756,14 @@ static int
 macho_add_fat (struct backtrace_state *state, const char *filename,
               int descriptor, int swapped, off_t offset,
               const unsigned char *match_uuid, uintptr_t base_address,
-              int skip_symtab, uint32_t nfat_arch,
+              int skip_symtab, uint32_t nfat_arch, int is_64,
               backtrace_error_callback error_callback, void *data,
               fileline *fileline_fn, int *found_sym)
 {
   int arch_view_valid;
   unsigned int cputype;
+  size_t arch_size;
   struct backtrace_view arch_view;
-  size_t archoffset;
   unsigned int i;
 
   arch_view_valid = 0;
@@ -765,21 +781,39 @@ macho_add_fat (struct backtrace_state *state, const char *filename,
   goto fail;
 #endif
 
+  if (is_64)
+    arch_size = sizeof (struct macho_fat_arch_64);
+  else
+    arch_size = sizeof (struct macho_fat_arch);
+
   if (!backtrace_get_view (state, descriptor, offset,
-                          nfat_arch * sizeof (struct macho_fat_arch),
+                          nfat_arch * arch_size,
                           error_callback, data, &arch_view))
     goto fail;
 
-  archoffset = 0;
   for (i = 0; i < nfat_arch; ++i)
     {
-      struct macho_fat_arch fat_arch;
+      struct macho_fat_arch_64 fat_arch;
       uint32_t fcputype;
 
-      memcpy (&fat_arch,
-             ((const char *) arch_view.data
-              + i * sizeof (struct macho_fat_arch)),
-             sizeof fat_arch);
+      if (is_64)
+       memcpy (&fat_arch,
+               (const char *) arch_view.data + i * arch_size,
+               arch_size);
+      else
+       {
+         struct macho_fat_arch fat_arch_32;
+
+         memcpy (&fat_arch_32,
+                 (const char *) arch_view.data + i * arch_size,
+                 arch_size);
+         fat_arch.cputype = fat_arch_32.cputype;
+         fat_arch.cpusubtype = fat_arch_32.cpusubtype;
+         fat_arch.offset = (uint64_t) fat_arch_32.offset;
+         fat_arch.size = (uint64_t) fat_arch_32.size;
+         fat_arch.align = fat_arch_32.align;
+         fat_arch.reserved = 0;
+       }
 
       fcputype = fat_arch.cputype;
       if (swapped)
@@ -787,19 +821,17 @@ macho_add_fat (struct backtrace_state *state, const char *filename,
 
       if (fcputype == cputype)
        {
-         uint32_t foffset;
+         uint64_t foffset;
 
          /* FIXME: What about cpusubtype?  */
          foffset = fat_arch.offset;
          if (swapped)
-           foffset = __builtin_bswap32 (foffset);
+           foffset = __builtin_bswap64 (foffset);
          backtrace_release_view (state, &arch_view, error_callback, data);
          return macho_add (state, filename, descriptor, foffset, match_uuid,
                            base_address, skip_symtab, error_callback, data,
                            fileline_fn, found_sym);
        }
-
-      archoffset += sizeof (struct macho_fat_arch);
     }
 
   error_callback (data, "could not find executable in fat file", 0);
@@ -980,6 +1012,7 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
       hdroffset = offset + sizeof (struct macho_header_64);
       break;
     case MACH_O_MH_MAGIC_FAT:
+    case MACH_O_MH_MAGIC_FAT_64:
       {
        struct macho_header_fat fat_header;
 
@@ -987,10 +1020,12 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
        memcpy (&fat_header, &header, sizeof fat_header);
        return macho_add_fat (state, filename, descriptor, 0, hdroffset,
                              match_uuid, base_address, skip_symtab,
-                             fat_header.nfat_arch, error_callback, data,
-                             fileline_fn, found_sym);
+                             fat_header.nfat_arch,
+                             header.magic == MACH_O_MH_MAGIC_FAT_64,
+                             error_callback, data, fileline_fn, found_sym);
       }
     case MACH_O_MH_CIGAM_FAT:
+    case MACH_O_MH_CIGAM_FAT_64:
       {
        struct macho_header_fat fat_header;
        uint32_t nfat_arch;
@@ -1000,8 +1035,9 @@ macho_add (struct backtrace_state *state, const char *filename, int descriptor,
        nfat_arch = __builtin_bswap32 (fat_header.nfat_arch);
        return macho_add_fat (state, filename, descriptor, 1, hdroffset,
                              match_uuid, base_address, skip_symtab,
-                             nfat_arch, error_callback, data,
-                             fileline_fn, found_sym);
+                             nfat_arch,
+                             header.magic == MACH_O_MH_CIGAM_FAT_64,
+                             error_callback, data, fileline_fn, found_sym);
       }
     default:
       error_callback (data, "executable file is not in Mach-O format", 0);