aboutsummaryrefslogtreecommitdiff
path: root/src/tools
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-07-31 19:11:29 +0000
committerrsesek@chromium.org <rsesek@chromium.org@4c0a9323-5329-0410-9bdc-e9ce6186880e>2014-07-31 19:11:29 +0000
commit9c932f1d0c5667846124663e738656db73595645 (patch)
tree6208adcf0b69510c9b01bbed395b0e3013900068 /src/tools
parentIn Mac dump_syms, allow reading debug data out of both the Mach-O file and th... (diff)
downloadbreakpad-9c932f1d0c5667846124663e738656db73595645.tar.xz
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
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/mac/upload_system_symbols/arch_constants.h28
-rw-r--r--src/tools/mac/upload_system_symbols/arch_reader.go239
-rw-r--r--src/tools/mac/upload_system_symbols/arch_reader_test.go82
-rw-r--r--src/tools/mac/upload_system_symbols/testdata/Makefile22
-rw-r--r--src/tools/mac/upload_system_symbols/testdata/archtest.c7
-rw-r--r--src/tools/mac/upload_system_symbols/upload_system_symbols.go51
6 files changed, 80 insertions, 349 deletions
diff --git a/src/tools/mac/upload_system_symbols/arch_constants.h b/src/tools/mac/upload_system_symbols/arch_constants.h
index ed318b24..2115e54e 100644
--- a/src/tools/mac/upload_system_symbols/arch_constants.h
+++ b/src/tools/mac/upload_system_symbols/arch_constants.h
@@ -28,19 +28,33 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <mach-o/fat.h>
+#include <mach-o/arch.h>
#include <mach-o/loader.h>
+#include <mach/machine.h>
// Go/Cgo does not support #define constants, so turn them into symbols
// that are reachable from Go.
-const cpu_type_t kCPUType_i386 = CPU_TYPE_I386;
-const cpu_type_t kCPUType_x86_64 = CPU_TYPE_X86_64;
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
+#endif
-const uint32_t kMachHeaderMagic32 = MH_MAGIC;
-const uint32_t kMachHeaderMagic64 = MH_MAGIC_64;
-const uint32_t kMachHeaderMagicFat = FAT_MAGIC;
-const uint32_t kMachHeaderCigamFat = FAT_CIGAM;
+#ifndef CPU_SUBTYPE_ARM64_ALL
+#define CPU_SUBTYPE_ARM64_ALL 0
+#endif
+
+const cpu_type_t kCPU_TYPE_ARM = CPU_TYPE_ARM;
+const cpu_type_t kCPU_TYPE_ARM64 = CPU_TYPE_ARM64;
+
+const cpu_subtype_t kCPU_SUBTYPE_ARM64_ALL = CPU_SUBTYPE_ARM64_ALL;
+const cpu_subtype_t kCPU_SUBTYPE_ARM_V7S = CPU_SUBTYPE_ARM_V7S;
+
+const char* GetNXArchInfoName(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
+ const NXArchInfo* arch_info = NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
+ if (!arch_info)
+ return 0;
+ return arch_info->name;
+}
const uint32_t kMachHeaderFtypeDylib = MH_DYLIB;
const uint32_t kMachHeaderFtypeBundle = MH_BUNDLE;
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 <mach-o/fat.h>
-#include <mach-o/loader.h>
-#include <string.h>
-
#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
+)
diff --git a/src/tools/mac/upload_system_symbols/arch_reader_test.go b/src/tools/mac/upload_system_symbols/arch_reader_test.go
deleted file mode 100644
index 5fa1d210..00000000
--- a/src/tools/mac/upload_system_symbols/arch_reader_test.go
+++ /dev/null
@@ -1,82 +0,0 @@
-/* Copyright 2014, 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.
-*/
-
-package main
-
-import (
- "testing"
-)
-
-func TestFat(t *testing.T) {
- tests := []struct {
- file string
- mht MachOType
- arches []string
- }{
- {"testdata/libarchtest32.dylib", MachODylib, []string{ArchI386}},
- {"testdata/libarchtest64.dylib", MachODylib, []string{ArchX86_64}},
- {"testdata/libarchtest.dylib", MachODylib, []string{ArchI386, ArchX86_64}},
- {"testdata/archtest32.exe", MachOExe, []string{ArchI386}},
- {"testdata/archtest64.exe", MachOExe, []string{ArchX86_64}},
- {"testdata/archtest.exe", MachOExe, []string{ArchI386, ArchX86_64}},
- }
-
- for _, e := range tests {
- imageinfo, err := GetMachOImageInfo(e.file)
- if err != nil {
- t.Errorf("Unexpected error: %v", err)
- }
-
- expected := make(map[string]bool)
- for _, arch := range e.arches {
- expected[arch] = false
- }
-
- if len(imageinfo) != len(e.arches) {
- t.Errorf("Wrong number of arches, got %d, expected %d", len(imageinfo), len(e.arches))
- }
-
- for _, ii := range imageinfo {
- if ii.Type != e.mht {
- t.Errorf("Wrong MachOType got %d, expected %d", ii.Type, e.mht)
- }
- if o, k := expected[ii.Arch]; o || !k {
- t.Errorf("Unexpected architecture %q", ii.Arch)
- }
- expected[ii.Arch] = true
- }
-
- for k, v := range expected {
- if !v {
- t.Errorf("Did not get expected architecture %s", k)
- }
- }
- }
-}
diff --git a/src/tools/mac/upload_system_symbols/testdata/Makefile b/src/tools/mac/upload_system_symbols/testdata/Makefile
deleted file mode 100644
index cb481a3c..00000000
--- a/src/tools/mac/upload_system_symbols/testdata/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-all: libarchtest.dylib archtest.exe
-
-archtest32.exe: archtest.c
- clang -m32 $< -o $@
-
-archtest64.exe: archtest.c
- clang -m64 $< -o $@
-
-archtest.exe: archtest32.exe archtest64.exe
- lipo $^ -create -output $@
-
-libarchtest32.dylib: archtest.c
- clang -m32 -dynamiclib $< -o $@
-
-libarchtest64.dylib: archtest.c
- clang -m64 -dynamiclib $< -o $@
-
-libarchtest.dylib: libarchtest32.dylib libarchtest64.dylib
- lipo $^ -create -output $@
-
-clean:
- rm -f *.dylib *.exe
diff --git a/src/tools/mac/upload_system_symbols/testdata/archtest.c b/src/tools/mac/upload_system_symbols/testdata/archtest.c
deleted file mode 100644
index 0931fca1..00000000
--- a/src/tools/mac/upload_system_symbols/testdata/archtest.c
+++ /dev/null
@@ -1,7 +0,0 @@
-int TestLibUsefulFunction() {
- return 42;
-}
-
-int main() {
- return 0;
-}
diff --git a/src/tools/mac/upload_system_symbols/upload_system_symbols.go b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
index 869a2773..35561208 100644
--- a/src/tools/mac/upload_system_symbols/upload_system_symbols.go
+++ b/src/tools/mac/upload_system_symbols/upload_system_symbols.go
@@ -43,6 +43,7 @@ Both i386 and x86_64 architectures will be dumped and uploaded.
package main
import (
+ "debug/macho"
"flag"
"fmt"
"io"
@@ -58,10 +59,11 @@ import (
)
var (
- breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.")
- uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.")
- dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.")
- systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.")
+ breakpadTools = flag.String("breakpad-tools", "out/Release/", "Path to the Breakpad tools directory, containing dump_syms and symupload.")
+ uploadOnlyPath = flag.String("upload-from", "", "Upload a directory of symbol files that has been dumped independently.")
+ dumpOnlyPath = flag.String("dump-to", "", "Dump the symbols to the specified directory, but do not upload them.")
+ systemRoot = flag.String("system-root", "", "Path to the root of the Mac OS X system whose symbols will be dumped.")
+ dumpArchitecture = flag.String("arch", "", "The CPU architecture for which symbols should be dumped. If not specified, dumps all architectures.")
)
var (
@@ -373,17 +375,46 @@ func (fq *findQueue) worker() {
continue
}
- imageinfos, err := GetMachOImageInfo(fp)
- if err != nil && err != ErrNotMachO {
+ f, err := os.Open(fp)
+ if err != nil {
log.Printf("%s: %v", fp, err)
continue
}
- for _, imageinfo := range imageinfos {
- if imageinfo.Type == MachODylib || imageinfo.Type == MachOBundle {
-
- fq.dq.DumpSymbols(fp, imageinfo.Arch)
+ fatFile, err := macho.NewFatFile(f)
+ if err == nil {
+ // The file is fat, so dump its architectures.
+ for _, fatArch := range fatFile.Arches {
+ fq.dumpMachOFile(fp, fatArch.File)
+ }
+ fatFile.Close()
+ } else if err == macho.ErrNotFat {
+ // The file isn't fat but may still be MachO.
+ thinFile, err := macho.NewFile(f)
+ if err != nil {
+ log.Printf("%s: %v", fp, err)
+ continue
}
+ fq.dumpMachOFile(fp, thinFile)
+ thinFile.Close()
+ } else {
+ f.Close()
}
}
}
+
+func (fq *findQueue) dumpMachOFile(fp string, image *macho.File) {
+ if image.Type != MachODylib && image.Type != MachOBundle {
+ return
+ }
+
+ arch := getArchStringFromHeader(image.FileHeader)
+ if arch == "" {
+ // Don't know about this architecture type.
+ return
+ }
+
+ if (*dumpArchitecture != "" && *dumpArchitecture == arch) || *dumpArchitecture == "" {
+ fq.dq.DumpSymbols(fp, arch)
+ }
+}