mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
bpf: Add logic for verifying whether a program fragment modifies register A.
This is useful for value matching rules which look for the value of the `A` register. If they do not modify this value, then we do not need to reload it between sequential matchers over the same data. PiperOrigin-RevId: 577266390
This commit is contained in:
committed by
gVisor bot
parent
b357d71828
commit
a27a5bc9fd
@@ -187,3 +187,18 @@ func (ins Instruction) JumpOffsets() []JumpOffset {
|
||||
}
|
||||
return []JumpOffset{{JumpDirect, ins.K}}
|
||||
}
|
||||
|
||||
// ModifiesRegisterA returns true iff this instruction modifies the value
|
||||
// of the "A" register.
|
||||
func (ins Instruction) ModifiesRegisterA() bool {
|
||||
switch ins.OpCode & instructionClassMask {
|
||||
case Ld:
|
||||
return true
|
||||
case Alu:
|
||||
return true
|
||||
case Misc:
|
||||
return ins.OpCode == Misc|Tax
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,3 +352,16 @@ func (f ProgramFragment) Outcomes() FragmentOutcomes {
|
||||
}
|
||||
return outcomes
|
||||
}
|
||||
|
||||
// MayModifyRegisterA returns whether this fragment may modify register A.
|
||||
// A value of "true" does not necessarily mean that A *will* be modified,
|
||||
// as the control flow of this fragment may skip over instructions that
|
||||
// modify the A register.
|
||||
func (f ProgramFragment) MayModifyRegisterA() bool {
|
||||
for pc := f.fromPC; pc < f.toPC; pc++ {
|
||||
if f.b.instructions[pc].ModifiesRegisterA() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -439,3 +439,39 @@ func TestProgramBuilderOutcomes(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProgramBuilderMayModifyRegisterA(t *testing.T) {
|
||||
t.Run("empty program", func(t *testing.T) {
|
||||
if got := NewProgramBuilder().Record()().MayModifyRegisterA(); got != false {
|
||||
t.Errorf("MayModifyRegisterA: got %v want %v", got, false)
|
||||
}
|
||||
})
|
||||
t.Run("does not modify register A", func(t *testing.T) {
|
||||
b := NewProgramBuilder()
|
||||
stop := b.Record()
|
||||
b.AddJump(Jmp|Ja, 0, 0, 0)
|
||||
b.AddJump(Jmp|Jeq|K, 0, 0, 0)
|
||||
b.AddStmt(Misc|Txa, 0)
|
||||
b.AddStmt(Ret|K, 1337)
|
||||
if got := stop().MayModifyRegisterA(); got != false {
|
||||
t.Errorf("MayModifyRegisterA: got %v want %v", got, false)
|
||||
}
|
||||
})
|
||||
for _, ins := range []Instruction{
|
||||
Stmt(Ld|Abs|W, 0),
|
||||
Stmt(Alu|Neg, 0),
|
||||
Stmt(Misc|Tax, 0),
|
||||
} {
|
||||
t.Run(fmt.Sprintf("modifies register A via %v", ins), func(t *testing.T) {
|
||||
b := NewProgramBuilder()
|
||||
stop := b.Record()
|
||||
b.AddJump(Jmp|Ja, 0, 0, 0)
|
||||
b.AddJump(Jmp|Jeq|K, 0, 0, 0)
|
||||
b.AddStmt(ins.OpCode, ins.K)
|
||||
b.AddStmt(Ret|K, 1337)
|
||||
if got := stop().MayModifyRegisterA(); got != true {
|
||||
t.Errorf("MayModifyRegisterA: got %v want %v", got, true)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user