DebugSession.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Demangle.h>
  8. #include <AK/HashMap.h>
  9. #include <AK/MappedFile.h>
  10. #include <AK/NonnullRefPtr.h>
  11. #include <AK/Optional.h>
  12. #include <AK/OwnPtr.h>
  13. #include <AK/String.h>
  14. #include <LibC/sys/arch/i386/regs.h>
  15. #include <LibDebug/DebugInfo.h>
  16. #include <signal.h>
  17. #include <stdio.h>
  18. #include <sys/ptrace.h>
  19. #include <sys/wait.h>
  20. #include <unistd.h>
  21. namespace Debug {
  22. class DebugSession {
  23. public:
  24. static OwnPtr<DebugSession> exec_and_attach(String const& command, String source_root = {});
  25. ~DebugSession();
  26. int pid() const { return m_debuggee_pid; }
  27. bool poke(u32* address, u32 data);
  28. Optional<u32> peek(u32* address) const;
  29. bool poke_debug(u32 register_index, u32 data);
  30. Optional<u32> peek_debug(u32 register_index) const;
  31. enum class BreakPointState {
  32. Enabled,
  33. Disabled,
  34. };
  35. struct BreakPoint {
  36. void* address { nullptr };
  37. u32 original_first_word { 0 };
  38. BreakPointState state { BreakPointState::Disabled };
  39. };
  40. struct InsertBreakpointAtSymbolResult {
  41. String library_name;
  42. FlatPtr address { 0 };
  43. };
  44. Optional<InsertBreakpointAtSymbolResult> insert_breakpoint(String const& symbol_name);
  45. struct InsertBreakpointAtSourcePositionResult {
  46. String library_name;
  47. String filename;
  48. size_t line_number { 0 };
  49. FlatPtr address { 0 };
  50. };
  51. Optional<InsertBreakpointAtSourcePositionResult> insert_breakpoint(String const& filename, size_t line_number);
  52. bool insert_breakpoint(void* address);
  53. bool disable_breakpoint(void* address);
  54. bool enable_breakpoint(void* address);
  55. bool remove_breakpoint(void* address);
  56. bool breakpoint_exists(void* address) const;
  57. struct WatchPoint {
  58. void* address { nullptr };
  59. u32 debug_register_index { 0 };
  60. u32 ebp { 0 };
  61. };
  62. bool insert_watchpoint(void* address, u32 ebp);
  63. bool remove_watchpoint(void* address);
  64. bool disable_watchpoint(void* address);
  65. bool watchpoint_exists(void* address) const;
  66. void dump_breakpoints()
  67. {
  68. for (auto addr : m_breakpoints.keys()) {
  69. dbgln("{}", addr);
  70. }
  71. }
  72. PtraceRegisters get_registers() const;
  73. void set_registers(PtraceRegisters const&);
  74. enum class ContinueType {
  75. FreeRun,
  76. Syscall,
  77. };
  78. void continue_debuggee(ContinueType type = ContinueType::FreeRun);
  79. // Returns the wstatus result of waitpid()
  80. int continue_debuggee_and_wait(ContinueType type = ContinueType::FreeRun);
  81. // Returns the new eip
  82. void* single_step();
  83. void detach();
  84. enum DesiredInitialDebugeeState {
  85. Running,
  86. Stopped
  87. };
  88. template<typename Callback>
  89. void run(DesiredInitialDebugeeState, Callback);
  90. enum DebugDecision {
  91. Continue,
  92. SingleStep,
  93. ContinueBreakAtSyscall,
  94. Detach,
  95. Kill,
  96. };
  97. enum DebugBreakReason {
  98. Breakpoint,
  99. Syscall,
  100. Exited,
  101. };
  102. struct LoadedLibrary {
  103. String name;
  104. NonnullRefPtr<MappedFile> file;
  105. NonnullOwnPtr<ELF::Image> image;
  106. NonnullOwnPtr<DebugInfo> debug_info;
  107. FlatPtr base_address;
  108. LoadedLibrary(String const& name, NonnullRefPtr<MappedFile> file, NonnullOwnPtr<ELF::Image> image, NonnullOwnPtr<DebugInfo>&& debug_info, FlatPtr base_address)
  109. : name(name)
  110. , file(move(file))
  111. , image(move(image))
  112. , debug_info(move(debug_info))
  113. , base_address(base_address)
  114. {
  115. }
  116. };
  117. template<typename Func>
  118. void for_each_loaded_library(Func f) const
  119. {
  120. for (const auto& lib_name : m_loaded_libraries.keys()) {
  121. const auto& lib = *m_loaded_libraries.get(lib_name).value();
  122. if (f(lib) == IterationDecision::Break)
  123. break;
  124. }
  125. }
  126. const LoadedLibrary* library_at(FlatPtr address) const;
  127. struct SymbolicationResult {
  128. String library_name;
  129. String symbol;
  130. };
  131. Optional<SymbolicationResult> symbolicate(FlatPtr address) const;
  132. Optional<DebugInfo::SourcePositionAndAddress> get_address_from_source_position(String const& file, size_t line) const;
  133. Optional<DebugInfo::SourcePosition> get_source_position(FlatPtr address) const;
  134. private:
  135. explicit DebugSession(pid_t, String source_root);
  136. // x86 breakpoint instruction "int3"
  137. static constexpr u8 BREAKPOINT_INSTRUCTION = 0xcc;
  138. void update_loaded_libs();
  139. int m_debuggee_pid { -1 };
  140. String m_source_root;
  141. bool m_is_debuggee_dead { false };
  142. HashMap<void*, BreakPoint> m_breakpoints;
  143. HashMap<void*, WatchPoint> m_watchpoints;
  144. // Maps from base address to loaded library
  145. HashMap<String, NonnullOwnPtr<LoadedLibrary>> m_loaded_libraries;
  146. };
  147. template<typename Callback>
  148. void DebugSession::run(DesiredInitialDebugeeState initial_debugee_state, Callback callback)
  149. {
  150. enum class State {
  151. FirstIteration,
  152. FreeRun,
  153. Syscall,
  154. ConsecutiveBreakpoint,
  155. SingleStep,
  156. };
  157. State state { State::FirstIteration };
  158. auto do_continue_and_wait = [&]() {
  159. int wstatus = continue_debuggee_and_wait((state == State::Syscall) ? ContinueType::Syscall : ContinueType::FreeRun);
  160. // FIXME: This check actually only checks whether the debuggee
  161. // stopped because it hit a breakpoint/syscall/is in single stepping mode or not
  162. if (WSTOPSIG(wstatus) != SIGTRAP) {
  163. callback(DebugBreakReason::Exited, Optional<PtraceRegisters>());
  164. m_is_debuggee_dead = true;
  165. return true;
  166. }
  167. return false;
  168. };
  169. for (;;) {
  170. if ((state == State::FirstIteration && initial_debugee_state == DesiredInitialDebugeeState::Running) || state == State::FreeRun || state == State::Syscall) {
  171. if (do_continue_and_wait())
  172. break;
  173. }
  174. if (state == State::FirstIteration)
  175. state = State::FreeRun;
  176. auto regs = get_registers();
  177. #if ARCH(I386)
  178. FlatPtr current_instruction = regs.eip;
  179. #else
  180. FlatPtr current_instruction = regs.rip;
  181. #endif
  182. auto debug_status = peek_debug(DEBUG_STATUS_REGISTER);
  183. if (debug_status.has_value() && (debug_status.value() & 0b1111) > 0) {
  184. // Tripped a watchpoint
  185. auto watchpoint_index = debug_status.value() & 0b1111;
  186. Optional<WatchPoint> watchpoint {};
  187. for (auto wp : m_watchpoints) {
  188. if ((watchpoint_index & (1 << wp.value.debug_register_index)) == 0)
  189. continue;
  190. watchpoint = wp.value;
  191. break;
  192. }
  193. if (watchpoint.has_value()) {
  194. auto required_ebp = watchpoint.value().ebp;
  195. auto found_ebp = false;
  196. #if ARCH(I386)
  197. FlatPtr current_ebp = regs.ebp;
  198. #else
  199. FlatPtr current_ebp = regs.rbp;
  200. #endif
  201. do {
  202. if (current_ebp == required_ebp) {
  203. found_ebp = true;
  204. break;
  205. }
  206. auto return_address = peek(reinterpret_cast<u32*>(current_ebp + sizeof(FlatPtr)));
  207. auto next_ebp = peek(reinterpret_cast<u32*>(current_ebp));
  208. VERIFY(return_address.has_value());
  209. VERIFY(next_ebp.has_value());
  210. current_instruction = return_address.value();
  211. current_ebp = next_ebp.value();
  212. } while (current_ebp && current_instruction);
  213. if (!found_ebp) {
  214. dbgln("Removing watchpoint at {:p} because it went out of scope!", watchpoint.value().address);
  215. remove_watchpoint(watchpoint.value().address);
  216. continue;
  217. }
  218. }
  219. }
  220. Optional<BreakPoint> current_breakpoint;
  221. if (state == State::FreeRun || state == State::Syscall) {
  222. current_breakpoint = m_breakpoints.get((void*)((uintptr_t)current_instruction - 1));
  223. if (current_breakpoint.has_value())
  224. state = State::FreeRun;
  225. } else {
  226. current_breakpoint = m_breakpoints.get((void*)current_instruction);
  227. }
  228. if (current_breakpoint.has_value()) {
  229. // We want to make the breakpoint transparent to the user of the debugger.
  230. // To achieve this, we perform two rollbacks:
  231. // 1. Set regs.eip to point at the actual address of the instruction we breaked on.
  232. // regs.eip currently points to one byte after the address of the original instruction,
  233. // because the cpu has just executed the INT3 we patched into the instruction.
  234. // 2. We restore the original first byte of the instruction,
  235. // because it was patched with INT3.
  236. auto breakpoint_addr = reinterpret_cast<uintptr_t>(current_breakpoint.value().address);
  237. #if ARCH(I386)
  238. regs.eip = breakpoint_addr;
  239. #else
  240. regs.rip = breakpoint_addr;
  241. #endif
  242. set_registers(regs);
  243. disable_breakpoint(current_breakpoint.value().address);
  244. }
  245. DebugBreakReason reason = (state == State::Syscall && !current_breakpoint.has_value()) ? DebugBreakReason::Syscall : DebugBreakReason::Breakpoint;
  246. DebugDecision decision = callback(reason, regs);
  247. if (reason == DebugBreakReason::Syscall) {
  248. // skip the exit from the syscall
  249. if (do_continue_and_wait())
  250. break;
  251. }
  252. if (decision == DebugDecision::Continue) {
  253. state = State::FreeRun;
  254. } else if (decision == DebugDecision::ContinueBreakAtSyscall) {
  255. state = State::Syscall;
  256. }
  257. bool did_single_step = false;
  258. // Re-enable the breakpoint if it wasn't removed by the user
  259. if (current_breakpoint.has_value() && m_breakpoints.contains(current_breakpoint.value().address)) {
  260. // The current breakpoint was removed to make it transparent to the user.
  261. // We now want to re-enable it - the code execution flow could hit it again.
  262. // To re-enable the breakpoint, we first perform a single step and execute the
  263. // instruction of the breakpoint, and then redo the INT3 patch in its first byte.
  264. // If the user manually inserted a breakpoint at were we breaked at originally,
  265. // we need to disable that breakpoint because we want to singlestep over it to execute the
  266. // instruction we breaked on (we re-enable it again later anyways).
  267. if (m_breakpoints.contains(current_breakpoint.value().address) && m_breakpoints.get(current_breakpoint.value().address).value().state == BreakPointState::Enabled) {
  268. disable_breakpoint(current_breakpoint.value().address);
  269. }
  270. auto stopped_address = single_step();
  271. enable_breakpoint(current_breakpoint.value().address);
  272. did_single_step = true;
  273. // If there is another breakpoint after the current one,
  274. // Then we are already on it (because of single_step)
  275. auto breakpoint_at_next_instruction = m_breakpoints.get(stopped_address);
  276. if (breakpoint_at_next_instruction.has_value()
  277. && breakpoint_at_next_instruction.value().state == BreakPointState::Enabled) {
  278. state = State::ConsecutiveBreakpoint;
  279. }
  280. }
  281. if (decision == DebugDecision::SingleStep) {
  282. state = State::SingleStep;
  283. }
  284. if (decision == DebugDecision::Detach) {
  285. detach();
  286. break;
  287. }
  288. if (decision == DebugDecision::Kill) {
  289. kill(m_debuggee_pid, SIGTERM);
  290. break;
  291. }
  292. if (state == State::SingleStep && !did_single_step) {
  293. single_step();
  294. }
  295. }
  296. }
  297. }