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"
|
"os"
|
||||||
|
|
||||||
"github.com/goplus/llgo/xtool/env/llvm"
|
"github.com/goplus/llgo/xtool/env/llvm"
|
||||||
|
nmtool "github.com/goplus/llgo/xtool/nm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if len(os.Args) != 2 {
|
if len(os.Args) < 2 {
|
||||||
fmt.Fprintln(os.Stderr, "Usage: nmdump libfile")
|
fmt.Fprintln(os.Stderr, "Usage: nmdump [flags] libfile")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
nm := llvm.New("").Nm()
|
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 {
|
for _, item := range items {
|
||||||
if item.File != "" {
|
if item.File != "" {
|
||||||
fmt.Printf("\n%s:\n", item.File)
|
fmt.Printf("\n%s:\n", item.File)
|
||||||
}
|
}
|
||||||
for _, sym := range item.Symbols {
|
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 {
|
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 {
|
} 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
|
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.
|
// Symbol represents a symbol in an object file.
|
||||||
type Symbol struct {
|
type Symbol struct {
|
||||||
Name string // symbol name
|
Name string // symbol name
|
||||||
Addr uint64 // symbol address
|
Addr uint64 // symbol address
|
||||||
Type SymbolType // symbol type
|
Type SymbolType // symbol type
|
||||||
FAddr bool // address is valid
|
FAddr bool // address is valid
|
||||||
|
VersionType VersionType // version type of the symbol
|
||||||
|
Version string // version information of the symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
// ObjectFile represents an object file.
|
// ObjectFile represents an object file.
|
||||||
@@ -76,11 +90,20 @@ type ObjectFile struct {
|
|||||||
Symbols []*Symbol // symbols
|
Symbols []*Symbol // symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
// List lists symbols in an archive file.
|
// List lists symbols in an archive file
|
||||||
func (p *Cmd) List(arfile string) (items []*ObjectFile, err error) {
|
// 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 stdout bytes.Buffer
|
||||||
var stderr 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.Stdout = &stdout
|
||||||
cmd.Stderr = &stderr
|
cmd.Stderr = &stderr
|
||||||
e := cmd.Run()
|
e := cmd.Run()
|
||||||
@@ -134,28 +157,48 @@ func listOutput(data []byte) (items []*ObjectFile, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
var sym *Symbol
|
var sym *Symbol
|
||||||
|
var fullSymName string
|
||||||
if is64bits(line) {
|
if is64bits(line) {
|
||||||
|
fullSymName = string(line[19:])
|
||||||
sym = &Symbol{
|
sym = &Symbol{
|
||||||
Name: string(line[19:]),
|
|
||||||
Type: SymbolType(line[17]),
|
Type: SymbolType(line[17]),
|
||||||
}
|
}
|
||||||
if sym.FAddr = hasAddr(line); sym.FAddr {
|
if sym.FAddr = hasAddr(line); sym.FAddr {
|
||||||
sym.Addr = hexUint64(line)
|
sym.Addr = hexUint64(line)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
fullSymName = string(line[11:])
|
||||||
sym = &Symbol{
|
sym = &Symbol{
|
||||||
Name: string(line[11:]),
|
|
||||||
Type: SymbolType(line[9]),
|
Type: SymbolType(line[9]),
|
||||||
}
|
}
|
||||||
if sym.FAddr = hasAddr(line); sym.FAddr {
|
if sym.FAddr = hasAddr(line); sym.FAddr {
|
||||||
sym.Addr = uint64(hexUint32(line))
|
sym.Addr = uint64(hexUint32(line))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sym.Name, sym.VersionType, sym.Version = parseSymName(fullSymName)
|
||||||
item.Symbols = append(item.Symbols, sym)
|
item.Symbols = append(item.Symbols, sym)
|
||||||
}
|
}
|
||||||
return
|
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 {
|
func hasAddr(line []byte) bool {
|
||||||
c := line[0]
|
c := line[0]
|
||||||
return c != ' ' && c != '-'
|
return c != ' ' && c != '-'
|
||||||
|
|||||||
Reference in New Issue
Block a user