github.com/undoio/delve@v1.9.0/pkg/dwarf/frame/table.go (about) 1 package frame 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "github.com/undoio/delve/pkg/dwarf/util" 9 ) 10 11 // DWRule wrapper of rule defined for register values. 12 type DWRule struct { 13 Rule Rule 14 Offset int64 15 Reg uint64 16 Expression []byte 17 } 18 19 // FrameContext wrapper of FDE context 20 type FrameContext struct { 21 loc uint64 22 order binary.ByteOrder 23 address uint64 24 CFA DWRule 25 Regs map[uint64]DWRule 26 initialRegs map[uint64]DWRule 27 prevRegs map[uint64]DWRule 28 buf *bytes.Buffer 29 cie *CommonInformationEntry 30 RetAddrReg uint64 31 codeAlignment uint64 32 dataAlignment int64 33 } 34 35 // Instructions used to recreate the table from the .debug_frame data. 36 const ( 37 DW_CFA_nop = 0x0 // No ops 38 DW_CFA_set_loc = 0x01 // op1: address 39 DW_CFA_advance_loc1 = iota // op1: 1-bytes delta 40 DW_CFA_advance_loc2 // op1: 2-byte delta 41 DW_CFA_advance_loc4 // op1: 4-byte delta 42 DW_CFA_offset_extended // op1: ULEB128 register, op2: ULEB128 offset 43 DW_CFA_restore_extended // op1: ULEB128 register 44 DW_CFA_undefined // op1: ULEB128 register 45 DW_CFA_same_value // op1: ULEB128 register 46 DW_CFA_register // op1: ULEB128 register, op2: ULEB128 register 47 DW_CFA_remember_state // No ops 48 DW_CFA_restore_state // No ops 49 DW_CFA_def_cfa // op1: ULEB128 register, op2: ULEB128 offset 50 DW_CFA_def_cfa_register // op1: ULEB128 register 51 DW_CFA_def_cfa_offset // op1: ULEB128 offset 52 DW_CFA_def_cfa_expression // op1: BLOCK 53 DW_CFA_expression // op1: ULEB128 register, op2: BLOCK 54 DW_CFA_offset_extended_sf // op1: ULEB128 register, op2: SLEB128 BLOCK 55 DW_CFA_def_cfa_sf // op1: ULEB128 register, op2: SLEB128 offset 56 DW_CFA_def_cfa_offset_sf // op1: SLEB128 offset 57 DW_CFA_val_offset // op1: ULEB128, op2: ULEB128 58 DW_CFA_val_offset_sf // op1: ULEB128, op2: SLEB128 59 DW_CFA_val_expression // op1: ULEB128, op2: BLOCK 60 DW_CFA_lo_user = 0x1c // op1: BLOCK 61 DW_CFA_hi_user = 0x3f // op1: ULEB128 register, op2: BLOCK 62 DW_CFA_advance_loc = (0x1 << 6) // High 2 bits: 0x1, low 6: delta 63 DW_CFA_offset = (0x2 << 6) // High 2 bits: 0x2, low 6: register 64 DW_CFA_restore = (0x3 << 6) // High 2 bits: 0x3, low 6: register 65 ) 66 67 // Rule rule defined for register values. 68 type Rule byte 69 70 const ( 71 RuleUndefined Rule = iota 72 RuleSameVal 73 RuleOffset 74 RuleValOffset 75 RuleRegister 76 RuleExpression 77 RuleValExpression 78 RuleArchitectural 79 RuleCFA // Value is rule.Reg + rule.Offset 80 RuleFramePointer // Value is stored at address rule.Reg + rule.Offset, but only if it's less than the current CFA, otherwise same value 81 ) 82 83 const low_6_offset = 0x3f 84 85 type instruction func(frame *FrameContext) 86 87 // // Mapping from DWARF opcode to function. 88 var fnlookup = map[byte]instruction{ 89 DW_CFA_advance_loc: advanceloc, 90 DW_CFA_offset: offset, 91 DW_CFA_restore: restore, 92 DW_CFA_set_loc: setloc, 93 DW_CFA_advance_loc1: advanceloc1, 94 DW_CFA_advance_loc2: advanceloc2, 95 DW_CFA_advance_loc4: advanceloc4, 96 DW_CFA_offset_extended: offsetextended, 97 DW_CFA_restore_extended: restoreextended, 98 DW_CFA_undefined: undefined, 99 DW_CFA_same_value: samevalue, 100 DW_CFA_register: register, 101 DW_CFA_remember_state: rememberstate, 102 DW_CFA_restore_state: restorestate, 103 DW_CFA_def_cfa: defcfa, 104 DW_CFA_def_cfa_register: defcfaregister, 105 DW_CFA_def_cfa_offset: defcfaoffset, 106 DW_CFA_def_cfa_expression: defcfaexpression, 107 DW_CFA_expression: expression, 108 DW_CFA_offset_extended_sf: offsetextendedsf, 109 DW_CFA_def_cfa_sf: defcfasf, 110 DW_CFA_def_cfa_offset_sf: defcfaoffsetsf, 111 DW_CFA_val_offset: valoffset, 112 DW_CFA_val_offset_sf: valoffsetsf, 113 DW_CFA_val_expression: valexpression, 114 DW_CFA_lo_user: louser, 115 DW_CFA_hi_user: hiuser, 116 } 117 118 func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext { 119 initialInstructions := make([]byte, len(cie.InitialInstructions)) 120 copy(initialInstructions, cie.InitialInstructions) 121 frame := &FrameContext{ 122 cie: cie, 123 Regs: make(map[uint64]DWRule), 124 RetAddrReg: cie.ReturnAddressRegister, 125 initialRegs: make(map[uint64]DWRule), 126 prevRegs: make(map[uint64]DWRule), 127 codeAlignment: cie.CodeAlignmentFactor, 128 dataAlignment: cie.DataAlignmentFactor, 129 buf: bytes.NewBuffer(initialInstructions), 130 } 131 132 frame.executeDwarfProgram() 133 return frame 134 } 135 136 // Unwind the stack to find the return address register. 137 func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameContext { 138 frame := executeCIEInstructions(fde.CIE) 139 frame.order = fde.order 140 frame.loc = fde.Begin() 141 frame.address = pc 142 frame.ExecuteUntilPC(fde.Instructions) 143 144 return frame 145 } 146 147 func (frame *FrameContext) executeDwarfProgram() { 148 for frame.buf.Len() > 0 { 149 executeDwarfInstruction(frame) 150 } 151 } 152 153 // ExecuteUntilPC execute dwarf instructions. 154 func (frame *FrameContext) ExecuteUntilPC(instructions []byte) { 155 frame.buf.Truncate(0) 156 frame.buf.Write(instructions) 157 158 // We only need to execute the instructions until 159 // ctx.loc > ctx.address (which is the address we 160 // are currently at in the traced process). 161 for frame.address >= frame.loc && frame.buf.Len() > 0 { 162 executeDwarfInstruction(frame) 163 } 164 } 165 166 func executeDwarfInstruction(frame *FrameContext) { 167 instruction, err := frame.buf.ReadByte() 168 if err != nil { 169 panic("Could not read from instruction buffer") 170 } 171 172 if instruction == DW_CFA_nop { 173 return 174 } 175 176 fn := lookupFunc(instruction, frame.buf) 177 178 fn(frame) 179 } 180 181 func lookupFunc(instruction byte, buf *bytes.Buffer) instruction { 182 const high_2_bits = 0xc0 183 var restore bool 184 185 // Special case the 3 opcodes that have their argument encoded in the opcode itself. 186 switch instruction & high_2_bits { 187 case DW_CFA_advance_loc: 188 instruction = DW_CFA_advance_loc 189 restore = true 190 191 case DW_CFA_offset: 192 instruction = DW_CFA_offset 193 restore = true 194 195 case DW_CFA_restore: 196 instruction = DW_CFA_restore 197 restore = true 198 } 199 200 if restore { 201 // Restore the last byte as it actually contains the argument for the opcode. 202 err := buf.UnreadByte() 203 if err != nil { 204 panic("Could not unread byte") 205 } 206 } 207 208 fn, ok := fnlookup[instruction] 209 if !ok { 210 panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction)) 211 } 212 213 return fn 214 } 215 216 func advanceloc(frame *FrameContext) { 217 b, err := frame.buf.ReadByte() 218 if err != nil { 219 panic("Could not read byte") 220 } 221 222 delta := b & low_6_offset 223 frame.loc += uint64(delta) * frame.codeAlignment 224 } 225 226 func advanceloc1(frame *FrameContext) { 227 delta, err := frame.buf.ReadByte() 228 if err != nil { 229 panic("Could not read byte") 230 } 231 232 frame.loc += uint64(delta) * frame.codeAlignment 233 } 234 235 func advanceloc2(frame *FrameContext) { 236 var delta uint16 237 binary.Read(frame.buf, frame.order, &delta) 238 239 frame.loc += uint64(delta) * frame.codeAlignment 240 } 241 242 func advanceloc4(frame *FrameContext) { 243 var delta uint32 244 binary.Read(frame.buf, frame.order, &delta) 245 246 frame.loc += uint64(delta) * frame.codeAlignment 247 } 248 249 func offset(frame *FrameContext) { 250 b, err := frame.buf.ReadByte() 251 if err != nil { 252 panic(err) 253 } 254 255 var ( 256 reg = b & low_6_offset 257 offset, _ = util.DecodeULEB128(frame.buf) 258 ) 259 260 frame.Regs[uint64(reg)] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset} 261 } 262 263 func restore(frame *FrameContext) { 264 b, err := frame.buf.ReadByte() 265 if err != nil { 266 panic(err) 267 } 268 269 reg := uint64(b & low_6_offset) 270 oldrule, ok := frame.initialRegs[reg] 271 if ok { 272 frame.Regs[reg] = DWRule{Offset: oldrule.Offset, Rule: RuleOffset} 273 } else { 274 frame.Regs[reg] = DWRule{Rule: RuleUndefined} 275 } 276 } 277 278 func setloc(frame *FrameContext) { 279 var loc uint64 280 binary.Read(frame.buf, frame.order, &loc) 281 282 frame.loc = loc + frame.cie.staticBase 283 } 284 285 func offsetextended(frame *FrameContext) { 286 var ( 287 reg, _ = util.DecodeULEB128(frame.buf) 288 offset, _ = util.DecodeULEB128(frame.buf) 289 ) 290 291 frame.Regs[reg] = DWRule{Offset: int64(offset) * frame.dataAlignment, Rule: RuleOffset} 292 } 293 294 func undefined(frame *FrameContext) { 295 reg, _ := util.DecodeULEB128(frame.buf) 296 frame.Regs[reg] = DWRule{Rule: RuleUndefined} 297 } 298 299 func samevalue(frame *FrameContext) { 300 reg, _ := util.DecodeULEB128(frame.buf) 301 frame.Regs[reg] = DWRule{Rule: RuleSameVal} 302 } 303 304 func register(frame *FrameContext) { 305 reg1, _ := util.DecodeULEB128(frame.buf) 306 reg2, _ := util.DecodeULEB128(frame.buf) 307 frame.Regs[reg1] = DWRule{Reg: reg2, Rule: RuleRegister} 308 } 309 310 func rememberstate(frame *FrameContext) { 311 frame.prevRegs = frame.Regs 312 } 313 314 func restorestate(frame *FrameContext) { 315 frame.Regs = frame.prevRegs 316 } 317 318 func restoreextended(frame *FrameContext) { 319 reg, _ := util.DecodeULEB128(frame.buf) 320 321 oldrule, ok := frame.initialRegs[reg] 322 if ok { 323 frame.Regs[reg] = DWRule{Offset: oldrule.Offset, Rule: RuleOffset} 324 } else { 325 frame.Regs[reg] = DWRule{Rule: RuleUndefined} 326 } 327 } 328 329 func defcfa(frame *FrameContext) { 330 reg, _ := util.DecodeULEB128(frame.buf) 331 offset, _ := util.DecodeULEB128(frame.buf) 332 333 frame.CFA.Rule = RuleCFA 334 frame.CFA.Reg = reg 335 frame.CFA.Offset = int64(offset) 336 } 337 338 func defcfaregister(frame *FrameContext) { 339 reg, _ := util.DecodeULEB128(frame.buf) 340 frame.CFA.Reg = reg 341 } 342 343 func defcfaoffset(frame *FrameContext) { 344 offset, _ := util.DecodeULEB128(frame.buf) 345 frame.CFA.Offset = int64(offset) 346 } 347 348 func defcfasf(frame *FrameContext) { 349 reg, _ := util.DecodeULEB128(frame.buf) 350 offset, _ := util.DecodeSLEB128(frame.buf) 351 352 frame.CFA.Rule = RuleCFA 353 frame.CFA.Reg = reg 354 frame.CFA.Offset = offset * frame.dataAlignment 355 } 356 357 func defcfaoffsetsf(frame *FrameContext) { 358 offset, _ := util.DecodeSLEB128(frame.buf) 359 offset *= frame.dataAlignment 360 frame.CFA.Offset = offset 361 } 362 363 func defcfaexpression(frame *FrameContext) { 364 var ( 365 l, _ = util.DecodeULEB128(frame.buf) 366 expr = frame.buf.Next(int(l)) 367 ) 368 369 frame.CFA.Expression = expr 370 frame.CFA.Rule = RuleExpression 371 } 372 373 func expression(frame *FrameContext) { 374 var ( 375 reg, _ = util.DecodeULEB128(frame.buf) 376 l, _ = util.DecodeULEB128(frame.buf) 377 expr = frame.buf.Next(int(l)) 378 ) 379 380 frame.Regs[reg] = DWRule{Rule: RuleExpression, Expression: expr} 381 } 382 383 func offsetextendedsf(frame *FrameContext) { 384 var ( 385 reg, _ = util.DecodeULEB128(frame.buf) 386 offset, _ = util.DecodeSLEB128(frame.buf) 387 ) 388 389 frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleOffset} 390 } 391 392 func valoffset(frame *FrameContext) { 393 var ( 394 reg, _ = util.DecodeULEB128(frame.buf) 395 offset, _ = util.DecodeULEB128(frame.buf) 396 ) 397 398 frame.Regs[reg] = DWRule{Offset: int64(offset), Rule: RuleValOffset} 399 } 400 401 func valoffsetsf(frame *FrameContext) { 402 var ( 403 reg, _ = util.DecodeULEB128(frame.buf) 404 offset, _ = util.DecodeSLEB128(frame.buf) 405 ) 406 407 frame.Regs[reg] = DWRule{Offset: offset * frame.dataAlignment, Rule: RuleValOffset} 408 } 409 410 func valexpression(frame *FrameContext) { 411 var ( 412 reg, _ = util.DecodeULEB128(frame.buf) 413 l, _ = util.DecodeULEB128(frame.buf) 414 expr = frame.buf.Next(int(l)) 415 ) 416 417 frame.Regs[reg] = DWRule{Rule: RuleValExpression, Expression: expr} 418 } 419 420 func louser(frame *FrameContext) { 421 frame.buf.Next(1) 422 } 423 424 func hiuser(frame *FrameContext) { 425 frame.buf.Next(1) 426 }