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.
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
return executeDwarfProgramUntilPC(fde, pc)
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) (*FrameContext, error) {
fctxt := executeDwarfProgramUntilPC(fde, pc)
if fctxt.err != nil {
return nil, fctxt.err
}
return fctxt, nil
}
type FrameDescriptionEntries []*FrameDescriptionEntry

View File

@ -30,6 +30,7 @@ type FrameContext struct {
codeAlignment uint64
dataAlignment int64
rememberedState *stateStack
err error
}
type rowState struct {
@ -179,7 +180,7 @@ func (frame *FrameContext) executeDwarfProgram() {
}
// ExecuteUntilPC execute dwarf instructions.
func (frame *FrameContext) ExecuteUntilPC(instructions []byte) {
func (frame *FrameContext) ExecuteUntilPC(instructions []byte) error {
frame.buf.Truncate(0)
frame.buf.Write(instructions)
@ -189,9 +190,13 @@ func (frame *FrameContext) ExecuteUntilPC(instructions []byte) {
for frame.address >= frame.loc && frame.buf.Len() > 0 {
executeDwarfInstruction(frame)
}
return frame.err
}
func executeDwarfInstruction(frame *FrameContext) {
if frame.err != nil {
return
}
instruction, err := frame.buf.ReadByte()
if err != nil {
panic("Could not read from instruction buffer")
@ -203,6 +208,11 @@ func executeDwarfInstruction(frame *FrameContext) {
fn := lookupFunc(instruction, frame.buf)
if fn == nil {
frame.err = fmt.Errorf("encountered an unexpected DWARF CFA opcode: %#v", instruction)
return
}
fn(frame)
}
@ -233,12 +243,7 @@ func lookupFunc(instruction byte, buf *bytes.Buffer) instruction {
}
}
fn, ok := fnlookup[instruction]
if !ok {
panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction))
}
return fn
return fnlookup[instruction]
}
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
// advances to the next frame.
func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uint64, retaddr uint64) {
logger := logflags.StackLogger()
fde, err := it.bi.frameEntries.FDEForPC(it.pc)
var framectx *frame.FrameContext
if _, nofde := err.(*frame.ErrNoFDEForPC); nofde {
framectx = it.bi.Arch.fixFrameUnwindContext(nil, it.pc, it.bi)
} 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)