• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

unpackdev / solgo / 8960975808

05 May 2024 08:34PM UTC coverage: 64.769% (-0.3%) from 65.065%
8960975808

push

github

web-flow
Opcode functions and instruction tree + JSON normalization (#210)

245 of 449 new or added lines in 61 files covered. (54.57%)

2 existing lines in 1 file now uncovered.

27471 of 42414 relevant lines covered (64.77%)

0.71 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/opcode/functions.go
1
package opcode
2

3
import (
4
        "fmt"
5
        "github.com/ethereum/go-ethereum/common"
6
)
7

8
// FunctionTreeNode represents a node in the opcode execution tree that represents a function.
9
type FunctionTreeNode struct {
10
        FunctionSignatureHex string `json:"functionSignatureHex"`
11
        FunctionSignature    string `json:"function_signature"`
12
        FunctionBytesHex     string `json:"function_bytes_hex"`
13
        FunctionBytes        []byte `json:"function_bytes"`
14
        HasFunctionSignature bool   `json:"has_function_signature"`
15
        *TreeNode
16
}
17

18
// GetFunctions extracts all functions from the opcode execution tree and returns them as a slice of FunctionTreeNode pointers.
NEW
19
func (d *Decompiler) GetFunctions() []*FunctionTreeNode {
×
NEW
20
        if len(d.instructions) == 0 {
×
NEW
21
                return nil
×
NEW
22
        }
×
23

NEW
24
        var functions []*FunctionTreeNode
×
NEW
25
        stack := []*FunctionTreeNode{nil}
×
NEW
26
        d.buildFunctions(stack, &functions)
×
NEW
27
        return functions
×
28
}
29

30
// buildFunctions traverses the opcode execution tree to identify and extract functions.
NEW
31
func (d *Decompiler) buildFunctions(stack []*FunctionTreeNode, functions *[]*FunctionTreeNode) {
×
NEW
32
        for _, instruction := range d.instructions {
×
NEW
33
                if instruction.OpCode.IsFunctionStart() {
×
NEW
34
                        functionSignatureBytes := d.calculateFunctionSignature(instruction.Offset)
×
NEW
35

×
NEW
36
                        functionSignature := ""
×
NEW
37
                        if len(functionSignatureBytes) >= 4 {
×
NEW
38
                                functionSignature = common.Bytes2Hex(functionSignatureBytes[:4])
×
NEW
39
                        }
×
40

NEW
41
                        functionNode := &FunctionTreeNode{
×
NEW
42
                                FunctionSignature:    functionSignature,
×
NEW
43
                                FunctionSignatureHex: fmt.Sprintf("0x%s", functionSignature),
×
NEW
44
                                FunctionBytesHex:     common.Bytes2Hex(functionSignatureBytes),
×
NEW
45
                                FunctionBytes:        functionSignatureBytes,
×
NEW
46
                                HasFunctionSignature: len(functionSignatureBytes) > 0,
×
NEW
47
                                TreeNode:             &TreeNode{Instruction: instruction, Children: make([]*TreeNode, 0)},
×
NEW
48
                        }
×
NEW
49

×
NEW
50
                        *functions = append(*functions, functionNode)
×
NEW
51
                        stack = append(stack, functionNode)
×
NEW
52
                } else if instruction.OpCode.IsFunctionEnd() {
×
NEW
53
                        if len(stack) == 0 {
×
NEW
54
                                fmt.Println("Error: Found function end without corresponding start.")
×
NEW
55
                                continue
×
56
                        }
NEW
57
                        stack = stack[:len(stack)-1]
×
NEW
58
                } else {
×
NEW
59
                        if len(stack) == 0 {
×
NEW
60
                                fmt.Println("Error: Found instruction outside of a function.")
×
NEW
61
                                continue
×
62
                        }
63

NEW
64
                        if parent := stack[len(stack)-1]; parent != nil {
×
NEW
65
                                parent.Children = append(parent.Children, &TreeNode{Instruction: instruction, Children: make([]*TreeNode, 0)})
×
NEW
66
                        }
×
67
                }
68
        }
69
}
70

71
// calculateFunctionSignature calculates the function signature from the EVM bytecode at the given offset.
NEW
72
func (d *Decompiler) calculateFunctionSignature(offset int) []byte {
×
NEW
73
        var targetInstruction *Instruction
×
NEW
74
        for i := offset - 1; i >= 0; i-- {
×
NEW
75
                if i >= len(d.instructions) {
×
NEW
76
                        break
×
77
                }
NEW
78
                instr := d.instructions[i]
×
NEW
79
                if instr.OpCode == JUMPDEST {
×
NEW
80
                        targetInstruction = &instr
×
NEW
81
                        break
×
82
                }
83
        }
84

NEW
85
        if targetInstruction == nil {
×
NEW
86
                return nil
×
NEW
87
        }
×
88

NEW
89
        var signature []byte
×
NEW
90
        for i := offset; i < len(d.instructions); i++ {
×
NEW
91
                instr := d.instructions[i]
×
NEW
92
                if instr.OpCode.IsPush() && len(instr.Args) == 4 {
×
NEW
93
                        signature = instr.Args
×
NEW
94
                        break
×
95
                }
96
        }
97

NEW
98
        return signature
×
99
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc