/
analysis.go
84 lines (71 loc) · 2.54 KB
/
analysis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package runtime
import (
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/holiman/uint256"
)
// Destinations 存储合约以及代码对应的位向量对象
// Key为代码哈希,Value为对应的合约代码的位向量
// JUMPDEST指令会使用此对象进行跳转位置判断
type Destinations map[common.Hash]bitvec
// Has 检查PC只想的代码是否存在JUMPDEST指令,并且跳转目标有效
func (d Destinations) Has(codehash common.Hash, code []byte, dest *uint256.Int) bool {
// 首先需要检查PC(指令指针),它不可能比代码长度还大,也不可能大于63位
// 注意,这里的参数dest就是PC指针
udest, overflow := dest.Uint64WithOverflow()
// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
// Don't bother checking for JUMPDEST in that case.
if overflow || udest >= uint64(len(code)) {
return false
}
// 查看丢应代码是否已经解析,如果没有则,立即执行解析
m, analysed := d[codehash]
if !analysed {
m = codeBitmap(code)
d[codehash] = m
}
// PC跳转位置,并且跳转的目的地为有效代码段
return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest)
}
// 位向量,未设置的位表示操作码,设置的位表示数据
type bitvec []byte
func (bits *bitvec) set(pos uint64) {
(*bits)[pos/8] |= 0x80 >> (pos % 8)
}
func (bits *bitvec) set8(pos uint64) {
(*bits)[pos/8] |= 0xFF >> (pos % 8)
(*bits)[pos/8+1] |= ^(0xFF >> (pos % 8))
}
// 检查pos对应的位置是否为有效代码段开始
func (bits *bitvec) codeSegment(pos uint64) bool {
return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0
}
// 检查区分代码中的指令和数据,并将数据位置1
func codeBitmap(code []byte) bitvec {
// bitmap长度会多加上4,避免代码以push32结束(这种情况下需要在最后设置4个byte,也就是32个位)
//
bits := make(bitvec, len(code)/8+1+4)
for pc := uint64(0); pc < uint64(len(code)); {
op := OpCode(code[pc])
// 从PUSH1到PUSH32的指令是连续的数字,下面才能这样处理
if op >= PUSH1 && op <= PUSH32 {
numbits := op - PUSH1 + 1
pc++
// 最小按照每8位进行设置
for ; numbits >= 8; numbits -= 8 {
bits.set8(pc) // 8
pc += 8
}
// 然后再设置剩余的不足8位的bit
for ; numbits > 0; numbits-- {
bits.set(pc)
pc++
}
} else {
pc++
}
}
return bits
}