+static bfd_boolean
+load_and_dump (bfd *abfd, ufile_ptr off, unsigned int len,
+ void (*dump)(bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off))
+{
+ unsigned char *buf;
+
+ if (len == 0)
+ return TRUE;
+
+ buf = xmalloc (len);
+
+ if (bfd_seek (abfd, off, SEEK_SET) == 0
+ && bfd_bread (buf, len, abfd) == len)
+ dump (abfd, buf, len, off);
+ else
+ return FALSE;
+
+ free (buf);
+ return TRUE;
+}
+
+static const bfd_mach_o_xlat_name bfd_mach_o_dyld_rebase_type_name[] =
+{
+ { "pointer", BFD_MACH_O_REBASE_TYPE_POINTER },
+ { "text_abs32", BFD_MACH_O_REBASE_TYPE_TEXT_ABSOLUTE32 },
+ { "text_pcrel32", BFD_MACH_O_REBASE_TYPE_TEXT_PCREL32 },
+ { NULL, 0 }
+};
+
+static void
+dump_dyld_info_rebase (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ unsigned int i;
+ bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+ unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+ for (i = 0; i < len; )
+ {
+ unsigned char b = buf[i++];
+ unsigned char imm = b & BFD_MACH_O_REBASE_IMMEDIATE_MASK;
+ bfd_vma leb;
+ unsigned int leblen;
+
+ printf (" [0x%04x] 0x%02x: ", i, b);
+ switch (b & BFD_MACH_O_REBASE_OPCODE_MASK)
+ {
+ case BFD_MACH_O_REBASE_OPCODE_DONE:
+ printf ("done\n");
+ return;
+ case BFD_MACH_O_REBASE_OPCODE_SET_TYPE_IMM:
+ printf ("set_type %s\n",
+ bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("set segment: %u and offset: 0x%08x\n",
+ imm, (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ printf ("add addr imm scaled: %u\n", imm * ptrsize);
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ printf ("rebase imm times: %u\n", imm);
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("rebase uleb times: %u\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("rebase add addr uleb: %u\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("rebase uleb times (%u)", (unsigned) leb);
+ i += leblen;
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf (" skipping uleb (%u)\n", (unsigned) leb);
+ i += leblen;
+ break;
+ default:
+ printf ("unknown\n");
+ return;
+ }
+ }
+ printf (" rebase commands without end!\n");
+}
+
+static void
+dump_dyld_info_bind (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ unsigned int i;
+ bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
+ unsigned int ptrsize = mdata->header.version == 2 ? 8 : 4;
+
+ for (i = 0; i < len; )
+ {
+ unsigned char b = buf[i++];
+ unsigned char imm = b & BFD_MACH_O_BIND_IMMEDIATE_MASK;
+ bfd_vma leb;
+ unsigned int leblen;
+
+ printf (" [0x%04x] 0x%02x: ", i, b);
+ switch (b & BFD_MACH_O_BIND_OPCODE_MASK)
+ {
+ case BFD_MACH_O_BIND_OPCODE_DONE:
+ printf ("done\n");
+ return;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+ printf ("set dylib ordinal imm: %u\n", imm);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("set dylib ordinal uleb: %u\n", imm);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+ imm = (imm != 0) ? imm | BFD_MACH_O_BIND_OPCODE_MASK : imm;
+ printf ("set dylib special imm: %d\n", imm);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ printf ("set symbol trailing flags imm: 0x%02x, ", imm);
+ for (; i < len && buf[i] != 0; i++)
+ putchar (buf[i] >= ' ' && buf[i] < 0x7f ? buf[i] : '?');
+ putchar ('\n');
+ i++;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_TYPE_IMM:
+ /* Kludge: use the same table as rebase type. */
+ printf ("set_type %s\n",
+ bfd_mach_o_get_name (bfd_mach_o_dyld_rebase_type_name, imm));
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_ADDEND_SLEB:
+ {
+ bfd_signed_vma svma;
+ svma = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("set addend sleb: 0x%08x\n", (unsigned) svma);
+ i += leblen;
+ }
+ break;
+ case BFD_MACH_O_BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("set segment: %u and offset: 0x%08x\n",
+ imm, (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND:
+ printf ("do bind\n");
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("do bind add addr uleb: 0x%08x\n", (unsigned) leb);
+ i += leblen;
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+ printf ("do bind add addr imm scaled: %u\n", imm * ptrsize);
+ break;
+ case BFD_MACH_O_BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf ("do bind uleb times (%u)", (unsigned) leb);
+ i += leblen;
+ leb = read_leb128 (buf + i, buf + len, 0, &leblen, NULL);
+ printf (" skipping uleb (%u)\n", (unsigned) leb);
+ i += leblen;
+ break;
+ default:
+ printf ("unknown\n");
+ return;
+ }
+ }
+ printf (" bind commands without end!\n");
+}
+
+struct export_info_data
+{
+ const unsigned char *name;
+ struct export_info_data *next;
+};
+
+static void
+dump_dyld_info_export_1 (bfd *abfd, unsigned char *buf, unsigned int len,
+ unsigned int off, struct export_info_data *parent,
+ struct export_info_data *base)
+{
+ bfd_vma size;
+ unsigned int leblen;
+ unsigned int child_count;
+ unsigned int i;
+
+ size = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ if (size != 0)
+ {
+ bfd_vma flags;
+ struct export_info_data *d;
+
+ flags = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ fputs (" ", stdout);
+ switch (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_MASK)
+ {
+ case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_REGULAR:
+ putchar ('-');
+ break;
+ case BFD_MACH_O_EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL:
+ putchar ('T');
+ break;
+ default:
+ putchar ('?');
+ break;
+ }
+ putchar ((flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION) ?
+ 'W' : '-');
+
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_REEXPORT)
+ {
+ bfd_vma lib;
+
+ lib = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ fputs (" [reexport] ", stdout);
+ for (d = base; d != NULL; d = d->next)
+ printf ("%s", d->name);
+
+ fputs (" (", stdout);
+ if (buf[off] != 0)
+ {
+ fputs ((const char *)buf + off, stdout);
+ putchar (' ');
+ off += strlen ((const char *)buf + off);
+ }
+ printf ("from dylib %u)\n", (unsigned) lib);
+ off++;
+ }
+ else
+ {
+ bfd_vma offset;
+ bfd_vma resolv = 0;
+
+ offset = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ {
+ resolv = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+ }
+
+ printf (" 0x%08x ", (unsigned) offset);
+ for (d = base; d != NULL; d = d->next)
+ printf ("%s", d->name);
+ if (flags & BFD_MACH_O_EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER)
+ printf (" [resolv: 0x%08x]", (unsigned) resolv);
+ printf ("\n");
+ }
+ }
+
+ child_count = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ for (i = 0; i < child_count; i++)
+ {
+ struct export_info_data sub_data;
+ bfd_vma sub_off;
+
+ sub_data.name = buf + off;
+ sub_data.next = NULL;
+ parent->next = &sub_data;
+
+ off += strlen ((const char *)buf + off) + 1;
+
+ sub_off = read_leb128 (buf + off, buf + len, 0, &leblen, NULL);
+ off += leblen;
+
+ dump_dyld_info_export_1 (abfd, buf, len, sub_off, &sub_data, base);
+ }
+}
+
+static void
+dump_dyld_info_export (bfd *abfd, unsigned char *buf, unsigned int len,
+ ufile_ptr off ATTRIBUTE_UNUSED)
+{
+ struct export_info_data data;
+
+ data.name = (const unsigned char *) "";
+ data.next = NULL;
+
+ printf (" fl offset sym (Flags: Tls Weak)\n");
+ dump_dyld_info_export_1 (abfd, buf, len, 0, &data, &data);
+}
+