github.com/undoio/delve@v1.9.0/pkg/proc/core/core.go (about) 1 package core 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 8 "github.com/undoio/delve/pkg/dwarf/op" 9 "github.com/undoio/delve/pkg/elfwriter" 10 "github.com/undoio/delve/pkg/proc" 11 "github.com/undoio/delve/pkg/proc/internal/ebpf" 12 ) 13 14 // ErrNoThreads core file did not contain any threads. 15 var ErrNoThreads = errors.New("no threads found in core file") 16 17 // A splicedMemory represents a memory space formed from multiple regions, 18 // each of which may override previously regions. For example, in the following 19 // core, the program text was loaded at 0x400000: 20 // Start End Page Offset 21 // 0x0000000000400000 0x000000000044f000 0x0000000000000000 22 // but then it's partially overwritten with an RW mapping whose data is stored 23 // in the core file: 24 // 25 // Type Offset VirtAddr PhysAddr 26 // FileSiz MemSiz Flags Align 27 // LOAD 0x0000000000004000 0x000000000049a000 0x0000000000000000 28 // 0x0000000000002000 0x0000000000002000 RW 1000 29 // 30 // This can be represented in a SplicedMemory by adding the original region, 31 // then putting the RW mapping on top of it. 32 type splicedMemory struct { 33 readers []readerEntry 34 } 35 36 type readerEntry struct { 37 offset uint64 38 length uint64 39 reader proc.MemoryReader 40 } 41 42 // Add adds a new region to the SplicedMemory, which may override existing regions. 43 func (r *splicedMemory) Add(reader proc.MemoryReader, off, length uint64) { 44 if length == 0 { 45 return 46 } 47 end := off + length - 1 48 newReaders := make([]readerEntry, 0, len(r.readers)) 49 add := func(e readerEntry) { 50 if e.length == 0 { 51 return 52 } 53 newReaders = append(newReaders, e) 54 } 55 inserted := false 56 // Walk through the list of regions, fixing up any that overlap and inserting the new one. 57 for _, entry := range r.readers { 58 entryEnd := entry.offset + entry.length - 1 59 switch { 60 case entryEnd < off: 61 // Entry is completely before the new region. 62 add(entry) 63 case end < entry.offset: 64 // Entry is completely after the new region. 65 if !inserted { 66 add(readerEntry{off, length, reader}) 67 inserted = true 68 } 69 add(entry) 70 case off <= entry.offset && entryEnd <= end: 71 // Entry is completely overwritten by the new region. Drop. 72 case entry.offset < off && entryEnd <= end: 73 // New region overwrites the end of the entry. 74 entry.length = off - entry.offset 75 add(entry) 76 case off <= entry.offset && end < entryEnd: 77 // New reader overwrites the beginning of the entry. 78 if !inserted { 79 add(readerEntry{off, length, reader}) 80 inserted = true 81 } 82 overlap := entry.offset - off 83 entry.offset += overlap 84 entry.length -= overlap 85 add(entry) 86 case entry.offset < off && end < entryEnd: 87 // New region punches a hole in the entry. Split it in two and put the new region in the middle. 88 add(readerEntry{entry.offset, off - entry.offset, entry.reader}) 89 add(readerEntry{off, length, reader}) 90 add(readerEntry{end + 1, entryEnd - end, entry.reader}) 91 inserted = true 92 default: 93 panic(fmt.Sprintf("Unhandled case: existing entry is %v len %v, new is %v len %v", entry.offset, entry.length, off, length)) 94 } 95 } 96 if !inserted { 97 newReaders = append(newReaders, readerEntry{off, length, reader}) 98 } 99 r.readers = newReaders 100 } 101 102 // ReadMemory implements MemoryReader.ReadMemory. 103 func (r *splicedMemory) ReadMemory(buf []byte, addr uint64) (n int, err error) { 104 started := false 105 for _, entry := range r.readers { 106 if entry.offset+entry.length <= addr { 107 if !started { 108 continue 109 } 110 return n, fmt.Errorf("hit unmapped area at %v after %v bytes", addr, n) 111 } 112 113 // The reading of the memory has been started after the first iteration 114 started = true 115 116 // Don't go past the region. 117 pb := buf 118 if addr+uint64(len(buf)) > entry.offset+entry.length { 119 pb = pb[:entry.offset+entry.length-addr] 120 } 121 pn, err := entry.reader.ReadMemory(pb, addr) 122 n += pn 123 if err != nil { 124 return n, fmt.Errorf("error while reading spliced memory at %#x: %v", addr, err) 125 } 126 if pn != len(pb) { 127 return n, nil 128 } 129 buf = buf[pn:] 130 addr += uint64(pn) 131 if len(buf) == 0 { 132 // Done, don't bother scanning the rest. 133 return n, nil 134 } 135 } 136 if n == 0 { 137 return 0, fmt.Errorf("offset %v did not match any regions", addr) 138 } 139 return n, nil 140 } 141 142 // offsetReaderAt wraps a ReaderAt into a MemoryReader, subtracting a fixed 143 // offset from the address. This is useful to represent a mapping in an address 144 // space. For example, if program text is mapped in at 0x400000, an 145 // OffsetReaderAt with offset 0x400000 can be wrapped around file.Open(program) 146 // to return the results of a read in that part of the address space. 147 type offsetReaderAt struct { 148 reader io.ReaderAt 149 offset uint64 150 } 151 152 // ReadMemory will read the memory at addr-offset. 153 func (r *offsetReaderAt) ReadMemory(buf []byte, addr uint64) (n int, err error) { 154 return r.reader.ReadAt(buf, int64(addr-r.offset)) 155 } 156 157 // process represents a core file. 158 type process struct { 159 mem proc.MemoryReader 160 Threads map[int]*thread 161 pid int 162 163 entryPoint uint64 164 165 bi *proc.BinaryInfo 166 breakpoints proc.BreakpointMap 167 } 168 169 // thread represents a thread in the core file being debugged. 170 type thread struct { 171 th osThread 172 p *process 173 common proc.CommonThread 174 } 175 176 type osThread interface { 177 registers() (proc.Registers, error) 178 pid() int 179 } 180 181 var ( 182 // ErrWriteCore is returned when attempting to write to the core 183 // process memory. 184 ErrWriteCore = errors.New("can not write to core process") 185 186 // ErrShortRead is returned on a short read. 187 ErrShortRead = errors.New("short read") 188 189 // ErrContinueCore is returned when trying to continue execution of a core process. 190 ErrContinueCore = errors.New("can not continue execution of core process") 191 192 // ErrChangeRegisterCore is returned when trying to change register values for core files. 193 ErrChangeRegisterCore = errors.New("can not change register values of core process") 194 ) 195 196 type openFn func(string, string) (*process, proc.Thread, error) 197 198 var openFns = []openFn{readLinuxOrPlatformIndependentCore, readAMD64Minidump} 199 200 // ErrUnrecognizedFormat is returned when the core file is not recognized as 201 // any of the supported formats. 202 var ErrUnrecognizedFormat = errors.New("unrecognized core format") 203 204 // OpenCore will open the core file and return a Process struct. 205 // If the DWARF information cannot be found in the binary, Delve will look 206 // for external debug files in the directories passed in. 207 func OpenCore(corePath, exePath string, debugInfoDirs []string) (*proc.Target, error) { 208 var p *process 209 var currentThread proc.Thread 210 var err error 211 for _, openFn := range openFns { 212 p, currentThread, err = openFn(corePath, exePath) 213 if err != ErrUnrecognizedFormat { 214 break 215 } 216 } 217 if err != nil { 218 return nil, err 219 } 220 221 if currentThread == nil { 222 return nil, ErrNoThreads 223 } 224 225 return proc.NewTarget(p, p.pid, currentThread, proc.NewTargetConfig{ 226 Path: exePath, 227 DebugInfoDirs: debugInfoDirs, 228 DisableAsyncPreempt: false, 229 StopReason: proc.StopAttached, 230 CanDump: false}) 231 } 232 233 // BinInfo will return the binary info. 234 func (p *process) BinInfo() *proc.BinaryInfo { 235 return p.bi 236 } 237 238 // EntryPoint will return the entry point address for this core file. 239 func (p *process) EntryPoint() (uint64, error) { 240 return p.entryPoint, nil 241 } 242 243 // WriteBreakpoint is a noop function since you 244 // cannot write breakpoints into core files. 245 func (p *process) WriteBreakpoint(*proc.Breakpoint) error { 246 return errors.New("cannot write a breakpoint to a core file") 247 } 248 249 // Recorded returns whether this is a live or recorded process. Always returns true for core files. 250 func (p *process) Recorded() (bool, string) { return true, "" } 251 252 // Restart will only return an error for core files, as they are not executing. 253 func (p *process) Restart(*proc.ContinueOnceContext, string) (proc.Thread, error) { 254 return nil, ErrContinueCore 255 } 256 257 // ChangeDirection will only return an error as you cannot continue a core process. 258 func (p *process) ChangeDirection(proc.Direction) error { return ErrContinueCore } 259 260 // GetDirection will always return forward. 261 func (p *process) GetDirection() proc.Direction { return proc.Forward } 262 263 // When does not apply to core files, it is to support the Mozilla 'rr' backend. 264 func (p *process) When() (string, error) { return "", nil } 265 266 // Checkpoint for core files returns an error, there is no execution of a core file. 267 func (p *process) Checkpoint(string) (int, error) { return -1, ErrContinueCore } 268 269 // Checkpoints returns nil on core files, you cannot set checkpoints when debugging core files. 270 func (p *process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil } 271 272 // ClearCheckpoint clears a checkpoint, but will only return an error for core files. 273 func (p *process) ClearCheckpoint(int) error { return errors.New("checkpoint not found") } 274 275 func (p *process) SupportsBPF() bool { 276 return false 277 } 278 279 func (dbp *process) SetUProbe(fnName string, goidOffset int64, args []ebpf.UProbeArgMap) error { 280 panic("not implemented") 281 } 282 283 // StartCallInjection notifies the backend that we are about to inject a function call. 284 func (p *process) StartCallInjection() (func(), error) { return func() {}, nil } 285 286 func (dbp *process) EnableURetProbes() error { 287 panic("not implemented") 288 } 289 290 func (dbp *process) DisableURetProbes() error { 291 panic("not implemented") 292 } 293 294 // ReadMemory will return memory from the core file at the specified location and put the 295 // read memory into `data`, returning the length read, and returning an error if 296 // the length read is shorter than the length of the `data` buffer. 297 func (p *process) ReadMemory(data []byte, addr uint64) (n int, err error) { 298 n, err = p.mem.ReadMemory(data, addr) 299 if err == nil && n != len(data) { 300 err = ErrShortRead 301 } 302 return n, err 303 } 304 305 // WriteMemory will only return an error for core files, you cannot write 306 // to the memory of a core process. 307 func (p *process) WriteMemory(addr uint64, data []byte) (int, error) { 308 return 0, ErrWriteCore 309 } 310 311 // ProcessMemory returns the memory of this thread's process. 312 func (t *thread) ProcessMemory() proc.MemoryReadWriter { 313 return t.p 314 } 315 316 // Location returns the location of this thread based on 317 // the value of the instruction pointer register. 318 func (t *thread) Location() (*proc.Location, error) { 319 regs, err := t.th.registers() 320 if err != nil { 321 return nil, err 322 } 323 pc := regs.PC() 324 f, l, fn := t.p.bi.PCToLine(pc) 325 return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil 326 } 327 328 // Breakpoint returns the current breakpoint this thread is stopped at. 329 // For core files this always returns an empty BreakpointState struct, as 330 // there are no breakpoints when debugging core files. 331 func (t *thread) Breakpoint() *proc.BreakpointState { 332 return &proc.BreakpointState{} 333 } 334 335 // ThreadID returns the ID for this thread. 336 func (t *thread) ThreadID() int { 337 return int(t.th.pid()) 338 } 339 340 // Registers returns the current value of the registers for this thread. 341 func (t *thread) Registers() (proc.Registers, error) { 342 return t.th.registers() 343 } 344 345 // RestoreRegisters will only return an error for core files, 346 // you cannot change register values for core files. 347 func (t *thread) RestoreRegisters(proc.Registers) error { 348 return ErrChangeRegisterCore 349 } 350 351 // BinInfo returns information about the binary. 352 func (t *thread) BinInfo() *proc.BinaryInfo { 353 return t.p.bi 354 } 355 356 // StepInstruction will only return an error for core files, 357 // you cannot execute a core file. 358 func (t *thread) StepInstruction() error { 359 return ErrContinueCore 360 } 361 362 // SetCurrentBreakpoint will always just return nil 363 // for core files, as there are no breakpoints in core files. 364 func (t *thread) SetCurrentBreakpoint(adjustPC bool) error { 365 return nil 366 } 367 368 // SoftExc returns true if this thread received a software exception during the last resume. 369 func (t *thread) SoftExc() bool { 370 return false 371 } 372 373 // Common returns a struct containing common information 374 // across thread implementations. 375 func (t *thread) Common() *proc.CommonThread { 376 return &t.common 377 } 378 379 // SetPC will always return an error, you cannot 380 // change register values when debugging core files. 381 func (t *thread) SetPC(uint64) error { 382 return ErrChangeRegisterCore 383 } 384 385 // SetSP will always return an error, you cannot 386 // change register values when debugging core files. 387 func (t *thread) SetSP(uint64) error { 388 return ErrChangeRegisterCore 389 } 390 391 // SetDX will always return an error, you cannot 392 // change register values when debugging core files. 393 func (t *thread) SetDX(uint64) error { 394 return ErrChangeRegisterCore 395 } 396 397 // ChangeRegs will always return an error, you cannot 398 // change register values when debugging core files. 399 func (t *thread) SetReg(regNum uint64, reg *op.DwarfRegister) error { 400 return ErrChangeRegisterCore 401 } 402 403 // Breakpoints will return all breakpoints for the process. 404 func (p *process) Breakpoints() *proc.BreakpointMap { 405 return &p.breakpoints 406 } 407 408 // EraseBreakpoint will always return an error as you cannot set or clear 409 // breakpoints on core files. 410 func (p *process) EraseBreakpoint(bp *proc.Breakpoint) error { 411 return proc.NoBreakpointError{Addr: bp.Addr} 412 } 413 414 // ClearInternalBreakpoints will always return nil and have no 415 // effect since you cannot set breakpoints on core files. 416 func (p *process) ClearInternalBreakpoints() error { 417 return nil 418 } 419 420 // ContinueOnce will always return an error because you 421 // cannot control execution of a core file. 422 func (p *process) ContinueOnce(cctx *proc.ContinueOnceContext) (proc.Thread, proc.StopReason, error) { 423 return nil, proc.StopUnknown, ErrContinueCore 424 } 425 426 // StepInstruction will always return an error 427 // as you cannot control execution of a core file. 428 func (p *process) StepInstruction() error { 429 return ErrContinueCore 430 } 431 432 // RequestManualStop will return nil and have no effect 433 // as you cannot control execution of a core file. 434 func (p *process) RequestManualStop(cctx *proc.ContinueOnceContext) error { 435 return nil 436 } 437 438 // CheckAndClearManualStopRequest will always return false and 439 // have no effect since there are no manual stop requests as 440 // there is no controlling execution of a core file. 441 func (p *process) CheckAndClearManualStopRequest() bool { 442 return false 443 } 444 445 // Memory returns the process memory. 446 func (p *process) Memory() proc.MemoryReadWriter { 447 return p 448 } 449 450 // Detach will always return nil and have no 451 // effect as you cannot detach from a core file 452 // and have it continue execution or exit. 453 func (p *process) Detach(bool) error { 454 return nil 455 } 456 457 // Valid returns whether the process is active. Always returns true 458 // for core files as it cannot exit or be otherwise detached from. 459 func (p *process) Valid() (bool, error) { 460 return true, nil 461 } 462 463 // ResumeNotify is a no-op on core files as we cannot 464 // control execution. 465 func (p *process) ResumeNotify(chan<- struct{}) { 466 } 467 468 // ThreadList will return a list of all threads currently in the process. 469 func (p *process) ThreadList() []proc.Thread { 470 r := make([]proc.Thread, 0, len(p.Threads)) 471 for _, v := range p.Threads { 472 r = append(r, v) 473 } 474 return r 475 } 476 477 // FindThread will return the thread with the corresponding thread ID. 478 func (p *process) FindThread(threadID int) (proc.Thread, bool) { 479 t, ok := p.Threads[threadID] 480 return t, ok 481 } 482 483 func (p *process) MemoryMap() ([]proc.MemoryMapEntry, error) { 484 return nil, proc.ErrMemoryMapNotSupported 485 } 486 487 func (p *process) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) { 488 return false, notes, nil 489 } 490 491 func (dbp *process) GetBufferedTracepoints() []ebpf.RawUProbeParams { 492 return nil 493 }