Skip to content

Instantly share code, notes, and snippets.

@davidbalbert
Created December 3, 2012 19:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidbalbert/4197567 to your computer and use it in GitHub Desktop.
Save davidbalbert/4197567 to your computer and use it in GitHub Desktop.
GDB 7.5.1 OS X 10.8 Mach-O fixes
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index 29ebba4..e44cf6d 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -3666,6 +3666,48 @@ bfd_mach_o_read_encryption_info (bfd *abfd, bfd_mach_o_load_command *command)
return TRUE;
}
+static bfd_boolean
+bfd_mach_o_read_main (bfd *abfd, bfd_mach_o_load_command *command)
+{
+ bfd_mach_o_main_command *cmd = &command->command.main;
+ struct mach_o_entry_point_command_external raw;
+
+ if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0
+ || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+ return FALSE;
+
+ cmd->entryoff = bfd_get_64 (abfd, raw.entryoff);
+ cmd->stacksize = bfd_get_64 (abfd, raw.stacksize);
+ return TRUE;
+}
+
+static bfd_boolean
+bfd_mach_o_read_source_version (bfd *abfd, bfd_mach_o_load_command *command)
+{
+ bfd_mach_o_source_version_command *cmd = &command->command.source_version;
+ struct mach_o_source_version_command_external raw;
+ bfd_uint64_t ver;
+
+ if (bfd_seek (abfd, command->offset + BFD_MACH_O_LC_SIZE, SEEK_SET) != 0
+ || bfd_bread (&raw, sizeof (raw), abfd) != sizeof (raw))
+ return FALSE;
+
+ ver = bfd_get_64 (abfd, raw.version);
+ /* Note: we use a serie of shift to avoid shift > 32 (for which gcc
+ generates warnings) in case of the host doesn't support 64 bit
+ integers. */
+ cmd->e = ver & 0x3ff;
+ ver >>= 10;
+ cmd->d = ver & 0x3ff;
+ ver >>= 10;
+ cmd->c = ver & 0x3ff;
+ ver >>= 10;
+ cmd->b = ver & 0x3ff;
+ ver >>= 10;
+ cmd->a = ver & 0xffffff;
+ return TRUE;
+}
+
static int
bfd_mach_o_read_segment (bfd *abfd,
bfd_mach_o_load_command *command,
@@ -3842,6 +3884,8 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
case BFD_MACH_O_LC_CODE_SIGNATURE:
case BFD_MACH_O_LC_SEGMENT_SPLIT_INFO:
case BFD_MACH_O_LC_FUNCTION_STARTS:
+ case BFD_MACH_O_LC_DATA_IN_CODE:
+ case BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS:
if (bfd_mach_o_read_linkedit (abfd, command) != 0)
return -1;
break;
@@ -3858,6 +3902,14 @@ bfd_mach_o_read_command (bfd *abfd, bfd_mach_o_load_command *command)
if (!bfd_mach_o_read_version_min (abfd, command))
return -1;
break;
+ case BFD_MACH_O_LC_MAIN:
+ if (!bfd_mach_o_read_main (abfd, command))
+ return -1;
+ break;
+ case BFD_MACH_O_LC_SOURCE_VERSION:
+ if (!bfd_mach_o_read_source_version (abfd, command))
+ return -1;
+ break;
default:
(*_bfd_error_handler)(_("%B: unknown load command 0x%lx"),
abfd, (unsigned long) command->type);
diff --git a/bfd/mach-o.h b/bfd/mach-o.h
index f228df0..1db8674 100644
--- a/bfd/mach-o.h
+++ b/bfd/mach-o.h
@@ -467,7 +467,7 @@ bfd_mach_o_fvmlib_command;
typedef struct bfd_mach_o_dyld_info_command
{
/* File offset and size to rebase info. */
- unsigned int rebase_off;
+ unsigned int rebase_off;
unsigned int rebase_size;
/* File offset and size of binding info. */
@@ -505,6 +505,23 @@ typedef struct bfd_mach_o_encryption_info_command
}
bfd_mach_o_encryption_info_command;
+typedef struct bfd_mach_o_main_command
+{
+ bfd_uint64_t entryoff;
+ bfd_uint64_t stacksize;
+}
+bfd_mach_o_main_command;
+
+typedef struct bfd_mach_o_source_version_command
+{
+ unsigned int a;
+ unsigned short b;
+ unsigned short c;
+ unsigned short d;
+ unsigned short e;
+}
+bfd_mach_o_source_version_command;
+
typedef struct bfd_mach_o_load_command
{
bfd_mach_o_load_command_type type;
@@ -527,6 +544,8 @@ typedef struct bfd_mach_o_load_command
bfd_mach_o_version_min_command version_min;
bfd_mach_o_encryption_info_command encryption_info;
bfd_mach_o_fvmlib_command fvmlib;
+ bfd_mach_o_main_command main;
+ bfd_mach_o_source_version_command source_version;
}
command;
}
diff --git a/include/mach-o/external.h b/include/mach-o/external.h
index 41a2932..4b0a83e 100644
--- a/include/mach-o/external.h
+++ b/include/mach-o/external.h
@@ -124,7 +124,7 @@ struct mach_o_reloc_info_external
#define BFD_MACH_O_SR_SCATTERED 0x80000000
/* For a non-scattered reloc, the relocation info is found in r_symbolnum.
- Bytes 1 to 3 contain the symbol number (0xffffff, in a non-scattered PAIR).
+ Bytes 1 to 3 contain the symbol number (0xffffff, in a non-scattered PAIR).
Byte 4 contains the relocation info - but with differing bit-positions
dependent on target endian-ness - as below. */
@@ -308,6 +308,28 @@ struct mach_o_fvmlib_command_external
unsigned char header_addr[4];
};
+struct mach_o_entry_point_command_external
+{
+ unsigned char entryoff[8]; /* File offset of the entry point. */
+ unsigned char stacksize[8]; /* Initial stack size, if no null. */
+};
+
+struct mach_o_source_version_command_external
+{
+ unsigned char version[8]; /* Version A.B.C.D.E, with 10 bits for B-E,
+ and 24 bits for A. */
+};
+
+/* The LD_DATA_IN_CODE command use a linkedit_data_command that points to
+ a table of entries. */
+
+struct mach_o_data_in_code_entry_external
+{
+ unsigned char offset[4]; /* Offset from the mach_header. */
+ unsigned char length[2]; /* Number of bytes. */
+ unsigned char kind[2]; /* Kind. See BFD_MACH_O_DICE_ values. */
+};
+
struct mach_o_fat_header_external
{
unsigned char magic[4];
diff --git a/include/mach-o/loader.h b/include/mach-o/loader.h
index 1b9b15e..952bc8f 100644
--- a/include/mach-o/loader.h
+++ b/include/mach-o/loader.h
@@ -146,9 +146,9 @@ typedef enum bfd_mach_o_load_command_type
/* Load a dynamically linked shared library that is allowed to be
missing (weak). */
BFD_MACH_O_LC_LOAD_WEAK_DYLIB = 0x18,
- BFD_MACH_O_LC_SEGMENT_64 = 0x19, /* 64-bit segment of this file to be
+ BFD_MACH_O_LC_SEGMENT_64 = 0x19, /* 64-bit segment of this file to be
mapped. */
- BFD_MACH_O_LC_ROUTINES_64 = 0x1a, /* Address of the dyld init routine
+ BFD_MACH_O_LC_ROUTINES_64 = 0x1a, /* Address of the dyld init routine
in a dylib. */
BFD_MACH_O_LC_UUID = 0x1b, /* 128-bit UUID of the executable. */
BFD_MACH_O_LC_RPATH = 0x1c, /* Run path addiions. */
@@ -162,7 +162,11 @@ typedef enum bfd_mach_o_load_command_type
BFD_MACH_O_LC_VERSION_MIN_MACOSX = 0x24, /* Minimal MacOSX version. */
BFD_MACH_O_LC_VERSION_MIN_IPHONEOS = 0x25, /* Minimal IOS version. */
BFD_MACH_O_LC_FUNCTION_STARTS = 0x26, /* Compressed table of func start. */
- BFD_MACH_O_LC_DYLD_ENVIRONMENT = 0x27 /* Env variable string for dyld. */
+ BFD_MACH_O_LC_DYLD_ENVIRONMENT = 0x27, /* Env variable string for dyld. */
+ BFD_MACH_O_LC_MAIN = 0x28, /* Entry point. */
+ BFD_MACH_O_LC_DATA_IN_CODE = 0x29, /* Table of non-instructions. */
+ BFD_MACH_O_LC_SOURCE_VERSION = 0x2a, /* Source version. */
+ BFD_MACH_O_LC_DYLIB_CODE_SIGN_DRS = 0x2b /* DRs from dylibs. */
}
bfd_mach_o_load_command_type;
@@ -250,7 +254,7 @@ bfd_mach_o_section_type;
#define BFD_MACH_O_SECTION_ATTRIBUTES_MASK 0xffffff00
/* System setable attributes. */
#define BFD_MACH_O_SECTION_ATTRIBUTES_SYS 0x00ffff00
-/* User attributes. */
+/* User attributes. */
#define BFD_MACH_O_SECTION_ATTRIBUTES_USR 0xff000000
typedef enum bfd_mach_o_section_attribute
@@ -261,7 +265,7 @@ typedef enum bfd_mach_o_section_attribute
/* Section has local relocation entries. */
BFD_MACH_O_S_ATTR_LOC_RELOC = 0x00000100,
- /* Section has external relocation entries. */
+ /* Section has external relocation entries. */
BFD_MACH_O_S_ATTR_EXT_RELOC = 0x00000200,
/* Section contains some machine instructions. */
@@ -272,7 +276,7 @@ typedef enum bfd_mach_o_section_attribute
/* Used with i386 stubs. */
BFD_MACH_O_S_SELF_MODIFYING_CODE = 0x04000000,
-
+
/* Blocks are live if they reference live blocks. */
BFD_MACH_O_S_ATTR_LIVE_SUPPORT = 0x08000000,
@@ -307,7 +311,7 @@ bfd_mach_o_section_attribute;
#define BFD_MACH_O_NO_SECT 0 /* Symbol not in any section of the image. */
/* Symbol n_desc reference flags. */
-#define BFD_MACH_O_REFERENCE_MASK 0x0f
+#define BFD_MACH_O_REFERENCE_MASK 0x07
#define BFD_MACH_O_REFERENCE_FLAG_UNDEFINED_NON_LAZY 0x00
#define BFD_MACH_O_REFERENCE_FLAG_UNDEFINED_LAZY 0x01
#define BFD_MACH_O_REFERENCE_FLAG_DEFINED 0x02
@@ -320,10 +324,24 @@ bfd_mach_o_section_attribute;
#define BFD_MACH_O_N_NO_DEAD_STRIP 0x20
#define BFD_MACH_O_N_WEAK_REF 0x40
#define BFD_MACH_O_N_WEAK_DEF 0x80
+#define BFD_MACH_O_N_REF_TO_WEAK 0x80
+
+#define BFD_MACH_O_N_ARM_THUMB_DEF 0x08
+#define BFD_MACH_O_N_SYMBOL_RESOLVER 0x100
#define BFD_MACH_O_INDIRECT_SYM_LOCAL 0x80000000
#define BFD_MACH_O_INDIRECT_SYM_ABS 0x40000000
+/* Constants for DATA_IN_CODE entries. */
+typedef enum bfd_mach_o_data_in_code_entry_kind
+{
+ BFD_MACH_O_DICE_KIND_DATA = 0x0001, /* Data */
+ BFD_MACH_O_DICE_JUMP_TABLES8 = 0x0002, /* 1 byte jump tables. */
+ BFD_MACH_O_DICE_JUMP_TABLES16 = 0x0003, /* 2 bytes. */
+ BFD_MACH_O_DICE_JUMP_TABLES32 = 0x0004, /* 4 bytes. */
+ BFD_MACH_O_DICE_ABS_JUMP_TABLES32 = 0x0005 /* Absolute jump table. */
+} bfd_mach_o_data_in_code_entry_kind;
+
/* Thread constants. */
typedef enum bfd_mach_o_ppc_thread_flavour
diff --git a/bfd/mach-o.c b/bfd/mach-o.c
index e44cf6d..4546540 100644
--- a/bfd/mach-o.c
+++ b/bfd/mach-o.c
@@ -3970,66 +3970,89 @@ bfd_mach_o_scan_start_address (bfd *abfd)
{
bfd_mach_o_data_struct *mdata = bfd_mach_o_get_data (abfd);
bfd_mach_o_thread_command *cmd = NULL;
+ bfd_mach_o_main_command *main_cmd = NULL;
unsigned long i;
for (i = 0; i < mdata->header.ncmds; i++)
- if ((mdata->commands[i].type == BFD_MACH_O_LC_THREAD) ||
- (mdata->commands[i].type == BFD_MACH_O_LC_UNIXTHREAD))
- {
- cmd = &mdata->commands[i].command.thread;
- break;
- }
-
- if (cmd == NULL)
- return FALSE;
+ {
+ if ((mdata->commands[i].type == BFD_MACH_O_LC_THREAD) ||
+ (mdata->commands[i].type == BFD_MACH_O_LC_UNIXTHREAD))
+ {
+ cmd = &mdata->commands[i].command.thread;
+ break;
+ }
+ else if (mdata->commands[i].type == BFD_MACH_O_LC_MAIN)
+ {
+ main_cmd = &mdata->commands[i].command.main;
+ break;
+ }
+ }
- /* FIXME: create a subtarget hook ? */
- for (i = 0; i < cmd->nflavours; i++)
+ if (cmd)
{
- if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_I386)
- && (cmd->flavours[i].flavour
- == (unsigned long) BFD_MACH_O_x86_THREAD_STATE32))
- {
- unsigned char buf[4];
+ /* FIXME: create a subtarget hook ? */
+ for (i = 0; i < cmd->nflavours; i++)
+ {
+ if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_I386)
+ && (cmd->flavours[i].flavour
+ == (unsigned long) BFD_MACH_O_x86_THREAD_STATE32))
+ {
+ unsigned char buf[4];
- if (bfd_seek (abfd, cmd->flavours[i].offset + 40, SEEK_SET) != 0
- || bfd_bread (buf, 4, abfd) != 4)
- return FALSE;
+ if (bfd_seek (abfd, cmd->flavours[i].offset + 40, SEEK_SET) != 0
+ || bfd_bread (buf, 4, abfd) != 4)
+ return FALSE;
- abfd->start_address = bfd_h_get_32 (abfd, buf);
- }
- else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_POWERPC)
- && (cmd->flavours[i].flavour == BFD_MACH_O_PPC_THREAD_STATE))
- {
- unsigned char buf[4];
+ abfd->start_address = bfd_h_get_32 (abfd, buf);
+ }
+ else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_POWERPC)
+ && (cmd->flavours[i].flavour == BFD_MACH_O_PPC_THREAD_STATE))
+ {
+ unsigned char buf[4];
- if (bfd_seek (abfd, cmd->flavours[i].offset + 0, SEEK_SET) != 0
- || bfd_bread (buf, 4, abfd) != 4)
- return FALSE;
+ if (bfd_seek (abfd, cmd->flavours[i].offset + 0, SEEK_SET) != 0
+ || bfd_bread (buf, 4, abfd) != 4)
+ return FALSE;
- abfd->start_address = bfd_h_get_32 (abfd, buf);
- }
- else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_POWERPC_64)
- && (cmd->flavours[i].flavour == BFD_MACH_O_PPC_THREAD_STATE64))
- {
- unsigned char buf[8];
+ abfd->start_address = bfd_h_get_32 (abfd, buf);
+ }
+ else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_POWERPC_64)
+ && (cmd->flavours[i].flavour == BFD_MACH_O_PPC_THREAD_STATE64))
+ {
+ unsigned char buf[8];
- if (bfd_seek (abfd, cmd->flavours[i].offset + 0, SEEK_SET) != 0
- || bfd_bread (buf, 8, abfd) != 8)
- return FALSE;
+ if (bfd_seek (abfd, cmd->flavours[i].offset + 0, SEEK_SET) != 0
+ || bfd_bread (buf, 8, abfd) != 8)
+ return FALSE;
- abfd->start_address = bfd_h_get_64 (abfd, buf);
- }
- else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_X86_64)
- && (cmd->flavours[i].flavour == BFD_MACH_O_x86_THREAD_STATE64))
- {
- unsigned char buf[8];
+ abfd->start_address = bfd_h_get_64 (abfd, buf);
+ }
+ else if ((mdata->header.cputype == BFD_MACH_O_CPU_TYPE_X86_64)
+ && (cmd->flavours[i].flavour == BFD_MACH_O_x86_THREAD_STATE64))
+ {
+ unsigned char buf[8];
- if (bfd_seek (abfd, cmd->flavours[i].offset + (16 * 8), SEEK_SET) != 0
- || bfd_bread (buf, 8, abfd) != 8)
- return FALSE;
+ if (bfd_seek (abfd, cmd->flavours[i].offset + (16 * 8), SEEK_SET) != 0
+ || bfd_bread (buf, 8, abfd) != 8)
+ return FALSE;
- abfd->start_address = bfd_h_get_64 (abfd, buf);
+ abfd->start_address = bfd_h_get_64 (abfd, buf);
+ }
+ }
+ }
+ else if (main_cmd)
+ {
+ bfd_vma text_address = 0;
+
+ if (mdata->nsects > 1)
+ {
+ bfd_mach_o_section *text_sect = mdata->sections[0];
+ if (text_sect)
+ {
+ text_address = text_sect->addr - text_sect->offset;
+ abfd->start_address = main_cmd->entryoff + text_address;
+ return TRUE;
+ }
}
}
@@ -4121,10 +4144,11 @@ bfd_mach_o_scan (bfd *abfd,
}
}
- if (bfd_mach_o_scan_start_address (abfd) < 0)
+ bfd_mach_o_flatten_sections (abfd);
+
+ if (!bfd_mach_o_scan_start_address (abfd))
return FALSE;
- bfd_mach_o_flatten_sections (abfd);
return TRUE;
}
@cinsk
Copy link

cinsk commented Feb 9, 2013

With this patch, I'm able to use GDB 7.5.1 on mountain lion. Thanks. However, unlike the Apple shipped version (gdb 6.3.50), GBD 7.5.1 + your patch could not trace into the dynamic libraries. GDB 7.5.1 "info shared" shows that it read the debugging information from the dynamic libraries, but next/step command fails. Could you look at that problem?

@davidbalbert
Copy link
Author

Hi @cinsk,

Sorry I didn't see this until now. Have you tried gdb 7.6? It has these patches incorporated (the first patch, was actually just a backport from gdb 7.6's dev branch).

Is it possible you're debugging a library compiled with Clang? From some of the experiments I did a few months ago, it seems gdb has trouble getting line number info from the DWARF debugging symbols that Clang generates (the same hello world program compiled with gcc-4.2 had no trouble). I'm not actually a gdb expert by a long shot. I mostly just keep the homebrew-dupes formula up to date. If this is an issue you're having, I actually filed a bug report a while ago: http://sourceware.org/bugzilla/show_bug.cgi?id=14870. It hasn't seen any activity since I reported it. If you're having the same issue, you should comment on the bug. Perhaps it will get someone to look at the bug.

Let me know if this helps.

Best,
-Dave

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment