github.com/decomp/exp@v0.0.0-20210624183419-6d058f5e1da6/cmd/bin2c/func.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	dbg "fmt"
     6  	"go/ast"
     7  	"go/printer"
     8  	"go/token"
     9  	"os"
    10  
    11  	"github.com/mewkiz/pkg/errutil"
    12  	"golang.org/x/arch/x86/x86asm"
    13  )
    14  
    15  // parseFunc parses the given function and returns a corresponding Go function.
    16  func parseFunc(text []byte, offset int) (*ast.FuncDecl, error) {
    17  	fn := &ast.FuncDecl{
    18  		Name: getLabel("sub", offset),
    19  		Type: &ast.FuncType{},
    20  		Body: new(ast.BlockStmt),
    21  	}
    22  
    23  	for {
    24  		// Decode instruction.
    25  		inst, err := x86asm.Decode(text[offset:], 32)
    26  		if err != nil {
    27  			return nil, errutil.Err(err)
    28  		}
    29  		dbg.Println("==================================")
    30  		dbg.Println("inst:", inst)
    31  
    32  		// Parse instruction.
    33  		stmt, err := parseInst(inst, offset)
    34  		if err != nil {
    35  			return nil, errutil.Err(err)
    36  		}
    37  		if stmt != nil {
    38  			// Access the underlying statement list of the block statement.
    39  			if block, ok := stmt.(*ast.BlockStmt); ok {
    40  				label := getLabel("loc", offset)
    41  				stmt = block.List[0]
    42  				stmt = &ast.LabeledStmt{Label: label, Stmt: stmt}
    43  				block.List[0] = stmt
    44  				fn.Body.List = append(fn.Body.List, block.List...)
    45  				for _, stmt := range block.List {
    46  					dbg.Println("stmt:", stmt)
    47  					//ast.Print(token.NewFileSet(), stmt)
    48  					printer.Fprint(os.Stderr, token.NewFileSet(), stmt)
    49  					dbg.Println()
    50  				}
    51  			} else {
    52  				label := getLabel("loc", offset)
    53  				stmt = &ast.LabeledStmt{Label: label, Stmt: stmt}
    54  				fn.Body.List = append(fn.Body.List, stmt)
    55  				dbg.Println("stmt:", stmt)
    56  				//ast.Print(token.NewFileSet(), stmt)
    57  				printer.Fprint(os.Stderr, token.NewFileSet(), stmt)
    58  				dbg.Println()
    59  			}
    60  		}
    61  		dbg.Println()
    62  
    63  		// Next.
    64  		offset += inst.Len
    65  		if inst.Op == x86asm.RET {
    66  			break
    67  		}
    68  	}
    69  
    70  	return fn, nil
    71  }
    72  
    73  // labels maps from offset to label identifiers.
    74  var labels = map[int]*ast.Ident{}
    75  
    76  // getLabel returns the label with the given prefix and at the given offset.
    77  func getLabel(prefix string, offset int) *ast.Ident {
    78  	if label, ok := labels[offset]; ok {
    79  		return label
    80  	}
    81  	addr := baseAddr + offset
    82  	name := fmt.Sprintf("%s_%X", prefix, addr)
    83  	label := ast.NewIdent(name)
    84  	labels[offset] = label
    85  	return label
    86  }