func findEntry(f *macho.File, bits int) (uint64, error) { var entry uint64 for _, l := range f.Loads { var cmd macho.LoadCmd data := l.Raw() binary.Read(bytes.NewReader(data), f.ByteOrder, &cmd) if cmd == macho.LoadCmdUnixThread { // LC_UNIXTHREAD if bits == 64 { ip := 144 entry = f.ByteOrder.Uint64(data[ip : ip+8]) } else { ip := 56 entry = uint64(f.ByteOrder.Uint32(data[ip : ip+4])) } return entry, nil } else if cmd == machoLoadCmdMain { // [8:16] == entry - __TEXT, data[16:24] == stack size __TEXT := f.Segment("__TEXT") if __TEXT == nil { return 0, errors.New("Found LC_MAIN but did not find __TEXT segment.") } entry = f.ByteOrder.Uint64(data[8:16]) + __TEXT.Addr return entry, nil } } return 0, errors.New("Could not find entry point.") }
func printFileInformation(f *macho.File) { log.Printf("ByteOrder: %s", f.ByteOrder) printHeader(&f.FileHeader) // Also f.FileHeader.Ncmd log.Printf("file has %d load commands", len(f.Loads)) log.Printf("file has %d sections", len(f.Sections)) printSections(f.Sections) printSymtab(f.Symtab) printDysymtab(f.Dysymtab) printImportedLibraries(f.ImportedLibraries()) }
// Open an input file. func open(name string) (*file, error) { efile, err := Open(name) var mfile *macho.File if err != nil { var merr error mfile, merr = macho.Open(name) if merr != nil { return nil, err } } r := &file{elf: efile, macho: mfile} if efile != nil { r.dwarf, err = efile.DWARF() } else { r.dwarf, err = mfile.DWARF() } if err != nil { return nil, err } var syms []sym if efile != nil { esyms, err := efile.Symbols() if err != nil { return nil, err } syms = make([]sym, 0, len(esyms)) for _, s := range esyms { if ST_TYPE(s.Info) == STT_FUNC { syms = append(syms, sym{s.Name, uintptr(s.Value)}) } } } else { syms = make([]sym, 0, len(mfile.Symtab.Syms)) for _, s := range mfile.Symtab.Syms { syms = append(syms, sym{s.Name, uintptr(s.Value)}) } } r.symsByName = make([]sym, len(syms)) copy(r.symsByName, syms) sort.Sort(symsByName(r.symsByName)) r.symsByAddr = syms sort.Sort(symsByAddr(r.symsByAddr)) return r, nil }
func (dbp *Process) parseDebugLineInfo(exe *macho.File, wg *sync.WaitGroup) { defer wg.Done() if sec := exe.Section("__debug_line"); sec != nil { debugLine, err := exe.Section("__debug_line").Data() if err != nil { fmt.Println("could not get __debug_line section", err) os.Exit(1) } dbp.lineInfo = line.Parse(debugLine) } else { fmt.Println("could not find __debug_line section in binary") os.Exit(1) } }
func (dbp *Process) parseDebugFrame(exe *macho.File, wg *sync.WaitGroup) { defer wg.Done() if sec := exe.Section("__debug_frame"); sec != nil { debugFrame, err := exe.Section("__debug_frame").Data() if err != nil { fmt.Println("could not get __debug_frame section", err) os.Exit(1) } dbp.frameEntries = frame.Parse(debugFrame) } else { fmt.Println("could not find __debug_frame section in binary") os.Exit(1) } }
//============================================================================ // main : Entry point. //---------------------------------------------------------------------------- func main() { var dwarfData *dwarf.Data var theFile *macho.File var theErr os.Error var relativeAddress uint64 var runtimeAddress uint64 var loadAddress uint64 var segmentAddress uint64 var pathMacho string var pathDsym string // Parse our arguments flag.Uint64Var(&runtimeAddress, "raddr", 0, "") flag.Uint64Var(&loadAddress, "laddr", 0, "") flag.StringVar(&pathMacho, "macho", "", "") flag.StringVar(&pathDsym, "dsym", "", "") flag.Parse() if runtimeAddress == 0 || loadAddress == 0 || pathMacho == "" || pathDsym == "" { printHelp() } // Find the text segment address theFile, theErr = macho.Open(pathMacho) if theErr != nil { fatalError("Can't open Mach-O file: " + theErr.String()) } segmentAddress = theFile.Segment("__TEXT").Addr theFile.Close() // Calculate the target address relativeAddress = runtimeAddress - loadAddress gTargetAddress = segmentAddress + relativeAddress // Find the target theFile, theErr = macho.Open(pathDsym) if theErr != nil { fatalError("Can't open .dsym file: " + theErr.String()) } dwarfData, theErr = theFile.DWARF() if theErr != nil { fatalError("Can't find DWARF info: " + theErr.String()) } processChildren(dwarfData.Reader(), 0, false) theFile.Close() }
func (dbp *Process) obtainGoSymbols(exe *macho.File, wg *sync.WaitGroup) { defer wg.Done() var ( symdat []byte pclndat []byte err error ) if sec := exe.Section("__gosymtab"); sec != nil { symdat, err = sec.Data() if err != nil { fmt.Println("could not get .gosymtab section", err) os.Exit(1) } } if sec := exe.Section("__gopclntab"); sec != nil { pclndat, err = sec.Data() if err != nil { fmt.Println("could not get .gopclntab section", err) os.Exit(1) } } pcln := gosym.NewLineTable(pclndat, exe.Section("__text").Addr) tab, err := gosym.NewTable(symdat, pcln) if err != nil { fmt.Println("could not get initialize line table", err) os.Exit(1) } dbp.goSymTable = tab }