Файловый менеджер - Редактировать - /var/www/html/objfile.zip
Ðазад
PK ! .Z � � objfile.gonu �[��� // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package objfile implements portable access to OS-specific executable files. package objfile import ( "cmd/internal/archive" "debug/dwarf" "debug/gosym" "fmt" "io" "os" "sort" ) type rawFile interface { symbols() (syms []Sym, err error) pcln() (textStart uint64, symtab, pclntab []byte, err error) text() (textStart uint64, text []byte, err error) goarch() string loadAddress() (uint64, error) dwarf() (*dwarf.Data, error) } // A File is an opened executable file. type File struct { r *os.File entries []*Entry } type Entry struct { name string raw rawFile } // A Sym is a symbol defined in an executable file. type Sym struct { Name string // symbol name Addr uint64 // virtual address of symbol Size int64 // size in bytes Code rune // nm code (T for text, D for data, and so on) Type string // XXX? Relocs []Reloc // in increasing Addr order } type Reloc struct { Addr uint64 // Address of first byte that reloc applies to. Size uint64 // Number of bytes Stringer RelocStringer } type RelocStringer interface { // insnOffset is the offset of the instruction containing the relocation // from the start of the symbol containing the relocation. String(insnOffset uint64) string } var openers = []func(io.ReaderAt) (rawFile, error){ openElf, openMacho, openPE, openPlan9, openXcoff, } // Open opens the named file. // The caller must call f.Close when the file is no longer needed. func Open(name string) (*File, error) { r, err := os.Open(name) if err != nil { return nil, err } if f, err := openGoFile(r); err == nil { return f, nil } else if _, ok := err.(archive.ErrGoObjOtherVersion); ok { return nil, fmt.Errorf("open %s: %v", name, err) } for _, try := range openers { if raw, err := try(r); err == nil { return &File{r, []*Entry{{raw: raw}}}, nil } } r.Close() return nil, fmt.Errorf("open %s: unrecognized object file", name) } func (f *File) Close() error { return f.r.Close() } func (f *File) Entries() []*Entry { return f.entries } func (f *File) Symbols() ([]Sym, error) { return f.entries[0].Symbols() } func (f *File) PCLineTable() (Liner, error) { return f.entries[0].PCLineTable() } func (f *File) Text() (uint64, []byte, error) { return f.entries[0].Text() } func (f *File) GOARCH() string { return f.entries[0].GOARCH() } func (f *File) LoadAddress() (uint64, error) { return f.entries[0].LoadAddress() } func (f *File) DWARF() (*dwarf.Data, error) { return f.entries[0].DWARF() } func (f *File) Disasm() (*Disasm, error) { return f.entries[0].Disasm() } func (e *Entry) Name() string { return e.name } func (e *Entry) Symbols() ([]Sym, error) { syms, err := e.raw.symbols() if err != nil { return nil, err } sort.Sort(byAddr(syms)) return syms, nil } type byAddr []Sym func (x byAddr) Less(i, j int) bool { return x[i].Addr < x[j].Addr } func (x byAddr) Len() int { return len(x) } func (x byAddr) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (e *Entry) PCLineTable() (Liner, error) { // If the raw file implements Liner directly, use that. // Currently, only Go intermediate objects and archives (goobj) use this path. if pcln, ok := e.raw.(Liner); ok { return pcln, nil } // Otherwise, read the pcln tables and build a Liner out of that. textStart, symtab, pclntab, err := e.raw.pcln() if err != nil { return nil, err } syms, err := e.raw.symbols() if err == nil { for _, s := range syms { if s.Name == "runtime.text" { textStart = s.Addr break } } } return gosym.NewTable(symtab, gosym.NewLineTable(pclntab, textStart)) } func (e *Entry) Text() (uint64, []byte, error) { return e.raw.text() } func (e *Entry) GOARCH() string { return e.raw.goarch() } // LoadAddress returns the expected load address of the file. // This differs from the actual load address for a position-independent // executable. func (e *Entry) LoadAddress() (uint64, error) { return e.raw.loadAddress() } // DWARF returns DWARF debug data for the file, if any. // This is for cmd/pprof to locate cgo functions. func (e *Entry) DWARF() (*dwarf.Data, error) { return e.raw.dwarf() } PK ! ~b^ ^ goobj.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of Go intermediate object files and archives. package objfile import ( "cmd/internal/archive" "cmd/internal/goobj" "cmd/internal/objabi" "cmd/internal/sys" "debug/dwarf" "debug/gosym" "errors" "fmt" "io" "os" ) type goobjFile struct { goobj *archive.GoObj r *goobj.Reader f *os.File arch *sys.Arch } func openGoFile(f *os.File) (*File, error) { a, err := archive.Parse(f, false) if err != nil { return nil, err } entries := make([]*Entry, 0, len(a.Entries)) L: for _, e := range a.Entries { switch e.Type { case archive.EntryPkgDef, archive.EntrySentinelNonObj: continue case archive.EntryGoObj: o := e.Obj b := make([]byte, o.Size) _, err := f.ReadAt(b, o.Offset) if err != nil { return nil, err } r := goobj.NewReaderFromBytes(b, false) var arch *sys.Arch for _, a := range sys.Archs { if a.Name == e.Obj.Arch { arch = a break } } entries = append(entries, &Entry{ name: e.Name, raw: &goobjFile{e.Obj, r, f, arch}, }) continue case archive.EntryNativeObj: nr := io.NewSectionReader(f, e.Offset, e.Size) for _, try := range openers { if raw, err := try(nr); err == nil { entries = append(entries, &Entry{ name: e.Name, raw: raw, }) continue L } } } return nil, fmt.Errorf("open %s: unrecognized archive member %s", f.Name(), e.Name) } return &File{f, entries}, nil } func goobjName(name string, ver int) string { if ver == 0 { return name } return fmt.Sprintf("%s<%d>", name, ver) } type goobjReloc struct { Off int32 Size uint8 Type objabi.RelocType Add int64 Sym string } func (r goobjReloc) String(insnOffset uint64) string { delta := int64(r.Off) - int64(insnOffset) s := fmt.Sprintf("[%d:%d]%s", delta, delta+int64(r.Size), r.Type) if r.Sym != "" { if r.Add != 0 { return fmt.Sprintf("%s:%s+%d", s, r.Sym, r.Add) } return fmt.Sprintf("%s:%s", s, r.Sym) } if r.Add != 0 { return fmt.Sprintf("%s:%d", s, r.Add) } return s } func (f *goobjFile) symbols() ([]Sym, error) { r := f.r var syms []Sym // Name of referenced indexed symbols. nrefName := r.NRefName() refNames := make(map[goobj.SymRef]string, nrefName) for i := 0; i < nrefName; i++ { rn := r.RefName(i) refNames[rn.Sym()] = rn.Name(r) } abiToVer := func(abi uint16) int { var ver int if abi == goobj.SymABIstatic { // Static symbol ver = 1 } return ver } resolveSymRef := func(s goobj.SymRef) string { var i uint32 switch p := s.PkgIdx; p { case goobj.PkgIdxInvalid: if s.SymIdx != 0 { panic("bad sym ref") } return "" case goobj.PkgIdxHashed64: i = s.SymIdx + uint32(r.NSym()) case goobj.PkgIdxHashed: i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()) case goobj.PkgIdxNone: i = s.SymIdx + uint32(r.NSym()+r.NHashed64def()+r.NHasheddef()) case goobj.PkgIdxBuiltin: name, abi := goobj.BuiltinName(int(s.SymIdx)) return goobjName(name, abi) case goobj.PkgIdxSelf: i = s.SymIdx default: return refNames[s] } sym := r.Sym(i) return goobjName(sym.Name(r), abiToVer(sym.ABI())) } // Defined symbols ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef()) for i := uint32(0); i < ndef; i++ { osym := r.Sym(i) if osym.Name(r) == "" { continue // not a real symbol } name := osym.Name(r) ver := osym.ABI() name = goobjName(name, abiToVer(ver)) typ := objabi.SymKind(osym.Type()) var code rune = '?' switch typ { case objabi.STEXT: code = 'T' case objabi.SRODATA: code = 'R' case objabi.SNOPTRDATA, objabi.SDATA: code = 'D' case objabi.SBSS, objabi.SNOPTRBSS, objabi.STLSBSS: code = 'B' } if ver >= goobj.SymABIstatic { code += 'a' - 'A' } sym := Sym{ Name: name, Addr: uint64(r.DataOff(i)), Size: int64(osym.Siz()), Code: code, } relocs := r.Relocs(i) sym.Relocs = make([]Reloc, len(relocs)) for j := range relocs { rel := &relocs[j] sym.Relocs[j] = Reloc{ Addr: uint64(r.DataOff(i)) + uint64(rel.Off()), Size: uint64(rel.Siz()), Stringer: goobjReloc{ Off: rel.Off(), Size: rel.Siz(), Type: objabi.RelocType(rel.Type()), Add: rel.Add(), Sym: resolveSymRef(rel.Sym()), }, } } syms = append(syms, sym) } // Referenced symbols n := ndef + uint32(r.NNonpkgref()) for i := ndef; i < n; i++ { osym := r.Sym(i) sym := Sym{Name: osym.Name(r), Code: 'U'} syms = append(syms, sym) } for i := 0; i < nrefName; i++ { rn := r.RefName(i) sym := Sym{Name: rn.Name(r), Code: 'U'} syms = append(syms, sym) } return syms, nil } func (f *goobjFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { // Should never be called. We implement Liner below, callers // should use that instead. return 0, nil, nil, fmt.Errorf("pcln not available in go object file") } // Find returns the file name, line, and function data for the given pc. // Returns "",0,nil if unknown. // This function implements the Liner interface in preference to pcln() above. func (f *goobjFile) PCToLine(pc uint64) (string, int, *gosym.Func) { r := f.r if f.arch == nil { return "", 0, nil } getSymData := func(s goobj.SymRef) []byte { if s.PkgIdx != goobj.PkgIdxHashed { // We don't need the data for non-hashed symbols, yet. panic("not supported") } i := uint32(s.SymIdx + uint32(r.NSym()+r.NHashed64def())) return r.BytesAt(r.DataOff(i), r.DataSize(i)) } ndef := uint32(r.NSym() + r.NHashed64def() + r.NHasheddef() + r.NNonpkgdef()) for i := uint32(0); i < ndef; i++ { osym := r.Sym(i) addr := uint64(r.DataOff(i)) if pc < addr || pc >= addr+uint64(osym.Siz()) { continue } var pcfileSym, pclineSym goobj.SymRef for _, a := range r.Auxs(i) { switch a.Type() { case goobj.AuxPcfile: pcfileSym = a.Sym() case goobj.AuxPcline: pclineSym = a.Sym() } } if pcfileSym.IsZero() || pclineSym.IsZero() { continue } pcline := getSymData(pclineSym) line := int(pcValue(pcline, pc-addr, f.arch)) pcfile := getSymData(pcfileSym) fileID := pcValue(pcfile, pc-addr, f.arch) fileName := r.File(int(fileID)) // Note: we provide only the name in the Func structure. // We could provide more if needed. return fileName, line, &gosym.Func{Sym: &gosym.Sym{Name: osym.Name(r)}} } return "", 0, nil } // pcValue looks up the given PC in a pc value table. target is the // offset of the pc from the entry point. func pcValue(tab []byte, target uint64, arch *sys.Arch) int32 { val := int32(-1) var pc uint64 for step(&tab, &pc, &val, pc == 0, arch) { if target < pc { return val } } return -1 } // step advances to the next pc, value pair in the encoded table. func step(p *[]byte, pc *uint64, val *int32, first bool, arch *sys.Arch) bool { uvdelta := readvarint(p) if uvdelta == 0 && !first { return false } if uvdelta&1 != 0 { uvdelta = ^(uvdelta >> 1) } else { uvdelta >>= 1 } vdelta := int32(uvdelta) pcdelta := readvarint(p) * uint32(arch.MinLC) *pc += uint64(pcdelta) *val += vdelta return true } // readvarint reads, removes, and returns a varint from *p. func readvarint(p *[]byte) uint32 { var v, shift uint32 s := *p for shift = 0; ; shift += 7 { b := s[0] s = s[1:] v |= (uint32(b) & 0x7F) << shift if b&0x80 == 0 { break } } *p = s return v } // We treat the whole object file as the text section. func (f *goobjFile) text() (textStart uint64, text []byte, err error) { text = make([]byte, f.goobj.Size) _, err = f.f.ReadAt(text, int64(f.goobj.Offset)) return } func (f *goobjFile) goarch() string { return f.goobj.Arch } func (f *goobjFile) loadAddress() (uint64, error) { return 0, fmt.Errorf("unknown load address") } func (f *goobjFile) dwarf() (*dwarf.Data, error) { return nil, errors.New("no DWARF data in go object file") } PK ! ���* * disasm.gonu �[��� // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package objfile import ( "bufio" "bytes" "container/list" "debug/gosym" "encoding/binary" "fmt" "io" "os" "path/filepath" "regexp" "sort" "strings" "text/tabwriter" "cmd/internal/src" "golang.org/x/arch/arm/armasm" "golang.org/x/arch/arm64/arm64asm" "golang.org/x/arch/ppc64/ppc64asm" "golang.org/x/arch/x86/x86asm" ) // Disasm is a disassembler for a given File. type Disasm struct { syms []Sym //symbols in file, sorted by address pcln Liner // pcln table text []byte // bytes of text segment (actual instructions) textStart uint64 // start PC of text textEnd uint64 // end PC of text goarch string // GOARCH string disasm disasmFunc // disassembler function for goarch byteOrder binary.ByteOrder // byte order for goarch } // Disasm returns a disassembler for the file f. func (e *Entry) Disasm() (*Disasm, error) { syms, err := e.Symbols() if err != nil { return nil, err } pcln, err := e.PCLineTable() if err != nil { return nil, err } textStart, textBytes, err := e.Text() if err != nil { return nil, err } goarch := e.GOARCH() disasm := disasms[goarch] byteOrder := byteOrders[goarch] if disasm == nil || byteOrder == nil { return nil, fmt.Errorf("unsupported architecture") } // Filter out section symbols, overwriting syms in place. keep := syms[:0] for _, sym := range syms { switch sym.Name { case "runtime.text", "text", "_text", "runtime.etext", "etext", "_etext": // drop default: keep = append(keep, sym) } } syms = keep d := &Disasm{ syms: syms, pcln: pcln, text: textBytes, textStart: textStart, textEnd: textStart + uint64(len(textBytes)), goarch: goarch, disasm: disasm, byteOrder: byteOrder, } return d, nil } // lookup finds the symbol name containing addr. func (d *Disasm) lookup(addr uint64) (name string, base uint64) { i := sort.Search(len(d.syms), func(i int) bool { return addr < d.syms[i].Addr }) if i > 0 { s := d.syms[i-1] if s.Addr != 0 && s.Addr <= addr && addr < s.Addr+uint64(s.Size) { return s.Name, s.Addr } } return "", 0 } // base returns the final element in the path. // It works on both Windows and Unix paths, // regardless of host operating system. func base(path string) string { path = path[strings.LastIndex(path, "/")+1:] path = path[strings.LastIndex(path, `\`)+1:] return path } // CachedFile contains the content of a file split into lines. type CachedFile struct { FileName string Lines [][]byte } // FileCache is a simple LRU cache of file contents. type FileCache struct { files *list.List maxLen int } // NewFileCache returns a FileCache which can contain up to maxLen cached file contents. func NewFileCache(maxLen int) *FileCache { return &FileCache{ files: list.New(), maxLen: maxLen, } } // Line returns the source code line for the given file and line number. // If the file is not already cached, reads it, inserts it into the cache, // and removes the least recently used file if necessary. // If the file is in cache, it is moved to the front of the list. func (fc *FileCache) Line(filename string, line int) ([]byte, error) { if filepath.Ext(filename) != ".go" { return nil, nil } // Clean filenames returned by src.Pos.SymFilename() // or src.PosBase.SymFilename() removing // the leading src.FileSymPrefix. filename = strings.TrimPrefix(filename, src.FileSymPrefix) // Expand literal "$GOROOT" rewritten by obj.AbsFile() filename = filepath.Clean(os.ExpandEnv(filename)) var cf *CachedFile var e *list.Element for e = fc.files.Front(); e != nil; e = e.Next() { cf = e.Value.(*CachedFile) if cf.FileName == filename { break } } if e == nil { content, err := os.ReadFile(filename) if err != nil { return nil, err } cf = &CachedFile{ FileName: filename, Lines: bytes.Split(content, []byte{'\n'}), } fc.files.PushFront(cf) if fc.files.Len() >= fc.maxLen { fc.files.Remove(fc.files.Back()) } } else { fc.files.MoveToFront(e) } // because //line directives can be out-of-range. (#36683) if line-1 >= len(cf.Lines) || line-1 < 0 { return nil, nil } return cf.Lines[line-1], nil } // Print prints a disassembly of the file to w. // If filter is non-nil, the disassembly only includes functions with names matching filter. // If printCode is true, the disassembly includs corresponding source lines. // The disassembly only includes functions that overlap the range [start, end). func (d *Disasm) Print(w io.Writer, filter *regexp.Regexp, start, end uint64, printCode bool, gnuAsm bool) { if start < d.textStart { start = d.textStart } if end > d.textEnd { end = d.textEnd } printed := false bw := bufio.NewWriter(w) var fc *FileCache if printCode { fc = NewFileCache(8) } tw := tabwriter.NewWriter(bw, 18, 8, 1, '\t', tabwriter.StripEscape) for _, sym := range d.syms { symStart := sym.Addr symEnd := sym.Addr + uint64(sym.Size) relocs := sym.Relocs if sym.Code != 'T' && sym.Code != 't' || symStart < d.textStart || symEnd <= start || end <= symStart || filter != nil && !filter.MatchString(sym.Name) { continue } if printed { fmt.Fprintf(bw, "\n") } printed = true file, _, _ := d.pcln.PCToLine(sym.Addr) fmt.Fprintf(bw, "TEXT %s(SB) %s\n", sym.Name, file) if symEnd > end { symEnd = end } code := d.text[:end-d.textStart] var lastFile string var lastLine int d.Decode(symStart, symEnd, relocs, gnuAsm, func(pc, size uint64, file string, line int, text string) { i := pc - d.textStart if printCode { if file != lastFile || line != lastLine { if srcLine, err := fc.Line(file, line); err == nil { fmt.Fprintf(tw, "%s%s%s\n", []byte{tabwriter.Escape}, srcLine, []byte{tabwriter.Escape}) } lastFile, lastLine = file, line } fmt.Fprintf(tw, " %#x\t", pc) } else { fmt.Fprintf(tw, " %s:%d\t%#x\t", base(file), line, pc) } if size%4 != 0 || d.goarch == "386" || d.goarch == "amd64" { // Print instruction as bytes. fmt.Fprintf(tw, "%x", code[i:i+size]) } else { // Print instruction as 32-bit words. for j := uint64(0); j < size; j += 4 { if j > 0 { fmt.Fprintf(tw, " ") } fmt.Fprintf(tw, "%08x", d.byteOrder.Uint32(code[i+j:])) } } fmt.Fprintf(tw, "\t%s\t\n", text) }) tw.Flush() } bw.Flush() } // Decode disassembles the text segment range [start, end), calling f for each instruction. func (d *Disasm) Decode(start, end uint64, relocs []Reloc, gnuAsm bool, f func(pc, size uint64, file string, line int, text string)) { if start < d.textStart { start = d.textStart } if end > d.textEnd { end = d.textEnd } code := d.text[:end-d.textStart] lookup := d.lookup for pc := start; pc < end; { i := pc - d.textStart text, size := d.disasm(code[i:], pc, lookup, d.byteOrder, gnuAsm) file, line, _ := d.pcln.PCToLine(pc) sep := "\t" for len(relocs) > 0 && relocs[0].Addr < i+uint64(size) { text += sep + relocs[0].Stringer.String(pc-start) sep = " " relocs = relocs[1:] } f(pc, uint64(size), file, line, text) pc += uint64(size) } } type lookupFunc = func(addr uint64) (sym string, base uint64) type disasmFunc func(code []byte, pc uint64, lookup lookupFunc, ord binary.ByteOrder, _ bool) (text string, size int) func disasm_386(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { return disasm_x86(code, pc, lookup, 32, gnuAsm) } func disasm_amd64(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { return disasm_x86(code, pc, lookup, 64, gnuAsm) } func disasm_x86(code []byte, pc uint64, lookup lookupFunc, arch int, gnuAsm bool) (string, int) { inst, err := x86asm.Decode(code, arch) var text string size := inst.Len if err != nil || size == 0 || inst.Op == 0 { size = 1 text = "?" } else { if gnuAsm { text = fmt.Sprintf("%-36s // %s", x86asm.GoSyntax(inst, pc, lookup), x86asm.GNUSyntax(inst, pc, nil)) } else { text = x86asm.GoSyntax(inst, pc, lookup) } } return text, size } type textReader struct { code []byte pc uint64 } func (r textReader) ReadAt(data []byte, off int64) (n int, err error) { if off < 0 || uint64(off) < r.pc { return 0, io.EOF } d := uint64(off) - r.pc if d >= uint64(len(r.code)) { return 0, io.EOF } n = copy(data, r.code[d:]) if n < len(data) { err = io.ErrUnexpectedEOF } return } func disasm_arm(code []byte, pc uint64, lookup lookupFunc, _ binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := armasm.Decode(code, armasm.ModeARM) var text string size := inst.Len if err != nil || size == 0 || inst.Op == 0 { size = 4 text = "?" } else if gnuAsm { text = fmt.Sprintf("%-36s // %s", armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}), armasm.GNUSyntax(inst)) } else { text = armasm.GoSyntax(inst, pc, lookup, textReader{code, pc}) } return text, size } func disasm_arm64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := arm64asm.Decode(code) var text string if err != nil || inst.Op == 0 { text = "?" } else if gnuAsm { text = fmt.Sprintf("%-36s // %s", arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}), arm64asm.GNUSyntax(inst)) } else { text = arm64asm.GoSyntax(inst, pc, lookup, textReader{code, pc}) } return text, 4 } func disasm_ppc64(code []byte, pc uint64, lookup lookupFunc, byteOrder binary.ByteOrder, gnuAsm bool) (string, int) { inst, err := ppc64asm.Decode(code, byteOrder) var text string size := inst.Len if err != nil || size == 0 { size = 4 text = "?" } else { if gnuAsm { text = fmt.Sprintf("%-36s // %s", ppc64asm.GoSyntax(inst, pc, lookup), ppc64asm.GNUSyntax(inst, pc)) } else { text = ppc64asm.GoSyntax(inst, pc, lookup) } } return text, size } var disasms = map[string]disasmFunc{ "386": disasm_386, "amd64": disasm_amd64, "arm": disasm_arm, "arm64": disasm_arm64, "ppc64": disasm_ppc64, "ppc64le": disasm_ppc64, } var byteOrders = map[string]binary.ByteOrder{ "386": binary.LittleEndian, "amd64": binary.LittleEndian, "arm": binary.LittleEndian, "arm64": binary.LittleEndian, "ppc64": binary.BigEndian, "ppc64le": binary.LittleEndian, "s390x": binary.BigEndian, } type Liner interface { // Given a pc, returns the corresponding file, line, and function data. // If unknown, returns "",0,nil. PCToLine(uint64) (string, int, *gosym.Func) } PK ! _��D D macho.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of Mach-O executables (OS X). package objfile import ( "debug/dwarf" "debug/macho" "fmt" "io" "sort" ) const stabTypeMask = 0xe0 type machoFile struct { macho *macho.File } func openMacho(r io.ReaderAt) (rawFile, error) { f, err := macho.NewFile(r) if err != nil { return nil, err } return &machoFile{f}, nil } func (f *machoFile) symbols() ([]Sym, error) { if f.macho.Symtab == nil { return nil, nil } // Build sorted list of addresses of all symbols. // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 for _, s := range f.macho.Symtab.Syms { // Skip stab debug info. if s.Type&stabTypeMask == 0 { addrs = append(addrs, s.Value) } } sort.Sort(uint64s(addrs)) var syms []Sym for _, s := range f.macho.Symtab.Syms { if s.Type&stabTypeMask != 0 { // Skip stab debug info. continue } sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) if i < len(addrs) { sym.Size = int64(addrs[i] - s.Value) } if s.Sect == 0 { sym.Code = 'U' } else if int(s.Sect) <= len(f.macho.Sections) { sect := f.macho.Sections[s.Sect-1] switch sect.Seg { case "__TEXT", "__DATA_CONST": sym.Code = 'R' case "__DATA": sym.Code = 'D' } switch sect.Seg + " " + sect.Name { case "__TEXT __text": sym.Code = 'T' case "__DATA __bss", "__DATA __noptrbss": sym.Code = 'B' } } syms = append(syms, sym) } return syms, nil } func (f *machoFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { if sect := f.macho.Section("__text"); sect != nil { textStart = sect.Addr } if sect := f.macho.Section("__gosymtab"); sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, err } } if sect := f.macho.Section("__gopclntab"); sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } func (f *machoFile) text() (textStart uint64, text []byte, err error) { sect := f.macho.Section("__text") if sect == nil { return 0, nil, fmt.Errorf("text section not found") } textStart = sect.Addr text, err = sect.Data() return } func (f *machoFile) goarch() string { switch f.macho.Cpu { case macho.Cpu386: return "386" case macho.CpuAmd64: return "amd64" case macho.CpuArm: return "arm" case macho.CpuArm64: return "arm64" case macho.CpuPpc64: return "ppc64" } return "" } type uint64s []uint64 func (x uint64s) Len() int { return len(x) } func (x uint64s) Swap(i, j int) { x[i], x[j] = x[j], x[i] } func (x uint64s) Less(i, j int) bool { return x[i] < x[j] } func (f *machoFile) loadAddress() (uint64, error) { if seg := f.macho.Segment("__TEXT"); seg != nil { return seg.Addr, nil } return 0, fmt.Errorf("unknown load address") } func (f *machoFile) dwarf() (*dwarf.Data, error) { return f.macho.DWARF() } PK ! Wq� � elf.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of ELF executables (Linux, FreeBSD, and so on). package objfile import ( "debug/dwarf" "debug/elf" "encoding/binary" "fmt" "io" ) type elfFile struct { elf *elf.File } func openElf(r io.ReaderAt) (rawFile, error) { f, err := elf.NewFile(r) if err != nil { return nil, err } return &elfFile{f}, nil } func (f *elfFile) symbols() ([]Sym, error) { elfSyms, err := f.elf.Symbols() if err != nil { return nil, err } var syms []Sym for _, s := range elfSyms { sym := Sym{Addr: s.Value, Name: s.Name, Size: int64(s.Size), Code: '?'} switch s.Section { case elf.SHN_UNDEF: sym.Code = 'U' case elf.SHN_COMMON: sym.Code = 'B' default: i := int(s.Section) if i < 0 || i >= len(f.elf.Sections) { break } sect := f.elf.Sections[i] switch sect.Flags & (elf.SHF_WRITE | elf.SHF_ALLOC | elf.SHF_EXECINSTR) { case elf.SHF_ALLOC | elf.SHF_EXECINSTR: sym.Code = 'T' case elf.SHF_ALLOC: sym.Code = 'R' case elf.SHF_ALLOC | elf.SHF_WRITE: sym.Code = 'D' } } if elf.ST_BIND(s.Info) == elf.STB_LOCAL { sym.Code += 'a' - 'A' } syms = append(syms, sym) } return syms, nil } func (f *elfFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { if sect := f.elf.Section(".text"); sect != nil { textStart = sect.Addr } sect := f.elf.Section(".gosymtab") if sect == nil { // try .data.rel.ro.gosymtab, for PIE binaries sect = f.elf.Section(".data.rel.ro.gosymtab") } if sect != nil { if symtab, err = sect.Data(); err != nil { return 0, nil, nil, err } } else { // if both sections failed, try the symbol symtab = f.symbolData("runtime.symtab", "runtime.esymtab") } sect = f.elf.Section(".gopclntab") if sect == nil { // try .data.rel.ro.gopclntab, for PIE binaries sect = f.elf.Section(".data.rel.ro.gopclntab") } if sect != nil { if pclntab, err = sect.Data(); err != nil { return 0, nil, nil, err } } else { // if both sections failed, try the symbol pclntab = f.symbolData("runtime.pclntab", "runtime.epclntab") } return textStart, symtab, pclntab, nil } func (f *elfFile) text() (textStart uint64, text []byte, err error) { sect := f.elf.Section(".text") if sect == nil { return 0, nil, fmt.Errorf("text section not found") } textStart = sect.Addr text, err = sect.Data() return } func (f *elfFile) goarch() string { switch f.elf.Machine { case elf.EM_386: return "386" case elf.EM_X86_64: return "amd64" case elf.EM_ARM: return "arm" case elf.EM_AARCH64: return "arm64" case elf.EM_PPC64: if f.elf.ByteOrder == binary.LittleEndian { return "ppc64le" } return "ppc64" case elf.EM_S390: return "s390x" } return "" } func (f *elfFile) loadAddress() (uint64, error) { for _, p := range f.elf.Progs { if p.Type == elf.PT_LOAD && p.Flags&elf.PF_X != 0 { // The memory mapping that contains the segment // starts at an aligned address. Apparently this // is what pprof expects, as it uses this and the // start address of the mapping to compute PC // delta. return p.Vaddr - p.Vaddr%p.Align, nil } } return 0, fmt.Errorf("unknown load address") } func (f *elfFile) dwarf() (*dwarf.Data, error) { return f.elf.DWARF() } func (f *elfFile) symbolData(start, end string) []byte { elfSyms, err := f.elf.Symbols() if err != nil { return nil } var addr, eaddr uint64 for _, s := range elfSyms { if s.Name == start { addr = s.Value } else if s.Name == end { eaddr = s.Value } if addr != 0 && eaddr != 0 { break } } if addr == 0 || eaddr < addr { return nil } size := eaddr - addr data := make([]byte, size) for _, prog := range f.elf.Progs { if prog.Vaddr <= addr && addr+size-1 <= prog.Vaddr+prog.Filesz-1 { if _, err := prog.ReadAt(data, int64(addr-prog.Vaddr)); err != nil { return nil } return data } } return nil } PK ! �OD8g g pe.gonu �[��� // Copyright 2013 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of PE executables (Microsoft Windows). package objfile import ( "debug/dwarf" "debug/pe" "fmt" "io" "sort" ) type peFile struct { pe *pe.File } func openPE(r io.ReaderAt) (rawFile, error) { f, err := pe.NewFile(r) if err != nil { return nil, err } return &peFile{f}, nil } func (f *peFile) symbols() ([]Sym, error) { // Build sorted list of addresses of all symbols. // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 imageBase, _ := f.imageBase() var syms []Sym for _, s := range f.pe.Symbols { const ( N_UNDEF = 0 // An undefined (extern) symbol N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) N_DEBUG = -2 // A debugging symbol ) sym := Sym{Name: s.Name, Addr: uint64(s.Value), Code: '?'} switch s.SectionNumber { case N_UNDEF: sym.Code = 'U' case N_ABS: sym.Code = 'C' case N_DEBUG: sym.Code = '?' default: if s.SectionNumber < 0 || len(f.pe.Sections) < int(s.SectionNumber) { return nil, fmt.Errorf("invalid section number in symbol table") } sect := f.pe.Sections[s.SectionNumber-1] const ( text = 0x20 data = 0x40 bss = 0x80 permW = 0x80000000 ) ch := sect.Characteristics switch { case ch&text != 0: sym.Code = 'T' case ch&data != 0: if ch&permW == 0 { sym.Code = 'R' } else { sym.Code = 'D' } case ch&bss != 0: sym.Code = 'B' } sym.Addr += imageBase + uint64(sect.VirtualAddress) } syms = append(syms, sym) addrs = append(addrs, sym.Addr) } sort.Sort(uint64s(addrs)) for i := range syms { j := sort.Search(len(addrs), func(x int) bool { return addrs[x] > syms[i].Addr }) if j < len(addrs) { syms[i].Size = int64(addrs[j] - syms[i].Addr) } } return syms, nil } func (f *peFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { imageBase, err := f.imageBase() if err != nil { return 0, nil, nil, err } if sect := f.pe.Section(".text"); sect != nil { textStart = imageBase + uint64(sect.VirtualAddress) } if pclntab, err = loadPETable(f.pe, "runtime.pclntab", "runtime.epclntab"); err != nil { // We didn't find the symbols, so look for the names used in 1.3 and earlier. // TODO: Remove code looking for the old symbols when we no longer care about 1.3. var err2 error if pclntab, err2 = loadPETable(f.pe, "pclntab", "epclntab"); err2 != nil { return 0, nil, nil, err } } if symtab, err = loadPETable(f.pe, "runtime.symtab", "runtime.esymtab"); err != nil { // Same as above. var err2 error if symtab, err2 = loadPETable(f.pe, "symtab", "esymtab"); err2 != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } func (f *peFile) text() (textStart uint64, text []byte, err error) { imageBase, err := f.imageBase() if err != nil { return 0, nil, err } sect := f.pe.Section(".text") if sect == nil { return 0, nil, fmt.Errorf("text section not found") } textStart = imageBase + uint64(sect.VirtualAddress) text, err = sect.Data() return } func findPESymbol(f *pe.File, name string) (*pe.Symbol, error) { for _, s := range f.Symbols { if s.Name != name { continue } if s.SectionNumber <= 0 { return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) } if len(f.Sections) < int(s.SectionNumber) { return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) } return s, nil } return nil, fmt.Errorf("no %s symbol found", name) } func loadPETable(f *pe.File, sname, ename string) ([]byte, error) { ssym, err := findPESymbol(f, sname) if err != nil { return nil, err } esym, err := findPESymbol(f, ename) if err != nil { return nil, err } if ssym.SectionNumber != esym.SectionNumber { return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) } sect := f.Sections[ssym.SectionNumber-1] data, err := sect.Data() if err != nil { return nil, err } return data[ssym.Value:esym.Value], nil } func (f *peFile) goarch() string { switch f.pe.Machine { case pe.IMAGE_FILE_MACHINE_I386: return "386" case pe.IMAGE_FILE_MACHINE_AMD64: return "amd64" case pe.IMAGE_FILE_MACHINE_ARMNT: return "arm" case pe.IMAGE_FILE_MACHINE_ARM64: return "arm64" default: return "" } } func (f *peFile) loadAddress() (uint64, error) { return f.imageBase() } func (f *peFile) imageBase() (uint64, error) { switch oh := f.pe.OptionalHeader.(type) { case *pe.OptionalHeader32: return uint64(oh.ImageBase), nil case *pe.OptionalHeader64: return oh.ImageBase, nil default: return 0, fmt.Errorf("pe file format not recognized") } } func (f *peFile) dwarf() (*dwarf.Data, error) { return f.pe.DWARF() } PK ! ���?� � xcoff.gonu �[��� // Copyright 2018 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of XCOFF executable (AIX) package objfile import ( "debug/dwarf" "fmt" "internal/xcoff" "io" "unicode" ) type xcoffFile struct { xcoff *xcoff.File } func openXcoff(r io.ReaderAt) (rawFile, error) { f, err := xcoff.NewFile(r) if err != nil { return nil, err } return &xcoffFile{f}, nil } func (f *xcoffFile) symbols() ([]Sym, error) { var syms []Sym for _, s := range f.xcoff.Symbols { const ( N_UNDEF = 0 // An undefined (extern) symbol N_ABS = -1 // An absolute symbol (e_value is a constant, not an address) N_DEBUG = -2 // A debugging symbol ) sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'} switch s.SectionNumber { case N_UNDEF: sym.Code = 'U' case N_ABS: sym.Code = 'C' case N_DEBUG: sym.Code = '?' default: if s.SectionNumber < 0 || len(f.xcoff.Sections) < int(s.SectionNumber) { return nil, fmt.Errorf("invalid section number in symbol table") } sect := f.xcoff.Sections[s.SectionNumber-1] // debug/xcoff returns an offset in the section not the actual address sym.Addr += sect.VirtualAddress if s.AuxCSect.SymbolType&0x3 == xcoff.XTY_LD { // The size of a function is contained in the // AUX_FCN entry sym.Size = s.AuxFcn.Size } else { sym.Size = s.AuxCSect.Length } sym.Size = s.AuxCSect.Length switch sect.Type { case xcoff.STYP_TEXT: if s.AuxCSect.StorageMappingClass == xcoff.XMC_RO { sym.Code = 'R' } else { sym.Code = 'T' } case xcoff.STYP_DATA: sym.Code = 'D' case xcoff.STYP_BSS: sym.Code = 'B' } if s.StorageClass == xcoff.C_HIDEXT { // Local symbol sym.Code = unicode.ToLower(sym.Code) } } syms = append(syms, sym) } return syms, nil } func (f *xcoffFile) pcln() (textStart uint64, symtab, pclntab []byte, err error) { if sect := f.xcoff.Section(".text"); sect != nil { textStart = sect.VirtualAddress } if pclntab, err = loadXCOFFTable(f.xcoff, "runtime.pclntab", "runtime.epclntab"); err != nil { return 0, nil, nil, err } symtab, _ = loadXCOFFTable(f.xcoff, "runtime.symtab", "runtime.esymtab") // ignore error, this symbol is not useful anyway return textStart, symtab, pclntab, nil } func (f *xcoffFile) text() (textStart uint64, text []byte, err error) { sect := f.xcoff.Section(".text") if sect == nil { return 0, nil, fmt.Errorf("text section not found") } textStart = sect.VirtualAddress text, err = sect.Data() return } func findXCOFFSymbol(f *xcoff.File, name string) (*xcoff.Symbol, error) { for _, s := range f.Symbols { if s.Name != name { continue } if s.SectionNumber <= 0 { return nil, fmt.Errorf("symbol %s: invalid section number %d", name, s.SectionNumber) } if len(f.Sections) < int(s.SectionNumber) { return nil, fmt.Errorf("symbol %s: section number %d is larger than max %d", name, s.SectionNumber, len(f.Sections)) } return s, nil } return nil, fmt.Errorf("no %s symbol found", name) } func loadXCOFFTable(f *xcoff.File, sname, ename string) ([]byte, error) { ssym, err := findXCOFFSymbol(f, sname) if err != nil { return nil, err } esym, err := findXCOFFSymbol(f, ename) if err != nil { return nil, err } if ssym.SectionNumber != esym.SectionNumber { return nil, fmt.Errorf("%s and %s symbols must be in the same section", sname, ename) } sect := f.Sections[ssym.SectionNumber-1] data, err := sect.Data() if err != nil { return nil, err } return data[ssym.Value:esym.Value], nil } func (f *xcoffFile) goarch() string { switch f.xcoff.TargetMachine { case xcoff.U802TOCMAGIC: return "ppc" case xcoff.U64_TOCMAGIC: return "ppc64" } return "" } func (f *xcoffFile) loadAddress() (uint64, error) { return 0, fmt.Errorf("unknown load address") } func (f *xcoffFile) dwarf() (*dwarf.Data, error) { return f.xcoff.DWARF() } PK ! �c� plan9obj.gonu �[��� // Copyright 2014 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Parsing of Plan 9 a.out executables. package objfile import ( "debug/dwarf" "debug/plan9obj" "errors" "fmt" "io" "sort" ) var validSymType = map[rune]bool{ 'T': true, 't': true, 'D': true, 'd': true, 'B': true, 'b': true, } type plan9File struct { plan9 *plan9obj.File } func openPlan9(r io.ReaderAt) (rawFile, error) { f, err := plan9obj.NewFile(r) if err != nil { return nil, err } return &plan9File{f}, nil } func (f *plan9File) symbols() ([]Sym, error) { plan9Syms, err := f.plan9.Symbols() if err != nil { return nil, err } // Build sorted list of addresses of all symbols. // We infer the size of a symbol by looking at where the next symbol begins. var addrs []uint64 for _, s := range plan9Syms { if !validSymType[s.Type] { continue } addrs = append(addrs, s.Value) } sort.Sort(uint64s(addrs)) var syms []Sym for _, s := range plan9Syms { if !validSymType[s.Type] { continue } sym := Sym{Addr: s.Value, Name: s.Name, Code: s.Type} i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value }) if i < len(addrs) { sym.Size = int64(addrs[i] - s.Value) } syms = append(syms, sym) } return syms, nil } func (f *plan9File) pcln() (textStart uint64, symtab, pclntab []byte, err error) { textStart = f.plan9.LoadAddress + f.plan9.HdrSize if pclntab, err = loadPlan9Table(f.plan9, "runtime.pclntab", "runtime.epclntab"); err != nil { // We didn't find the symbols, so look for the names used in 1.3 and earlier. // TODO: Remove code looking for the old symbols when we no longer care about 1.3. var err2 error if pclntab, err2 = loadPlan9Table(f.plan9, "pclntab", "epclntab"); err2 != nil { return 0, nil, nil, err } } if symtab, err = loadPlan9Table(f.plan9, "runtime.symtab", "runtime.esymtab"); err != nil { // Same as above. var err2 error if symtab, err2 = loadPlan9Table(f.plan9, "symtab", "esymtab"); err2 != nil { return 0, nil, nil, err } } return textStart, symtab, pclntab, nil } func (f *plan9File) text() (textStart uint64, text []byte, err error) { sect := f.plan9.Section("text") if sect == nil { return 0, nil, fmt.Errorf("text section not found") } textStart = f.plan9.LoadAddress + f.plan9.HdrSize text, err = sect.Data() return } func findPlan9Symbol(f *plan9obj.File, name string) (*plan9obj.Sym, error) { syms, err := f.Symbols() if err != nil { return nil, err } for _, s := range syms { if s.Name != name { continue } return &s, nil } return nil, fmt.Errorf("no %s symbol found", name) } func loadPlan9Table(f *plan9obj.File, sname, ename string) ([]byte, error) { ssym, err := findPlan9Symbol(f, sname) if err != nil { return nil, err } esym, err := findPlan9Symbol(f, ename) if err != nil { return nil, err } sect := f.Section("text") if sect == nil { return nil, err } data, err := sect.Data() if err != nil { return nil, err } textStart := f.LoadAddress + f.HdrSize return data[ssym.Value-textStart : esym.Value-textStart], nil } func (f *plan9File) goarch() string { switch f.plan9.Magic { case plan9obj.Magic386: return "386" case plan9obj.MagicAMD64: return "amd64" case plan9obj.MagicARM: return "arm" } return "" } func (f *plan9File) loadAddress() (uint64, error) { return 0, fmt.Errorf("unknown load address") } func (f *plan9File) dwarf() (*dwarf.Data, error) { return nil, errors.New("no DWARF data in Plan 9 file") } PK ! .Z � � objfile.gonu �[��� PK ! ~b^ ^ # goobj.gonu �[��� PK ! ���* * �0 disasm.gonu �[��� PK ! _��D D [ macho.gonu �[��� PK ! Wq� � }g elf.gonu �[��� PK ! �OD8g g uw pe.gonu �[��� PK ! ���?� � � xcoff.gonu �[��� PK ! �c� � plan9obj.gonu �[��� PK A 2�
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0.01 |
proxy
|
phpinfo
|
ÐаÑтройка