Libdwarf updates from upstream, including bugfixes and proper mach-o universal binaru support. Huge thanks to the awesome maintainer.

This commit is contained in:
Jeremy 2023-09-30 19:24:27 -04:00
parent d4bc913607
commit 1d0a6642cf
No known key found for this signature in database
GPG Key ID: 19AA8270105E8EB4
17 changed files with 900 additions and 62 deletions

View File

@ -27,6 +27,13 @@
*/ */
#ifndef DWARF_ABBREV_H
#define DWARF_ABBREV_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* In a given CU, one of these is (eventually) set up /* In a given CU, one of these is (eventually) set up
for every abbreviation we need to find (and for all for every abbreviation we need to find (and for all
those earlier in the abbreviations for that CU). those earlier in the abbreviations for that CU).
@ -67,3 +74,9 @@ int _dwarf_count_abbrev_entries(Dwarf_Debug dbg,
Dwarf_Unsigned *abbrev_implicit_const_count_out, Dwarf_Unsigned *abbrev_implicit_const_count_out,
Dwarf_Byte_Ptr *abbrev_ptr_out, Dwarf_Byte_Ptr *abbrev_ptr_out,
Dwarf_Error *error); Dwarf_Error *error);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DWARF_ABBREV_H */

View File

@ -1140,7 +1140,9 @@ _dwarf_free_all_of_one_debug(Dwarf_Debug dbg)
/* de_alloc_tree might be NULL if /* de_alloc_tree might be NULL if
global_de_alloc_tree_on is zero. */ global_de_alloc_tree_on is zero. */
if (dbg->de_alloc_tree) { if (dbg->de_alloc_tree) {
dbg->de_in_tdestroy = TRUE;
dwarf_tdestroy(dbg->de_alloc_tree,tdestroy_free_node); dwarf_tdestroy(dbg->de_alloc_tree,tdestroy_free_node);
dbg->de_in_tdestroy = FALSE;
dbg->de_alloc_tree = 0; dbg->de_alloc_tree = 0;
} }
_dwarf_free_static_errlist(); _dwarf_free_static_errlist();

View File

@ -26,6 +26,13 @@
Fifth Floor, Boston MA 02110-1301, USA. Fifth Floor, Boston MA 02110-1301, USA.
*/ */
#ifndef DWARF_ALLOC_H
#define DWARF_ALLOC_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* #define DWARF_SIMPLE_MALLOC 1 */ /* #define DWARF_SIMPLE_MALLOC 1 */
char * _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned); char * _dwarf_get_alloc(Dwarf_Debug, Dwarf_Small, Dwarf_Unsigned);
@ -43,3 +50,9 @@ void _dwarf_error_destructor(void *);
void _dwarf_add_to_static_err_list(Dwarf_Error err); void _dwarf_add_to_static_err_list(Dwarf_Error err);
void _dwarf_flush_static_error_list(void); void _dwarf_flush_static_error_list(void);
void _dwarf_free_static_errlist(void); void _dwarf_free_static_errlist(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DWARF_ALLOC_H */

View File

@ -682,6 +682,8 @@ static const char _dwarf_errmsgs[DW_DLE_LAST+1][DW_MAX_MSG_LEN] = {
{"DW_DLE_LINE_COUNT_WRONG(500) A count in a line table is " {"DW_DLE_LINE_COUNT_WRONG(500) A count in a line table is "
"not valid. Corrupt data."}, "not valid. Corrupt data."},
{"DW_DLE_ARITHMETIC_OVERFLOW(501) Arithmetic overflow. " {"DW_DLE_ARITHMETIC_OVERFLOW(501) Arithmetic overflow. "
" Corrupt Dwarf." } " Corrupt Dwarf." },
{" DW_DLE_UNIVERSAL_BINARY_ERROR(502) Error reading Mach-O "
"uninversal binary head. Corrupt Mach-O object." }
}; };
#endif /* DWARF_ERRMSG_LIST_H */ #endif /* DWARF_ERRMSG_LIST_H */

View File

@ -2160,7 +2160,9 @@ dwarf_get_fde_for_die(Dwarf_Debug dbg,
} }
/* DW_DLV_OK */ /* DW_DLV_OK */
/* This is the only situation this is set. */ /* This is the only situation this is set.
and is really dangerous. as fde and cie
are set for dealloc by dwarf_finish(). */
new_fde->fd_fde_owns_cie = TRUE; new_fde->fd_fde_owns_cie = TRUE;
/* Now read the cie corresponding to the fde, /* Now read the cie corresponding to the fde,
_dwarf_read_cie_fde_prefix checks _dwarf_read_cie_fde_prefix checks
@ -3416,15 +3418,22 @@ _dwarf_frame_destructor(void *frame)
struct Dwarf_Frame_s *fp = frame; struct Dwarf_Frame_s *fp = frame;
_dwarf_free_fde_table(fp); _dwarf_free_fde_table(fp);
} }
void void
_dwarf_fde_destructor(void *f) _dwarf_fde_destructor(void *f)
{ {
struct Dwarf_Fde_s *fde = f; struct Dwarf_Fde_s *fde = f;
if (fde->fd_fde_owns_cie) { if (fde->fd_fde_owns_cie) {
/* This is just for dwarf_get_fde_for_die() */ Dwarf_Debug dbg = fde->fd_dbg;
if (!dbg->de_in_tdestroy) {
/* This is just for dwarf_get_fde_for_die() and
must not be applied in alloc tree destruction. */
dwarf_dealloc(fde->fd_dbg,fde->fd_cie,DW_DLA_CIE); dwarf_dealloc(fde->fd_dbg,fde->fd_cie,DW_DLA_CIE);
fde->fd_cie = 0; fde->fd_cie = 0;
} }
}
if (fde->fd_have_fde_tab) { if (fde->fd_have_fde_tab) {
_dwarf_free_fde_table(&fde->fd_fde_table); _dwarf_free_fde_table(&fde->fd_fde_table);
fde->fd_have_fde_tab = false; fde->fd_have_fde_tab = false;

View File

@ -975,10 +975,12 @@ _dwarf_create_cie_from_after_start(Dwarf_Debug dbg,
&gnu_personality_handler_addr, &gnu_personality_handler_addr,
error); error);
if (resz != DW_DLV_OK) { if (resz != DW_DLV_OK) {
if (resz == DW_DLV_ERROR) {
_dwarf_error_string(dbg, error, _dwarf_error_string(dbg, error,
DW_DLE_FRAME_AUGMENTATION_UNKNOWN, DW_DLE_FRAME_AUGMENTATION_UNKNOWN,
"DW_DLE_FRAME_AUGMENTATION_UNKNOWN " "DW_DLE_FRAME_AUGMENTATION_UNKNOWN "
" Reading gnu aug encodings failed"); " Reading gnu aug encodings failed");
} /* DW_DLV_NO_ENTRY seems impossible. */
return resz; return resz;
} }
frame_ptr += adlen; frame_ptr += adlen;
@ -1119,7 +1121,7 @@ _dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
address_range in the FDE are read according to the CIE address_range in the FDE are read according to the CIE
augmentation string instructions. */ augmentation string instructions. */
{ if (cieptr) {
Dwarf_Small *fp_updated = 0; Dwarf_Small *fp_updated = 0;
int res = _dwarf_read_encoded_ptr(dbg, int res = _dwarf_read_encoded_ptr(dbg,
section_pointer, section_pointer,
@ -1150,6 +1152,15 @@ _dwarf_create_fde_from_after_start(Dwarf_Debug dbg,
return res; return res;
} }
frame_ptr = fp_updated; frame_ptr = fp_updated;
} else {
_dwarf_error_string(dbg, error,
DW_DLE_AUG_DATA_LENGTH_BAD,
"DW_DLE_AUG_DATA_LENGTH_BAD: The "
"gcc augmentation cannot be read, "
"as no cie pointer is available "
"to get critical data, "
"Corrupt DWARF");
return DW_DLV_ERROR;
} }
{ {
Dwarf_Unsigned adlen = 0; Dwarf_Unsigned adlen = 0;

View File

@ -125,6 +125,24 @@ set_global_paths_init(Dwarf_Debug dbg, Dwarf_Error* error)
} }
/* New in December 2018. */ /* New in December 2018. */
int dwarf_init_path_a(const char *path,
char * true_path_out_buffer,
unsigned true_path_bufferlen,
unsigned groupnumber,
unsigned universalnumber,
Dwarf_Handler errhand,
Dwarf_Ptr errarg,
Dwarf_Debug * ret_dbg,
Dwarf_Error * error)
{
return dwarf_init_path_dl_a(path,
true_path_out_buffer,true_path_bufferlen,
groupnumber,universalnumber,
errhand,errarg,ret_dbg,
0,0,0,
error);
}
int dwarf_init_path(const char *path, int dwarf_init_path(const char *path,
char * true_path_out_buffer, char * true_path_out_buffer,
unsigned true_path_bufferlen, unsigned true_path_bufferlen,
@ -134,9 +152,11 @@ int dwarf_init_path(const char *path,
Dwarf_Debug * ret_dbg, Dwarf_Debug * ret_dbg,
Dwarf_Error * error) Dwarf_Error * error)
{ {
return dwarf_init_path_dl(path, unsigned int universalnumber = 0;
return dwarf_init_path_dl_a(path,
true_path_out_buffer,true_path_bufferlen, true_path_out_buffer,true_path_bufferlen,
groupnumber,errhand,errarg,ret_dbg, groupnumber,universalnumber,
errhand,errarg,ret_dbg,
0,0,0, 0,0,0,
error); error);
} }
@ -192,6 +212,30 @@ dwarf_init_path_dl(const char *path,
unsigned int dl_path_count, unsigned int dl_path_count,
unsigned char * path_source, unsigned char * path_source,
Dwarf_Error * error) Dwarf_Error * error)
{
unsigned int universalnumber = 0;
int res = 0;
res = dwarf_init_path_dl_a(path,
true_path_out_buffer, true_path_bufferlen,
groupnumber,universalnumber,
errhand,errarg,ret_dbg, dl_path_array,
dl_path_count,path_source,error);
return res;
}
int
dwarf_init_path_dl_a(const char *path,
char * true_path_out_buffer,
unsigned true_path_bufferlen,
unsigned groupnumber,
unsigned universalnumber,
Dwarf_Handler errhand,
Dwarf_Ptr errarg,
Dwarf_Debug * ret_dbg,
char ** dl_path_array,
unsigned int dl_path_count,
unsigned char * path_source,
Dwarf_Error * error)
{ {
unsigned ftype = 0; unsigned ftype = 0;
unsigned endian = 0; unsigned endian = 0;
@ -302,9 +346,11 @@ dwarf_init_path_dl(const char *path,
*ret_dbg = dbg; *ret_dbg = dbg;
return res; return res;
} }
case DW_FTYPE_APPLEUNIVERSAL:
case DW_FTYPE_MACH_O: { case DW_FTYPE_MACH_O: {
res = _dwarf_macho_setup(fd, res = _dwarf_macho_setup(fd,
file_path, file_path,
universalnumber,
ftype,endian,offsetsize,filesize, ftype,endian,offsetsize,filesize,
groupnumber,errhand,errarg,&dbg,error); groupnumber,errhand,errarg,&dbg,error);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
@ -355,6 +401,7 @@ dwarf_init_b(int fd,
unsigned ftype = 0; unsigned ftype = 0;
unsigned endian = 0; unsigned endian = 0;
unsigned offsetsize = 0; unsigned offsetsize = 0;
unsigned universalnumber = 0;
Dwarf_Unsigned filesize = 0; Dwarf_Unsigned filesize = 0;
int res = 0; int res = 0;
int errcode = 0; int errcode = 0;
@ -387,10 +434,12 @@ dwarf_init_b(int fd,
set_global_paths_init(*ret_dbg,error); set_global_paths_init(*ret_dbg,error);
return res2; return res2;
} }
case DW_FTYPE_APPLEUNIVERSAL:
case DW_FTYPE_MACH_O: { case DW_FTYPE_MACH_O: {
int resm = 0; int resm = 0;
resm = _dwarf_macho_setup(fd,"", resm = _dwarf_macho_setup(fd,"",
universalnumber,
ftype,endian,offsetsize,filesize, ftype,endian,offsetsize,filesize,
group_number,errhand,errarg,ret_dbg,error); group_number,errhand,errarg,ret_dbg,error);
if (resm != DW_DLV_OK) { if (resm != DW_DLV_OK) {

View File

@ -76,6 +76,35 @@ extern "C" {
#define TYP(n,l) char (n)[(l)] #define TYP(n,l) char (n)[(l)]
#endif /* TYP */ #endif /* TYP */
/* This is Apple internal naming for Universal Binaries
and is not 'Inclusive Terminology" !! */
#define FAT_MAGIC 0xcafebabe
#define FAT_CIGAM 0xbebafeca
#define FAT_MAGIC_64 0xcafebabf
#define FAT_CIGAM_64 0xbfbafeca
struct fat_header {
TYP(magic,4); /* FAT_MAGIC or FAT_MAGIC_64 */
TYP(nfat_arch,4); /* number of structs that follow */
};
struct fat_arch {
TYP(cputype ,4); /* cpu specifier (int) */
TYP(cpusubtype,4); /* machine specifier (int) */
TYP(offset,4); /* file offset to this object file */
TYP(size,4); /* size of this object file */
TYP(align,4); /* alignment as a power of 2 */
};
struct fat_arch_64 {
TYP(cputype,4); /* cpu specifier (int) */
TYP(cpusubtype,4); /* machine specifier (int) */
TYP(offset,8); /* file offset to this object file */
TYP(size,8); /* size of this object file */
TYP(align,4); /* alignment as a power of 2 */
TYP(reserved,4); /* reserved */
};
/* /*
* The 32-bit mach header appears at the very * The 32-bit mach header appears at the very
* beginning of the object file for * beginning of the object file for

View File

@ -75,6 +75,8 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <unistd.h> /* close() */ #include <unistd.h> /* close() */
#endif /* _WIN32 */ #endif /* _WIN32 */
#include <stdio.h> /* debugging printf */
#include "dwarf.h" #include "dwarf.h"
#include "libdwarf.h" #include "libdwarf.h"
#include "libdwarf_private.h" #include "libdwarf_private.h"
@ -85,10 +87,26 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dwarf_reading.h" #include "dwarf_reading.h"
#include "dwarf_memcpy_swap.h" #include "dwarf_memcpy_swap.h"
#include "dwarf_object_read_common.h" #include "dwarf_object_read_common.h"
#include "dwarf_universal.h"
#include "dwarf_machoread.h" #include "dwarf_machoread.h"
#include "dwarf_object_detector.h" #include "dwarf_object_detector.h"
#include "dwarf_macho_loader.h" #include "dwarf_macho_loader.h"
#if 0
static void
dump_bytes(const char *msg,Dwarf_Small * start, long len)
{
Dwarf_Small *end = start + len;
Dwarf_Small *cur = start;
printf("%s (0x%lx) ",msg,(unsigned long)start);
for (; cur < end; cur++) {
printf("%02x", *cur);
}
printf("\n");
}
#endif /*0*/
/* MACH-O and dwarf section names */ /* MACH-O and dwarf section names */
static struct macho_sect_names_s { static struct macho_sect_names_s {
char const *ms_moname; char const *ms_moname;
@ -111,12 +129,21 @@ static struct macho_sect_names_s {
}; };
static int static int
_dwarf_macho_object_access_init( _dwarf_object_detector_universal_head_fd(
int fd, int fd,
Dwarf_Unsigned dw_filesize,
unsigned int *dw_contentcount,
Dwarf_Universal_Head * dw_head,
int *errcode);
static int _dwarf_macho_object_access_init(
int fd,
unsigned uninumber,
unsigned ftype, unsigned ftype,
unsigned endian, unsigned endian,
unsigned offsetsize, unsigned offsetsize,
size_t filesize, unsigned * universalbinary_count,
Dwarf_Unsigned filesize,
Dwarf_Obj_Access_Interface_a **binary_interface, Dwarf_Obj_Access_Interface_a **binary_interface,
int *localerrnum); int *localerrnum);
@ -192,6 +219,7 @@ macho_load_section (void *obj, Dwarf_Unsigned section_index,
if (0 < section_index && if (0 < section_index &&
section_index < macho->mo_dwarf_sectioncount) { section_index < macho->mo_dwarf_sectioncount) {
int res = 0; int res = 0;
Dwarf_Unsigned inner = macho->mo_inner_offset;
struct generic_macho_section *sp = struct generic_macho_section *sp =
macho->mo_dwarf_sections + section_index; macho->mo_dwarf_sections + section_index;
@ -214,8 +242,9 @@ macho_load_section (void *obj, Dwarf_Unsigned section_index,
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(macho->mo_fd, res = RRMOA(macho->mo_fd,
sp->loaded_data, (off_t)sp->offset, sp->loaded_data, (off_t)(inner+sp->offset),
(size_t)sp->size, (off_t)macho->mo_filesize, error); (size_t)sp->size,
(off_t)(inner+macho->mo_filesize), error);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
free(sp->loaded_data); free(sp->loaded_data);
sp->loaded_data = 0; sp->loaded_data = 0;
@ -276,13 +305,14 @@ load_macho_header32(dwarf_macho_object_access_internals_t *mfp,
{ {
struct mach_header mh32; struct mach_header mh32;
int res = 0; int res = 0;
Dwarf_Unsigned inner = mfp->mo_inner_offset;
if (sizeof(mh32) > mfp->mo_filesize) { if (sizeof(mh32) > mfp->mo_filesize) {
*errcode = DW_DLE_FILE_TOO_SMALL; *errcode = DW_DLE_FILE_TOO_SMALL;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd, &mh32, 0, sizeof(mh32), res = RRMOA(mfp->mo_fd, &mh32, inner, sizeof(mh32),
(off_t)mfp->mo_filesize, errcode); (off_t)(inner+mfp->mo_filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -316,13 +346,14 @@ load_macho_header64(dwarf_macho_object_access_internals_t *mfp,
{ {
struct mach_header_64 mh64; struct mach_header_64 mh64;
int res = 0; int res = 0;
Dwarf_Unsigned inner = mfp->mo_inner_offset;
if (sizeof(mh64) > mfp->mo_filesize) { if (sizeof(mh64) > mfp->mo_filesize) {
*errcode = DW_DLE_FILE_TOO_SMALL; *errcode = DW_DLE_FILE_TOO_SMALL;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd, &mh64, 0, sizeof(mh64), res = RRMOA(mfp->mo_fd, &mh64, inner, sizeof(mh64),
(off_t)mfp->mo_filesize, errcode); (off_t)(inner+mfp->mo_filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -378,15 +409,16 @@ load_segment_command_content32(
Dwarf_Unsigned filesize = mfp->mo_filesize; Dwarf_Unsigned filesize = mfp->mo_filesize;
Dwarf_Unsigned segoffset = mmp->offset_this_command; Dwarf_Unsigned segoffset = mmp->offset_this_command;
Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc);
Dwarf_Unsigned inner = mfp->mo_inner_offset;
if (mmp->offset_this_command > filesize || if (segoffset > filesize ||
mmp->cmdsize > filesize || mmp->cmdsize > filesize ||
(mmp->cmdsize + mmp->offset_this_command) > filesize ) { (mmp->cmdsize + segoffset) > filesize ) {
*errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd, &sc, (off_t)mmp->offset_this_command, res = RRMOA(mfp->mo_fd, &sc, (off_t)(inner+segoffset),
sizeof(sc), (off_t)filesize, errcode); sizeof(sc), (off_t)(inner+filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -432,6 +464,8 @@ load_segment_command_content32(
return DW_DLV_OK; return DW_DLV_OK;
} }
void fuck() {}
static int static int
load_segment_command_content64( load_segment_command_content64(
dwarf_macho_object_access_internals_t *mfp, dwarf_macho_object_access_internals_t *mfp,
@ -444,15 +478,17 @@ load_segment_command_content64(
Dwarf_Unsigned filesize = mfp->mo_filesize; Dwarf_Unsigned filesize = mfp->mo_filesize;
Dwarf_Unsigned segoffset = mmp->offset_this_command; Dwarf_Unsigned segoffset = mmp->offset_this_command;
Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc);
Dwarf_Unsigned inner = mfp->mo_inner_offset;
if (segoffset > filesize || if (segoffset > filesize ||
mmp->cmdsize > filesize || mmp->cmdsize > filesize ||
(mmp->cmdsize + segoffset) > filesize ) { (mmp->cmdsize + segoffset) > filesize ) {
*errcode = DW_DLE_MACHO_CORRUPT_COMMAND; *errcode = DW_DLE_MACHO_CORRUPT_COMMAND;
fuck();
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd,&sc,segoffset, res = RRMOA(mfp->mo_fd,&sc,inner+segoffset,
sizeof(sc), (off_t)filesize, errcode); sizeof(sc), (off_t)(inner+filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -468,11 +504,13 @@ load_segment_command_content64(
msp->filesize > filesize) { msp->filesize > filesize) {
/* corrupt */ /* corrupt */
*errcode = DW_DLE_MACHO_CORRUPT_COMMAND; *errcode = DW_DLE_MACHO_CORRUPT_COMMAND;
fuck();
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
if ((msp->fileoff+msp->filesize ) > filesize) { if ((msp->fileoff+msp->filesize ) > filesize) {
/* corrupt */ /* corrupt */
*errcode = DW_DLE_MACHO_CORRUPT_COMMAND; *errcode = DW_DLE_MACHO_CORRUPT_COMMAND;
fuck();
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot); ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot);
@ -489,9 +527,9 @@ load_segment_command_content64(
(unsigned long)mfp->mo_filesize); (unsigned long)mfp->mo_filesize);
#endif #endif
*errcode = DW_DLE_MACHO_CORRUPT_COMMAND; *errcode = DW_DLE_MACHO_CORRUPT_COMMAND;
fuck();
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
ASNAR(mfp->mo_copy_word,msp->flags,sc.flags); ASNAR(mfp->mo_copy_word,msp->flags,sc.flags);
msp->macho_command_index = mmpindex; msp->macho_command_index = mmpindex;
msp->sectionsoffset = afterseghdr; msp->sectionsoffset = afterseghdr;
@ -580,6 +618,7 @@ _dwarf_macho_load_dwarf_section_details32(
struct section mosec; struct section mosec;
int res = 0; int res = 0;
Dwarf_Unsigned endoffset = 0; Dwarf_Unsigned endoffset = 0;
Dwarf_Unsigned inner = mfp->mo_inner_offset;
endoffset = curoff + sizeof(mosec); endoffset = curoff + sizeof(mosec);
if (curoff >= mfp->mo_filesize || if (curoff >= mfp->mo_filesize ||
@ -596,8 +635,8 @@ _dwarf_macho_load_dwarf_section_details32(
*errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS; *errcode = DW_DLE_MACHO_CORRUPT_SECTIONDETAILS;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec), res = RRMOA(mfp->mo_fd, &mosec, (off_t)(inner+curoff), sizeof(mosec),
(off_t)mfp->mo_filesize, errcode); (off_t)(inner+mfp->mo_filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -667,8 +706,8 @@ _dwarf_macho_load_dwarf_section_details64(
for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) { for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) {
int res = 0; int res = 0;
struct section_64 mosec; struct section_64 mosec;
Dwarf_Unsigned endoffset = 0; Dwarf_Unsigned endoffset = 0;
Dwarf_Unsigned inner = mfp->mo_inner_offset;
endoffset = curoff + sizeof(mosec); endoffset = curoff + sizeof(mosec);
if (curoff >= mfp->mo_filesize || if (curoff >= mfp->mo_filesize ||
@ -686,8 +725,9 @@ _dwarf_macho_load_dwarf_section_details64(
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec), res = RRMOA(mfp->mo_fd, &mosec,
(off_t)mfp->mo_filesize, errcode); (off_t)(inner+curoff), sizeof(mosec),
(off_t)(inner+mfp->mo_filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -773,6 +813,7 @@ _dwarf_load_macho_commands(
struct generic_macho_command *mcp = 0; struct generic_macho_command *mcp = 0;
unsigned segment_command_count = 0; unsigned segment_command_count = 0;
int res = 0; int res = 0;
Dwarf_Unsigned inner = mfp->mo_inner_offset;
if (mfp->mo_command_count >= mfp->mo_filesize) { if (mfp->mo_command_count >= mfp->mo_filesize) {
/* corrupt object. */ /* corrupt object. */
@ -795,8 +836,9 @@ _dwarf_load_macho_commands(
} }
mcp = mfp->mo_commands; mcp = mfp->mo_commands;
for ( ; cmdi < mfp->mo_header.ncmds; ++cmdi,++mcp ) { for ( ; cmdi < mfp->mo_header.ncmds; ++cmdi,++mcp ) {
res = RRMOA(mfp->mo_fd, &mc, (off_t)curoff, sizeof(mc), res = RRMOA(mfp->mo_fd, &mc,
(off_t)mfp->mo_filesize, errcode); (off_t)(inner+curoff), sizeof(mc),
(off_t)(inner+mfp->mo_filesize), errcode);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
return res; return res;
} }
@ -825,10 +867,11 @@ _dwarf_load_macho_commands(
int int
_dwarf_macho_setup(int fd, _dwarf_macho_setup(int fd,
char *true_path, char *true_path,
unsigned universalnumber,
unsigned ftype, unsigned ftype,
unsigned endian, unsigned endian,
unsigned offsetsize, unsigned offsetsize,
size_t filesize, Dwarf_Unsigned filesize,
unsigned groupnumber, unsigned groupnumber,
Dwarf_Handler errhand, Dwarf_Handler errhand,
Dwarf_Ptr errarg, Dwarf_Ptr errarg,
@ -838,10 +881,14 @@ _dwarf_macho_setup(int fd,
dwarf_macho_object_access_internals_t *intfc = 0; dwarf_macho_object_access_internals_t *intfc = 0;
int res = DW_DLV_OK; int res = DW_DLV_OK;
int localerrnum = 0; int localerrnum = 0;
unsigned universalbinary_count = 0;
res = _dwarf_macho_object_access_init( res = _dwarf_macho_object_access_init(
fd, fd,
ftype,endian,offsetsize,filesize, universalnumber,
ftype,endian,offsetsize,
&universalbinary_count,
filesize,
&binary_interface, &binary_interface,
&localerrnum); &localerrnum);
if (res != DW_DLV_OK) { if (res != DW_DLV_OK) {
@ -861,6 +908,8 @@ _dwarf_macho_setup(int fd,
} }
intfc = binary_interface->ai_object; intfc = binary_interface->ai_object;
intfc->mo_path = strdup(true_path); intfc->mo_path = strdup(true_path);
(*dbg)->de_universalbinary_index = universalnumber;
(*dbg)->de_universalbinary_count = universalbinary_count;
return res; return res;
} }
@ -877,15 +926,86 @@ static Dwarf_Obj_Access_Methods_a const macho_methods = {
NULL NULL
}; };
/* Reads universal binary headers, gets to
the chosen inner binary, and returns the
values from the inner binary.
The filesize being that of the inner binary,
and the fileoffset being the offset of the inner
binary (so by definition > 0);
*/
static int
_dwarf_macho_inner_object_fd(int fd,
unsigned int uninumber,
Dwarf_Unsigned outer_filesize,
unsigned int *ftype,
unsigned int *unibinarycount,
unsigned int *endian,
unsigned int *offsetsize,
Dwarf_Unsigned *fileoffset,
Dwarf_Unsigned *filesize,
int *errcode)
{
int res = 0;
Dwarf_Universal_Head head = 0;
Dwarf_Unsigned innerbase = 0;
Dwarf_Unsigned innersize = 0;
res = _dwarf_object_detector_universal_head_fd(
fd, outer_filesize, unibinarycount,
&head, errcode);
if (res != DW_DLV_OK) {
return res;
}
if (uninumber >= *unibinarycount) {
*errcode = DW_DLE_UNIVERSAL_BINARY_ERROR;
_dwarf_dealloc_universal_head(head);
return DW_DLV_ERROR;
}
/* Now find the precise details of uninumber
instance we want */
innerbase = head->au_arches[uninumber].au_offset;
innersize = head->au_arches[uninumber].au_size;
if (innersize >= outer_filesize ||
innerbase >= outer_filesize) {
*errcode = DW_DLE_UNIVERSAL_BINARY_ERROR;
_dwarf_dealloc_universal_head(head);
return DW_DLV_ERROR;
}
/* Now access inner to return its specs */
{
/* But ignore the size this returns!
we determined that above. the following call
does not get the inner size, we got that
just above here! */
Dwarf_Unsigned fake_size = 0;
res = _dwarf_object_detector_fd_a(fd,
ftype,endian,offsetsize,innerbase,&fake_size,
errcode);
if (res != DW_DLV_OK) {
_dwarf_dealloc_universal_head(head);
return res;
}
}
*fileoffset = innerbase;
*filesize = innersize;
_dwarf_dealloc_universal_head(head);
return DW_DLV_OK;
}
/* On any error this frees internals argument. */ /* On any error this frees internals argument. */
static int static int
_dwarf_macho_object_access_internals_init( _dwarf_macho_object_access_internals_init(
dwarf_macho_object_access_internals_t * internals, dwarf_macho_object_access_internals_t * internals,
int fd, int fd,
unsigned uninumber,
unsigned ftype, unsigned ftype,
unsigned endian, unsigned endian,
unsigned offsetsize, unsigned offsetsize,
size_t filesize, unsigned *unibinarycount,
Dwarf_Unsigned filesize,
int *errcode) int *errcode)
{ {
dwarf_macho_object_access_internals_t * intfc = internals; dwarf_macho_object_access_internals_t * intfc = internals;
@ -893,6 +1013,12 @@ _dwarf_macho_object_access_internals_init(
struct generic_macho_section *sp = 0; struct generic_macho_section *sp = 0;
struct Dwarf_Obj_Access_Interface_a_s *localdoas; struct Dwarf_Obj_Access_Interface_a_s *localdoas;
int res = 0; int res = 0;
unsigned int ftypei = ftype;
unsigned int endiani = endian;
unsigned int offsetsizei = offsetsize;
Dwarf_Unsigned filesizei = filesize;
Dwarf_Unsigned fileoffseti = 0;
unsigned int unibinarycounti = 0;
/* Must malloc as _dwarf_destruct_macho_access() /* Must malloc as _dwarf_destruct_macho_access()
forces that due to other uses. */ forces that due to other uses. */
@ -903,15 +1029,34 @@ _dwarf_macho_object_access_internals_init(
*errcode = DW_DLE_ALLOC_FAIL; *errcode = DW_DLE_ALLOC_FAIL;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_a_s)); if (ftype == DW_FTYPE_APPLEUNIVERSAL) {
res = _dwarf_macho_inner_object_fd(fd,
uninumber,
filesize,
&ftypei,&unibinarycounti,&endiani,
&offsetsizei,&fileoffseti,&filesizei,errcode);
if (res != DW_DLV_OK) {
if (res == DW_DLV_ERROR) {
*errcode = DW_DLE_UNIVERSAL_BINARY_ERROR;
}
return res;
}
*unibinarycount = unibinarycounti;
endian = endiani;
}
memset(localdoas,0,
sizeof(struct Dwarf_Obj_Access_Interface_a_s));
intfc->mo_ident[0] = 'M'; intfc->mo_ident[0] = 'M';
intfc->mo_ident[1] = '1'; intfc->mo_ident[1] = '1';
intfc->mo_fd = fd; intfc->mo_fd = fd;
intfc->mo_is_64bit = ((offsetsize==64)?TRUE:FALSE); intfc->mo_offsetsize = offsetsizei;
intfc->mo_offsetsize = offsetsize; intfc->mo_pointersize = offsetsizei;
intfc->mo_pointersize = offsetsize; intfc->mo_inner_offset = fileoffseti;
intfc->mo_filesize = filesize; intfc->mo_filesize = filesizei;
intfc->mo_ftype = ftype; intfc->mo_ftype = ftypei;
intfc->mo_uninumber = uninumber;
intfc->mo_universal_count = unibinarycounti;
#ifdef WORDS_BIGENDIAN #ifdef WORDS_BIGENDIAN
if (endian == DW_END_little ) { if (endian == DW_END_little ) {
@ -974,10 +1119,12 @@ _dwarf_macho_object_access_internals_init(
static int static int
_dwarf_macho_object_access_init( _dwarf_macho_object_access_init(
int fd, int fd,
unsigned uninumber,
unsigned ftype, unsigned ftype,
unsigned endian, unsigned endian,
unsigned offsetsize, unsigned offsetsize,
size_t filesize, unsigned * universalbinary_count,
Dwarf_Unsigned filesize,
Dwarf_Obj_Access_Interface_a **binary_interface, Dwarf_Obj_Access_Interface_a **binary_interface,
int *localerrnum) int *localerrnum)
{ {
@ -986,7 +1133,8 @@ _dwarf_macho_object_access_init(
dwarf_macho_object_access_internals_t *internals = 0; dwarf_macho_object_access_internals_t *internals = 0;
Dwarf_Obj_Access_Interface_a *intfc = 0; Dwarf_Obj_Access_Interface_a *intfc = 0;
internals = malloc(sizeof(dwarf_macho_object_access_internals_t)); internals = malloc(
sizeof(dwarf_macho_object_access_internals_t));
if (!internals) { if (!internals) {
*localerrnum = DW_DLE_ALLOC_FAIL; *localerrnum = DW_DLE_ALLOC_FAIL;
/* Impossible case, we hope. Give up. */ /* Impossible case, we hope. Give up. */
@ -995,7 +1143,10 @@ _dwarf_macho_object_access_init(
memset(internals,0,sizeof(*internals)); memset(internals,0,sizeof(*internals));
res = _dwarf_macho_object_access_internals_init(internals, res = _dwarf_macho_object_access_internals_init(internals,
fd, fd,
ftype, endian, offsetsize, filesize, uninumber,
ftype, endian, offsetsize,
universalbinary_count,
filesize,
localerrnum); localerrnum);
if (res != DW_DLV_OK){ if (res != DW_DLV_OK){
/* *err is already set and the call freed internals. */ /* *err is already set and the call freed internals. */
@ -1015,3 +1166,267 @@ _dwarf_macho_object_access_init(
*binary_interface = intfc; *binary_interface = intfc;
return DW_DLV_OK; return DW_DLV_OK;
} }
static unsigned long
magic_copy(unsigned char *d, unsigned len)
{
unsigned i = 0;
unsigned long v = 0;
v = d[0];
for (i = 1 ; i < len; ++i) {
v <<= 8;
v |= d[i];
}
return v;
}
static int
fill_in_uni_arch_32(
struct fat_arch * fa,
struct Dwarf_Universal_Head_s *duhd,
void (*word_swap) (void *, const void *, size_t))
{
Dwarf_Unsigned i = 0;
struct Dwarf_Universal_Arch_s * dua = 0;
dua = duhd->au_arches;
for ( ; i < duhd->au_count; ++i,++fa,++dua) {
ASNAR(word_swap,dua->au_cputype,fa->cputype);
ASNAR(word_swap,dua->au_cpusubtype,fa->cpusubtype);
ASNAR(word_swap,dua->au_offset,fa->offset);
ASNAR(word_swap,dua->au_size,fa->size);
ASNAR(word_swap,dua->au_align,fa->align);
dua->au_reserved = 0;
}
return DW_DLV_OK;
}
static int
fill_in_uni_arch_64(
struct fat_arch_64 * fa,
struct Dwarf_Universal_Head_s *duhd,
void (*word_swap) (void *, const void *, size_t))
{
Dwarf_Unsigned i = 0;
struct Dwarf_Universal_Arch_s * dua = 0;
dua = duhd->au_arches;
for ( ; i < duhd->au_count; ++i,++fa,++dua) {
ASNAR(word_swap,dua->au_cputype,fa->cputype);
ASNAR(word_swap,dua->au_cpusubtype,fa->cpusubtype);
ASNAR(word_swap,dua->au_offset,fa->offset);
ASNAR(word_swap,dua->au_size,fa->size);
ASNAR(word_swap,dua->au_align,fa->align);
ASNAR(word_swap,dua->au_align,fa->align);
ASNAR(word_swap,dua->au_reserved,fa->reserved);
}
return DW_DLV_OK;
}
static const struct Dwarf_Universal_Head_s duhzero;
static const struct fat_header fhzero;
static int
_dwarf_object_detector_universal_head_fd(
int fd,
Dwarf_Unsigned dw_filesize,
unsigned int *dw_contentcount,
Dwarf_Universal_Head * dw_head,
int *errcode)
{
struct Dwarf_Universal_Head_s duhd;
struct Dwarf_Universal_Head_s *duhdp = 0;
struct fat_header fh;
int res = 0;
void (*word_swap) (void *, const void *, size_t);
int locendian = 0;
int locoffsetsize = 0;
duhd = duhzero;
fh = fhzero;
/* A universal head is always at offset zero. */
res = RRMOA(fd,&fh,0,sizeof(fh), dw_filesize,errcode);
if (res != DW_DLV_OK) {
printf("Reading struct for universal binary "
"header failed\n");
return res;
}
duhd.au_magic = magic_copy((unsigned char *)&fh.magic[0],4);
if (duhd.au_magic == FAT_MAGIC) {
locendian = DW_END_big;
locoffsetsize = 32;
} else if (duhd.au_magic == FAT_CIGAM) {
locendian = DW_END_little;
locoffsetsize = 32;
}else if (duhd.au_magic == FAT_MAGIC_64) {
locendian = DW_END_big;
locoffsetsize = 64;
} else if (duhd.au_magic == FAT_CIGAM_64) {
locendian = DW_END_little;
locoffsetsize = 64;
} else {
printf("Reading magic number universal compare failed " "Inconsistent\n");
*errcode = DW_DLE_FILE_WRONG_TYPE;
return DW_DLV_ERROR;
}
#ifdef WORDS_BIGENDIAN
if (locendian == DW_END_little) {
word_swap = _dwarf_memcpy_swap_bytes;
} else {
word_swap = _dwarf_memcpy_noswap_bytes;
}
#else /* LITTLE ENDIAN */
if (locendian == DW_END_little) {
word_swap = _dwarf_memcpy_noswap_bytes;
} else {
word_swap = _dwarf_memcpy_swap_bytes;
}
#endif /* LITTLE- BIG-ENDIAN */
ASNAR(word_swap,duhd.au_count,fh.nfat_arch);
/* The limit is a first-cut safe heuristic. */
if (duhd.au_count >= (dw_filesize/2) ) {
*errcode = DW_DLE_UNIVERSAL_BINARY_ERROR ;
return DW_DLV_ERROR;
}
duhd.au_arches = (struct Dwarf_Universal_Arch_s*)
calloc(duhd.au_count, sizeof(struct Dwarf_Universal_Arch_s));
if (!duhd.au_arches) {
*errcode = DW_DLE_ALLOC_FAIL;
return DW_DLV_ERROR;
}
if (locoffsetsize == 32) {
struct fat_arch * fa = 0;
fa = (struct fat_arch *)calloc(duhd.au_count,
sizeof(struct fat_arch));
if (!fa) {
*errcode = DW_DLE_ALLOC_FAIL;
free(duhd.au_arches);
duhd.au_arches = 0;
free(fa);
return res;
}
res = RRMOA(fd,fa,/*offset=*/sizeof(fh),
duhd.au_count*sizeof(*fa),
dw_filesize,errcode);
if (res != DW_DLV_OK) {
free(duhd.au_arches);
duhd.au_arches = 0;
free(fa);
return res;
}
res = fill_in_uni_arch_32(fa,&duhd,word_swap);
if (res != DW_DLV_OK) {
free(duhd.au_arches);
duhd.au_arches = 0;
free(fa);
return res;
}
free(fa);
fa = 0;
} else { /* 64 */
struct fat_arch_64 * fa = 0;
fa = (struct fat_arch_64 *)calloc(duhd.au_count,
sizeof(struct fat_arch));
if (!fa) {
*errcode = DW_DLE_ALLOC_FAIL;
free(duhd.au_arches);
duhd.au_arches = 0;
return res;
}
res = RRMOA(fd,fa,/*offset*/sizeof(fh),
duhd.au_count*sizeof(fa),
dw_filesize,errcode);
if (res == DW_DLV_ERROR) {
free(duhd.au_arches);
duhd.au_arches = 0;
free(fa);
return res;
}
res = fill_in_uni_arch_64(fa,&duhd,word_swap);
if (res != DW_DLV_OK) {
free(duhd.au_arches);
duhd.au_arches = 0;
return res;
}
free(fa);
fa = 0;
}
duhdp = malloc(sizeof(*duhdp));
if (!duhdp) {
free(duhd.au_arches);
duhd.au_arches = 0;
*errcode = DW_DLE_ALLOC_FAIL;
return res;
}
memcpy(duhdp,&duhd,sizeof(duhd));
*dw_contentcount = duhd.au_count;
duhdp->au_arches = duhd.au_arches;
*dw_head = duhdp;
return res;
}
#if 0
static void
print_arch_item(unsigned int i,
struct Dwarf_Universal_Arch_s* arch)
{
printf(" Universal Binary Index " LONGESTUFMT "\n",i);
printf(" cpu " LONGESTXFMT "\n",arch->au_cputype);
printf(" cpusubt " LONGESTXFMT "\n",arch->au_cpusubtype);
printf(" offset " LONGESTXFMT "\n",arch->au_offset);
printf(" size " LONGESTXFMT "\n",arch->au_size);
printf(" align " LONGESTXFMT "\n",arch->au_align);
}
#endif
int
_dwarf_object_detector_universal_instance(
Dwarf_Universal_Head dw_head,
Dwarf_Unsigned dw_index_of,
Dwarf_Unsigned *dw_cpu_type,
Dwarf_Unsigned *dw_cpusubtype,
Dwarf_Unsigned *dw_offset,
Dwarf_Unsigned *dw_size,
Dwarf_Unsigned *dw_align,
int *errcode)
{
struct Dwarf_Universal_Arch_s* arch = 0;
if (!dw_head) {
printf("Missing argument to "
"dwarf_object_detector_universal_instance");
*errcode = DW_DLE_UNIVERSAL_BINARY_ERROR;
return DW_DLV_ERROR;
}
if (dw_index_of >= dw_head->au_count){
printf("Requested index 0x%lu"
" to specific binary "
"is too larg: valid: 0 to 0x%lu\n",
(unsigned long)dw_index_of,
(unsigned long)dw_head->au_count);
return DW_DLV_NO_ENTRY;
}
arch = dw_head->au_arches +dw_index_of;
*dw_cpu_type = arch->au_cputype;
*dw_cpusubtype = arch->au_cpusubtype;
*dw_offset = arch->au_offset;
*dw_size = arch->au_size;
*dw_align = arch->au_align;
#if 0
print_arch_item(dw_index_of,arch);
#endif
return DW_DLV_OK;
}
void
_dwarf_dealloc_universal_head(Dwarf_Universal_Head dw_head)
{
if (!dw_head) {
return;
}
free(dw_head->au_arches);
dw_head->au_arches = 0;
free(dw_head);
}

View File

@ -33,6 +33,22 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef DWARF_MACHOREAD_H #ifndef DWARF_MACHOREAD_H
#define DWARF_MACHOREAD_H #define DWARF_MACHOREAD_H
struct Dwarf_Universal_Arch_s;
struct Dwarf_Universal_Head_s {
Dwarf_Unsigned au_magic;
Dwarf_Unsigned au_count;
struct Dwarf_Universal_Arch_s * au_arches;
};
struct Dwarf_Universal_Arch_s {
Dwarf_Unsigned au_cputype;
Dwarf_Unsigned au_cpusubtype;
Dwarf_Unsigned au_offset;
Dwarf_Unsigned au_size;
Dwarf_Unsigned au_align;
Dwarf_Unsigned au_reserved;
};
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif /* __cplusplus */ #endif /* __cplusplus */
@ -102,12 +118,14 @@ typedef struct dwarf_macho_filedata_s {
const char * mo_path; /* libdwarf must free.*/ const char * mo_path; /* libdwarf must free.*/
int mo_fd; int mo_fd;
int mo_destruct_close_fd; /*aka: lib owns fd */ int mo_destruct_close_fd; /*aka: lib owns fd */
int mo_is_64bit;
Dwarf_Unsigned mo_filesize; Dwarf_Unsigned mo_filesize;
Dwarf_Unsigned mo_inner_offset; /* for universal inner */
Dwarf_Small mo_offsetsize; /* 32 or 64 section data */ Dwarf_Small mo_offsetsize; /* 32 or 64 section data */
Dwarf_Small mo_pointersize; Dwarf_Small mo_pointersize;
int mo_ftype; int mo_ftype;
Dwarf_Small mo_endian; Dwarf_Small mo_endian;
unsigned mo_uninumber; /* for universal binary */
unsigned mo_universal_count; /* for universal binary*/
/*Dwarf_Small mo_machine; */ /*Dwarf_Small mo_machine; */
void (*mo_copy_word) (void *, const void *, unsigned long); void (*mo_copy_word) (void *, const void *, unsigned long);

View File

@ -56,6 +56,7 @@ EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "dwarf_memcpy_swap.h" #include "dwarf_memcpy_swap.h"
#include "dwarf_object_read_common.h" #include "dwarf_object_read_common.h"
#include "dwarf_object_detector.h" #include "dwarf_object_detector.h"
#include "dwarf_macho_loader.h"
#include "dwarf_string.h" #include "dwarf_string.h"
#ifndef O_BINARY #ifndef O_BINARY
@ -431,6 +432,39 @@ is_pe_object(int fd,
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
static int
is_mach_o_universal(struct elf_header *h,
unsigned *endian,
unsigned *offsetsize)
{
unsigned long magicval = 0;
unsigned locendian = 0;
unsigned locoffsetsize = 0;
/* No swapping here. Need to match size of
the universal-object magic field. */
magicval = magic_copy(h->e_ident,4);
if (magicval == FAT_MAGIC) {
locendian = DW_END_big;
locoffsetsize = 32;
} else if (magicval == FAT_CIGAM) {
locendian = DW_END_little;
locoffsetsize = 32;
}else if (magicval == FAT_MAGIC_64) {
locendian = DW_END_big;
locoffsetsize = 64;
} else if (magicval == FAT_CIGAM_64) {
locendian = DW_END_little;
locoffsetsize = 64;
} else {
return FALSE;
}
*endian = locendian;
*offsetsize = locoffsetsize;
return TRUE;
}
static int static int
is_mach_o_magic(struct elf_header *h, is_mach_o_magic(struct elf_header *h,
unsigned *endian, unsigned *endian,
@ -470,6 +504,25 @@ dwarf_object_detector_fd(int fd,
unsigned *offsetsize, unsigned *offsetsize,
Dwarf_Unsigned *filesize, Dwarf_Unsigned *filesize,
int *errcode) int *errcode)
{
Dwarf_Unsigned fileoffsetbase = 0;
int res = 0;
res = _dwarf_object_detector_fd_a(fd,
ftype,endian,offsetsize,
fileoffsetbase,filesize,
errcode);
return res;
}
int
_dwarf_object_detector_fd_a(int fd,
unsigned *ftype,
unsigned *endian,
unsigned *offsetsize,
Dwarf_Unsigned fileoffsetbase,
Dwarf_Unsigned *filesize,
int *errcode)
{ {
struct elf_header h; struct elf_header h;
size_t readlen = sizeof(h); size_t readlen = sizeof(h);
@ -477,6 +530,7 @@ dwarf_object_detector_fd(int fd,
off_t fsize = 0; off_t fsize = 0;
off_t lsval = 0; off_t lsval = 0;
ssize_t readval = 0; ssize_t readval = 0;
Dwarf_Unsigned remaininglen = 0;
fsize = lseek(fd,0L,SEEK_END); fsize = lseek(fd,0L,SEEK_END);
if (fsize < 0) { if (fsize < 0) {
@ -488,7 +542,19 @@ dwarf_object_detector_fd(int fd,
*errcode = DW_DLE_FILE_TOO_SMALL; *errcode = DW_DLE_FILE_TOO_SMALL;
return DW_DLV_ERROR; return DW_DLV_ERROR;
} }
lsval = lseek(fd,0L,SEEK_SET); remaininglen = fsize - fileoffsetbase;
if ((Dwarf_Unsigned)fsize <= fileoffsetbase) {
printf("FAIL: fsize <= offsetbase impossible\n");
*errcode = DW_DLE_SEEK_ERROR;
return DW_DLV_ERROR;
}
if (remaininglen <= readlen) {
/* Not a real object file */
*errcode = DW_DLE_FILE_TOO_SMALL;
return DW_DLV_ERROR;
}
lsval = lseek(fd,fileoffsetbase,SEEK_SET);
if (lsval < 0) { if (lsval < 0) {
*errcode = DW_DLE_SEEK_ERROR; *errcode = DW_DLE_SEEK_ERROR;
return DW_DLV_ERROR; return DW_DLV_ERROR;
@ -509,23 +575,28 @@ dwarf_object_detector_fd(int fd,
return res; return res;
} }
*ftype = DW_FTYPE_ELF; *ftype = DW_FTYPE_ELF;
*filesize = (size_t)fsize; *filesize = (Dwarf_Unsigned)fsize;
return DW_DLV_OK;
}
if (is_mach_o_universal(&h,endian,offsetsize)) {
*ftype = DW_FTYPE_APPLEUNIVERSAL;
*filesize = (Dwarf_Unsigned)fsize;
return DW_DLV_OK; return DW_DLV_OK;
} }
if (is_mach_o_magic(&h,endian,offsetsize)) { if (is_mach_o_magic(&h,endian,offsetsize)) {
*ftype = DW_FTYPE_MACH_O; *ftype = DW_FTYPE_MACH_O;
*filesize = (size_t)fsize; *filesize = (Dwarf_Unsigned)fsize;
return DW_DLV_OK; return DW_DLV_OK;
} }
if (is_archive_magic(&h)) { if (is_archive_magic(&h)) {
*ftype = DW_FTYPE_ARCHIVE; *ftype = DW_FTYPE_ARCHIVE;
*filesize = (size_t)fsize; *filesize = (Dwarf_Unsigned)fsize;
return DW_DLV_OK; return DW_DLV_OK;
} }
res = is_pe_object(fd,fsize,endian,offsetsize,errcode); res = is_pe_object(fd,fsize,endian,offsetsize,errcode);
if (res == DW_DLV_OK ) { if (res == DW_DLV_OK ) {
*ftype = DW_FTYPE_PE; *ftype = DW_FTYPE_PE;
*filesize = (size_t)fsize; *filesize = (Dwarf_Unsigned)fsize;
return DW_DLV_OK; return DW_DLV_OK;
} }
/* Unknown object format. */ /* Unknown object format. */

View File

@ -76,6 +76,15 @@ extern "C" {
*errcode when the function returns DW_DLV_ERROR) *errcode when the function returns DW_DLV_ERROR)
will hopefully suffice for most purposes. */ will hopefully suffice for most purposes. */
/* Added September 2023 for Mach-O universal binaries */
int _dwarf_object_detector_fd_a(int dw_fd,
unsigned int *dw_ftype,
unsigned int *dw_endian,
unsigned int *dw_offsetsize,
Dwarf_Unsigned dw_offset_base,
Dwarf_Unsigned *dw_filesize,
int *dw_errcode);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif /* __cplusplus */ #endif /* __cplusplus */

View File

@ -594,6 +594,7 @@ struct Dwarf_Debug_s {
under de_obj_file. */ under de_obj_file. */
int de_fd; int de_fd;
char de_owns_fd; char de_owns_fd;
char de_in_tdestroy; /* for de_alloc_tree DW202309-001 */
/* DW_PATHSOURCE_BASIC or MACOS or DEBUGLINK */ /* DW_PATHSOURCE_BASIC or MACOS or DEBUGLINK */
unsigned char de_path_source; unsigned char de_path_source;
/* de_path is only set automatically if dwarf_init_path() /* de_path is only set automatically if dwarf_init_path()
@ -753,6 +754,14 @@ struct Dwarf_Debug_s {
Dwarf_Unsigned de_frame_same_value_number; Dwarf_Unsigned de_frame_same_value_number;
Dwarf_Unsigned de_frame_undefined_value_number; Dwarf_Unsigned de_frame_undefined_value_number;
/* If count > 0 means the DW_FTYPE_APPLEUNIVERSAL
we initially read has this number of
binaries in it, and de_universalbinary_index
is the index of the current object inside
the universal binary. */
unsigned int de_universalbinary_count;
unsigned int de_universalbinary_index;
unsigned char de_big_endian_object; /* Non-zero if unsigned char de_big_endian_object; /* Non-zero if
object being read is big-endian. */ object being read is big-endian. */
@ -1010,10 +1019,11 @@ void _dwarf_destruct_elf_nlaccess(
extern int _dwarf_macho_setup(int fd, extern int _dwarf_macho_setup(int fd,
char *true_path, char *true_path,
unsigned universalnumber,
unsigned ftype, unsigned ftype,
unsigned endian, unsigned endian,
unsigned offsetsize, unsigned offsetsize,
size_t filesize, Dwarf_Unsigned filesize,
unsigned groupnumber, unsigned groupnumber,
Dwarf_Handler errhand, Dwarf_Handler errhand,
Dwarf_Ptr errarg, Dwarf_Ptr errarg,

View File

@ -2106,3 +2106,25 @@ int dwarf_cu_header_basics(Dwarf_Die die,
} }
return DW_DLV_OK; return DW_DLV_OK;
} }
int
dwarf_get_universalbinary_count(
Dwarf_Debug dbg,
Dwarf_Unsigned *current_index,
Dwarf_Unsigned *available_count)
{
if (!dbg) {
return DW_DLV_NO_ENTRY;
}
if (!dbg->de_universalbinary_count ) {
return DW_DLV_NO_ENTRY;
}
if (current_index) {
*current_index = dbg->de_universalbinary_index;
}
if (available_count) {
*available_count = dbg->de_universalbinary_count;
}
return DW_DLV_OK;
}

View File

@ -1274,6 +1274,9 @@ int
dwarf_rnglists_get_rle_head( dwarf_rnglists_get_rle_head(
Dwarf_Attribute attr, Dwarf_Attribute attr,
Dwarf_Half theform, Dwarf_Half theform,
/* attr_val is either an offset
(theform == DW_FORM_sec_offset)
or an index DW_FORM_rnglistx. */
Dwarf_Unsigned attr_val, Dwarf_Unsigned attr_val,
Dwarf_Rnglists_Head *head_out, Dwarf_Rnglists_Head *head_out,
Dwarf_Unsigned *entries_count_out, Dwarf_Unsigned *entries_count_out,

63
bundled/libdwarf/dwarf_universal.h vendored Normal file
View File

@ -0,0 +1,63 @@
/* Copyright (c) 2023, David Anderson
All rights reserved.
Redistribution and use in source and binary forms, with
or without modification, are permitted provided that the
following conditions are met:
Redistributions of source code must retain the above
copyright notice, this list of conditions and the following
disclaimer.
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 COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */
#ifndef DWARF_UNIVERSAL_H
#define DWARF_UNIVERSAL_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
struct Dwarf_Universal_Head_s;
typedef struct Dwarf_Universal_Head_s * Dwarf_Universal_Head;
int _dwarf_object_detector_universal_head(
char *dw_path,
Dwarf_Unsigned dw_filesize,
unsigned int *dw_contentcount,
Dwarf_Universal_Head * dw_head,
int *errcode);
int _dwarf_object_detector_universal_instance(
Dwarf_Universal_Head dw_head,
Dwarf_Unsigned dw_index_of,
Dwarf_Unsigned *dw_cpu_type,
Dwarf_Unsigned *dw_cpu_subtype,
Dwarf_Unsigned *dw_offset,
Dwarf_Unsigned *dw_size,
Dwarf_Unsigned *dw_align,
int *errcode);
void _dwarf_dealloc_universal_head(Dwarf_Universal_Head dw_head);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DWARF_UNIVERSAL_H */

View File

@ -99,10 +99,10 @@ extern "C" {
*/ */
/* Semantic Version identity for this libdwarf.h */ /* Semantic Version identity for this libdwarf.h */
#define DW_LIBDWARF_VERSION "0.8.0" #define DW_LIBDWARF_VERSION "0.8.1"
#define DW_LIBDWARF_VERSION_MAJOR 0 #define DW_LIBDWARF_VERSION_MAJOR 0
#define DW_LIBDWARF_VERSION_MINOR 8 #define DW_LIBDWARF_VERSION_MINOR 8
#define DW_LIBDWARF_VERSION_MICRO 0 #define DW_LIBDWARF_VERSION_MICRO 1
#define DW_PATHSOURCE_unspecified 0 #define DW_PATHSOURCE_unspecified 0
#define DW_PATHSOURCE_basic 1 #define DW_PATHSOURCE_basic 1
@ -115,6 +115,7 @@ extern "C" {
#define DW_FTYPE_MACH_O 2 /* MacOS. */ #define DW_FTYPE_MACH_O 2 /* MacOS. */
#define DW_FTYPE_PE 3 /* Windows */ #define DW_FTYPE_PE 3 /* Windows */
#define DW_FTYPE_ARCHIVE 4 /* unix archive */ #define DW_FTYPE_ARCHIVE 4 /* unix archive */
#define DW_FTYPE_APPLEUNIVERSAL 5
#endif /* DW_FTYPE_UNKNOWN */ #endif /* DW_FTYPE_UNKNOWN */
/* standard return values for functions */ /* standard return values for functions */
#define DW_DLV_NO_ENTRY -1 #define DW_DLV_NO_ENTRY -1
@ -1385,9 +1386,10 @@ typedef struct Dwarf_Rnglists_Head_s * Dwarf_Rnglists_Head;
#define DW_DLE_LINE_INDEX_WRONG 499 #define DW_DLE_LINE_INDEX_WRONG 499
#define DW_DLE_LINE_COUNT_WRONG 500 #define DW_DLE_LINE_COUNT_WRONG 500
#define DW_DLE_ARITHMETIC_OVERFLOW 501 #define DW_DLE_ARITHMETIC_OVERFLOW 501
#define DW_DLE_UNIVERSAL_BINARY_ERROR 502
/*! @note DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */ /*! @note DW_DLE_LAST MUST EQUAL LAST ERROR NUMBER */
#define DW_DLE_LAST 501 #define DW_DLE_LAST 502
#define DW_DLE_LO_USER 0x10000 #define DW_DLE_LO_USER 0x10000
/*! @} */ /*! @} */
@ -1403,6 +1405,10 @@ typedef struct Dwarf_Rnglists_Head_s * Dwarf_Rnglists_Head;
/*! @brief Initialization based on path, the most common /*! @brief Initialization based on path, the most common
initialization. initialization.
On a Mach-O universal binary this function can
only return information about the first (zero index)
object in the universal binary.
@param dw_path @param dw_path
Pass in the path to the object file to open. Pass in the path to the object file to open.
@param dw_true_path_out_buffer @param dw_true_path_out_buffer
@ -1448,6 +1454,8 @@ typedef struct Dwarf_Rnglists_Head_s * Dwarf_Rnglists_Head;
@see dwarf_init_path_dl dwarf_init_b @see dwarf_init_path_dl dwarf_init_b
@see exampleinit @see exampleinit
*/ */
DW_API int dwarf_init_path(const char * dw_path, DW_API int dwarf_init_path(const char * dw_path,
char * dw_true_path_out_buffer, char * dw_true_path_out_buffer,
unsigned int dw_true_path_bufferlen, unsigned int dw_true_path_bufferlen,
@ -1457,6 +1465,28 @@ DW_API int dwarf_init_path(const char * dw_path,
Dwarf_Debug* dw_dbg, Dwarf_Debug* dw_dbg,
Dwarf_Error* dw_error); Dwarf_Error* dw_error);
/*! @brief Initialization based on path
This identical to dwarf_init_path() except that it
adds a new argument, dw_universalnumber,
with which you can specify which object in
a Mach-O universal binary you wish to open.
It is always safe and appropriate to pass
zero as the dw_universalnumber.
Elf and PE and (non-universal) Mach-O object
files ignore the value of dw_universalnumber.
*/
DW_API int dwarf_init_path_a(const char * dw_path,
char * dw_true_path_out_buffer,
unsigned int dw_true_path_bufferlen,
unsigned int dw_groupnumber,
unsigned int dw_universalnumber,
Dwarf_Handler dw_errhand,
Dwarf_Ptr dw_errarg,
Dwarf_Debug* dw_dbg,
Dwarf_Error* dw_error);
/*! @brief Initialization following GNU debuglink section data. /*! @brief Initialization following GNU debuglink section data.
Sets the true-path with DWARF if there is Sets the true-path with DWARF if there is
@ -1525,6 +1555,35 @@ DW_API int dwarf_init_path_dl(const char * dw_path,
unsigned char * dw_dl_path_source, unsigned char * dw_dl_path_source,
Dwarf_Error* dw_error); Dwarf_Error* dw_error);
/*! @brief Initialization based on path with debuglink
This identical to dwarf_init_path_dl() except that it
adds a new argument, dw_universalnumber,
with which you can specify which object in
a Mach-O universal binary you wish to open.
It is always safe and appropriate to pass
zero as the dw_universalnumber.
Elf and PE and (non-universal) Mach-O object
files ignore the value of dw_universalnumber.
Mach-O objects do not contain or use debuglink
data.
*/
DW_API int dwarf_init_path_dl_a(const char * dw_path,
char * dw_true_path_out_buffer,
unsigned int dw_true_path_bufferlen,
unsigned int dw_groupnumber,
unsigned int dw_universalnumber,
Dwarf_Handler dw_errhand,
Dwarf_Ptr dw_errarg,
Dwarf_Debug* dw_dbg,
char ** dw_dl_path_array,
unsigned int dw_dl_path_array_size,
unsigned char * dw_dl_path_source,
Dwarf_Error* dw_error);
/*! @brief Initialization based on Unix/Linux (etc) path /*! @brief Initialization based on Unix/Linux (etc) path
This version allows specifying any number of debuglink This version allows specifying any number of debuglink
global paths to search on for debuglink targets. global paths to search on for debuglink targets.
@ -3964,7 +4023,8 @@ DW_API void dwarf_dealloc_ranges(Dwarf_Debug dw_dbg,
@param dw_attr @param dw_attr
The attribute referring to .debug_rnglists The attribute referring to .debug_rnglists
@param dw_theform @param dw_theform
The form number. The form number, DW_FORM_sec_offset or
DW_FORM_rnglistx.
@param dw_index_or_offset_value @param dw_index_or_offset_value
If the form is an index, pass it here. If the form is an index, pass it here.
If the form is an offset, pass that here. If the form is an offset, pass that here.
@ -5428,13 +5488,13 @@ DW_API int dwarf_get_fde_info_for_cfa_reg3_c(Dwarf_Fde dw_fde,
Dwarf_Bool * dw_has_more_rows, Dwarf_Bool * dw_has_more_rows,
Dwarf_Addr * dw_subsequent_pc, Dwarf_Addr * dw_subsequent_pc,
Dwarf_Error * dw_error); Dwarf_Error * dw_error);
/*! @brief Get the value of the CFA for a particular pc value(obsolete) /*! @brief Get the value of the CFA for a particular pc value
@see dwarf_get_fde_info_for_cfa_reg3_c @see dwarf_get_fde_info_for_cfa_reg3_c
This is the earlier version that returns a dw_offset
of Dwarf_Unsigned, requiring you to cast to Dwarf_Signed
to work with the value.
This is the earlier version that returns a dw_offset
of type Dwarf_Unsigned, requiring you to cast to Dwarf_Signed
to work with the value.
*/ */
DW_API int dwarf_get_fde_info_for_cfa_reg3_b(Dwarf_Fde dw_fde, DW_API int dwarf_get_fde_info_for_cfa_reg3_b(Dwarf_Fde dw_fde,
@ -8846,11 +8906,50 @@ DW_API Dwarf_Small dwarf_set_default_address_size(
Dwarf_Debug dw_dbg, Dwarf_Debug dw_dbg,
Dwarf_Small dw_value); Dwarf_Small dw_value);
/*! @brief Retrieve universal binary index
For Mach-O universal binaries this returns
relevant information.
For non-universal binaries (Mach-O, Elf,
or PE) the values are not meaningful, so
the function returns DW_DLV_NO_ENTRY..
@param dw_dbg
The Dwarf_Debug of interest.
@param dw_current_index
If dw_current_index is passed in non-null the function
returns the universal-binary index of the current
object (which came from a universal binary).
@param dw_available_count
If dw_current_index is passed in non-null the function
returns the count of binaries in
the universal binary.
@return
Returns DW_DLV_NO_ENTRY if the object file is
not from a Mach-O universal binary.
Returns DW_DLV_NO_ENTRY if dw_dbg is passed in NULL.
Never returns DW_DLV_ERROR.
*/
DW_API int dwarf_get_universalbinary_count(
Dwarf_Debug dw_dbg,
Dwarf_Unsigned *dw_current_index,
Dwarf_Unsigned *dw_available_count);
/*! @} /*! @}
*/ */
/*! @defgroup objectdetector Determine Object Type of a File /*! @defgroup objectdetector Determine Object Type of a File
@{ @{
This group of functions are unlikely to be called
by your code unless your code needs to know
the basic data about an object file without
actually opening a Dwarf_Debug.
These are crucial for libdwarf itself.
*/ */
DW_API int dwarf_object_detector_path_b(const char * dw_path, DW_API int dwarf_object_detector_path_b(const char * dw_path,
char *dw_outpath_buffer, char *dw_outpath_buffer,