gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/core/core.go (about) 1 package core 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 8 "gitlab.com/Raven-IO/raven-delve/pkg/dwarf/op" 9 "gitlab.com/Raven-IO/raven-delve/pkg/elfwriter" 10 "gitlab.com/Raven-IO/raven-delve/pkg/proc" 11 "gitlab.com/Raven-IO/raven-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 *proc.TargetGroup. 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.TargetGroup, 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 grp, addTarget := proc.NewGroup(p, proc.NewTargetGroupConfig{ 226 DebugInfoDirs: debugInfoDirs, 227 DisableAsyncPreempt: false, 228 CanDump: false, 229 }) 230 _, err = addTarget(p, p.pid, currentThread, exePath, proc.StopAttached, "") 231 return grp, err 232 } 233 234 // BinInfo will return the binary info. 235 func (p *process) BinInfo() *proc.BinaryInfo { 236 return p.bi 237 } 238 239 // EntryPoint will return the entry point address for this core file. 240 func (p *process) EntryPoint() (uint64, error) { 241 return p.entryPoint, nil 242 } 243 244 // WriteBreakpoint is a noop function since you 245 // cannot write breakpoints into core files. 246 func (p *process) WriteBreakpoint(*proc.Breakpoint) error { 247 return errors.New("cannot write a breakpoint to a core file") 248 } 249 250 // Recorded returns whether this is a live or recorded process. Always returns true for core files. 251 func (p *process) Recorded() (bool, string) { return true, "" } 252 253 // Restart will only return an error for core files, as they are not executing. 254 func (p *process) Restart(*proc.ContinueOnceContext, string) (proc.Thread, error) { 255 return nil, ErrContinueCore 256 } 257 258 // ChangeDirection will only return an error as you cannot continue a core process. 259 func (p *process) ChangeDirection(proc.Direction) error { return ErrContinueCore } 260 261 // GetDirection will always return forward. 262 func (p *process) GetDirection() proc.Direction { return proc.Forward } 263 264 // When does not apply to core files, it is to support the Mozilla 'rr' backend. 265 func (p *process) When() (string, error) { return "", nil } 266 267 // Checkpoint for core files returns an error, there is no execution of a core file. 268 func (p *process) Checkpoint(string) (int, error) { return -1, ErrContinueCore } 269 270 // Checkpoints returns nil on core files, you cannot set checkpoints when debugging core files. 271 func (p *process) Checkpoints() ([]proc.Checkpoint, error) { return nil, nil } 272 273 // ClearCheckpoint clears a checkpoint, but will only return an error for core files. 274 func (p *process) ClearCheckpoint(int) error { return errors.New("checkpoint not found") } 275 276 func (p *process) SupportsBPF() bool { 277 return false 278 } 279 280 func (p *process) SetUProbe(fnName string, goidOffset int64, args []ebpf.UProbeArgMap) error { 281 panic("not implemented") 282 } 283 284 // StartCallInjection notifies the backend that we are about to inject a function call. 285 func (p *process) StartCallInjection() (func(), error) { return func() {}, nil } 286 287 func (p *process) EnableURetProbes() error { 288 panic("not implemented") 289 } 290 291 func (p *process) DisableURetProbes() error { 292 panic("not implemented") 293 } 294 295 // ReadMemory will return memory from the core file at the specified location and put the 296 // read memory into `data`, returning the length read, and returning an error if 297 // the length read is shorter than the length of the `data` buffer. 298 func (p *process) ReadMemory(data []byte, addr uint64) (n int, err error) { 299 n, err = p.mem.ReadMemory(data, addr) 300 if err == nil && n != len(data) { 301 err = ErrShortRead 302 } 303 return n, err 304 } 305 306 // WriteMemory will only return an error for core files, you cannot write 307 // to the memory of a core process. 308 func (p *process) WriteMemory(addr uint64, data []byte) (int, error) { 309 return 0, ErrWriteCore 310 } 311 312 // FollowExec enables (or disables) follow exec mode 313 func (p *process) FollowExec(bool) error { 314 return nil 315 } 316 317 // ProcessMemory returns the memory of this thread's process. 318 func (t *thread) ProcessMemory() proc.MemoryReadWriter { 319 return t.p 320 } 321 322 // Location returns the location of this thread based on 323 // the value of the instruction pointer register. 324 func (t *thread) Location() (*proc.Location, error) { 325 regs, err := t.th.registers() 326 if err != nil { 327 return nil, err 328 } 329 pc := regs.PC() 330 f, l, fn := t.p.bi.PCToLine(pc) 331 return &proc.Location{PC: pc, File: f, Line: l, Fn: fn}, nil 332 } 333 334 // Breakpoint returns the current breakpoint this thread is stopped at. 335 // For core files this always returns an empty BreakpointState struct, as 336 // there are no breakpoints when debugging core files. 337 func (t *thread) Breakpoint() *proc.BreakpointState { 338 return &proc.BreakpointState{} 339 } 340 341 // ThreadID returns the ID for this thread. 342 func (t *thread) ThreadID() int { 343 return t.th.pid() 344 } 345 346 // Registers returns the current value of the registers for this thread. 347 func (t *thread) Registers() (proc.Registers, error) { 348 return t.th.registers() 349 } 350 351 // RestoreRegisters will only return an error for core files, 352 // you cannot change register values for core files. 353 func (t *thread) RestoreRegisters(proc.Registers) error { 354 return ErrChangeRegisterCore 355 } 356 357 // BinInfo returns information about the binary. 358 func (t *thread) BinInfo() *proc.BinaryInfo { 359 return t.p.bi 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 // SetReg 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 func (*process) ContinueOnce(cctx *proc.ContinueOnceContext) (proc.Thread, proc.StopReason, error) { 421 return nil, proc.StopUnknown, ErrContinueCore 422 } 423 424 // StepInstruction will always return an error 425 // as you cannot control execution of a core file. 426 func (p *process) StepInstruction(int) error { 427 return ErrContinueCore 428 } 429 430 // RequestManualStop will return nil and have no effect 431 // as you cannot control execution of a core file. 432 func (p *process) RequestManualStop(cctx *proc.ContinueOnceContext) error { 433 return nil 434 } 435 436 // CheckAndClearManualStopRequest will always return false and 437 // have no effect since there are no manual stop requests as 438 // there is no controlling execution of a core file. 439 func (p *process) CheckAndClearManualStopRequest() bool { 440 return false 441 } 442 443 // Memory returns the process memory. 444 func (p *process) Memory() proc.MemoryReadWriter { 445 return p 446 } 447 448 // Detach will always return nil and have no 449 // effect as you cannot detach from a core file 450 // and have it continue execution or exit. 451 func (p *process) Detach(int, bool) error { 452 return nil 453 } 454 455 func (p *process) Close() error { 456 return nil 457 } 458 459 // Valid returns whether the process is active. Always returns true 460 // for core files as it cannot exit or be otherwise detached from. 461 func (p *process) Valid() (bool, error) { 462 return true, nil 463 } 464 465 // ResumeNotify is a no-op on core files as we cannot 466 // control execution. 467 func (p *process) ResumeNotify(chan<- struct{}) { 468 } 469 470 // ThreadList will return a list of all threads currently in the process. 471 func (p *process) ThreadList() []proc.Thread { 472 r := make([]proc.Thread, 0, len(p.Threads)) 473 for _, v := range p.Threads { 474 r = append(r, v) 475 } 476 return r 477 } 478 479 // FindThread will return the thread with the corresponding thread ID. 480 func (p *process) FindThread(threadID int) (proc.Thread, bool) { 481 t, ok := p.Threads[threadID] 482 return t, ok 483 } 484 485 func (p *process) MemoryMap() ([]proc.MemoryMapEntry, error) { 486 return nil, proc.ErrMemoryMapNotSupported 487 } 488 489 func (p *process) DumpProcessNotes(notes []elfwriter.Note, threadDone func()) (threadsDone bool, out []elfwriter.Note, err error) { 490 return false, notes, nil 491 } 492 493 func (p *process) GetBufferedTracepoints() []ebpf.RawUProbeParams { 494 return nil 495 }