| // Copyright (c) 2010, 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: |
| // |
| // * 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. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // 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 |
| // OWNER 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. |
| |
| // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
| |
| // macho_dump.cc: Dump the contents of a Mach-O file. This is mostly |
| // a test program for the Mach_O::FatReader and Mach_O::Reader classes. |
| |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <mach-o/arch.h> |
| #include <sys/mman.h> |
| #include <stdint.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "common/byte_cursor.h" |
| #include "common/mac/arch_utilities.h" |
| #include "common/mac/macho_reader.h" |
| #include "common/path_helper.h" |
| |
| using google_breakpad::ByteBuffer; |
| using std::ostringstream; |
| using std::string; |
| using std::vector; |
| |
| namespace { |
| namespace mach_o = google_breakpad::mach_o; |
| |
| string program_name; |
| |
| int check_syscall(int result, const char *operation, const char *filename) { |
| if (result < 0) { |
| fprintf(stderr, "%s: %s '%s': %s\n", |
| program_name.c_str(), operation, |
| filename, strerror(errno)); |
| exit(1); |
| } |
| return result; |
| } |
| |
| class DumpSection: public mach_o::Reader::SectionHandler { |
| public: |
| DumpSection() : index_(0) { } |
| bool HandleSection(const mach_o::Section §ion) { |
| printf(" section %d '%s' in segment '%s'\n" |
| " address: 0x%llx\n" |
| " alignment: 1 << %d B\n" |
| " flags: %d\n" |
| " size: %ld\n", |
| index_++, section.section_name.c_str(), section.segment_name.c_str(), |
| section.address, section.align, |
| mach_o::SectionFlags(section.flags), |
| section.contents.Size()); |
| return true; |
| } |
| |
| private: |
| int index_; |
| }; |
| |
| class DumpCommand: public mach_o::Reader::LoadCommandHandler { |
| public: |
| DumpCommand(mach_o::Reader *reader) : reader_(reader), index_(0) { } |
| bool UnknownCommand(mach_o::LoadCommandType type, |
| const ByteBuffer &contents) { |
| printf(" load command %d: %d", index_++, type); |
| return true; |
| } |
| bool SegmentCommand(const mach_o::Segment &segment) { |
| printf(" load command %d: %s-bit segment '%s'\n" |
| " address: 0x%llx\n" |
| " memory size: 0x%llx\n" |
| " maximum protection: 0x%x\n" |
| " initial protection: 0x%x\n" |
| " flags: %d\n" |
| " section_list size: %ld B\n", |
| index_++, (segment.bits_64 ? "64" : "32"), segment.name.c_str(), |
| segment.vmaddr, segment.vmsize, segment.maxprot, |
| segment.initprot, mach_o::SegmentFlags(segment.flags), |
| segment.section_list.Size()); |
| |
| DumpSection dump_section; |
| return reader_->WalkSegmentSections(segment, &dump_section); |
| } |
| private: |
| mach_o::Reader *reader_; |
| int index_; |
| }; |
| |
| void DumpFile(const char *filename) { |
| int fd = check_syscall(open(filename, O_RDONLY), "opening", filename); |
| struct stat attributes; |
| check_syscall(fstat(fd, &attributes), |
| "getting file attributes for", filename); |
| void *mapping = mmap(NULL, attributes.st_size, PROT_READ, |
| MAP_PRIVATE, fd, 0); |
| close(fd); |
| check_syscall(mapping == (void *)-1 ? -1 : 0, |
| "mapping contents of", filename); |
| |
| mach_o::FatReader::Reporter fat_reporter(filename); |
| mach_o::FatReader fat_reader(&fat_reporter); |
| if (!fat_reader.Read(reinterpret_cast<uint8_t *>(mapping), |
| attributes.st_size)) { |
| exit(1); |
| } |
| printf("filename: %s\n", filename); |
| size_t object_files_size; |
| const SuperFatArch* super_fat_object_files = |
| fat_reader.object_files(&object_files_size); |
| struct fat_arch *object_files; |
| if (!super_fat_object_files->ConvertToFatArch(object_files)) { |
| exit(1); |
| } |
| printf(" object file count: %ld\n", object_files_size); |
| for (size_t i = 0; i < object_files_size; i++) { |
| const struct fat_arch &file = object_files[i]; |
| const NXArchInfo *fat_arch_info = |
| google_breakpad::BreakpadGetArchInfoFromCpuType( |
| file.cputype, file.cpusubtype); |
| printf("\n object file %ld:\n" |
| " fat header:\n:" |
| " CPU type: %s (%s)\n" |
| " size: %d B\n" |
| " alignment: 1<<%d B\n", |
| i, fat_arch_info->name, fat_arch_info->description, |
| file.size, file.align); |
| |
| ostringstream name; |
| name << filename; |
| if (object_files_size > 1) |
| name << ", object file #" << i; |
| ByteBuffer file_contents(reinterpret_cast<uint8_t *>(mapping) |
| + file.offset, file.size); |
| mach_o::Reader::Reporter reporter(name.str()); |
| mach_o::Reader reader(&reporter); |
| if (!reader.Read(file_contents, file.cputype, file.cpusubtype)) { |
| exit(1); |
| } |
| |
| const NXArchInfo *macho_arch_info = |
| NXGetArchInfoFromCpuType(reader.cpu_type(), |
| reader.cpu_subtype()); |
| printf(" Mach-O header:\n" |
| " word size: %s\n" |
| " CPU type: %s (%s)\n" |
| " File type: %d\n" |
| " flags: %x\n", |
| (reader.bits_64() ? "64 bits" : "32 bits"), |
| macho_arch_info->name, macho_arch_info->description, |
| reader.file_type(), reader.flags()); |
| |
| DumpCommand dump_command(&reader); |
| reader.WalkLoadCommands(&dump_command); |
| } |
| munmap(mapping, attributes.st_size); |
| } |
| |
| } // namespace |
| |
| int main(int argc, char **argv) { |
| program_name = google_breakpad::BaseName(argv[0]); |
| if (argc == 1) { |
| fprintf(stderr, "Usage: %s FILE ...\n" |
| "Dump the contents of the Mach-O or fat binary files " |
| "'FILE ...'.\n", program_name.c_str()); |
| } |
| for (int i = 1; i < argc; i++) { |
| DumpFile(argv[i]); |
| } |
| } |