dwarf/frame: handle unknown opcodes more gracefully (#4037)

Instead of panic'ing on unknown opcodes (there are a few around which
gdb handles) report an error and continue as if the FDE did not exist.

Fixes #4035
This commit is contained in:
Alessandro Arzilli
2025-06-25 19:12:20 +02:00
committed by GitHub
parent 50a45f1b07
commit 26806dcaf3
3 changed files with 25 additions and 12 deletions

View File

@ -55,8 +55,12 @@ func (fde *FrameDescriptionEntry) Translate(delta uint64) {
} }
// EstablishFrame set up frame for the given PC. // EstablishFrame set up frame for the given PC.
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext { func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) (*FrameContext, error) {
return executeDwarfProgramUntilPC(fde, pc) fctxt := executeDwarfProgramUntilPC(fde, pc)
if fctxt.err != nil {
return nil, fctxt.err
}
return fctxt, nil
} }
type FrameDescriptionEntries []*FrameDescriptionEntry type FrameDescriptionEntries []*FrameDescriptionEntry

View File

@ -30,6 +30,7 @@ type FrameContext struct {
codeAlignment uint64 codeAlignment uint64
dataAlignment int64 dataAlignment int64
rememberedState *stateStack rememberedState *stateStack
err error
} }
type rowState struct { type rowState struct {
@ -179,7 +180,7 @@ func (frame *FrameContext) executeDwarfProgram() {
} }
// ExecuteUntilPC execute dwarf instructions. // ExecuteUntilPC execute dwarf instructions.
func (frame *FrameContext) ExecuteUntilPC(instructions []byte) { func (frame *FrameContext) ExecuteUntilPC(instructions []byte) error {
frame.buf.Truncate(0) frame.buf.Truncate(0)
frame.buf.Write(instructions) frame.buf.Write(instructions)
@ -189,9 +190,13 @@ func (frame *FrameContext) ExecuteUntilPC(instructions []byte) {
for frame.address >= frame.loc && frame.buf.Len() > 0 { for frame.address >= frame.loc && frame.buf.Len() > 0 {
executeDwarfInstruction(frame) executeDwarfInstruction(frame)
} }
return frame.err
} }
func executeDwarfInstruction(frame *FrameContext) { func executeDwarfInstruction(frame *FrameContext) {
if frame.err != nil {
return
}
instruction, err := frame.buf.ReadByte() instruction, err := frame.buf.ReadByte()
if err != nil { if err != nil {
panic("Could not read from instruction buffer") panic("Could not read from instruction buffer")
@ -203,6 +208,11 @@ func executeDwarfInstruction(frame *FrameContext) {
fn := lookupFunc(instruction, frame.buf) fn := lookupFunc(instruction, frame.buf)
if fn == nil {
frame.err = fmt.Errorf("encountered an unexpected DWARF CFA opcode: %#v", instruction)
return
}
fn(frame) fn(frame)
} }
@ -233,12 +243,7 @@ func lookupFunc(instruction byte, buf *bytes.Buffer) instruction {
} }
} }
fn, ok := fnlookup[instruction] return fnlookup[instruction]
if !ok {
panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction))
}
return fn
} }
func advanceloc(frame *FrameContext) { func advanceloc(frame *FrameContext) {

View File

@ -508,15 +508,19 @@ func (it *stackIterator) appendInlineCalls(callback func(Stackframe) bool, frame
// it.regs.CFA; the caller has to eventually switch it.regs when the iterator // it.regs.CFA; the caller has to eventually switch it.regs when the iterator
// advances to the next frame. // advances to the next frame.
func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) { func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) {
logger := logflags.StackLogger()
fde, err := it.bi.frameEntries.FDEForPC(it.pc) fde, err := it.bi.frameEntries.FDEForPC(it.pc)
var framectx *frame.FrameContext var framectx *frame.FrameContext
if _, nofde := err.(*frame.ErrNoFDEForPC); nofde { if _, nofde := err.(*frame.ErrNoFDEForPC); nofde {
framectx = it.bi.Arch.fixFrameUnwindContext(nil, it.pc, it.bi) framectx = it.bi.Arch.fixFrameUnwindContext(nil, it.pc, it.bi)
} else { } else {
framectx = it.bi.Arch.fixFrameUnwindContext(fde.EstablishFrame(it.pc), it.pc, it.bi) fctxt, err := fde.EstablishFrame(it.pc)
if err != nil {
logger.Errorf("Error executing Frame Debug Entry for PC %x: %v", it.pc, err)
}
framectx = it.bi.Arch.fixFrameUnwindContext(fctxt, it.pc, it.bi)
} }
logger := logflags.StackLogger()
logger.Debugf("advanceRegs at %#x", it.pc) logger.Debugf("advanceRegs at %#x", it.pc)