x/debug/dwarf: support DW_CFA_offset_extended in DWARF call frame information parsing.

This call frame instruction takes two operands and specifies that the
value in the previous frame of the register given in the first operand
is saved at an offset from the Canonical Frame Address given in the
second operand.

Change-Id: Ie9c114de97e403cffd1b7687b9540a37d64e1a1d
Reviewed-on: https://go-review.googlesource.com/11538
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/dwarf/frame.go b/dwarf/frame.go
index 185a500..c112c02 100644
--- a/dwarf/frame.go
+++ b/dwarf/frame.go
@@ -258,7 +258,13 @@
 
 		// Register Rule instructions (6.4.2.3)
 		case frameOffsetExtended: // ops: ULEB128 register ULEB128 offset
-			return 0, fmt.Errorf("unimplemented frameOffsetExtended")
+			// The same as frameOffset, but with the register specified in an operand.
+			reg := b.uint()
+			// For Go binaries we only see this in the CIE for the return address register.
+			if reg != uint64(m.returnAddressRegister) {
+				return 0, fmt.Errorf("invalid frameOffsetExtended: register R%d should be R%d", reg, m.returnAddressRegister)
+			}
+			m.returnRegisterOffset = int64(b.uint()) * m.dataAlignmentFactor
 		case frameRestoreExtended: // op: ULEB128 register
 			return 0, fmt.Errorf("unimplemented frameRestoreExtended")
 		case frameUndefined: // op: ULEB128 register; unimplemented