From 0e0054779bcabbc4f5c2796e4f6479b2a251df39 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 20 Apr 2024 09:55:43 +0800 Subject: [PATCH] nmindex: support 32bits && multiple directories --- chore/nmindex/nmindex.go | 27 +++++++++++++++++---- x/nm/index.go | 34 +++++++++++++++++++++++---- x/nm/nm.go | 51 ++++++++++++++++++++++++++++++++++------ 3 files changed, 96 insertions(+), 16 deletions(-) diff --git a/chore/nmindex/nmindex.go b/chore/nmindex/nmindex.go index 7337467a..afeffef5 100644 --- a/chore/nmindex/nmindex.go +++ b/chore/nmindex/nmindex.go @@ -51,10 +51,6 @@ The commands are: func makeIndex() { env := llvm.New() - if env.Root() == "" { - fmt.Fprintln(os.Stderr, "Please set LLGO_LLVM_ROOT first.") - return - } home, err := os.UserHomeDir() check(err) @@ -62,7 +58,13 @@ func makeIndex() { os.MkdirAll(idxDir, 0755) b := nm.NewIndexBuilder(env.Nm()) - err = b.Index(env.Root()+"/lib", idxDir, func(path string) { + libDirs := []string{ + usrLib(false), + usrLib(true), + stdLib("LLGO_STDROOT"), + stdLib("LLGO_USRROOT"), + } + err = b.Index(libDirs, idxDir, func(path string) { fmt.Println("==>", path) }) check(err) @@ -72,6 +74,21 @@ func query() { panic("todo") } +func stdLib(where string) string { + dir := os.Getenv(where) + if dir != "" { + dir += "/lib" + } + return dir +} + +func usrLib(local bool) string { + if local { + return "/usr/local/lib" + } + return "/usr/lib" +} + func check(err error) { if err != nil { panic(err) diff --git a/x/nm/index.go b/x/nm/index.go index bbdecca6..4f6f859b 100644 --- a/x/nm/index.go +++ b/x/nm/index.go @@ -18,6 +18,8 @@ package nm import ( "bytes" + "crypto/md5" + "encoding/base64" "log" "os" "path/filepath" @@ -32,7 +34,24 @@ func NewIndexBuilder(nm *Cmd) *IndexBuilder { return &IndexBuilder{nm} } -func (p *IndexBuilder) Index(fromDir, toDir string, progress func(path string)) (err error) { +func (p *IndexBuilder) Index(fromDir []string, toDir string, progress func(path string)) error { + for _, dir := range fromDir { + if dir == "" { + continue + } + if e := p.IndexDir(dir, toDir, progress); e != nil { + if !os.IsNotExist(e) { + log.Println(e) + } + } + } + return nil +} + +func (p *IndexBuilder) IndexDir(fromDir, toDir string, progress func(path string)) error { + if abs, e := filepath.Abs(fromDir); e == nil { + fromDir = abs + } return filepath.WalkDir(fromDir, func(path string, d os.DirEntry, err error) error { if err != nil { return err @@ -44,7 +63,9 @@ func (p *IndexBuilder) Index(fromDir, toDir string, progress func(path string)) switch filepath.Ext(fname) { case ".a", ".dylib", ".so", ".dll", ".lib": progress(path) - outFile := filepath.Join(toDir, strings.TrimPrefix(fname, "lib")+".pub") + hash := md5.Sum([]byte(path)) + hashStr := base64.RawURLEncoding.EncodeToString(hash[:]) + outFile := filepath.Join(toDir, strings.TrimPrefix(fname, "lib")+hashStr+".pub") e := p.IndexFile(path, outFile) if e != nil { log.Println(e) @@ -67,12 +88,17 @@ func (p *IndexBuilder) IndexFile(arFile, outFile string) (err error) { for _, item := range items { for _, sym := range item.Symbols { switch sym.Type { - case Text, Data, BSS, Rodata, 'S': + case Text, Data, BSS, Rodata, 'S', 'C', 'W', 'A': b.WriteByte(byte(sym.Type)) b.WriteByte(' ') b.WriteString(sym.Name) b.WriteByte('\n') - case Undefined, LocalText, LocalData, LocalBSS, LocalASym, 'I', 'i', 'a': + case Undefined, LocalText, LocalData, LocalBSS, LocalASym, 'I', 'i', 'a', 'w': + /* + if sym.Type != Undefined && strings.Contains(sym.Name, "fprintf") { + log.Printf("skip symbol type %c: %s\n", sym.Type, sym.Name) + } + */ default: log.Printf("unknown symbol type %c: %s\n", sym.Type, sym.Name) } diff --git a/x/nm/nm.go b/x/nm/nm.go index 35454a9c..90f0b4b1 100644 --- a/x/nm/nm.go +++ b/x/nm/nm.go @@ -19,6 +19,7 @@ package nm import ( "bytes" "errors" + "fmt" "os" "os/exec" "strings" @@ -109,23 +110,47 @@ func listOutput(data []byte) (items []*ObjectFile, err error) { err = errInvalidOutput return } - if len(line) < 19 { + if len(line) < 10 { err = errInvalidOutput return } - sym := &Symbol{ - Name: string(line[19:]), - Type: SymbolType(line[17]), - } - if sym.FAddr = line[0] != ' '; sym.FAddr { - sym.Addr = hexUint64(line) + var sym *Symbol + if is64bits(line) { + sym = &Symbol{ + Name: string(line[19:]), + Type: SymbolType(line[17]), + } + if sym.FAddr = line[0] != ' '; sym.FAddr { + sym.Addr = hexUint64(line) + } + } else { + sym = &Symbol{ + Name: string(line[11:]), + Type: SymbolType(line[9]), + } + if sym.FAddr = line[0] != ' '; sym.FAddr { + sym.Addr = uint64(hexUint32(line)) + } } item.Symbols = append(item.Symbols, sym) } return } +func is64bits(line []byte) bool { + if line[0] != ' ' { + return line[8] != ' ' + } + return line[9] == ' ' +} + func hexUint64(b []byte) uint64 { + defer func() { + if e := recover(); e != nil { + fmt.Fprintln(os.Stderr, "-->", string(b)) + panic(e) + } + }() _ = b[15] // bounds check hint to compiler; see golang.org/issue/14808 return hex(b[15]) | hex(b[14])<<4 | hex(b[13])<<8 | hex(b[12])<<12 | hex(b[11])<<16 | hex(b[10])<<20 | hex(b[9])<<24 | hex(b[8])<<28 | @@ -133,6 +158,18 @@ func hexUint64(b []byte) uint64 { hex(b[3])<<48 | hex(b[2])<<52 | hex(b[1])<<56 | hex(b[0])<<60 } +func hexUint32(b []byte) uint64 { + defer func() { + if e := recover(); e != nil { + fmt.Fprintln(os.Stderr, "-->", string(b)) + panic(e) + } + }() + _ = b[7] // bounds check hint to compiler; see golang.org/issue/14808 + return hex(b[7]) | hex(b[6])<<4 | hex(b[5])<<8 | hex(b[4])<<12 | + hex(b[3])<<16 | hex(b[2])<<20 | hex(b[1])<<24 | hex(b[0])<<28 +} + func hex(b byte) uint64 { return hexTable[b] }