lib/twib/interfaces/ITwibDebugger.rb in twib-0.1.0 vs lib/twib/interfaces/ITwibDebugger.rb in twib-0.1.1
- old
+ new
@@ -1,11 +1,13 @@
require "twib/interface.rb"
require "twib/switch/debug.rb"
module Twib
module Interfaces
+ # Debug interface bound to a specific process.
class ITwibDebugger < Interface
+ # @api private
module Command
QUERY_MEMORY = 10
READ_MEMORY = 11
WRITE_MEMORY = 12
LIST_THREADS = 13
@@ -15,69 +17,110 @@
CONTINUE_DEBUG_EVENT = 17
SET_THREAD_CONTEXT = 18
GET_NSO_INFOS = 19
WAIT_EVENT = 20
end
-
+
+ # Queries process segment information at the given address.
+ #
+ # debug.query_memory(0)
+ # # => {:base=>0, :size=>62308483072, :memory_type=>0,
+ # # :memory_attribute=>0, :permission=>0,
+ # # :device_ref_count=>0, :ipc_ref_count=>0}
+ #
+ # @param addr [Integer] Address to query
+ # @return [Hash]
def query_memory(addr)
Hash[
[:base, :size, :memory_type, :memory_attribute,
:permission, :device_ref_count, :ipc_ref_count].zip(
send(Command::QUERY_MEMORY, [addr].pack("Q<")).wait_ok.payload.unpack("Q<Q<L<L<L<L<L<"))]
end
-
+
+ # Reads from process memory at the given address.
+ # @param addr [Integer] Address to read from
+ # @param size [Integer] How many bytes to read
+ # @return [String]
def read_memory(addr, size)
send(Command::READ_MEMORY, [addr, size].pack("Q<Q<")).wait_ok.payload
end
-
+
+ # Writes to process memory at the given address.
+ # @param addr [Integer] Address to write to
+ # @param string [String] Data to write
+ # @return [String]
def write_memory(addr, string)
send(Command::WRITE_MEMORY, [addr].pack("Q<") + string).wait_ok
+ string
end
-
+
+ # Lists threads in the target process.
+ # @return [self]
def list_threads
raise "nyi"
end
-
+
+ # Gets a debug event from the target process.
+ # @return [Switch::Debug::Event, nil] A debug event, or nil if none were left
def get_debug_event
rs = send(Command::GET_DEBUG_EVENT).wait
if rs.result_code == 0x8c01 then # no debug events left
return nil
+ else
+ rs.assert_ok
end
return Switch::Debug::Event::Event.unpack(rs.payload)
end
-
+
+ # Gets a thread's context.
+ # @return [self]
def get_thread_context(thread_id)
raise "nyi"
end
-
+
+ # Breaks the target process.
+ # @return [self]
def break_process
raise "nyi"
end
-
+
+ # Continues the target process.
+ # @param flags [Integer] See http://www.switchbrew.org/index.php?title=SVC#ContinueDebugFlagsOld
+ # @return [self]
def continue_debug_event(flags, thread_ids=[])
send(Command::CONTINUE_DEBUG_EVENT, ([flags] + thread_ids).pack("L<Q<*")).wait_ok
- nil
+ self
end
-
+
+ # Sets a thread's context.
+ # @return [self]
def set_thread_context(thread_id)
raise "nyi"
end
-
+
+ # Queries NSO info for the target process.
+ # @return [Array<Hash>]
def get_nso_infos
response = send(Command::GET_NSO_INFOS).wait_ok.payload
count = response.unpack("Q<")[0]
count.times.map do |i|
Hash[
[:base, :size, :build_id].zip(response[8 + 0x30 * i, 0x30].unpack("Q<Q<a32"))]
end
end
-
+
+ # Yields from a separate thread when a debug event is available.
+ # @return [self]
def wait_event_async(&block)
send(Command::WAIT_EVENT, String.new, &block)
+ self
end
-
+
+ # Waits for a debug event to become available.
+ # @return [self]
def wait_event
send(Command::WAIT_EVENT).wait_ok
+ self
end
end
end
end