@@ -323,6 +323,10 @@
#endif /* __GNUC__ */
#endif
+#ifndef ELFTC_VCSID
+#define ELFTC_VCSID(ID) /* nothing */
+#endif
+
#endif /* ELFTC_VCSID */
/*
@@ -54,8 +54,8 @@
libdwarf_attr.c \
libdwarf_die.c \
libdwarf_error.c \
- libdwarf_elf_access.c \
- libdwarf_elf_init.c \
+ libdwarf_macho_access.c \
+ libdwarf_macho_init.c \
libdwarf_frame.c \
libdwarf_info.c \
libdwarf_init.c \
@@ -335,3 +335,5 @@
dwarf_pro_vars.c: dwarf_pro_nametbl.m4 dwarf_pro_vars.m4
.include "${TOP}/mk/elftoolchain.lib.mk"
+
+CFLAGS += -Wno-unused-parameter -Wno-cast-align ${EXTRA_CFLAGS}
@@ -378,7 +378,23 @@
STAILQ_ENTRY(_Dwarf_Rel_Section) drs_next; /* Next reloc section. */
} *Dwarf_Rel_Section;
+#ifdef __APPLE__
typedef struct {
+ Dwarf_Addr addr;
+ Dwarf_Unsigned size;
+ const char *name;
+ char *name_alloc;
+} Dwarf_MachO_Section;
+
+typedef struct {
+ Dwarf_Ptr map_base;
+ Dwarf_Bool is_64;
+ Dwarf_Unsigned seccnt;
+ Dwarf_MachO_Section *sec;
+ Dwarf_Obj_Access_Methods eo_methods;
+} Dwarf_MachO_Object;
+#else
+typedef struct {
Elf_Data *ed_data;
void *ed_alloc;
} Dwarf_Elf_Data;
@@ -392,6 +408,7 @@
size_t eo_strndx;
Dwarf_Obj_Access_Methods eo_methods;
} Dwarf_Elf_Object;
+#endif
struct _Dwarf_Debug {
Dwarf_Obj_Access_Interface *dbg_iface;
@@ -523,6 +540,18 @@
int _dwarf_die_parse(Dwarf_Debug, Dwarf_Section *, Dwarf_CU, int,
uint64_t, uint64_t, Dwarf_Die *, int, Dwarf_Error *);
void _dwarf_die_pro_cleanup(Dwarf_P_Debug);
+#ifdef __APPLE__
+void _dwarf_macho_deinit(Dwarf_Debug);
+int _dwarf_macho_init(Dwarf_Debug, Dwarf_Ptr, Dwarf_Error *);
+int _dwarf_macho_load_section(void *, Dwarf_Half, Dwarf_Small **,
+ int *);
+Dwarf_Endianness _dwarf_macho_get_byte_order(void *);
+Dwarf_Small _dwarf_macho_get_length_size(void *);
+Dwarf_Small _dwarf_macho_get_pointer_size(void *);
+Dwarf_Unsigned _dwarf_macho_get_section_count(void *);
+int _dwarf_macho_get_section_info(void *, Dwarf_Half,
+ Dwarf_Obj_Access_Section *, int *);
+#else
void _dwarf_elf_deinit(Dwarf_Debug);
int _dwarf_elf_init(Dwarf_Debug, Elf *, Dwarf_Error *);
int _dwarf_elf_load_section(void *, Dwarf_Half, Dwarf_Small **,
@@ -533,6 +562,7 @@
Dwarf_Unsigned _dwarf_elf_get_section_count(void *);
int _dwarf_elf_get_section_info(void *, Dwarf_Half,
Dwarf_Obj_Access_Section *, int *);
+#endif
void _dwarf_expr_cleanup(Dwarf_P_Debug);
int _dwarf_expr_into_block(Dwarf_P_Expr, Dwarf_Error *);
Dwarf_Section *_dwarf_find_next_types_section(Dwarf_Debug, Dwarf_Section *);
@@ -80,7 +80,11 @@
if (error->err_error == DW_DLE_ELF)
snprintf(error->err_msg, sizeof(error->err_msg),
+#ifdef __APPLE__
+ "ELF error : %d [%s(%d)]", error->err_elferror,
+#else
"ELF error : %s [%s(%d)]", elf_errmsg(error->err_elferror),
+#endif
error->err_func, error->err_line);
else
snprintf(error->err_msg, sizeof(error->err_msg),
@@ -37,7 +37,11 @@
return (DW_DLV_OK);
_dwarf_deinit(dbg);
+#ifdef __APPLE__
+ _dwarf_macho_deinit(dbg);
+#else
_dwarf_elf_deinit(dbg);
+#endif
free(dbg);
@@ -29,7 +29,48 @@
ELFTC_VCSID("$Id$");
+#ifdef __APPLE__
int
+dwarf_macho_init(Dwarf_Ptr map_base, int mode, Dwarf_Handler errhand, Dwarf_Ptr errarg,
+ Dwarf_Debug *ret_dbg, Dwarf_Error *error)
+{
+ Dwarf_Debug dbg;
+ int ret;
+
+ if (map_base == NULL || ret_dbg == NULL) {
+ DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (mode != DW_DLC_READ) {
+ DWARF_SET_ERROR(NULL, error, DW_DLE_ARGUMENT);
+ return (DW_DLV_ERROR);
+ }
+
+ if (_dwarf_alloc(&dbg, mode, error) != DW_DLE_NONE)
+ return (DW_DLV_ERROR);
+
+ if (_dwarf_macho_init(dbg, map_base, error) != DW_DLE_NONE) {
+ free(dbg);
+ return (DW_DLV_ERROR);
+ }
+
+ if ((ret = _dwarf_init(dbg, 0, errhand, errarg, error)) !=
+ DW_DLE_NONE) {
+ _dwarf_macho_deinit(dbg);
+ free(dbg);
+ if (ret == DW_DLE_DEBUG_INFO_NULL)
+ return (DW_DLV_NO_ENTRY);
+ else
+ return (DW_DLV_ERROR);
+ }
+
+ *ret_dbg = dbg;
+
+ return (DW_DLV_OK);
+}
+#else
+int
dwarf_elf_init(Elf *elf, int mode, Dwarf_Handler errhand, Dwarf_Ptr errarg,
Dwarf_Debug *ret_dbg, Dwarf_Error *error)
{
@@ -135,6 +176,7 @@
return (DW_DLV_OK);
}
+#endif /* __APPLE__ */
int
dwarf_object_init(Dwarf_Obj_Access_Interface *iface, Dwarf_Handler errhand,
@@ -544,8 +544,13 @@
Dwarf_P_Die, Dwarf_P_Die, Dwarf_Error *);
int dwarf_diename(Dwarf_Die, char **, Dwarf_Error *);
int dwarf_dieoffset(Dwarf_Die, Dwarf_Off *, Dwarf_Error *);
+#ifdef __APPLE__
+int dwarf_macho_init(Dwarf_Ptr, int, Dwarf_Handler, Dwarf_Ptr,
+ Dwarf_Debug *, Dwarf_Error *);
+#else
int dwarf_elf_init(Elf *, int, Dwarf_Handler, Dwarf_Ptr,
Dwarf_Debug *, Dwarf_Error *);
+#endif
int dwarf_end_macro_file(Dwarf_P_Debug, Dwarf_Error *);
const char *dwarf_errmsg_(Dwarf_Error *);
int dwarf_expand_frame_instructions(Dwarf_Cie, Dwarf_Ptr,
@@ -0,0 +1,131 @@
+/*-
+ * Copyright (c) 2014 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "_libdwarf.h"
+
+ELFTC_VCSID("$Id: libdwarf_elf_access.c 2070 2011-10-27 03:05:32Z jkoshy $");
+
+int
+_dwarf_macho_get_section_info(void *obj, Dwarf_Half ndx,
+ Dwarf_Obj_Access_Section *ret_section, int *error)
+{
+ Dwarf_MachO_Object *e;
+
+ e = obj;
+ assert(e != NULL);
+
+ if (ret_section == NULL) {
+ if (error)
+ *error = DW_DLE_ARGUMENT;
+ return (DW_DLV_ERROR);
+ }
+
+ if (ndx >= e->seccnt) {
+ if (error)
+ *error = DW_DLE_NO_ENTRY;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ ret_section->addr = e->sec[ndx].addr;
+ ret_section->size = e->sec[ndx].size;
+ ret_section->name = e->sec[ndx].name;
+
+ return (DW_DLV_OK);
+}
+
+Dwarf_Endianness
+_dwarf_macho_get_byte_order(void *obj)
+{
+ /* We only support x86 */
+ return (DW_OBJECT_LSB);
+}
+
+Dwarf_Small
+_dwarf_macho_get_length_size(void *obj)
+{
+ Dwarf_MachO_Object *e;
+
+ e = obj;
+ assert(e != NULL);
+
+ if (e->is_64)
+ return (8);
+ else
+ return (4);
+}
+
+Dwarf_Small
+_dwarf_macho_get_pointer_size(void *obj)
+{
+ Dwarf_MachO_Object *e;
+
+ e = obj;
+ assert(e != NULL);
+
+ if (e->is_64)
+ return (8);
+ else
+ return (4);
+}
+
+Dwarf_Unsigned
+_dwarf_macho_get_section_count(void *obj)
+{
+ Dwarf_MachO_Object *e;
+
+ e = obj;
+ assert(e != NULL);
+
+ return (e->seccnt);
+}
+
+int
+_dwarf_macho_load_section(void *obj, Dwarf_Half ndx, Dwarf_Small** ret_data,
+ int *error)
+{
+ Dwarf_MachO_Object *e;
+
+ e = obj;
+ assert(e != NULL);
+
+ if (ret_data == NULL) {
+ if (error)
+ *error = DW_DLE_ARGUMENT;
+ return (DW_DLV_ERROR);
+ }
+
+ if (ndx >= e->seccnt) {
+ if (error)
+ *error = DW_DLE_NO_ENTRY;
+ return (DW_DLV_NO_ENTRY);
+ }
+
+ /* XXX: currently not applying relocs */
+ /* XXX: why does elf version sometimes alloc memory and memcpy? */
+ *ret_data = (Dwarf_Small *) e->sec[ndx].addr;
+
+ return (DW_DLV_OK);
+}
@@ -0,0 +1,287 @@
+/*-
+ * Copyright (c) 2014 Google, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "_libdwarf.h"
+#include <mach-o/loader.h> /* mach_header */
+
+static const char *debug_name[] = {
+ /* Note how "__" is used instead of "." */
+ "__debug_abbrev",
+ "__debug_aranges",
+ "__debug_frame",
+ "__debug_info",
+ "__debug_types",
+ "__debug_line",
+ "__debug_pubnames",
+ "__eh_frame",
+ "__debug_macinfo",
+ "__debug_str",
+ "__debug_loc",
+ "__debug_pubtypes",
+ "__debug_ranges",
+ "__debug_static_func",
+ "__debug_static_vars",
+ "__debug_typenames",
+ "__debug_weaknames",
+ NULL
+};
+
+static int
+_dwarf_macho_init_sect(Dwarf_MachO_Section *ob, Dwarf_Addr addr, Dwarf_Unsigned size,
+ char sectname[16])
+{
+ size_t sz = sizeof(char[16]) + 1;
+ ob->addr = addr;
+ ob->size = size;
+ if ((ob->name_alloc = calloc(sz, sizeof(char))) == NULL) {
+ return DW_DLE_MEMORY;
+ }
+ /* Replace "__" with "." as that's what the rest of the code expects */
+ if (sectname[0] == '_' && sectname[1] == '_') {
+ /* Mach-O section names are not null-terminate if they take up the
+ * full 16-char max
+ */
+ snprintf(ob->name_alloc, sz, ".%.*s", (int)sizeof(char[16])-2, sectname+2);
+ } else
+ snprintf(ob->name_alloc, sz, "%s", sectname);
+ ob->name_alloc[sz - 1] = '\0';
+ ob->name = ob->name_alloc;
+ return DW_DLE_NONE;
+}
+
+int
+_dwarf_macho_init(Dwarf_Debug dbg, Dwarf_Ptr map_base, Dwarf_Error *error)
+{
+ Dwarf_Obj_Access_Interface *iface;
+ Dwarf_MachO_Object *e;
+ int i, j, n, ret;
+ struct mach_header *hdr = (struct mach_header *) map_base;
+ struct mach_header_64 *hdr64;
+ struct load_command *cmd, *cmd_stop;
+ int is_64;
+
+ /* We deliberately don't check hdr->filetype as we don't want to limit
+ * ourselves to just MH_EXECUTE, MH_DYLIB, or MH_BUNDLE in case others
+ * have symbols as well.
+ */
+ if (hdr->magic == MH_MAGIC && hdr->cputype == CPU_TYPE_X86)
+ is_64 = 0;
+ else if (hdr->magic == MH_MAGIC_64 && hdr->cputype == CPU_TYPE_X86_64) {
+ is_64 = 1;
+ hdr64 = (struct mach_header_64 *) map_base;
+ } else {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_ELF);
+ return DW_DLE_ELF;
+ }
+
+ ret = DW_DLE_NONE;
+
+ if ((iface = calloc(1, sizeof(*iface))) == NULL) {
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ if ((e = calloc(1, sizeof(*e))) == NULL) {
+ free(iface);
+ DWARF_SET_ERROR(dbg, error, DW_DLE_MEMORY);
+ return (DW_DLE_MEMORY);
+ }
+
+ e->map_base = map_base;
+ e->is_64 = is_64;
+ e->eo_methods.get_section_info = _dwarf_macho_get_section_info;
+ e->eo_methods.get_byte_order = _dwarf_macho_get_byte_order;
+ e->eo_methods.get_length_size = _dwarf_macho_get_length_size;
+ e->eo_methods.get_pointer_size = _dwarf_macho_get_pointer_size;
+ e->eo_methods.get_section_count = _dwarf_macho_get_section_count;
+ e->eo_methods.load_section = _dwarf_macho_load_section;
+
+ iface->object = e;
+ iface->methods = &e->eo_methods;
+
+ dbg->dbg_iface = iface;
+
+ /* XXX: not supporting relocation right now which is what this is used for */
+ dbg->dbg_machine = EM_NONE;
+
+ /* We need two passes: one to count the sections we care about and
+ * the second to fill in the data.
+ */
+ n = 0;
+ if (is_64) {
+ cmd = (struct load_command *)(hdr64 + 1);
+ cmd_stop = (struct load_command *)((char *)cmd + hdr64->sizeofcmds);
+ } else {
+ cmd = (struct load_command *)(hdr + 1);
+ cmd_stop = (struct load_command *)((char *)cmd + hdr->sizeofcmds);
+ }
+ while (cmd < cmd_stop) {
+ if (cmd->cmd == LC_SEGMENT || cmd->cmd == LC_SEGMENT_64) {
+ if (is_64) {
+ struct segment_command_64 *seg64 = (struct segment_command_64 *) cmd;
+ struct section_64 *sec64 = (struct section_64 *)(seg64 + 1);
+ struct section_64 *sec64_stop = (struct section_64 *)
+ ((char *)seg64 + seg64->cmdsize);
+ while (sec64 < sec64_stop) {
+ for (i = 0; debug_name[i] != NULL; i++) {
+ /* sectname is not null-terminated if it's the full 16-char size.
+ * XXX: we assume we have a match if the 1st 16 chars match,
+ * for the handful that are longer than 16.
+ */
+ if (strncmp(debug_name[i], sec64->sectname,
+ sizeof(sec64->sectname)) == 0) {
+ n++;
+ break;
+ }
+ }
+ sec64++;
+ }
+ } else {
+ struct segment_command *seg = (struct segment_command *) cmd;
+ struct section *sec = (struct section *)(seg + 1);
+ struct section *sec_stop = (struct section *)
+ ((char *)seg + seg->cmdsize);
+ while (sec < sec_stop) {
+ for (i = 0; debug_name[i] != NULL; i++) {
+ if (strncmp(debug_name[i], sec->sectname,
+ sizeof(sec->sectname)) == 0) {
+ n++;
+ break;
+ }
+ }
+ sec++;
+ }
+ }
+ }
+ cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
+ }
+
+ e->seccnt = n;
+
+ if (n == 0)
+ return (DW_DLE_NONE);
+
+ if ((e->sec = calloc(n, sizeof(*e->sec))) == NULL) {
+ DWARF_SET_ERROR(NULL, error, DW_DLE_MEMORY);
+ ret = DW_DLE_MEMORY;
+ goto fail_cleanup;
+ }
+
+ j = 0;
+ if (is_64)
+ cmd = (struct load_command *)(hdr64 + 1);
+ else
+ cmd = (struct load_command *)(hdr + 1);
+ while (cmd < cmd_stop) {
+ if (cmd->cmd == LC_SEGMENT || cmd->cmd == LC_SEGMENT_64) {
+ if (is_64) {
+ struct segment_command_64 *seg64 = (struct segment_command_64 *) cmd;
+ struct section_64 *sec64 = (struct section_64 *)(seg64 + 1);
+ struct section_64 *sec64_stop = (struct section_64 *)
+ ((char *)seg64 + seg64->cmdsize);
+ while (sec64 < sec64_stop) {
+ for (i = 0; debug_name[i] != NULL; i++) {
+ if (strncmp(debug_name[i], sec64->sectname,
+ sizeof(sec64->sectname)) == 0) {
+ int res = _dwarf_macho_init_sect(&e->sec[j],
+ (Dwarf_Addr)map_base + sec64->offset,
+ sec64->size, sec64->sectname);
+ if (res != DW_DLE_NONE) {
+ DWARF_SET_ERROR(dbg, error, res);
+ ret = res;
+ goto fail_cleanup;
+ }
+ j++;
+ break;
+ }
+ }
+ sec64++;
+ }
+ } else {
+ struct segment_command *seg = (struct segment_command *) cmd;
+ struct section *sec = (struct section *)(seg + 1);
+ struct section *sec_stop = (struct section *)
+ ((char *)seg + seg->cmdsize);
+ while (sec < sec_stop) {
+ for (i = 0; debug_name[i] != NULL; i++) {
+ if (strncmp(debug_name[i], sec->sectname,
+ sizeof(sec->sectname)) == 0) {
+ int res = _dwarf_macho_init_sect(&e->sec[j],
+ (Dwarf_Addr)map_base + sec->offset,
+ sec->size, sec->sectname);
+ if (res != DW_DLE_NONE) {
+ DWARF_SET_ERROR(dbg, error, res);
+ ret = res;
+ goto fail_cleanup;
+ }
+ j++;
+ break;
+ }
+ }
+ sec++;
+ }
+ }
+ }
+ cmd = (struct load_command *)((char *)cmd + cmd->cmdsize);
+ }
+
+ assert(j == n);
+
+ return (DW_DLE_NONE);
+
+fail_cleanup:
+
+ _dwarf_macho_deinit(dbg);
+
+ return (ret);
+}
+
+void
+_dwarf_macho_deinit(Dwarf_Debug dbg)
+{
+ Dwarf_Obj_Access_Interface *iface;
+ Dwarf_MachO_Object *e;
+ Dwarf_Unsigned i;
+
+ iface = dbg->dbg_iface;
+ assert(iface != NULL);
+
+ e = iface->object;
+ assert(e != NULL);
+
+ if (e->sec) {
+ for (i = 0; i < e->seccnt; i++) {
+ if (e->sec[i].name_alloc)
+ free(e->sec[i].name_alloc);
+ }
+ free(e->sec);
+ }
+
+ free(e);
+ free(iface);
+
+ dbg->dbg_iface = NULL;
+}
@@ -63,3 +63,5 @@
.endif
.include "${TOP}/mk/elftoolchain.lib.mk"
+
+CFLAGS += -Wno-unused-parameter -Wno-cast-align ${EXTRA_CFLAGS}