1// LLDB C++ API Test: Verify that when the Debugger stdin 2// is set to a FILE *, lldb can still successfully run a 3// python command in a stop hook. 4 5#include <errno.h> 6#include <mutex> 7#include <stdio.h> 8#include <string> 9#include <vector> 10 11%include_SB_APIs% 12 13#include "common.h" 14 15#if !defined(PATH_MAX) 16#define PATH_MAX 4096 17#endif 18 19using namespace lldb; 20 21void test(SBDebugger &dbg, std::vector<std::string> args) { 22 // The problem we had was that when the thread that was 23 // waiting on input went into the call to 'read' it had 24 // the file handle lock. Then when the python interpreter 25 // Initialized itself to run the python command, it tried 26 // to flush the file channel, and that deadlocked. 27 // This only happens when Async is true, since otherwise 28 // the process event is handled on the I/O read thread, 29 // which sidestepped the problem. 30 dbg.SetAsync(true); 31 32 SBTarget target = dbg.CreateTarget(args.at(0).c_str()); 33 if (!target.IsValid()) 34 throw Exception("invalid target"); 35 36 SBBreakpoint breakpoint = target.BreakpointCreateByName("next"); 37 if (!breakpoint.IsValid()) 38 throw Exception("invalid breakpoint"); 39 40 SBCommandInterpreter interp = dbg.GetCommandInterpreter(); 41 SBCommandReturnObject result; 42 43 // Bring in the python command. We actually add two commands, 44 // one that runs in the stop hook and sets a variable when it 45 // runs, and one that reports out the variable so we can ensure 46 // that we did indeed run the stop hook. 47 const char *source_dir = "%SOURCE_DIR%"; 48 SBFileSpec script_spec(source_dir); 49 script_spec.AppendPathComponent("some_cmd.py"); 50 char path[PATH_MAX]; 51 script_spec.GetPath(path, PATH_MAX); 52 53 std::string import_command("command script import "); 54 import_command.append(path); 55 interp.HandleCommand(import_command.c_str(), result); 56 if (!result.Succeeded()) 57 throw Exception("Couldn't import %SOURCE_DIR%/some_cmd.py"); 58 59 SBProcess process = target.LaunchSimple(nullptr, nullptr, nullptr); 60 if (!process.IsValid()) 61 throw Exception("Couldn't launch process."); 62 if (process.GetState() != lldb::eStateStopped) 63 throw Exception("Process was not stopped"); 64 65 process.SetSelectedThreadByIndexID(0); 66 67 // Now add the stop hook: 68 interp.HandleCommand("target stop-hook add -o some-cmd", result); 69 if (!result.Succeeded()) 70 throw Exception("Couldn't add a stop hook."); 71 72 // Now switch the I/O over to a pipe, which will be handled by the 73 // NativeFile class: 74 int to_lldb_des[2]; 75 int pipe_result = pipe(to_lldb_des); 76 FILE *fh_lldb_in = fdopen(to_lldb_des[0], "r"); 77 FILE *fh_to_lldb = fdopen(to_lldb_des[1], "w"); 78 79 // We need to reset the handle before destroying the debugger 80 // or the same deadlock will stall exiting: 81 class Cleanup { 82 public: 83 Cleanup(SBDebugger dbg, int filedes[2]) : m_dbg(dbg) { 84 m_file = m_dbg.GetInputFileHandle(); 85 m_filedes[0] = filedes[0]; 86 m_filedes[1] = filedes[1]; 87 } 88 ~Cleanup() { 89 m_dbg.SetInputFileHandle(m_file, false); 90 close(m_filedes[0]); 91 close(m_filedes[1]); 92 } 93 94 private: 95 FILE *m_file; 96 SBDebugger m_dbg; 97 int m_filedes[2]; 98 }; 99 Cleanup cleanup(dbg, to_lldb_des); 100 101 dbg.SetInputFileHandle(fh_lldb_in, false); 102 103 // Now run the command interpreter. You have to pass true to 104 // start thread so we will run the I/O in a separate thread. 105 dbg.RunCommandInterpreter(false, true); 106 107 // Now issue a stepi, and fetch the running and stopped events: 108 fprintf(fh_to_lldb, "thread step-inst\n"); 109 110 SBEvent proc_event; 111 StateType state; 112 bool got_event; 113 114 got_event = dbg.GetListener().WaitForEventForBroadcaster( 115 100, process.GetBroadcaster(), proc_event); 116 if (!got_event) 117 throw Exception("Didn't get running event"); 118 state = SBProcess::GetStateFromEvent(proc_event); 119 if (state != eStateRunning) 120 throw Exception("Event wasn't a running event."); 121 122 got_event = dbg.GetListener().WaitForEventForBroadcaster( 123 100, process.GetBroadcaster(), proc_event); 124 if (!got_event) 125 throw Exception("Didn't get a stopped event"); 126 state = SBProcess::GetStateFromEvent(proc_event); 127 if (state != eStateStopped) 128 throw Exception("Event wasn't a stop event."); 129 130 // At this point the stop hook should have run. Check that: 131 interp.HandleCommand("report-cmd", result); 132 if (!result.Succeeded()) 133 throw Exception("Didn't actually call stop hook."); 134} 135