github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/cmd/h2ll/ll.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "os" 6 "os/exec" 7 "strings" 8 9 "github.com/decomp/exp/bin" 10 "github.com/llir/llvm/asm" 11 "github.com/llir/llvm/ir" 12 "github.com/llir/llvm/ir/metadata" 13 "github.com/pkg/errors" 14 ) 15 16 // llFuncSigs translates the given function signatures from C to LLVM IR. 17 func llFuncSigs(module *ir.Module, sigs map[bin.Address]FuncSig, funcAddrs []bin.Address) ([]*ir.Func, error) { 18 var funcs []*ir.Func 19 nameToFunc := make(map[string]*ir.Func) 20 for _, f := range module.Funcs { 21 if _, ok := nameToFunc[f.GlobalName]; ok { 22 return nil, errors.Errorf("function name %q already present", f.Ident()) 23 } 24 nameToFunc[f.GlobalName] = f 25 } 26 for _, funcAddr := range funcAddrs { 27 sig := sigs[funcAddr] 28 f, ok := locateFunc(sig.Name, nameToFunc) 29 if !ok { 30 return nil, errors.Errorf("unable to locate function %q", sig.Name) 31 } 32 f.Blocks = nil 33 md := &metadata.Attachment{ 34 Name: "addr", 35 Node: &metadata.Tuple{ 36 Fields: []metadata.Field{&metadata.String{Value: funcAddr.String()}}, 37 }, 38 } 39 f.Metadata = append(f.Metadata, md) 40 funcs = append(funcs, f) 41 } 42 return funcs, nil 43 } 44 45 // locateFunc locates the named function. 46 func locateFunc(funcName string, nameToFunc map[string]*ir.Func) (*ir.Func, bool) { 47 // IDA may include _imp prefix to imports. 48 // 49 // a: ExitProcess 50 // b: __imp_ExitProcess 51 if strings.HasPrefix(funcName, "__imp_") { 52 if f, ok := nameToFunc[funcName[len("__imp_"):]]; ok { 53 return f, true 54 } 55 } 56 57 // IDA seems to ignore a leading underscore in function names when printing 58 // the function signature. 59 // 60 // a: _crt_cpp_init 61 // b: crt_cpp_init 62 if strings.HasPrefix(funcName, "_") { 63 if f, ok := nameToFunc[funcName[len("_"):]]; ok { 64 return f, true 65 } 66 } 67 if f, ok := nameToFunc[funcName]; ok { 68 return f, true 69 } 70 // TODO: Fix handling of constructors and destructors. 71 switch funcName { 72 case "??1type_info@@UAE@XZ": 73 return locateFunc("type_info_create", nameToFunc) 74 case "??_Gtype_info@@UAEPAXI@Z": 75 return locateFunc("type_info_delete", nameToFunc) 76 } 77 // a: WinMain 78 // b: _WinMain@16 79 if pos := strings.IndexAny(funcName, "@"); pos != -1 { 80 return locateFunc(funcName[:pos], nameToFunc) 81 } 82 return nil, false 83 } 84 85 // compile compiles the given C source into LLVM IR. 86 func compile(input string) (*ir.Module, error) { 87 out := &bytes.Buffer{} 88 cmd := exec.Command("clang", "-m32", "-S", "-emit-llvm", "-x", "c", "-Wno-return-type", "-Wno-invalid-noreturn", "-o", "-", "-") 89 cmd.Stdin = strings.NewReader(input) 90 cmd.Stdout = out 91 cmd.Stderr = os.Stderr 92 if err := cmd.Run(); err != nil { 93 return nil, errors.WithStack(err) 94 } 95 module, err := asm.ParseBytes("<stdin>", out.Bytes()) 96 if err != nil { 97 return nil, errors.WithStack(err) 98 } 99 return module, nil 100 }