From 9c932f1d0c5667846124663e738656db73595645 Mon Sep 17 00:00:00 2001 From: "rsesek@chromium.org" Date: Thu, 31 Jul 2014 19:11:29 +0000 Subject: upload_system_symbols: Use the Go1.3 improvements to debug/macho. This removes the custom MachO header reading functionality, since the stdlib can now read Fat files. R=andybons@chromium.org, mark@chromium.org Review URL: https://breakpad.appspot.com/10684002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1360 4c0a9323-5329-0410-9bdc-e9ce6186880e --- src/tools/mac/upload_system_symbols/arch_reader.go | 239 ++------------------- 1 file changed, 18 insertions(+), 221 deletions(-) (limited to 'src/tools/mac/upload_system_symbols/arch_reader.go') diff --git a/src/tools/mac/upload_system_symbols/arch_reader.go b/src/tools/mac/upload_system_symbols/arch_reader.go index 0468836e..f6064823 100644 --- a/src/tools/mac/upload_system_symbols/arch_reader.go +++ b/src/tools/mac/upload_system_symbols/arch_reader.go @@ -31,238 +31,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package main import ( - "encoding/binary" - "errors" - "fmt" - "os" - "reflect" - "unsafe" + "debug/macho" ) /* -#include -#include -#include - #include "arch_constants.h" */ import "C" -var ( - ErrNotMachO = errors.New("GetMachOImageInfo: file is not a supported Mach-O image") - ErrUnsupportedArch = errors.New("GetMachOImageInfo: unknown architecture detected") -) - -const ( - ArchI386 = "i386" - ArchX86_64 = "x86_64" -) - -type MachOType int - -const ( - MachODylib MachOType = C.kMachHeaderFtypeDylib - MachOBundle = C.kMachHeaderFtypeBundle - MachOExe = C.kMachHeaderFtypeExe -) - -type ImageInfo struct { - Type MachOType - Arch string -} - -// GetMachOImageInfo will read the file at filepath and determine if it is -// Mach-O. If it is, it will return a slice of ImageInfo that describe the -// images in the file (may be more than one if it is a fat image). -func GetMachOImageInfo(filepath string) ([]ImageInfo, error) { - f, err := os.Open(filepath) - if err != nil { - return nil, err - } - defer f.Close() - - // Read the magic number to determine the type of file this is. - var magic uint32 - err = binary.Read(f, binary.LittleEndian, &magic) - if err != nil { - return nil, err - } - - // Rewind the file since the magic number is a field in the header - // structs. - f.Seek(0, os.SEEK_SET) - - switch magic { - case C.kMachHeaderMagic32: - return readThinHeader(f, C.kMachHeaderMagic32) - case C.kMachHeaderMagic64: - return readThinHeader(f, C.kMachHeaderMagic64) - case C.kMachHeaderCigamFat: // Fat header is big-endian but was read in little. - return readFatHeader(f) - } - - return nil, ErrNotMachO -} - -func readThinHeader(f *os.File, expectedMagic uint32) ([]ImageInfo, error) { - var ( - magic, filetype uint32 - cpu C.cpu_type_t - err error - ) - - if expectedMagic == C.kMachHeaderMagic32 { - magic, cpu, filetype, err = readThin32Header(f) - } else if expectedMagic == C.kMachHeaderMagic64 { - magic, cpu, filetype, err = readThin64Header(f) - } else { - panic(fmt.Sprintf("Unexpected magic %#x", magic)) - } - if err != nil { - return nil, err - } - - if magic != expectedMagic { - return nil, fmt.Errorf("readThinHeader: unexpected magic number %#x", magic) - } - - arch := cpuTypeToArch(cpu) - if arch == "" { - return nil, ErrUnsupportedArch - } - return []ImageInfo{{MachOType(filetype), arch}}, nil -} - -func readThin32Header(f *os.File) (uint32, C.cpu_type_t, uint32, error) { - var machHeader C.struct_mach_header - err := readStruct(f, binary.LittleEndian, unsafe.Pointer(&machHeader), C.struct_mach_header{}) - if err != nil { - return 0, 0, 0, err +// getArchStringFromHeader takes a MachO FileHeader and returns a string that +// represents the CPU type and subtype. +// This function is a Go version of src/common/mac/arch_utilities.cc:BreakpadGetArchInfoFromCpuType(). +func getArchStringFromHeader(header macho.FileHeader) string { + // TODO(rsesek): As of 10.9.4, OS X doesn't list these in /usr/include/mach/machine.h. + if header.Cpu == C.kCPU_TYPE_ARM64 && header.SubCpu == C.kCPU_SUBTYPE_ARM64_ALL { + return "arm64" } - return uint32(machHeader.magic), machHeader.cputype, uint32(machHeader.filetype), nil -} - -func readThin64Header(f *os.File) (uint32, C.cpu_type_t, uint32, error) { - var machHeader C.struct_mach_header_64 - err := readStruct(f, binary.LittleEndian, unsafe.Pointer(&machHeader), C.struct_mach_header_64{}) - if err != nil { - return 0, 0, 0, err - } - return uint32(machHeader.magic), machHeader.cputype, uint32(machHeader.filetype), nil -} - -func readFatHeader(f *os.File) ([]ImageInfo, error) { - var fatHeader C.struct_fat_header - err := readStruct(f, binary.BigEndian, unsafe.Pointer(&fatHeader), C.struct_fat_header{}) - if err != nil { - return nil, err - } - - if fatHeader.magic != C.kMachHeaderMagicFat { - return nil, fmt.Errorf("readFatHeader: unexpected magic number %#x", fatHeader.magic) - } - - // Read the fat_arch headers. - headers := make([]C.struct_fat_arch, fatHeader.nfat_arch) - for i := 0; i < int(fatHeader.nfat_arch); i++ { - var fatArch C.struct_fat_arch - err = readStruct(f, binary.BigEndian, unsafe.Pointer(&fatArch), C.struct_fat_arch{}) - if err != nil { - return nil, fmt.Errorf("readFatHeader: %v", err) - } - headers[i] = fatArch - } - - seenArches := make(map[string]int) - - // Now go to each arch in the fat image and read its mach header. - infos := make([]ImageInfo, 0, len(headers)) - for _, header := range headers { - f.Seek(int64(header.offset), os.SEEK_SET) - - var thinarch []ImageInfo - var expectedArch string - switch header.cputype { - case C.kCPUType_i386: - thinarch, err = readThinHeader(f, C.kMachHeaderMagic32) - expectedArch = ArchI386 - case C.kCPUType_x86_64: - thinarch, err = readThinHeader(f, C.kMachHeaderMagic64) - expectedArch = ArchX86_64 - default: - err = ErrUnsupportedArch - } - - if err != nil { - return nil, err - } - if thinarch[0].Arch != expectedArch { - return nil, fmt.Errorf("readFatHeader: expected arch %d, got %d", thinarch[0].Arch, expectedArch) - } - - infos = append(infos, thinarch[0]) - seenArches[thinarch[0].Arch]++ + if header.Cpu == C.kCPU_TYPE_ARM && header.SubCpu == C.kCPU_SUBTYPE_ARM_V7S { + return "armv7s" } - for arch, count := range seenArches { - if count != 1 { - return nil, fmt.Errorf("readFatHeader: duplicate arch %s detected", arch) - } - } - - return infos, nil -} - -// TODO(rsesek): Support more arches. -func cpuTypeToArch(cpu C.cpu_type_t) string { - switch cpu { - case C.kCPUType_i386: - return ArchI386 - case C.kCPUType_x86_64: - return ArchX86_64 - default: + cstr := C.GetNXArchInfoName(C.cpu_type_t(header.Cpu), C.cpu_subtype_t(header.SubCpu)) + if cstr == nil { return "" } + return C.GoString(cstr) } -// readStruct is a incomplete version of binary.Read that uses unsafe pointers -// to set values in unexported fields. From |f|, this will read the fields of -// the |destType| template instance, in the specified byte |order|, and place -// the resulting memory into |dest|. -func readStruct(f *os.File, order binary.ByteOrder, dest unsafe.Pointer, destType interface{}) error { - rv := reflect.ValueOf(destType) - rt := rv.Type() - destPtr := uintptr(dest) - - for i := 0; i < rv.NumField(); i++ { - field := rv.Field(i) - fieldType := rt.Field(i) - - var vp unsafe.Pointer - var err error - - switch field.Kind() { - case reflect.Int32: - var v int32 - vp = unsafe.Pointer(&v) - err = binary.Read(f, order, &v) - case reflect.Uint32: - var v uint32 - vp = unsafe.Pointer(&v) - err = binary.Read(f, order, &v) - default: - err = fmt.Errorf("readStruct: unsupported type %v", fieldType) - } - - if err != nil { - return err - } - - memcpy(destPtr+fieldType.Offset, vp, fieldType.Type.Size()) - } - return nil -} - -func memcpy(dest uintptr, value unsafe.Pointer, size uintptr) { - C.memcpy(unsafe.Pointer(dest), value, C.size_t(size)) -} +const ( + MachODylib macho.Type = C.kMachHeaderFtypeDylib + MachOBundle = C.kMachHeaderFtypeBundle + MachOExe = C.kMachHeaderFtypeExe +) -- cgit v1.2.1