1 /* 2 Copyright (c) 2019, David Anderson 3 All rights reserved. 4 cc 5 Redistribution and use in source and binary forms, with 6 or without modification, are permitted provided that the 7 following conditions are met: 8 9 Redistributions of source code must retain the above 10 copyright notice, this list of conditions and the following 11 disclaimer. 12 13 Redistributions in binary form must reproduce the above 14 copyright notice, this list of conditions and the following 15 disclaimer in the documentation and/or other materials 16 provided with the distribution. 17 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 19 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 20 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 29 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 30 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* This file reads the parts of an Apple mach-o object 34 file appropriate to reading DWARF debugging data. 35 Overview: 36 _dwarf_macho_setup() Does all macho setup. 37 calls _dwarf_macho_access_init() 38 calls _dwarf_macho_object_access_internals_init() 39 Creates internals record 'M', 40 dwarf_macho_object_access_internals_t 41 Sets flags/data in internals record 42 Loads macho object data needed later. 43 Sets methods struct to access macho object. 44 calls _dwarf_object_init_b() Creates Dwarf_Debug, independent 45 of any macho code. 46 Sets internals record into dbg. 47 ---------------------- 48 _dwarf_destruct_macho_access(). This frees 49 the macho internals record created in 50 _dwarf_macho_object_access_internals_init() 51 in case of errors during setup or when 52 dwarf_finish() is called. Works safely for 53 partially or fully set-up macho internals record. 54 55 Other than in _dwarf_macho_setup() the macho code 56 knows nothing about Dwarf_Debug, and the rest of 57 libdwarf knows nothing about the content of the 58 macho internals record. 59 60 */ 61 62 #ifdef _WIN32 63 #define _CRT_SECURE_NO_WARNINGS 64 #endif /* _WIN32 */ 65 66 #include "config.h" 67 #include <stdio.h> 68 #ifdef HAVE_STDLIB_H 69 #include <stdlib.h> 70 #endif /* HAVE_STDLIB_H */ 71 #ifdef HAVE_MALLOC_H 72 /* Useful include for some Windows compilers. */ 73 #include <malloc.h> 74 #endif /* HAVE_MALLOC_H */ 75 #include <string.h> 76 #include <sys/types.h> /* open() */ 77 #include <sys/stat.h> /* open() */ 78 #include <fcntl.h> /* open() */ 79 #include <time.h> 80 #ifdef HAVE_UNISTD_H 81 #include <unistd.h> /* lseek read close */ 82 #elif defined(_WIN32) && defined(_MSC_VER) 83 #include <io.h> 84 #endif /* HAVE_UNISTD_H */ 85 86 /* Windows specific header files */ 87 #if defined(_WIN32) && defined(HAVE_STDAFX_H) 88 #include "stdafx.h" 89 #endif /* HAVE_STDAFX_H */ 90 91 #include "libdwarf.h" 92 #include "libdwarfdefs.h" 93 #include "dwarf_base_types.h" 94 #include "dwarf_opaque.h" 95 #include "dwarf_error.h" /* for _dwarf_error() declaration */ 96 #include "dwarf_reading.h" 97 #include "memcpy_swap.h" 98 #include "dwarf_object_read_common.h" 99 #include "dwarf_machoread.h" 100 #include "dwarf_object_detector.h" 101 #include "dwarf_macho_loader.h" 102 103 #ifndef TYP 104 #define TYP(n,l) char n[l] 105 #endif /* TYPE */ 106 107 #ifdef WORDS_BIGENDIAN 108 #define ASNAR(func,t,s) \ 109 do { \ 110 unsigned tbyte = sizeof(t) - sizeof(s); \ 111 t = 0; \ 112 func(((char *)&t)+tbyte ,&s[0],sizeof(s)); \ 113 } while (0) 114 #else /* LITTLE ENDIAN */ 115 #define ASNAR(func,t,s) \ 116 do { \ 117 t = 0; \ 118 func(&t,&s[0],sizeof(s)); \ 119 } while (0) 120 #endif /* end LITTLE- BIG-ENDIAN */ 121 122 123 /* MACH-O and dwarf section names */ 124 static struct macho_sect_names_s { 125 char const *ms_moname; 126 char const *ms_dwname; 127 } const SectionNames [] = { 128 { "", "" }, /* ELF index-0 entry */ 129 { "__debug_abbrev", ".debug_abbrev" }, 130 { "__debug_aranges", ".debug_aranges" }, 131 { "__debug_frame", ".debug_frame" }, 132 { "__debug_info", ".debug_info" }, 133 { "__debug_line", ".debug_line" }, 134 { "__debug_macinfo", ".debug_macinfo" }, 135 { "__debug_loc", ".debug_loc" }, 136 { "__debug_pubnames", ".debug_pubnames" }, 137 { "__debug_pubtypes", ".debug_pubtypes" }, 138 { "__debug_str", ".debug_str" }, 139 { "__debug_ranges", ".debug_ranges" }, 140 { "__debug_macro", ".debug_macro" }, 141 { "__debug_gdb_scri", ".debug_gdb_scripts" } 142 }; 143 144 static int 145 _dwarf_macho_object_access_init( 146 int fd, 147 unsigned ftype, 148 unsigned endian, 149 unsigned offsetsize, 150 size_t filesize, 151 Dwarf_Unsigned access, 152 Dwarf_Obj_Access_Interface **binary_interface, 153 int *localerrnum); 154 155 156 static Dwarf_Endianness macho_get_byte_order (void *obj) 157 { 158 dwarf_macho_object_access_internals_t *macho = 159 (dwarf_macho_object_access_internals_t*)(obj); 160 return macho->mo_endian; 161 } 162 163 164 static Dwarf_Small macho_get_length_size (void *obj) 165 { 166 dwarf_macho_object_access_internals_t *macho = 167 (dwarf_macho_object_access_internals_t*)(obj); 168 return macho->mo_offsetsize/8; 169 } 170 171 172 static Dwarf_Small macho_get_pointer_size (void *obj) 173 { 174 dwarf_macho_object_access_internals_t *macho = 175 (dwarf_macho_object_access_internals_t*)(obj); 176 return macho->mo_pointersize/8; 177 } 178 179 180 static Dwarf_Unsigned macho_get_section_count (void *obj) 181 { 182 dwarf_macho_object_access_internals_t *macho = 183 (dwarf_macho_object_access_internals_t*)(obj); 184 return macho->mo_dwarf_sectioncount; 185 } 186 187 static int macho_get_section_info (void *obj, 188 Dwarf_Half section_index, 189 Dwarf_Obj_Access_Section *return_section, 190 UNUSEDARG int *error) 191 { 192 dwarf_macho_object_access_internals_t *macho = 193 (dwarf_macho_object_access_internals_t*)(obj); 194 195 196 if (section_index < macho->mo_dwarf_sectioncount) { 197 struct generic_macho_section *sp = 0; 198 199 sp = macho->mo_dwarf_sections + section_index; 200 return_section->addr = 0; 201 return_section->type = 0; 202 return_section->size = sp->size; 203 return_section->name = sp->dwarfsectname; 204 return_section->link = 0; 205 return_section->info = 0; 206 return_section->entrysize = 0; 207 return DW_DLV_OK; 208 } 209 return DW_DLV_NO_ENTRY; 210 } 211 212 static int 213 macho_load_section (void *obj, Dwarf_Half section_index, 214 Dwarf_Small **return_data, int *error) 215 { 216 dwarf_macho_object_access_internals_t *macho = 217 (dwarf_macho_object_access_internals_t*)(obj); 218 219 if (0 < section_index && 220 section_index < macho->mo_dwarf_sectioncount) { 221 int res = 0; 222 223 struct generic_macho_section *sp = 224 macho->mo_dwarf_sections + section_index; 225 if(sp->loaded_data) { 226 *return_data = sp->loaded_data; 227 return DW_DLV_OK; 228 } 229 if (!sp->size) { 230 return DW_DLV_NO_ENTRY; 231 } 232 if ((sp->size + sp->offset) > 233 macho->mo_filesize) { 234 *error = DW_DLE_FILE_TOO_SMALL; 235 return DW_DLV_ERROR; 236 } 237 238 sp->loaded_data = malloc((size_t)sp->size); 239 if (!sp->loaded_data) { 240 *error = DW_DLE_ALLOC_FAIL; 241 return DW_DLV_ERROR; 242 } 243 res = RRMOA(macho->mo_fd, 244 sp->loaded_data, (off_t)sp->offset, 245 (size_t)sp->size, (off_t)macho->mo_filesize, error); 246 if (res != DW_DLV_OK) { 247 free(sp->loaded_data); 248 sp->loaded_data = 0; 249 return res; 250 } 251 *return_data = sp->loaded_data; 252 return DW_DLV_OK; 253 } 254 return DW_DLV_NO_ENTRY; 255 } 256 257 void 258 _dwarf_destruct_macho_access( 259 struct Dwarf_Obj_Access_Interface_s *aip) 260 { 261 dwarf_macho_object_access_internals_t *mp = 0; 262 Dwarf_Unsigned i = 0; 263 264 if(!aip) { 265 return; 266 } 267 mp = (dwarf_macho_object_access_internals_t *)aip->object; 268 if (mp->mo_destruct_close_fd) { 269 close(mp->mo_fd); 270 mp->mo_fd = -1; 271 } 272 if (mp->mo_commands){ 273 free(mp->mo_commands); 274 mp->mo_commands = 0; 275 } 276 if (mp->mo_segment_commands){ 277 free(mp->mo_segment_commands); 278 mp->mo_segment_commands = 0; 279 } 280 free((char *)mp->mo_path); 281 if (mp->mo_dwarf_sections) { 282 struct generic_macho_section *sp = 0; 283 284 sp = mp->mo_dwarf_sections; 285 for( i=0; i < mp->mo_dwarf_sectioncount; ++i,++sp) { 286 if (sp->loaded_data) { 287 free(sp->loaded_data); 288 sp->loaded_data = 0; 289 } 290 } 291 free(mp->mo_dwarf_sections); 292 mp->mo_dwarf_sections = 0; 293 } 294 free(mp); 295 free(aip); 296 return; 297 } 298 299 /* load_macho_header32(dwarf_macho_object_access_internals_t *mfp)*/ 300 static int 301 load_macho_header32(dwarf_macho_object_access_internals_t *mfp, int *errcode) 302 { 303 struct mach_header mh32; 304 int res = 0; 305 306 if (sizeof(mh32) > mfp->mo_filesize) { 307 *errcode = DW_DLE_FILE_TOO_SMALL; 308 return DW_DLV_ERROR; 309 } 310 res = RRMOA(mfp->mo_fd, &mh32, 0, sizeof(mh32), 311 (off_t)mfp->mo_filesize, errcode); 312 if (res != DW_DLV_OK) { 313 return res; 314 } 315 /* Do not adjust endianness of magic, leave as-is. */ 316 ASNAR(memcpy,mfp->mo_header.magic,mh32.magic); 317 ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh32.cputype); 318 ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype,mh32.cpusubtype); 319 ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh32.filetype); 320 ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh32.ncmds); 321 ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds,mh32.sizeofcmds); 322 ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh32.flags); 323 mfp->mo_header.reserved = 0; 324 mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds; 325 mfp->mo_command_start_offset = sizeof(mh32); 326 return DW_DLV_OK; 327 } 328 329 /* load_macho_header64(dwarf_macho_object_access_internals_t *mfp) */ 330 static int 331 load_macho_header64(dwarf_macho_object_access_internals_t *mfp, 332 int *errcode) 333 { 334 struct mach_header_64 mh64; 335 int res = 0; 336 337 if (sizeof(mh64) > mfp->mo_filesize) { 338 *errcode = DW_DLE_FILE_TOO_SMALL; 339 return DW_DLV_ERROR; 340 } 341 res = RRMOA(mfp->mo_fd, &mh64, 0, sizeof(mh64), 342 (off_t)mfp->mo_filesize, errcode); 343 if (res != DW_DLV_OK) { 344 return res; 345 } 346 /* Do not adjust endianness of magic, leave as-is. */ 347 ASNAR(memcpy,mfp->mo_header.magic,mh64.magic); 348 ASNAR(mfp->mo_copy_word,mfp->mo_header.cputype,mh64.cputype); 349 ASNAR(mfp->mo_copy_word,mfp->mo_header.cpusubtype,mh64.cpusubtype); 350 ASNAR(mfp->mo_copy_word,mfp->mo_header.filetype,mh64.filetype); 351 ASNAR(mfp->mo_copy_word,mfp->mo_header.ncmds,mh64.ncmds); 352 ASNAR(mfp->mo_copy_word,mfp->mo_header.sizeofcmds,mh64.sizeofcmds); 353 ASNAR(mfp->mo_copy_word,mfp->mo_header.flags,mh64.flags); 354 ASNAR(mfp->mo_copy_word,mfp->mo_header.reserved,mh64.reserved); 355 mfp->mo_command_count = (unsigned int)mfp->mo_header.ncmds; 356 mfp->mo_command_start_offset = sizeof(mh64); 357 return DW_DLV_OK; 358 } 359 360 int 361 dwarf_load_macho_header(dwarf_macho_object_access_internals_t *mfp, 362 int *errcode) 363 { 364 int res = 0; 365 366 if (mfp->mo_offsetsize == 32) { 367 res = load_macho_header32(mfp,errcode); 368 } else if (mfp->mo_offsetsize == 64) { 369 res = load_macho_header64(mfp,errcode); 370 } else { 371 *errcode = DW_DLE_OFFSET_SIZE; 372 return DW_DLV_ERROR; 373 } 374 return res; 375 } 376 377 378 static int 379 load_segment_command_content32( 380 dwarf_macho_object_access_internals_t *mfp, 381 struct generic_macho_command *mmp, 382 struct generic_macho_segment_command *msp, 383 Dwarf_Unsigned mmpindex, 384 int *errcode) 385 { 386 struct segment_command sc; 387 int res = 0; 388 Dwarf_Unsigned filesize = mfp->mo_filesize; 389 Dwarf_Unsigned segoffset = mmp->offset_this_command; 390 Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); 391 392 if (mmp->offset_this_command > filesize || 393 mmp->cmdsize > filesize || 394 (mmp->cmdsize + mmp->offset_this_command) > filesize ) { 395 *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; 396 return DW_DLV_ERROR; 397 } 398 res = RRMOA(mfp->mo_fd, &sc, (off_t)mmp->offset_this_command, sizeof(sc), 399 (off_t)filesize, errcode); 400 if (res != DW_DLV_OK) { 401 return res; 402 } 403 ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd); 404 ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize); 405 strncpy(msp->segname,sc.segname,16); 406 msp->segname[15] =0; 407 ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr); 408 ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize); 409 ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff); 410 ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize); 411 if (msp->fileoff > mfp->mo_filesize || 412 msp->filesize > mfp->mo_filesize) { 413 /* corrupt */ 414 *errcode = DW_DLE_FILE_OFFSET_BAD; 415 return DW_DLV_ERROR; 416 } 417 if ((msp->fileoff+msp->filesize ) > filesize) { 418 /* corrupt */ 419 *errcode = DW_DLE_FILE_OFFSET_BAD; 420 return DW_DLV_ERROR; 421 } 422 ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot); 423 ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot); 424 ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects); 425 ASNAR(mfp->mo_copy_word,msp->flags,sc.flags); 426 msp->macho_command_index = mmpindex; 427 msp->sectionsoffset = afterseghdr; 428 return DW_DLV_OK; 429 } 430 static int 431 load_segment_command_content64( 432 dwarf_macho_object_access_internals_t *mfp, 433 struct generic_macho_command *mmp, 434 struct generic_macho_segment_command *msp, 435 Dwarf_Unsigned mmpindex,int *errcode) 436 { 437 struct segment_command_64 sc; 438 int res = 0; 439 Dwarf_Unsigned filesize = mfp->mo_filesize; 440 Dwarf_Unsigned segoffset = mmp->offset_this_command; 441 Dwarf_Unsigned afterseghdr = segoffset + sizeof(sc); 442 443 if (mmp->offset_this_command > filesize || 444 mmp->cmdsize > filesize || 445 (mmp->cmdsize + mmp->offset_this_command) > filesize ) { 446 *errcode = DW_DLE_FILE_OFFSET_BAD; 447 return DW_DLV_ERROR; 448 } 449 res = RRMOA(mfp->mo_fd, &sc, (off_t)mmp->offset_this_command, sizeof(sc), 450 (off_t)filesize, errcode); 451 if (res != DW_DLV_OK) { 452 return res; 453 } 454 ASNAR(mfp->mo_copy_word,msp->cmd,sc.cmd); 455 ASNAR(mfp->mo_copy_word,msp->cmdsize,sc.cmdsize); 456 strncpy(msp->segname,sc.segname,16); 457 msp->segname[16] =0; 458 ASNAR(mfp->mo_copy_word,msp->vmaddr,sc.vmaddr); 459 ASNAR(mfp->mo_copy_word,msp->vmsize,sc.vmsize); 460 ASNAR(mfp->mo_copy_word,msp->fileoff,sc.fileoff); 461 ASNAR(mfp->mo_copy_word,msp->filesize,sc.filesize); 462 if (msp->fileoff > filesize || 463 msp->filesize > filesize) { 464 /* corrupt */ 465 *errcode = DW_DLE_FILE_OFFSET_BAD; 466 return DW_DLV_ERROR; 467 } 468 if ((msp->fileoff+msp->filesize ) > filesize) { 469 /* corrupt */ 470 *errcode = DW_DLE_FILE_OFFSET_BAD; 471 return DW_DLV_ERROR; 472 } 473 ASNAR(mfp->mo_copy_word,msp->maxprot,sc.maxprot); 474 ASNAR(mfp->mo_copy_word,msp->initprot,sc.initprot); 475 ASNAR(mfp->mo_copy_word,msp->nsects,sc.nsects); 476 ASNAR(mfp->mo_copy_word,msp->flags,sc.flags); 477 msp->macho_command_index = mmpindex; 478 msp->sectionsoffset = afterseghdr; 479 return DW_DLV_OK; 480 } 481 482 static int 483 dwarf_macho_load_segment_commands( 484 dwarf_macho_object_access_internals_t *mfp,int *errcode) 485 { 486 Dwarf_Unsigned i = 0; 487 struct generic_macho_command *mmp = 0; 488 struct generic_macho_segment_command *msp = 0; 489 490 if (mfp->mo_segment_count < 1) { 491 return DW_DLV_OK; 492 } 493 mfp->mo_segment_commands = 494 (struct generic_macho_segment_command *) 495 calloc(sizeof(struct generic_macho_segment_command), 496 (size_t)mfp->mo_segment_count); 497 if (!mfp->mo_segment_commands) { 498 *errcode = DW_DLE_ALLOC_FAIL; 499 return DW_DLV_ERROR; 500 } 501 502 mmp = mfp->mo_commands; 503 msp = mfp->mo_segment_commands; 504 for (i = 0 ; i < mfp->mo_command_count; ++i,++mmp) { 505 unsigned cmd = (unsigned)mmp->cmd; 506 int res = 0; 507 508 if (cmd == LC_SEGMENT) { 509 res = load_segment_command_content32(mfp,mmp,msp,i,errcode); 510 ++msp; 511 } else if (cmd == LC_SEGMENT_64) { 512 res = load_segment_command_content64(mfp,mmp,msp,i,errcode); 513 ++msp; 514 } 515 if (res != DW_DLV_OK) { 516 return res; 517 } 518 } 519 return DW_DLV_OK; 520 } 521 522 static int 523 dwarf_macho_load_dwarf_section_details32( 524 dwarf_macho_object_access_internals_t *mfp, 525 struct generic_macho_segment_command *segp, 526 Dwarf_Unsigned segi, int *errcode) 527 { 528 Dwarf_Unsigned seci = 0; 529 Dwarf_Unsigned seccount = segp->nsects; 530 Dwarf_Unsigned secalloc = seccount+1; 531 Dwarf_Unsigned curoff = segp->sectionsoffset; 532 Dwarf_Unsigned shdrlen = sizeof(struct section); 533 534 struct generic_macho_section *secs = 0; 535 536 secs = (struct generic_macho_section *)calloc( 537 sizeof(struct generic_macho_section), 538 (size_t)secalloc); 539 if (!secs) { 540 *errcode = DW_DLE_ALLOC_FAIL; 541 return DW_DLV_OK; 542 } 543 mfp->mo_dwarf_sections = secs; 544 mfp->mo_dwarf_sectioncount = secalloc; 545 if ((curoff > mfp->mo_filesize) || 546 (seccount > mfp->mo_filesize) || 547 (curoff+(seccount*sizeof(struct section)) > 548 mfp->mo_filesize)) { 549 *errcode = DW_DLE_FILE_TOO_SMALL; 550 return DW_DLV_ERROR; 551 } 552 secs->offset_of_sec_rec = curoff; 553 /* Leave 0 section all zeros except our offset, 554 elf-like in a sense */ 555 secs->dwarfsectname = ""; 556 ++secs; 557 seci = 1; 558 for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) { 559 struct section mosec; 560 int res = 0; 561 562 res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec), 563 (off_t)mfp->mo_filesize, errcode); 564 if (res != DW_DLV_OK) { 565 return res; 566 } 567 strncpy(secs->sectname,mosec.sectname,16); 568 secs->sectname[16] = 0; 569 strncpy(secs->segname,mosec.segname,16); 570 secs->segname[16] = 0; 571 ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr); 572 ASNAR(mfp->mo_copy_word,secs->size,mosec.size); 573 ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset); 574 ASNAR(mfp->mo_copy_word,secs->align,mosec.align); 575 ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff); 576 ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc); 577 ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags); 578 if (secs->offset > mfp->mo_filesize || 579 secs->size > mfp->mo_filesize || 580 (secs->offset+secs->size) > mfp->mo_filesize) { 581 *errcode = DW_DLE_FILE_OFFSET_BAD; 582 return DW_DLV_ERROR; 583 } 584 secs->reserved1 = 0; 585 secs->reserved2 = 0; 586 secs->reserved3 = 0; 587 secs->generic_segment_num = segi; 588 secs->offset_of_sec_rec = curoff; 589 } 590 return DW_DLV_OK; 591 } 592 static int 593 dwarf_macho_load_dwarf_section_details64( 594 dwarf_macho_object_access_internals_t *mfp, 595 struct generic_macho_segment_command *segp, 596 Dwarf_Unsigned segi, 597 int *errcode) 598 { 599 Dwarf_Unsigned seci = 0; 600 Dwarf_Unsigned seccount = segp->nsects; 601 Dwarf_Unsigned secalloc = seccount+1; 602 Dwarf_Unsigned curoff = segp->sectionsoffset; 603 Dwarf_Unsigned shdrlen = sizeof(struct section_64); 604 struct generic_macho_section *secs = 0; 605 606 secs = (struct generic_macho_section *)calloc( 607 sizeof(struct generic_macho_section), 608 (size_t)secalloc); 609 if (!secs) { 610 *errcode = DW_DLE_ALLOC_FAIL; 611 return DW_DLV_ERROR; 612 } 613 mfp->mo_dwarf_sections = secs; 614 mfp->mo_dwarf_sectioncount = secalloc; 615 secs->offset_of_sec_rec = curoff; 616 /* Leave 0 section all zeros except our offset, 617 elf-like in a sense */ 618 secs->dwarfsectname = ""; 619 ++secs; 620 if ((curoff > mfp->mo_filesize) || 621 (seccount > mfp->mo_filesize) || 622 (curoff+(seccount*sizeof(struct section_64)) > 623 mfp->mo_filesize)) { 624 *errcode = DW_DLE_FILE_TOO_SMALL; 625 return DW_DLV_ERROR; 626 } 627 seci = 1; 628 for (; seci < secalloc; ++seci,++secs,curoff += shdrlen ) { 629 int res = 0; 630 struct section_64 mosec; 631 632 res = RRMOA(mfp->mo_fd, &mosec, (off_t)curoff, sizeof(mosec), 633 (off_t)mfp->mo_filesize, errcode); 634 if (res != DW_DLV_OK) { 635 return res; 636 } 637 strncpy(secs->sectname,mosec.sectname,16); 638 secs->sectname[16] = 0; 639 strncpy(secs->segname,mosec.segname,16); 640 secs->segname[16] = 0; 641 ASNAR(mfp->mo_copy_word,secs->addr,mosec.addr); 642 ASNAR(mfp->mo_copy_word,secs->size,mosec.size); 643 ASNAR(mfp->mo_copy_word,secs->offset,mosec.offset); 644 ASNAR(mfp->mo_copy_word,secs->align,mosec.align); 645 ASNAR(mfp->mo_copy_word,secs->reloff,mosec.reloff); 646 ASNAR(mfp->mo_copy_word,secs->nreloc,mosec.nreloc); 647 ASNAR(mfp->mo_copy_word,secs->flags,mosec.flags); 648 if (secs->offset > mfp->mo_filesize || 649 secs->size > mfp->mo_filesize || 650 (secs->offset+secs->size) > mfp->mo_filesize) { 651 *errcode = DW_DLE_FILE_OFFSET_BAD; 652 return DW_DLV_OK; 653 } 654 secs->reserved1 = 0; 655 secs->reserved2 = 0; 656 secs->reserved3 = 0; 657 secs->offset_of_sec_rec = curoff; 658 secs->generic_segment_num = segi; 659 } 660 return DW_DLV_OK; 661 } 662 663 static int 664 dwarf_macho_load_dwarf_section_details( 665 dwarf_macho_object_access_internals_t *mfp, 666 struct generic_macho_segment_command *segp, 667 Dwarf_Unsigned segi,int *errcode) 668 { 669 int res = 0; 670 671 if (mfp->mo_offsetsize == 32) { 672 res = dwarf_macho_load_dwarf_section_details32(mfp, 673 segp,segi,errcode); 674 } else if (mfp->mo_offsetsize == 64) { 675 res = dwarf_macho_load_dwarf_section_details64(mfp, 676 segp,segi,errcode); 677 } else { 678 *errcode = DW_DLE_OFFSET_SIZE; 679 return DW_DLV_ERROR; 680 } 681 return res; 682 } 683 684 static int 685 dwarf_macho_load_dwarf_sections( 686 dwarf_macho_object_access_internals_t *mfp,int *errcode) 687 { 688 Dwarf_Unsigned segi = 0; 689 690 struct generic_macho_segment_command *segp = 691 mfp->mo_segment_commands; 692 for ( ; segi < mfp->mo_segment_count; ++segi,++segp) { 693 int res = 0; 694 695 if (strcmp(segp->segname,"__DWARF")) { 696 continue; 697 } 698 /* Found DWARF, for now assume only one such. */ 699 res = dwarf_macho_load_dwarf_section_details(mfp,segp,segi,errcode); 700 return res; 701 } 702 return DW_DLV_OK; 703 } 704 705 /* Works the same, 32 or 64 bit */ 706 int 707 dwarf_load_macho_commands( 708 dwarf_macho_object_access_internals_t *mfp,int *errcode) 709 { 710 Dwarf_Unsigned cmdi = 0; 711 Dwarf_Unsigned curoff = mfp->mo_command_start_offset; 712 Dwarf_Unsigned cmdspace = 0; 713 struct load_command mc; 714 struct generic_macho_command *mcp = 0; 715 unsigned segment_command_count = 0; 716 int res = 0; 717 718 if (mfp->mo_command_count >= mfp->mo_filesize) { 719 /* corrupt object. */ 720 *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; 721 return DW_DLV_ERROR; 722 } 723 if ((curoff + mfp->mo_command_count * sizeof(mc)) >= 724 mfp->mo_filesize) { 725 /* corrupt object. */ 726 *errcode = DW_DLE_MACH_O_SEGOFFSET_BAD; 727 return DW_DLV_ERROR; 728 } 729 730 mfp->mo_commands = (struct generic_macho_command *) calloc( 731 mfp->mo_command_count,sizeof(struct generic_macho_command)); 732 if( !mfp->mo_commands) { 733 /* out of memory */ 734 *errcode = DW_DLE_ALLOC_FAIL; 735 return DW_DLV_ERROR; 736 } 737 mcp = mfp->mo_commands; 738 for ( ; cmdi < mfp->mo_header.ncmds; ++cmdi,++mcp ) { 739 res = RRMOA(mfp->mo_fd, &mc, (off_t)curoff, sizeof(mc), 740 (off_t)mfp->mo_filesize, errcode); 741 if (res != DW_DLV_OK) { 742 return res; 743 } 744 ASNAR(mfp->mo_copy_word,mcp->cmd,mc.cmd); 745 ASNAR(mfp->mo_copy_word,mcp->cmdsize,mc.cmdsize); 746 mcp->offset_this_command = curoff; 747 curoff += mcp->cmdsize; 748 cmdspace += mcp->cmdsize; 749 if (mcp->cmdsize > mfp->mo_filesize || 750 curoff > mfp->mo_filesize) { 751 /* corrupt object */ 752 *errcode = DW_DLE_FILE_OFFSET_BAD; 753 return DW_DLV_ERROR; 754 } 755 if (mcp->cmd == LC_SEGMENT || mcp->cmd == LC_SEGMENT_64) { 756 segment_command_count++; 757 } 758 } 759 mfp->mo_segment_count = segment_command_count; 760 res = dwarf_macho_load_segment_commands(mfp,errcode); 761 if (res != DW_DLV_OK) { 762 return res; 763 } 764 res = dwarf_macho_load_dwarf_sections(mfp,errcode); 765 return res; 766 } 767 int 768 _dwarf_macho_setup(int fd, 769 char *true_path, 770 unsigned ftype, 771 unsigned endian, 772 unsigned offsetsize, 773 size_t filesize, 774 Dwarf_Unsigned access, 775 unsigned groupnumber, 776 Dwarf_Handler errhand, 777 Dwarf_Ptr errarg, 778 Dwarf_Debug *dbg,Dwarf_Error *error) 779 { 780 Dwarf_Obj_Access_Interface *binary_interface = 0; 781 dwarf_macho_object_access_internals_t *intfc = 0; 782 int res = DW_DLV_OK; 783 int localerrnum = 0; 784 785 res = _dwarf_macho_object_access_init( 786 fd, 787 ftype,endian,offsetsize,filesize,access, 788 &binary_interface, 789 &localerrnum); 790 if (res != DW_DLV_OK) { 791 if (res == DW_DLV_NO_ENTRY) { 792 return res; 793 } 794 _dwarf_error(NULL, error, localerrnum); 795 return DW_DLV_ERROR; 796 } 797 /* allocates and initializes Dwarf_Debug, 798 generic code */ 799 res = dwarf_object_init_b(binary_interface, errhand, errarg, 800 groupnumber, dbg, error); 801 if (res != DW_DLV_OK){ 802 _dwarf_destruct_macho_access(binary_interface); 803 return res; 804 } 805 intfc = binary_interface->object; 806 intfc->mo_path = strdup(true_path); 807 return res; 808 } 809 810 811 static Dwarf_Obj_Access_Methods const macho_methods = { 812 macho_get_section_info, 813 macho_get_byte_order, 814 macho_get_length_size, 815 macho_get_pointer_size, 816 macho_get_section_count, 817 macho_load_section, 818 /* We do not do macho relocations. dsym files do not require it. */ 819 NULL 820 }; 821 822 /* On any error this frees internals argument. */ 823 static int 824 _dwarf_macho_object_access_internals_init( 825 dwarf_macho_object_access_internals_t * internals, 826 int fd, 827 unsigned ftype, 828 unsigned endian, 829 unsigned offsetsize, 830 size_t filesize, 831 UNUSEDARG Dwarf_Unsigned access, 832 int *errcode) 833 { 834 dwarf_macho_object_access_internals_t * intfc = internals; 835 Dwarf_Unsigned i = 0; 836 struct generic_macho_section *sp = 0; 837 struct Dwarf_Obj_Access_Interface_s *localdoas; 838 int res = 0; 839 840 /* Must malloc as _dwarf_destruct_macho_access() 841 forces that due to other uses. */ 842 localdoas = (struct Dwarf_Obj_Access_Interface_s *) 843 malloc(sizeof(struct Dwarf_Obj_Access_Interface_s)); 844 if (!localdoas) { 845 free(internals); 846 *errcode = DW_DLE_ALLOC_FAIL; 847 return DW_DLV_ERROR; 848 } 849 memset(localdoas,0,sizeof(struct Dwarf_Obj_Access_Interface_s)); 850 intfc->mo_ident[0] = 'M'; 851 intfc->mo_ident[1] = '1'; 852 intfc->mo_fd = fd; 853 intfc->mo_is_64bit = ((offsetsize==64)?TRUE:FALSE); 854 intfc->mo_offsetsize = offsetsize; 855 intfc->mo_pointersize = offsetsize; 856 intfc->mo_filesize = filesize; 857 intfc->mo_ftype = ftype; 858 859 #ifdef WORDS_BIGENDIAN 860 if (endian == DW_ENDIAN_LITTLE ) { 861 intfc->mo_copy_word = _dwarf_memcpy_swap_bytes; 862 intfc->mo_endian = DW_OBJECT_LSB; 863 } else { 864 intfc->mo_copy_word = _dwarf_memcpy_noswap_bytes; 865 intfc->mo_endian = DW_OBJECT_MSB; 866 } 867 #else /* LITTLE ENDIAN */ 868 if (endian == DW_ENDIAN_LITTLE ) { 869 intfc->mo_copy_word = _dwarf_memcpy_noswap_bytes; 870 intfc->mo_endian = DW_OBJECT_LSB; 871 } else { 872 intfc->mo_copy_word = _dwarf_memcpy_swap_bytes; 873 intfc->mo_endian = DW_OBJECT_MSB; 874 } 875 #endif /* LITTLE- BIG-ENDIAN */ 876 res = dwarf_load_macho_header(intfc,errcode); 877 if (res != DW_DLV_OK) { 878 localdoas->object = intfc; 879 localdoas->methods = 0; 880 _dwarf_destruct_macho_access(localdoas); 881 return res; 882 } 883 /* Load sections */ 884 res = dwarf_load_macho_commands(intfc,errcode); 885 if (res != DW_DLV_OK) { 886 localdoas->methods = 0; 887 localdoas->object = intfc; 888 _dwarf_destruct_macho_access(localdoas); 889 return res; 890 } 891 sp = intfc->mo_dwarf_sections+1; 892 for(i = 1; i < intfc->mo_dwarf_sectioncount ; ++i,++sp) { 893 int j = 1; 894 int lim = sizeof(SectionNames)/sizeof(SectionNames[0]); 895 sp->dwarfsectname = ""; 896 for( ; j < lim; ++j) { 897 if(!strcmp(sp->sectname,SectionNames[j].ms_moname)) { 898 sp->dwarfsectname = SectionNames[j].ms_dwname; 899 break; 900 } 901 } 902 } 903 free(localdoas); 904 return DW_DLV_OK; 905 } 906 907 908 static int 909 _dwarf_macho_object_access_init( 910 int fd, 911 unsigned ftype, 912 unsigned endian, 913 unsigned offsetsize, 914 size_t filesize, 915 Dwarf_Unsigned access, 916 Dwarf_Obj_Access_Interface **binary_interface, 917 int *localerrnum) 918 { 919 920 int res = 0; 921 dwarf_macho_object_access_internals_t *internals = 0; 922 Dwarf_Obj_Access_Interface *intfc = 0; 923 924 internals = malloc(sizeof(dwarf_macho_object_access_internals_t)); 925 if (!internals) { 926 *localerrnum = DW_DLE_ALLOC_FAIL; 927 /* Impossible case, we hope. Give up. */ 928 return DW_DLV_ERROR; 929 } 930 memset(internals,0,sizeof(*internals)); 931 res = _dwarf_macho_object_access_internals_init(internals, 932 fd, 933 ftype, endian, offsetsize, filesize, 934 access, 935 localerrnum); 936 if (res != DW_DLV_OK){ 937 /* *err is already set and the call freed internals. */ 938 return DW_DLV_ERROR; 939 } 940 941 intfc = malloc(sizeof(Dwarf_Obj_Access_Interface)); 942 if (!intfc) { 943 /* Impossible case, we hope. Give up. */ 944 free(internals); 945 *localerrnum = DW_DLE_ALLOC_FAIL; 946 return DW_DLV_ERROR; 947 } 948 /* Initialize the interface struct */ 949 intfc->object = internals; 950 intfc->methods = &macho_methods; 951 *binary_interface = intfc; 952 return DW_DLV_OK; 953 } 954