Merge pull request #829 from luoliwoshang/xtool/nm
xtool/nm:flags option & symbol version
This commit is contained in:
@@ -22,25 +22,41 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/xtool/env/llvm"
|
||||
nmtool "github.com/goplus/llgo/xtool/nm"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: nmdump libfile")
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: nmdump [flags] libfile")
|
||||
return
|
||||
}
|
||||
|
||||
nm := llvm.New("").Nm()
|
||||
items, err := nm.List(os.Args[1])
|
||||
|
||||
var flags []string
|
||||
libfile := os.Args[len(os.Args)-1]
|
||||
if len(os.Args) > 2 {
|
||||
flags = os.Args[1 : len(os.Args)-1]
|
||||
}
|
||||
|
||||
items, err := nm.List(libfile, flags...)
|
||||
|
||||
for _, item := range items {
|
||||
if item.File != "" {
|
||||
fmt.Printf("\n%s:\n", item.File)
|
||||
}
|
||||
for _, sym := range item.Symbols {
|
||||
var versionInfo string
|
||||
switch sym.VersionType {
|
||||
case nmtool.VersionSpecific:
|
||||
versionInfo = fmt.Sprintf("@%s", sym.Version)
|
||||
case nmtool.VersionDefault:
|
||||
versionInfo = fmt.Sprintf("@@%s", sym.Version)
|
||||
}
|
||||
if sym.FAddr {
|
||||
fmt.Printf("%016x %c %s\n", sym.Addr, sym.Type, sym.Name)
|
||||
fmt.Printf("%016x %c %s%s\n", sym.Addr, sym.Type, sym.Name, versionInfo)
|
||||
} else {
|
||||
fmt.Printf("%16s %c %s\n", "", sym.Type, sym.Name)
|
||||
fmt.Printf("%16s %c %s%s\n", "", sym.Type, sym.Name, versionInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,12 +62,26 @@ const (
|
||||
LocalASym = SymbolType('s') // Local symbol in an assembler source file
|
||||
)
|
||||
|
||||
// VersionType represents the version type of a symbol.
|
||||
// This is specific to Linux systems.
|
||||
// On macOS , this will always be VersionNone.
|
||||
// https://sourceware.org/binutils/docs/binutils/nm.html
|
||||
type VersionType int
|
||||
|
||||
const (
|
||||
VersionNone VersionType = iota // No version information
|
||||
VersionSpecific // Specific version (@)
|
||||
VersionDefault // Default version (@@)
|
||||
)
|
||||
|
||||
// Symbol represents a symbol in an object file.
|
||||
type Symbol struct {
|
||||
Name string // symbol name
|
||||
Addr uint64 // symbol address
|
||||
Type SymbolType // symbol type
|
||||
FAddr bool // address is valid
|
||||
Name string // symbol name
|
||||
Addr uint64 // symbol address
|
||||
Type SymbolType // symbol type
|
||||
FAddr bool // address is valid
|
||||
VersionType VersionType // version type of the symbol
|
||||
Version string // version information of the symbol
|
||||
}
|
||||
|
||||
// ObjectFile represents an object file.
|
||||
@@ -76,11 +90,20 @@ type ObjectFile struct {
|
||||
Symbols []*Symbol // symbols
|
||||
}
|
||||
|
||||
// List lists symbols in an archive file.
|
||||
func (p *Cmd) List(arfile string) (items []*ObjectFile, err error) {
|
||||
// List lists symbols in an archive file
|
||||
// accepts optional nm command flags.
|
||||
// Note: The available flags may vary depending on the operating system.
|
||||
// On Linux, the -D flag is used to display dynamic symbols from the dynamic symbol table.
|
||||
// On macOS, there's no -D flag. The nm command displays all symbols (including dynamic ones) by default.
|
||||
// This difference is due to the distinct ways Linux (using ELF format) and macOS (using Mach-O format)
|
||||
// When working with dynamic libraries:
|
||||
// On Linux: Use 'nm -D /path/to/library.so'
|
||||
// On macOS: Simply use 'nm /path/to/library.dylib'
|
||||
func (p *Cmd) List(arfile string, options ...string) (items []*ObjectFile, err error) {
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
cmd := exec.Command(p.app, arfile)
|
||||
args := append(options, arfile)
|
||||
cmd := exec.Command(p.app, args...)
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
e := cmd.Run()
|
||||
@@ -134,28 +157,48 @@ func listOutput(data []byte) (items []*ObjectFile, err error) {
|
||||
return
|
||||
}
|
||||
var sym *Symbol
|
||||
var fullSymName string
|
||||
if is64bits(line) {
|
||||
fullSymName = string(line[19:])
|
||||
sym = &Symbol{
|
||||
Name: string(line[19:]),
|
||||
Type: SymbolType(line[17]),
|
||||
}
|
||||
if sym.FAddr = hasAddr(line); sym.FAddr {
|
||||
sym.Addr = hexUint64(line)
|
||||
}
|
||||
} else {
|
||||
fullSymName = string(line[11:])
|
||||
sym = &Symbol{
|
||||
Name: string(line[11:]),
|
||||
Type: SymbolType(line[9]),
|
||||
}
|
||||
if sym.FAddr = hasAddr(line); sym.FAddr {
|
||||
sym.Addr = uint64(hexUint32(line))
|
||||
}
|
||||
}
|
||||
|
||||
sym.Name, sym.VersionType, sym.Version = parseSymName(fullSymName)
|
||||
item.Symbols = append(item.Symbols, sym)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func parseSymName(symName string) (name string, versionType VersionType, version string) {
|
||||
if idx := strings.LastIndex(symName, "@"); idx != -1 {
|
||||
name = symName[:idx]
|
||||
version = symName[idx+1:]
|
||||
if idx > 0 && symName[idx-1] == '@' {
|
||||
versionType = VersionDefault
|
||||
name = symName[:idx-1]
|
||||
} else {
|
||||
versionType = VersionSpecific
|
||||
}
|
||||
} else {
|
||||
name = symName
|
||||
versionType = VersionNone
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func hasAddr(line []byte) bool {
|
||||
c := line[0]
|
||||
return c != ' ' && c != '-'
|
||||
|
||||
Reference in New Issue
Block a user