Class: Ptrace::Target

Inherits:
Object
  • Object
show all
Defined in:
lib/Ptrace.rb

Overview

A target process managed by ptrace.

Usage:

tgt = Target.attach(pid)
loop do
  begin
    tgt.step
    puts tgt.regs.read.inspect
  rescue Ptrace::InvalidProcessError
    break
  end
end

tgt = Target.launch(cmd)
loop do
  begin
    state = tgt.syscall_state
    puts state.inspect
  rescue Ptrace::InvalidProcessError
    break
  end
end

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(pid) ⇒ Target

Create a Ptrace::Target object for process ‘pid’. The process is assumed to have been launched or attached to by ptrace, e.g. using Target.launch or Target.attach.



379
380
381
382
383
384
385
386
387
388
389
# File 'lib/Ptrace.rb', line 379

def initialize(pid)
  @pid = pid
  @text = MemArea.new(MemArea::MEM_TEXT, pid)
  @data = MemArea.new(MemArea::MEM_DATA, pid)
  @user = MemArea.new(MemArea::MEM_USER, pid)
  @regs = RegSet.new(RegSet::GEN, pid)
  @fpregs = RegSet.new(RegSet::FP, pid)
  @fpxregs = RegSet.new(RegSet::Ext, pid)
  @options = Options.new(pid)
  @valid = true
end

Instance Attribute Details

#dataObject

Data segment for process.



364
365
366
# File 'lib/Ptrace.rb', line 364

def data
  @data
end

#fpregsObject

extended FPU registers for process.



352
353
354
# File 'lib/Ptrace.rb', line 352

def fpregs
  @fpregs
end

#optionsObject

Ptrace options.



372
373
374
# File 'lib/Ptrace.rb', line 372

def options
  @options
end

#pidObject

PID of target process.



344
345
346
# File 'lib/Ptrace.rb', line 344

def pid
  @pid
end

#regsObject

General (CPU) registers for process.



348
349
350
# File 'lib/Ptrace.rb', line 348

def regs
  @regs
end

#textObject

Text (code) segment for process.



360
361
362
# File 'lib/Ptrace.rb', line 360

def text
  @text
end

#userObject

Target ‘user’ (task) area.



368
369
370
# File 'lib/Ptrace.rb', line 368

def user
  @user
end

Class Method Details

.attach(pid) ⇒ Object

PT_ATTACH : Attach to running process ‘pid’ and return a Ptrace::Target object. Raises an exception if the attach fails.



395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'lib/Ptrace.rb', line 395

def self.attach(pid)
  tgt = Target.new(pid)
  begin
    Ptrace::Debugger.send_cmd( Ptrace::Debugger.commands[:attach], pid, nil)
    Process.waitpid(pid)
  rescue RuntimeError => e
    case e.message
      when 'PTRACE: Operation not permitted'
        raise OperationNotPermittedError.new(e.message)
      when 'PTRACE: No such process'
        raise InvalidProcessError.new(e.message)
      else
        raise
    end
  end
  return tgt
end

.launch(cmd) ⇒ Object

PT_TRACE_ME : Launch command ‘cmd’ and return a Ptrace::Target object for controlling it. Raises an exception if the command cannot be launched; returns nil if the command cannot be traced.



419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/Ptrace.rb', line 419

def self.launch(cmd)
  pid = fork
  if ! pid
    begin
      Ptrace::Debugger.send_cmd(Ptrace::Debugger.commands[:traceme], nil, 
                                nil)
      exec(cmd)
    rescue RuntimeError => e
      case e.message
        when 'PTRACE: Operation not permitted'
          raise OperationNotPermittedError.new(e.message)
        when 'PTRACE: No such process'
          raise InvalidProcessError.new(e.message)
        else
          raise
      end
    end

  elsif pid == -1
    return nil

  else
    Process.waitpid(pid)
    tgt = Target.new(pid)
    return tgt
  end
end

Instance Method Details

#contObject

PT_CONTINUE: Continue execution of target.



529
530
531
532
# File 'lib/Ptrace.rb', line 529

def cont
  ptrace_send( :cont )
  Process.waitpid(@pid)
end

#detachObject

PT_DETACH : Detach from the process. Note: This makes the Ptrace::Target object invalid.



477
478
479
480
481
# File 'lib/Ptrace.rb', line 477

def detach
  ptrace_send( :detach )
  Process.waitpid(@pid)
  @valid = false
end

#event_msgObject



457
458
459
460
461
# File 'lib/Ptrace.rb', line 457

def event_msg
  # send signal
  # For PTRACE_EVENT_EXIT this is the child's exit status. For PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK and PTRACE_EVENT_CLONE this is the PID of the new process. 
  # Debugger.event_msg
end

#killObject

PT_KILL : Terminate the process. Note: This makes the Ptrace::Target object invalid.



467
468
469
470
471
# File 'lib/Ptrace.rb', line 467

def kill
  ptrace_send( :kill )
  Process.waitpid(@pid)
  @valid = false
end

#signal(sig = nil) ⇒ Object



449
450
451
452
453
# File 'lib/Ptrace.rb', line 449

def signal(sig=nil)
  # if sig, send
  # else:
  Signal.read(pid)
end

#stepObject

PT_STEP : Step a single instruction.



486
487
488
489
# File 'lib/Ptrace.rb', line 486

def step
  ptrace_send( :singlestep )
  Process.waitpid(@pid)
end

#syscallObject

PT_SYSCALL : Execute until the start or end of the next system call.

Usage:

tgt.syscall
in_regs = tgt.regs.read
tgt.syscall
out_regs = tgt.regs.read


500
501
502
503
# File 'lib/Ptrace.rb', line 500

def syscall
  ptrace_send( :syscall )
  Process.waitpid(@pid)
end

#syscall_stateObject

Wrapper for recording syscalls. This issues a PT_SYSCALL to stop the target at the next syscall, records the ‘in’ register set, issues a PT_SYSCALL to stop the target after the syscall returns, records the ‘out’ register set, and returns a Hash { :in, :out } of the register sets. The target is stopped on return from this syscall.



512
513
514
515
516
517
518
519
520
521
522
523
524
# File 'lib/Ptrace.rb', line 512

def syscall_state
  begin
    state = {}
    syscall
    state[:in] = @regs.read
    syscall
    state[:out] = @regs.read
    state
  rescue InvalidProcessError
    # Program exited without a syscall
    return state
  end
end

#sysemuObject

PT_SYSEMU



537
538
539
# File 'lib/Ptrace.rb', line 537

def sysemu
  ptrace_send( :sysemu )
end

#sysemu_stepObject

PT_SYSEMU_SINGLESTEP



544
545
546
# File 'lib/Ptrace.rb', line 544

def sysemu_step
  ptrace_send( :sysemu_singlestep )
end