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
@ -24,12 +24,40 @@ type FrameContext struct {
|
||||
CFA DWRule
|
||||
Regs map[uint64]DWRule
|
||||
initialRegs map[uint64]DWRule
|
||||
prevRegs map[uint64]DWRule
|
||||
buf *bytes.Buffer
|
||||
cie *CommonInformationEntry
|
||||
RetAddrReg uint64
|
||||
codeAlignment uint64
|
||||
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.
|
||||
@ -123,10 +151,10 @@ func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
|
||||
Regs: make(map[uint64]DWRule),
|
||||
RetAddrReg: cie.ReturnAddressRegister,
|
||||
initialRegs: make(map[uint64]DWRule),
|
||||
prevRegs: make(map[uint64]DWRule),
|
||||
codeAlignment: cie.CodeAlignmentFactor,
|
||||
dataAlignment: cie.DataAlignmentFactor,
|
||||
buf: bytes.NewBuffer(initialInstructions),
|
||||
rememberedState: newStateStack(),
|
||||
}
|
||||
|
||||
frame.executeDwarfProgram()
|
||||
@ -308,11 +336,18 @@ func register(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) {
|
||||
frame.Regs = frame.prevRegs
|
||||
restored := frame.rememberedState.pop()
|
||||
|
||||
frame.CFA = restored.cfa
|
||||
frame.Regs = restored.regs
|
||||
}
|
||||
|
||||
func restoreextended(frame *FrameContext) {
|
||||
|
Loading…
Reference in New Issue
Block a user