DWARF CFI: use a stack for restore/remember opcodes (#3480)
Implementing the `DW_CFA_remember_state` and `DW_CFA_restore_state` according to the DWARF specification requires us to create a stack that can store an arbitrary number of elements, that is, there could be multiple "pushes" before "popping" them. From the 5th revision of the spec [0]: > 6.4.2.4 Row State Instructions > DW_CFA_remember_state > The DW_CFA_remember_state instruction takes no operands. The required > action is to push the set of rules for every register onto an implicit stack. > DW_CFA_restore_state > DW_CFA_restore_state > The DW_CFA_restore_state instruction takes no operands. The required action > is to pop the set of rules off the implicit stack and place them in the > current row. - [0]: https://dwarfstd.org/doc/DWARF5.pdf Signed-off-by: Francisco Javier Honduvilla Coto <javierhonduco@gmail.com>
This commit is contained in:
parent
789f8b4054
commit
908876d6aa
@ -18,18 +18,46 @@ type DWRule struct {
|
|||||||
|
|
||||||
// FrameContext wrapper of FDE context
|
// FrameContext wrapper of FDE context
|
||||||
type FrameContext struct {
|
type FrameContext struct {
|
||||||
loc uint64
|
loc uint64
|
||||||
order binary.ByteOrder
|
order binary.ByteOrder
|
||||||
address uint64
|
address uint64
|
||||||
CFA DWRule
|
CFA DWRule
|
||||||
Regs map[uint64]DWRule
|
Regs map[uint64]DWRule
|
||||||
initialRegs map[uint64]DWRule
|
initialRegs map[uint64]DWRule
|
||||||
prevRegs map[uint64]DWRule
|
buf *bytes.Buffer
|
||||||
buf *bytes.Buffer
|
cie *CommonInformationEntry
|
||||||
cie *CommonInformationEntry
|
RetAddrReg uint64
|
||||||
RetAddrReg uint64
|
codeAlignment uint64
|
||||||
codeAlignment uint64
|
dataAlignment int64
|
||||||
dataAlignment int64
|
rememberedState *stateStack
|
||||||
|
}
|
||||||
|
|
||||||
|
type rowState struct {
|
||||||
|
cfa DWRule
|
||||||
|
regs map[uint64]DWRule
|
||||||
|
}
|
||||||
|
|
||||||
|
// stateStack is a stack where `DW_CFA_remember_state` pushes
|
||||||
|
// its CFA and registers state and `DW_CFA_restore_state`
|
||||||
|
// pops them.
|
||||||
|
type stateStack struct {
|
||||||
|
items []rowState
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStateStack() *stateStack {
|
||||||
|
return &stateStack{
|
||||||
|
items: make([]rowState, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stack *stateStack) push(state rowState) {
|
||||||
|
stack.items = append(stack.items, state)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (stack *stateStack) pop() rowState {
|
||||||
|
restored := stack.items[len(stack.items)-1]
|
||||||
|
stack.items = stack.items[0 : len(stack.items)-1]
|
||||||
|
return restored
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instructions used to recreate the table from the .debug_frame data.
|
// Instructions used to recreate the table from the .debug_frame data.
|
||||||
@ -119,14 +147,14 @@ func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
|
|||||||
initialInstructions := make([]byte, len(cie.InitialInstructions))
|
initialInstructions := make([]byte, len(cie.InitialInstructions))
|
||||||
copy(initialInstructions, cie.InitialInstructions)
|
copy(initialInstructions, cie.InitialInstructions)
|
||||||
frame := &FrameContext{
|
frame := &FrameContext{
|
||||||
cie: cie,
|
cie: cie,
|
||||||
Regs: make(map[uint64]DWRule),
|
Regs: make(map[uint64]DWRule),
|
||||||
RetAddrReg: cie.ReturnAddressRegister,
|
RetAddrReg: cie.ReturnAddressRegister,
|
||||||
initialRegs: make(map[uint64]DWRule),
|
initialRegs: make(map[uint64]DWRule),
|
||||||
prevRegs: make(map[uint64]DWRule),
|
codeAlignment: cie.CodeAlignmentFactor,
|
||||||
codeAlignment: cie.CodeAlignmentFactor,
|
dataAlignment: cie.DataAlignmentFactor,
|
||||||
dataAlignment: cie.DataAlignmentFactor,
|
buf: bytes.NewBuffer(initialInstructions),
|
||||||
buf: bytes.NewBuffer(initialInstructions),
|
rememberedState: newStateStack(),
|
||||||
}
|
}
|
||||||
|
|
||||||
frame.executeDwarfProgram()
|
frame.executeDwarfProgram()
|
||||||
@ -308,11 +336,18 @@ func register(frame *FrameContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func rememberstate(frame *FrameContext) {
|
func rememberstate(frame *FrameContext) {
|
||||||
frame.prevRegs = frame.Regs
|
clonedRegs := make(map[uint64]DWRule, len(frame.Regs))
|
||||||
|
for k, v := range frame.Regs {
|
||||||
|
clonedRegs[k] = v
|
||||||
|
}
|
||||||
|
frame.rememberedState.push(rowState{cfa: frame.CFA, regs: clonedRegs})
|
||||||
}
|
}
|
||||||
|
|
||||||
func restorestate(frame *FrameContext) {
|
func restorestate(frame *FrameContext) {
|
||||||
frame.Regs = frame.prevRegs
|
restored := frame.rememberedState.pop()
|
||||||
|
|
||||||
|
frame.CFA = restored.cfa
|
||||||
|
frame.Regs = restored.regs
|
||||||
}
|
}
|
||||||
|
|
||||||
func restoreextended(frame *FrameContext) {
|
func restoreextended(frame *FrameContext) {
|
||||||
|
Loading…
Reference in New Issue
Block a user