Renamed Interface to Monitor, since it's no longer the gdb interface . . .
[aesalon.git] / src / monitor / ptrace / Portal.cpp
blobeebdccc3b3383fe360bc00c3cb6e19493247d710
1 #include <iostream>
2 #include <sys/user.h>
3 #include <sys/ptrace.h>
4 #include <sys/types.h>
5 #include <sys/wait.h>
6 #include <unistd.h>
7 #include <errno.h>
8 #include <signal.h>
9 #include <cstring>
10 #include <iostream>
12 #include "Portal.h"
14 #include "ExitObserver.h"
15 #include "TrapObserver.h"
17 #include "Message.h"
19 namespace Aesalon {
20 namespace Monitor {
21 namespace PTrace {
23 Portal::Portal(Misc::SmartPointer<Platform::ArgumentList> argument_list) : pid(0) {
25 pid = fork();
26 if(pid == -1)
27 throw PTraceException(Misc::StreamAsString() << "Forking to create child process failed: " << strerror(errno));
28 else if(pid == 0) {
29 ptrace(PTRACE_TRACEME, 0, NULL, NULL);
30 if(execv(argument_list->get_argument(0).c_str(), argument_list->get_as_argv()) == -1) {
31 throw PTraceException(Misc::StreamAsString() << "Failed to execute process: " << strerror(errno));
35 /*ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD);*/
37 add_signal_observer(new ExitObserver());
38 add_signal_observer(new TrapObserver());
41 Platform::MemoryAddress Portal::get_register(register_e which) const {
42 struct user_regs_struct registers;
43 if(ptrace(PTRACE_GETREGS, pid, NULL, &registers) == -1)
44 throw PTraceException(Misc::StreamAsString() << "Couldn't get register values: " << strerror(errno));
46 switch(which) {
47 #if AESALON_PLATFORM == AESALON_PLATFORM_x86_64
48 case RAX:
49 std::cout << "Value of RAX requested; RAX is " << registers.rax << ", ORIG_RAX is " << registers.orig_rax << std::endl;
50 return registers.orig_rax;
51 case RBX:
52 return registers.rbx;
53 case RIP:
54 return registers.rip;
55 #endif
56 default:
57 throw PTraceException("Value of invalid register requested");
61 Word Portal::read_memory(Platform::MemoryAddress address) const {
62 SWord return_value = ptrace(PTRACE_PEEKDATA, pid, address, NULL);
63 if(return_value == -1 && errno != 0)
64 throw PTraceException(Misc::StreamAsString() << "Couldn't read memory: " << strerror(errno));
65 /* NOTE: what happens if return_value is < 0? . .. */
66 return return_value;
69 void Portal::write_memory(Platform::MemoryAddress address, Word value) {
70 if(ptrace(PTRACE_POKEDATA, pid, address, value) == -1)
71 throw PTraceException(Misc::StreamAsString() << "Couldn't write memory: " << strerror(errno));
74 void Portal::write_memory(Platform::MemoryAddress address, Byte value) {
75 Word current_value = read_memory(address);
76 current_value &= ~0xff;
77 write_memory(address, current_value | value);
80 void Portal::attach() {
81 ptrace(PTRACE_ATTACH, pid, NULL, NULL);
84 void Portal::place_breakpoint(Platform::MemoryAddress address) {
85 Byte original = read_memory(address) & 0xff;
86 add_breakpoint(new Breakpoint(address, original));
87 write_memory(address, Byte(0xcc));
90 Misc::SmartPointer<Breakpoint> Portal::get_breakpoint_by_id(std::size_t which) const {
91 for(breakpoint_list_t::const_iterator i = breakpoint_list.begin(); i != breakpoint_list.end(); i ++) {
92 if((*i)->get_id() == which) return *i;
94 return NULL;
97 Misc::SmartPointer<Breakpoint> Portal::get_breakpoint_by_address(Platform::MemoryAddress address) const {
98 for(breakpoint_list_t::const_iterator i = breakpoint_list.begin(); i != breakpoint_list.end(); i ++) {
99 if((*i)->get_address() == address) return *i;
101 return NULL;
105 void Portal::handle_signal() {
106 int signal;
107 int status = wait_for_signal();
108 if(!WIFEXITED(status) && WIFSTOPPED(status)) {
109 siginfo_t signal_info;
110 if(ptrace(PTRACE_GETSIGINFO, pid, NULL, &signal_info) == -1) {
111 throw PTraceException(Misc::StreamAsString() << "Failed to get signal information: " << strerror(errno));
113 signal = signal_info.si_signo;
115 else signal = -1;
117 std::cout << "Portal::handle_signal(): status: (" << status << "): ";
119 for(int mask = 1 << 20; mask > 0; mask >>= 1) {
120 std::cout << ((status & mask)?"1":"0");
123 std::cout << ", signal: " << signal << std::endl;
125 for(signal_observer_list_t::iterator i = signal_observer_list.begin(); i != signal_observer_list.end(); i ++) {
126 if((*i)->handle_signal(signal, status)) return;
130 void Portal::continue_execution(int signal) {
131 if(ptrace(PTRACE_CONT, pid, NULL, NULL) == -1)
132 throw PTraceException(Misc::StreamAsString() << "Couldn't continue program execution: " << strerror(errno));
135 void Portal::single_step() {
136 if(ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) == -1)
137 throw PTraceException(Misc::StreamAsString() << "Couldn't single-step program:" << strerror(errno));
140 int Portal::wait_for_signal() {
141 int status;
142 if(waitpid(pid, &status, 0) == -1) throw PTraceException(Misc::StreamAsString() << "Couldn't waitpid() on child: " << strerror(errno));
143 return status;
146 void Portal::handle_breakpoint() {
147 Misc::SmartPointer<Breakpoint> breakpoint = get_breakpoint_by_address(get_register(RIP));
148 if(!breakpoint.is_valid()) {
149 Message(Message::DEBUG_MESSAGE, "handle_breakpoint() called on non-breakpoint");
150 return;
152 write_memory(breakpoint->get_address(), breakpoint->get_original());
153 single_step();
154 write_memory(breakpoint->get_address(), breakpoint->get_breakpoint_character());
157 } // namespace PTrace
158 } // namespace Monitor
159 } // namespace Aesalon