From adacbd262bdead7f30f1beba0fedfa515e4aa7e2 Mon Sep 17 00:00:00 2001 From: xushiwei Date: Sat, 20 Apr 2024 00:44:36 +0800 Subject: [PATCH] nmindex --- chore/nmindex/nmindex.go | 79 ++++++++++++++++++++++++++++++++++++ x/env/llvm/llvm.go | 45 +++++++++++++++++++++ x/nm/index.go | 86 ++++++++++++++++++++++++++++++++++++++++ x/nm/nm.go | 1 + 4 files changed, 211 insertions(+) create mode 100644 chore/nmindex/nmindex.go create mode 100644 x/env/llvm/llvm.go create mode 100644 x/nm/index.go diff --git a/chore/nmindex/nmindex.go b/chore/nmindex/nmindex.go new file mode 100644 index 00000000..7337467a --- /dev/null +++ b/chore/nmindex/nmindex.go @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package main + +import ( + "fmt" + "os" + + "github.com/goplus/llgo/x/env/llvm" + "github.com/goplus/llgo/x/nm" +) + +func main() { + if len(os.Args) < 2 { + fmt.Fprint(os.Stderr, `Usage: + nmindex [arguments] + +The commands are: + + mk Create index file + q Query a symbol + +`) + return + } + + cmd := os.Args[1] + switch cmd { + case "mk": + makeIndex() + case "q": + query() + default: + fmt.Fprintf(os.Stderr, "unknown command: %s\n", cmd) + } +} + +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) + idxDir := home + "/.llgo/nmindex" + os.MkdirAll(idxDir, 0755) + + b := nm.NewIndexBuilder(env.Nm()) + err = b.Index(env.Root()+"/lib", idxDir, func(path string) { + fmt.Println("==>", path) + }) + check(err) +} + +func query() { + panic("todo") +} + +func check(err error) { + if err != nil { + panic(err) + } +} diff --git a/x/env/llvm/llvm.go b/x/env/llvm/llvm.go new file mode 100644 index 00000000..0013fb3e --- /dev/null +++ b/x/env/llvm/llvm.go @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package llvm + +import ( + "os" + + "github.com/goplus/llgo/x/nm" +) + +type Env struct { + root string + nmprefix string +} + +func New() *Env { + var nmprefix string + var root = os.Getenv("LLGO_LLVM_ROOT") + if root != "" { + nmprefix = root + "/bin/llvm-" + } + return &Env{root, nmprefix} +} + +func (p *Env) Root() string { + return p.root +} + +func (p *Env) Nm() *nm.Cmd { + return nm.New(p.nmprefix + "nm") +} diff --git a/x/nm/index.go b/x/nm/index.go new file mode 100644 index 00000000..bbdecca6 --- /dev/null +++ b/x/nm/index.go @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package nm + +import ( + "bytes" + "log" + "os" + "path/filepath" + "strings" +) + +type IndexBuilder struct { + nm *Cmd +} + +func NewIndexBuilder(nm *Cmd) *IndexBuilder { + return &IndexBuilder{nm} +} + +func (p *IndexBuilder) Index(fromDir, toDir string, progress func(path string)) (err error) { + return filepath.WalkDir(fromDir, func(path string, d os.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + fname := d.Name() + switch filepath.Ext(fname) { + case ".a", ".dylib", ".so", ".dll", ".lib": + progress(path) + outFile := filepath.Join(toDir, strings.TrimPrefix(fname, "lib")+".pub") + e := p.IndexFile(path, outFile) + if e != nil { + log.Println(e) + } + } + return nil + }) +} + +func (p *IndexBuilder) IndexFile(arFile, outFile string) (err error) { + items, err := p.nm.List(arFile) + if err != nil { + return + } + var b bytes.Buffer + b.WriteString("file ") + b.WriteString(arFile) + b.WriteByte('\n') + nbase := b.Len() + for _, item := range items { + for _, sym := range item.Symbols { + switch sym.Type { + case Text, Data, BSS, Rodata, 'S': + b.WriteByte(byte(sym.Type)) + b.WriteByte(' ') + b.WriteString(sym.Name) + b.WriteByte('\n') + case Undefined, LocalText, LocalData, LocalBSS, LocalASym, 'I', 'i', 'a': + default: + log.Printf("unknown symbol type %c: %s\n", sym.Type, sym.Name) + } + } + } + buf := b.Bytes() + if len(buf) <= nbase { + return + } + return os.WriteFile(outFile, buf, 0666) +} diff --git a/x/nm/nm.go b/x/nm/nm.go index 99c7d65d..35454a9c 100644 --- a/x/nm/nm.go +++ b/x/nm/nm.go @@ -58,6 +58,7 @@ const ( LocalText = SymbolType('t') // Local text (code) section symbol LocalData = SymbolType('d') // Local data (local var) section symbol LocalBSS = SymbolType('b') // Local BSS (uninitialized local var) section symbol + LocalASym = SymbolType('s') // Local symbol in an assembler source file ) // Symbol represents a symbol in an object file.