diff -r b4b157088bc8 gdb-768/src/bfd/mach-o.c --- a/gdb-768/src/bfd/mach-o.c Wed Aug 12 10:58:48 2009 +0100 +++ b/gdb-768/src/bfd/mach-o.c Wed Aug 26 15:09:04 2009 +0100 @@ -1905,14 +1905,40 @@ char *sname; const char *prefix = "LC_SEGMENT"; unsigned int snamelen; + // bfd_mach_o_segment_command structure is missing the cmd and cmdsize fields...DUH! - fG! + unsigned int cmd=0, cmdsize=0; + // this will hold our calculated value of nsects (the real one!) + unsigned int realnsects=0; +// To calculate the real number of sections we can use this information: +// cmdsize +// Common to all loadcommand structures. For this structure, set this field to +// sizeof(segment_command) plus the size of all the section data structures that follow +// (sizeof(segment_command + (sizeof(section) * segment->nsect))). + if (wide) { BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT_64); + // read cmd and cmdsize - fG! + bfd_seek (abfd, command->offset, SEEK_SET); + if (bfd_bread ((PTR) buf, 8, abfd) != 8) + { + printf("\nERROR: 8 bytes bfd_read for cmd and cmdsize failed!\n"); + return -1; + } + cmd = bfd_h_get_64 (abfd, buf); + cmdsize = bfd_h_get_64 (abfd, buf + 8); + // calculate the real number of sections + // segment_command_64 structure is 72 bytes + realnsects = (cmdsize - 72 ) / 80; + bfd_seek (abfd, command->offset + 8, SEEK_SET); if (bfd_bread ((PTR) buf, 64, abfd) != 64) - return -1; + { + printf("\nERROR: 64 bytes bfd_read failed!\n"); + return -1; + } memcpy (seg->segname, buf, 16); @@ -1929,9 +1955,28 @@ { BFD_ASSERT (command->type == BFD_MACH_O_LC_SEGMENT); + // read cmd and cmdsize - fG! + bfd_seek (abfd, command->offset, SEEK_SET); + // can't read data, so error ! + if (bfd_bread ((PTR) buf, 8, abfd) != 8) + { + printf("\nERROR: can't read data to retrieve cmd and cmdsize\n"); + return -1; + } + // retrieve cmd and cmdsize + cmd = bfd_h_get_32 (abfd, buf); + cmdsize = bfd_h_get_32 (abfd, buf + 4); + // calculate the real number of sections + // segment_command structure is 56 bytes + realnsects = (cmdsize - 56 ) / 68; + + // and get back to normal gdb processing bfd_seek (abfd, command->offset + 8, SEEK_SET); if (bfd_bread ((PTR) buf, 48, abfd) != 48) - return -1; + { + printf("\nERROR: can't read data to retrieve the whole header\n"); + return -1; + } memcpy (seg->segname, buf, 16); @@ -1948,12 +1993,18 @@ snamelen = strlen (prefix) + 1 + strlen (seg->segname) + 1; sname = (char *) bfd_alloc (abfd, snamelen); if (sname == NULL) + { + printf("\nERROR: bfd_alloc for sname failed!\n"); return -1; + } sprintf (sname, "%s.%s", prefix, seg->segname); bfdsec = bfd_make_section_anyway (abfd, sname); if (bfdsec == NULL) + { + printf("\nERROR: bfd_make_section_anyway failed!\n"); return -1; + } bfdsec->vma = seg->vmaddr; bfdsec->lma = seg->vmaddr; @@ -1966,14 +2017,48 @@ seg->segment = bfdsec; if (seg->nsects != 0) - { - seg->sections = - ((bfd_mach_o_section *) - bfd_alloc (abfd, seg->nsects * sizeof (bfd_mach_o_section))); - if (seg->sections == NULL) - return -1; - - for (i = 0; i < seg->nsects; i++) + { + // check if the reported number of sections is correct + // filesize = Indicates the number of bytes occupied by this segment on disk. Each section has a size of 68 bytes (32bits) or 80 bytes (64 bits). + // if the size of the whole segment (filesize) is less than the size of all the sections reported by the header, + // then it's certain we have a problem, most probably the anti-debug trick + // the real number of sections can be calculated from the cmdsize. + // formula is: (sizeof(segment_command + (sizeof(section) * segment->nsect))) = cmdsize (at each segment header!) - retrieved from Mac OS X ABI Mach-O File Format Reference + // 64 bits + if (wide) + { + if ((unsigned long long)seg->filesize <= (unsigned long long)seg->nsects*80 || seg->nsects > realnsects) + { + printf("\n\n***WARNING***: Possible number of sections anti-debug trick detected at segment %s !\n", seg->segname); + printf("Number of sections reported from the header is %lli, the real number should be %lli\n", (unsigned long long)seg->nsects, (unsigned long long)realnsects); + // this would allow gdb to process the file but then dyld will fail so until Apple fixes the problem there's no interest doing it + // printf("Fixing to allow gdb to parse and work with this binary...\n"); + // seg->nsects = realnsects; + } + } + // 32 bits + else + { + if ((unsigned long long)seg->filesize < (unsigned long long)seg->nsects*68 || seg->nsects > realnsects) + { + printf("\n\n***WARNING***: Possible number of sections anti-debug trick detected at segment %s !\n", seg->segname); + printf("Number of sections reported from the header is %lli, the real number should be %lli\n", (unsigned long long)seg->nsects, (unsigned long long)realnsects); + // this would allow gdb to process the file but then dyld will fail so until Apple fixes the problem there's no interest doing it + // printf("Fixing to allow gdb to parse and work with this binary...\n"); + // seg->nsects = realnsects; + } + } + + // back to gdb normal code + seg->sections = ((bfd_mach_o_section *) bfd_alloc (abfd, seg->nsects * sizeof (bfd_mach_o_section))); + // The 0xFFFFFFFF value will fail here since it's trying to allocate an huge amount of memory + if (seg->sections == NULL) + { + printf("\nERROR: bfd_alloc for seg->sections failed! Most probably because nsects is too big!\n"); + return -1; + } + + for (i = 0; i < seg->nsects; i++) { bfd_vma segoff; if (wide) @@ -1983,9 +2068,12 @@ if (bfd_mach_o_scan_read_section (abfd, &seg->sections[i], segoff, wide) != 0) + { + printf("\nERROR: bfd_mach_o_scan_read_section failed!\n"); return -1; + } } - } + } return 0; } @@ -2008,6 +2096,7 @@ unsigned char buf[8]; bfd_seek (abfd, command->offset, SEEK_SET); + if (bfd_bread ((PTR) buf, 8, abfd) != 8) return -1;