diff options
author | Ed Maste <emaste@FreeBSD.org> | 2014-02-18 16:23:10 +0000 |
---|---|---|
committer | Ed Maste <emaste@FreeBSD.org> | 2014-02-18 16:23:10 +0000 |
commit | 866dcdacfe59f5f448e008fe2c4cb9dfcf72b2ec (patch) | |
tree | 95cb16075f0af1b3a05b9b84eb18dda8e6c903e9 /tools/driver | |
parent | de889deb2c386f2a7831befaf226e5c86685fa53 (diff) | |
download | src-866dcdacfe59f5f448e008fe2c4cb9dfcf72b2ec.tar.gz src-866dcdacfe59f5f448e008fe2c4cb9dfcf72b2ec.zip |
Import lldb as of SVN r201577 (git 2bdc2f6)vendor/lldb/lldb-r201577
(A number of files not required for the FreeBSD build have been removed.)
Sponsored by: DARPA, AFRL
Notes
Notes:
svn path=/vendor/lldb/dist/; revision=262182
svn path=/vendor/lldb/lldb-r201577/; revision=262183; tag=vendor/lldb/lldb-r201577
Diffstat (limited to 'tools/driver')
-rw-r--r-- | tools/driver/Driver.cpp | 984 | ||||
-rw-r--r-- | tools/driver/Driver.h | 80 | ||||
-rw-r--r-- | tools/driver/ELWrapper.cpp | 422 | ||||
-rw-r--r-- | tools/driver/ELWrapper.h | 122 | ||||
-rw-r--r-- | tools/driver/GetOptWrapper.cpp | 33 | ||||
-rw-r--r-- | tools/driver/GetOptWrapper.h | 49 | ||||
-rw-r--r-- | tools/driver/IOChannel.cpp | 656 | ||||
-rw-r--r-- | tools/driver/IOChannel.h | 154 | ||||
-rw-r--r-- | tools/driver/Platform.h | 3 |
9 files changed, 122 insertions, 2381 deletions
diff --git a/tools/driver/Driver.cpp b/tools/driver/Driver.cpp index e2742425dd4c..78d3a7e1c037 100644 --- a/tools/driver/Driver.cpp +++ b/tools/driver/Driver.cpp @@ -18,7 +18,6 @@ #include <string> #include <thread> -#include "IOChannel.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" @@ -83,20 +82,12 @@ static OptionDefinition g_options[] = "Tells the debugger to use the file <filename> as the program to be debugged." }, { LLDB_OPT_SET_3, false, "core" , 'c', required_argument, 0, eArgTypeFilename, "Tells the debugger to use the fullpath to <path> as the core file." }, + { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid, + "Tells the debugger to attach to a process with the given pid." }, { LLDB_OPT_SET_4, true , "attach-name" , 'n', required_argument, 0, eArgTypeProcessName, "Tells the debugger to attach to a process with the given name." }, { LLDB_OPT_SET_4, true , "wait-for" , 'w', no_argument , 0, eArgTypeNone, "Tells the debugger to wait for a process with the given pid or name to launch before attaching." }, - { LLDB_OPT_SET_5, true , "attach-pid" , 'p', required_argument, 0, eArgTypePid, - "Tells the debugger to attach to a process with the given pid." }, - { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang, - "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. " - "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python " - "extensions have been implemented." }, - { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself." }, - { LLDB_3_TO_5, false, "source-quietly" , 'b', no_argument , 0, eArgTypeNone, - "Tells the debugger to print out extra information for debugging itself." }, { LLDB_3_TO_5, false, "source" , 's', required_argument, 0, eArgTypeFilename, "Tells the debugger to read in and execute the lldb commands in the given file, after any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "one-line" , 'o', required_argument, 0, eArgTypeNone, @@ -105,6 +96,8 @@ static OptionDefinition g_options[] = "Tells the debugger to read in and execute the lldb commands in the given file, before any file provided on the command line has been loaded." }, { LLDB_3_TO_5, false, "one-line-before-file" , 'O', required_argument, 0, eArgTypeNone, "Tells the debugger to execute this one-line lldb command before any file provided on the command line has been loaded." }, + { LLDB_3_TO_5, false, "source-quietly" , 'Q', no_argument , 0, eArgTypeNone, + "Tells the debugger suppress output from commands provided in the -s, -S, -O and -o commands." }, { LLDB_3_TO_5, false, "editor" , 'e', no_argument , 0, eArgTypeNone, "Tells the debugger to open source files using the host's \"external editor\" mechanism." }, { LLDB_3_TO_5, false, "no-lldbinit" , 'x', no_argument , 0, eArgTypeNone, @@ -113,6 +106,12 @@ static OptionDefinition g_options[] = "Do not use colors." }, { LLDB_OPT_SET_6, true , "python-path" , 'P', no_argument , 0, eArgTypeNone, "Prints out the path to the lldb.py file for this version of lldb." }, + { LLDB_3_TO_5, false, "script-language", 'l', required_argument, 0, eArgTypeScriptLang, + "Tells the debugger to use the specified scripting language for user-defined scripts, rather than the default. " + "Valid scripting languages that can be specified include Python, Perl, Ruby and Tcl. Currently only the Python " + "extensions have been implemented." }, + { LLDB_3_TO_5, false, "debug" , 'd', no_argument , 0, eArgTypeNone, + "Tells the debugger to print out extra information for debugging itself." }, { 0, false, NULL , 0 , 0 , 0, eArgTypeNone, NULL } }; @@ -121,14 +120,7 @@ static const uint32_t last_option_set_with_args = 2; Driver::Driver () : SBBroadcaster ("Driver"), m_debugger (SBDebugger::Create(false)), - m_editline_pty (), - m_editline_slave_fh (NULL), - m_editline_reader (), - m_io_channel_ap (), - m_option_data (), - m_executing_user_command (false), - m_waiting_for_command (false), - m_done(false) + m_option_data () { // We want to be able to handle CTRL+D in the terminal to have it terminate // certain input @@ -145,24 +137,6 @@ Driver::~Driver () g_debugger_name = NULL; } -void -Driver::CloseIOChannelFile () -{ - // Write an End of File sequence to the file descriptor to ensure any - // read functions can exit. - char eof_str[] = "\x04"; - int mfd = m_editline_pty.GetMasterFileDescriptor(); - if (mfd != -1) - ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str)); - - m_editline_pty.CloseMasterFileDescriptor(); - - if (m_editline_slave_fh) - { - ::fclose (m_editline_slave_fh); - m_editline_slave_fh = NULL; - } -} // This function takes INDENT, which tells how many spaces to output at the front // of each line; TEXT, which is the text that is to be output. It outputs the @@ -346,7 +320,11 @@ ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data) } indent_level -= 5; - + + fprintf (out, "\n%*sNotes:\n", + indent_level, ""); + indent_level += 5; + fprintf (out, "\n%*sMultiple \"-s\" and \"-o\" options can be provided. They will be processed from left to right in order, " "\n%*swith the source files and commands interleaved. The same is true of the \"-S\" and \"-O\" options." "\n%*sThe before file and after file sets can intermixed freely, the command parser will sort them out." @@ -356,9 +334,9 @@ ShowUsage (FILE *out, OptionDefinition *option_table, Driver::OptionData data) indent_level, "", indent_level, ""); - fprintf (out, "\n%*s(If you don't provide -f then the first argument will be the file to be debugged" - "\n%*s so '%s -- <filename> [<ARG1> [<ARG2>]]' also works." - "\n%*s Remember to end the options with \"--\" if any of your arguments have a \"-\" in them.)\n\n", + fprintf (out, "\n%*sIf you don't provide -f then the first argument will be the file to be debugged" + "\n%*swhich means that '%s -- <filename> [<ARG1> [<ARG2>]]' also works." + "\n%*sBut remember to end the options with \"--\" if any of your arguments have a \"-\" in them.\n\n", indent_level, "", indent_level, "", name, @@ -521,7 +499,7 @@ Driver::ExecuteInitialCommands (bool before_file) const char *executed_command = command; if (is_file) { - ::snprintf (command_string, sizeof(command_string), "command source '%s'", command); + ::snprintf (command_string, sizeof(command_string), "command source -s %i '%s'", m_option_data.m_source_quietly, command); executed_command = command_string; } @@ -530,23 +508,27 @@ Driver::ExecuteInitialCommands (bool before_file) { const size_t output_size = result.GetOutputSize(); if (output_size > 0) - m_io_channel_ap->OutWrite (result.GetOutput(dump_stream_only_if_no_immediate), output_size, NO_ASYNC); + { + const char *cstr = result.GetOutput(dump_stream_only_if_no_immediate); + if (cstr) + printf ("%s", cstr); + } const size_t error_size = result.GetErrorSize(); if (error_size > 0) - m_io_channel_ap->OutWrite (result.GetError(dump_stream_only_if_no_immediate), error_size, NO_ASYNC); + { + const char *cstr = result.GetError(dump_stream_only_if_no_immediate); + if (cstr) + printf ("%s", cstr); + } } if (result.Succeeded() == false) { - char error_buffer[1024]; - size_t error_size; const char *type = before_file ? "before file" : "after_file"; if (is_file) - error_size = ::snprintf(error_buffer, sizeof(error_buffer), "Aborting %s command execution, command file: '%s' failed.\n", type, command); + ::fprintf(stderr, "Aborting %s command execution, command file: '%s' failed.\n", type, command); else - error_size = ::snprintf(error_buffer, sizeof(error_buffer), "Aborting %s command execution, command: '%s' failed.\n", type, command); - - m_io_channel_ap->OutWrite(error_buffer, error_size, NO_ASYNC); + ::fprintf(stderr, "Aborting %s command execution, command: '%s' failed.\n", type, command); break; } result.Clear(); @@ -747,7 +729,7 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) m_option_data.m_debug_mode = true; break; - case 'q': + case 'Q': m_option_data.m_source_quietly = true; break; @@ -861,524 +843,9 @@ Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting) return error; } -size_t -Driver::GetProcessSTDOUT () -{ - // The process has stuff waiting for stdout; get it and write it out to the appropriate place. - char stdio_buffer[1024]; - size_t len; - size_t total_bytes = 0; - while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDOUT (stdio_buffer, sizeof (stdio_buffer))) > 0) - { - m_io_channel_ap->OutWrite (stdio_buffer, len, NO_ASYNC); - total_bytes += len; - } - return total_bytes; -} - -size_t -Driver::GetProcessSTDERR () -{ - // The process has stuff waiting for stderr; get it and write it out to the appropriate place. - char stdio_buffer[1024]; - size_t len; - size_t total_bytes = 0; - while ((len = m_debugger.GetSelectedTarget().GetProcess().GetSTDERR (stdio_buffer, sizeof (stdio_buffer))) > 0) - { - m_io_channel_ap->ErrWrite (stdio_buffer, len, NO_ASYNC); - total_bytes += len; - } - return total_bytes; -} - -void -Driver::UpdateSelectedThread () -{ - using namespace lldb; - SBProcess process(m_debugger.GetSelectedTarget().GetProcess()); - if (process.IsValid()) - { - SBThread curr_thread (process.GetSelectedThread()); - SBThread thread; - StopReason curr_thread_stop_reason = eStopReasonInvalid; - curr_thread_stop_reason = curr_thread.GetStopReason(); - - if (!curr_thread.IsValid() || - curr_thread_stop_reason == eStopReasonInvalid || - curr_thread_stop_reason == eStopReasonNone) - { - // Prefer a thread that has just completed its plan over another thread as current thread. - SBThread plan_thread; - SBThread other_thread; - const size_t num_threads = process.GetNumThreads(); - size_t i; - for (i = 0; i < num_threads; ++i) - { - thread = process.GetThreadAtIndex(i); - StopReason thread_stop_reason = thread.GetStopReason(); - switch (thread_stop_reason) - { - case eStopReasonInvalid: - case eStopReasonNone: - break; - - case eStopReasonTrace: - case eStopReasonBreakpoint: - case eStopReasonWatchpoint: - case eStopReasonSignal: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonThreadExiting: - if (!other_thread.IsValid()) - other_thread = thread; - break; - case eStopReasonPlanComplete: - if (!plan_thread.IsValid()) - plan_thread = thread; - break; - } - } - if (plan_thread.IsValid()) - process.SetSelectedThread (plan_thread); - else if (other_thread.IsValid()) - process.SetSelectedThread (other_thread); - else - { - if (curr_thread.IsValid()) - thread = curr_thread; - else - thread = process.GetThreadAtIndex(0); - - if (thread.IsValid()) - process.SetSelectedThread (thread); - } - } - } -} - -// This function handles events that were broadcast by the process. -void -Driver::HandleBreakpointEvent (const SBEvent &event) -{ - using namespace lldb; - const uint32_t event_type = SBBreakpoint::GetBreakpointEventTypeFromEvent (event); - - if (event_type & eBreakpointEventTypeAdded - || event_type & eBreakpointEventTypeRemoved - || event_type & eBreakpointEventTypeEnabled - || event_type & eBreakpointEventTypeDisabled - || event_type & eBreakpointEventTypeCommandChanged - || event_type & eBreakpointEventTypeConditionChanged - || event_type & eBreakpointEventTypeIgnoreChanged - || event_type & eBreakpointEventTypeLocationsResolved) - { - // Don't do anything about these events, since the breakpoint commands already echo these actions. - } - else if (event_type & eBreakpointEventTypeLocationsAdded) - { - char message[256]; - uint32_t num_new_locations = SBBreakpoint::GetNumBreakpointLocationsFromEvent(event); - if (num_new_locations > 0) - { - SBBreakpoint breakpoint = SBBreakpoint::GetBreakpointFromEvent(event); - int message_len = ::snprintf (message, sizeof(message), "%d location%s added to breakpoint %d\n", - num_new_locations, - num_new_locations == 1 ? "" : "s", - breakpoint.GetID()); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - } - else if (event_type & eBreakpointEventTypeLocationsRemoved) - { - // These locations just get disabled, not sure it is worth spamming folks about this on the command line. - } - else if (event_type & eBreakpointEventTypeLocationsResolved) - { - // This might be an interesting thing to note, but I'm going to leave it quiet for now, it just looked noisy. - } -} - -// This function handles events that were broadcast by the process. -void -Driver::HandleProcessEvent (const SBEvent &event) -{ - using namespace lldb; - const uint32_t event_type = event.GetType(); - - if (event_type & SBProcess::eBroadcastBitSTDOUT) - { - // The process has stdout available, get it and write it out to the - // appropriate place. - GetProcessSTDOUT (); - } - else if (event_type & SBProcess::eBroadcastBitSTDERR) - { - // The process has stderr available, get it and write it out to the - // appropriate place. - GetProcessSTDERR (); - } - else if (event_type & SBProcess::eBroadcastBitStateChanged) - { - // Drain all stout and stderr so we don't see any output come after - // we print our prompts - GetProcessSTDOUT (); - GetProcessSTDERR (); - // Something changed in the process; get the event and report the process's current status and location to - // the user. - StateType event_state = SBProcess::GetStateFromEvent (event); - if (event_state == eStateInvalid) - return; - - SBProcess process (SBProcess::GetProcessFromEvent (event)); - assert (process.IsValid()); - - switch (event_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateStepping: - case eStateDetached: - { - char message[1024]; - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " %s\n", process.GetProcessID(), - m_debugger.StateAsCString (event_state)); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - break; - - case eStateRunning: - // Don't be chatty when we run... - break; - - case eStateExited: - { - SBCommandReturnObject result; - m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); - m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); - m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); - } - break; - - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - // Make sure the program hasn't been auto-restarted: - if (SBProcess::GetRestartedFromEvent (event)) - { - size_t num_reasons = SBProcess::GetNumRestartedReasonsFromEvent(event); - if (num_reasons > 0) - { - // FIXME: Do we want to report this, or would that just be annoyingly chatty? - if (num_reasons == 1) - { - char message[1024]; - const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, 0); - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted: %s\n", - process.GetProcessID(), reason ? reason : "<UNKNOWN REASON>"); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - else - { - char message[1024]; - int message_len = ::snprintf (message, sizeof(message), "Process %" PRIu64 " stopped and restarted, reasons:\n", - process.GetProcessID()); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - for (size_t i = 0; i < num_reasons; i++) - { - const char *reason = SBProcess::GetRestartedReasonAtIndexFromEvent (event, i); - int message_len = ::snprintf(message, sizeof(message), "\t%s\n", reason ? reason : "<UNKNOWN REASON>"); - m_io_channel_ap->OutWrite(message, message_len, ASYNC); - } - } - } - } - else - { - if (GetDebugger().GetSelectedTarget() == process.GetTarget()) - { - SBCommandReturnObject result; - UpdateSelectedThread (); - m_debugger.GetCommandInterpreter().HandleCommand("process status", result, false); - m_io_channel_ap->ErrWrite (result.GetError(), result.GetErrorSize(), ASYNC); - m_io_channel_ap->OutWrite (result.GetOutput(), result.GetOutputSize(), ASYNC); - } - else - { - SBStream out_stream; - uint32_t target_idx = GetDebugger().GetIndexOfTarget(process.GetTarget()); - if (target_idx != UINT32_MAX) - out_stream.Printf ("Target %d: (", target_idx); - else - out_stream.Printf ("Target <unknown index>: ("); - process.GetTarget().GetDescription (out_stream, eDescriptionLevelBrief); - out_stream.Printf (") stopped.\n"); - m_io_channel_ap->OutWrite (out_stream.GetData(), out_stream.GetSize(), ASYNC); - } - } - break; - } - } -} - -void -Driver::HandleThreadEvent (const SBEvent &event) -{ - // At present the only thread event we handle is the Frame Changed event, and all we do for that is just - // reprint the thread status for that thread. - using namespace lldb; - const uint32_t event_type = event.GetType(); - if (event_type == SBThread::eBroadcastBitStackChanged - || event_type == SBThread::eBroadcastBitThreadSelected) - { - SBThread thread = SBThread::GetThreadFromEvent (event); - if (thread.IsValid()) - { - SBStream out_stream; - thread.GetStatus(out_stream); - m_io_channel_ap->OutWrite (out_stream.GetData (), out_stream.GetSize (), ASYNC); - } - } -} - -// This function handles events broadcast by the IOChannel (HasInput, UserInterrupt, or ThreadShouldExit). - -bool -Driver::HandleIOEvent (const SBEvent &event) -{ - bool quit = false; - - const uint32_t event_type = event.GetType(); - - if (event_type & IOChannel::eBroadcastBitHasUserInput) - { - // We got some input (i.e. a command string) from the user; pass it off to the command interpreter for - // handling. - - const char *command_string = SBEvent::GetCStringFromEvent(event); - if (command_string == NULL) - command_string = ""; - SBCommandReturnObject result; - - // We don't want the result to bypass the OutWrite function in IOChannel, as this can result in odd - // output orderings and problems with the prompt. - - // Note that we are in the process of executing a command - m_executing_user_command = true; - - m_debugger.GetCommandInterpreter().HandleCommand (command_string, result, true); - - // Note that we are back from executing a user command - m_executing_user_command = false; - - // Display any STDOUT/STDERR _prior_ to emitting the command result text - GetProcessSTDOUT (); - GetProcessSTDERR (); - - const bool only_if_no_immediate = true; - - // Now emit the command output text from the command we just executed - const size_t output_size = result.GetOutputSize(); - if (output_size > 0) - m_io_channel_ap->OutWrite (result.GetOutput(only_if_no_immediate), output_size, NO_ASYNC); - - // Now emit the command error text from the command we just executed - const size_t error_size = result.GetErrorSize(); - if (error_size > 0) - m_io_channel_ap->OutWrite (result.GetError(only_if_no_immediate), error_size, NO_ASYNC); - - // We are done getting and running our command, we can now clear the - // m_waiting_for_command so we can get another one. - m_waiting_for_command = false; - - // If our editline input reader is active, it means another input reader - // got pushed onto the input reader and caused us to become deactivated. - // When the input reader above us gets popped, we will get re-activated - // and our prompt will refresh in our callback - if (m_editline_reader.IsActive()) - { - ReadyForCommand (); - } - } - else if (event_type & IOChannel::eBroadcastBitUserInterrupt) - { - // This is here to handle control-c interrupts from the user. It has not yet really been implemented. - // TO BE DONE: PROPERLY HANDLE CONTROL-C FROM USER - //m_io_channel_ap->CancelInput(); - // Anything else? Send Interrupt to process? - } - else if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || - (event_type & IOChannel::eBroadcastBitThreadDidExit)) - { - // If the IOChannel thread is trying to go away, then it is definitely - // time to end the debugging session. - quit = true; - } - - return quit; -} - -void -Driver::MasterThreadBytesReceived (void *baton, const void *src, size_t src_len) -{ - Driver *driver = (Driver*)baton; - driver->GetFromMaster ((const char *)src, src_len); -} - -void -Driver::GetFromMaster (const char *src, size_t src_len) -{ - // Echo the characters back to the Debugger's stdout, that way if you - // type characters while a command is running, you'll see what you've typed. - FILE *out_fh = m_debugger.GetOutputFileHandle(); - if (out_fh) - ::fwrite (src, 1, src_len, out_fh); -} - -size_t -Driver::EditLineInputReaderCallback -( - void *baton, - SBInputReader *reader, - InputReaderAction notification, - const char *bytes, - size_t bytes_len -) -{ - Driver *driver = (Driver *)baton; - - switch (notification) - { - case eInputReaderActivate: - break; - - case eInputReaderReactivate: - if (driver->m_executing_user_command == false) - driver->ReadyForCommand(); - break; - - case eInputReaderDeactivate: - break; - - case eInputReaderAsynchronousOutputWritten: - if (driver->m_io_channel_ap.get() != NULL) - driver->m_io_channel_ap->RefreshPrompt(); - break; - - case eInputReaderInterrupt: - if (driver->m_io_channel_ap.get() != NULL) - { - SBProcess process(driver->GetDebugger().GetSelectedTarget().GetProcess()); - if (!driver->m_io_channel_ap->EditLineHasCharacters() - && process.IsValid() - && (process.GetState() == lldb::eStateRunning || process.GetState() == lldb::eStateAttaching)) - { - process.SendAsyncInterrupt (); - } - else - { - driver->m_io_channel_ap->OutWrite ("^C\n", 3, NO_ASYNC); - // I wish I could erase the entire input line, but there's no public API for that. - driver->m_io_channel_ap->EraseCharsBeforeCursor(); - driver->m_io_channel_ap->RefreshPrompt(); - } - } - break; - - case eInputReaderEndOfFile: - if (driver->m_io_channel_ap.get() != NULL) - { - driver->m_io_channel_ap->OutWrite ("^D\n", 3, NO_ASYNC); - driver->m_io_channel_ap->RefreshPrompt (); - } - write (driver->m_editline_pty.GetMasterFileDescriptor(), "quit\n", 5); - break; - - case eInputReaderGotToken: - write (driver->m_editline_pty.GetMasterFileDescriptor(), bytes, bytes_len); - break; - - case eInputReaderDone: - break; - } - return bytes_len; -} - void Driver::MainLoop () { -#if defined(_MSC_VER) - m_editline_slave_fh = stdin; - FILE *editline_output_slave_fh = stdout; - lldb_utility::PseudoTerminal editline_output_pty; -#else - - char error_str[1024]; - if (m_editline_pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, error_str, sizeof(error_str)) == false) - { - ::fprintf (stderr, "error: failed to open driver pseudo terminal : %s", error_str); - exit(1); - } - else - { - const char *driver_slave_name = m_editline_pty.GetSlaveName (error_str, sizeof(error_str)); - if (driver_slave_name == NULL) - { - ::fprintf (stderr, "error: failed to get slave name for driver pseudo terminal : %s", error_str); - exit(2); - } - else - { - m_editline_slave_fh = ::fopen (driver_slave_name, "r+"); - if (m_editline_slave_fh == NULL) - { - SBError error; - error.SetErrorToErrno(); - ::fprintf (stderr, "error: failed to get open slave for driver pseudo terminal : %s", - error.GetCString()); - exit(3); - } - - ::setbuf (m_editline_slave_fh, NULL); - } - } - - lldb_utility::PseudoTerminal editline_output_pty; - FILE *editline_output_slave_fh = NULL; - - if (editline_output_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, error_str, sizeof (error_str)) == false) - { - ::fprintf (stderr, "error: failed to open output pseudo terminal : %s", error_str); - exit(1); - } - else - { - const char *output_slave_name = editline_output_pty.GetSlaveName (error_str, sizeof(error_str)); - if (output_slave_name == NULL) - { - ::fprintf (stderr, "error: failed to get slave name for output pseudo terminal : %s", error_str); - exit(2); - } - else - { - editline_output_slave_fh = ::fopen (output_slave_name, "r+"); - if (editline_output_slave_fh == NULL) - { - SBError error; - error.SetErrorToErrno(); - ::fprintf (stderr, "error: failed to get open slave for output pseudo terminal : %s", - error.GetCString()); - exit(3); - } - ::setbuf (editline_output_slave_fh, NULL); - } - } -#endif - - // struct termios stdin_termios; - if (::tcgetattr(STDIN_FILENO, &g_old_stdin_termios) == 0) { g_old_stdin_termios_is_valid = true; @@ -1394,43 +861,6 @@ Driver::MainLoop () m_debugger.SetUseExternalEditor(m_option_data.m_use_external_editor); - // You have to drain anything that comes to the master side of the PTY. master_out_comm is - // for that purpose. The reason you need to do this is a curious reason... editline will echo - // characters to the PTY when it gets characters while el_gets is not running, and then when - // you call el_gets (or el_getc) it will try to reset the terminal back to raw mode which blocks - // if there are unconsumed characters in the out buffer. - // However, you don't need to do anything with the characters, since editline will dump these - // unconsumed characters after printing the prompt again in el_gets. - - SBCommunication master_out_comm("driver.editline"); - master_out_comm.SetCloseOnEOF (false); - master_out_comm.AdoptFileDesriptor(m_editline_pty.GetMasterFileDescriptor(), false); - master_out_comm.SetReadThreadBytesReceivedCallback(Driver::MasterThreadBytesReceived, this); - - if (master_out_comm.ReadThreadStart () == false) - { - ::fprintf (stderr, "error: failed to start master out read thread"); - exit(5); - } - - SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); - - m_io_channel_ap.reset (new IOChannel(m_editline_slave_fh, editline_output_slave_fh, stdout, stderr, this)); - -#if !defined (_MSC_VER) - SBCommunication out_comm_2("driver.editline_output"); - out_comm_2.SetCloseOnEOF (false); - out_comm_2.AdoptFileDesriptor (editline_output_pty.GetMasterFileDescriptor(), false); - out_comm_2.SetReadThreadBytesReceivedCallback (IOChannel::LibeditOutputBytesReceived, m_io_channel_ap.get()); - - if (out_comm_2.ReadThreadStart () == false) - { - ::fprintf (stderr, "error: failed to start libedit output read thread"); - exit (5); - } -#endif - - struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) @@ -1439,286 +869,114 @@ Driver::MainLoop () m_debugger.SetTerminalWidth (window_size.ws_col); } - // Since input can be redirected by the debugger, we must insert our editline - // input reader in the queue so we know when our reader should be active - // and so we can receive bytes only when we are supposed to. - SBError err (m_editline_reader.Initialize (m_debugger, - Driver::EditLineInputReaderCallback, // callback - this, // baton - eInputReaderGranularityByte, // token_size - NULL, // end token - NULL means never done - NULL, // prompt - taken care of elsewhere - false)); // echo input - don't need Debugger - // to do this, we handle it elsewhere + SBCommandInterpreter sb_interpreter = m_debugger.GetCommandInterpreter(); - if (err.Fail()) + // Before we handle any options from the command line, we parse the + // .lldbinit file in the user's home directory. + SBCommandReturnObject result; + sb_interpreter.SourceInitFileInHomeDirectory(result); + if (GetDebugMode()) { - ::fprintf (stderr, "error: %s", err.GetCString()); - exit (6); + result.PutError (m_debugger.GetErrorFileHandle()); + result.PutOutput (m_debugger.GetOutputFileHandle()); } - - m_debugger.PushInputReader (m_editline_reader); - SBListener listener(m_debugger.GetListener()); - if (listener.IsValid()) + // Now we handle options we got from the command line + // First source in the commands specified to be run before the file arguments are processed. + ExecuteInitialCommands(true); + + // Was there a core file specified? + std::string core_file_spec(""); + if (!m_option_data.m_core_file.empty()) + core_file_spec.append("--core ").append(m_option_data.m_core_file); + + char command_string[PATH_MAX * 2]; + const size_t num_args = m_option_data.m_args.size(); + if (num_args > 0) { - - listener.StartListeningForEventClass(m_debugger, - SBTarget::GetBroadcasterClassName(), - SBTarget::eBroadcastBitBreakpointChanged); - listener.StartListeningForEventClass(m_debugger, - SBThread::GetBroadcasterClassName(), - SBThread::eBroadcastBitStackChanged | - SBThread::eBroadcastBitThreadSelected); - listener.StartListeningForEvents (*m_io_channel_ap, - IOChannel::eBroadcastBitHasUserInput | - IOChannel::eBroadcastBitUserInterrupt | - IOChannel::eBroadcastBitThreadShouldExit | - IOChannel::eBroadcastBitThreadDidStart | - IOChannel::eBroadcastBitThreadDidExit); - - if (m_io_channel_ap->Start ()) + char arch_name[64]; + if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) + ::snprintf (command_string, + sizeof (command_string), + "target create --arch=%s %s \"%s\"", + arch_name, + core_file_spec.c_str(), + m_option_data.m_args[0].c_str()); + else + ::snprintf (command_string, + sizeof(command_string), + "target create %s \"%s\"", + core_file_spec.c_str(), + m_option_data.m_args[0].c_str()); + + m_debugger.HandleCommand (command_string); + + if (num_args > 1) { - bool iochannel_thread_exited = false; - - listener.StartListeningForEvents (sb_interpreter.GetBroadcaster(), - SBCommandInterpreter::eBroadcastBitQuitCommandReceived | - SBCommandInterpreter::eBroadcastBitAsynchronousOutputData | - SBCommandInterpreter::eBroadcastBitAsynchronousErrorData); - - // Before we handle any options from the command line, we parse the - // .lldbinit file in the user's home directory. - SBCommandReturnObject result; - sb_interpreter.SourceInitFileInHomeDirectory(result); - if (GetDebugMode()) - { - result.PutError (m_debugger.GetErrorFileHandle()); - result.PutOutput (m_debugger.GetOutputFileHandle()); - } - - // Now we handle options we got from the command line - // First source in the commands specified to be run before the file arguments are processed. - ExecuteInitialCommands(true); - - // Was there a core file specified? - std::string core_file_spec(""); - if (!m_option_data.m_core_file.empty()) - core_file_spec.append("--core ").append(m_option_data.m_core_file); - - char command_string[PATH_MAX * 2]; - const size_t num_args = m_option_data.m_args.size(); - if (num_args > 0) - { - char arch_name[64]; - if (m_debugger.GetDefaultArchitecture (arch_name, sizeof (arch_name))) - ::snprintf (command_string, - sizeof (command_string), - "target create --arch=%s %s \"%s\"", - arch_name, - core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - else - ::snprintf (command_string, - sizeof(command_string), - "target create %s \"%s\"", - core_file_spec.c_str(), - m_option_data.m_args[0].c_str()); - - m_debugger.HandleCommand (command_string); - - if (num_args > 1) - { - m_debugger.HandleCommand ("settings clear target.run-args"); - char arg_cstr[1024]; - for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) - { - ::snprintf (arg_cstr, - sizeof(arg_cstr), - "settings append target.run-args \"%s\"", - m_option_data.m_args[arg_idx].c_str()); - m_debugger.HandleCommand (arg_cstr); - } - } - } - else if (!core_file_spec.empty()) - { - ::snprintf (command_string, - sizeof(command_string), - "target create %s", - core_file_spec.c_str()); - m_debugger.HandleCommand (command_string);; - } - - // Now that all option parsing is done, we try and parse the .lldbinit - // file in the current working directory - sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); - if (GetDebugMode()) - { - result.PutError(m_debugger.GetErrorFileHandle()); - result.PutOutput(m_debugger.GetOutputFileHandle()); - } - - // Now execute the commands specified for after the file arguments are processed. - ExecuteInitialCommands(false); - - SBEvent event; - - // Make sure the IO channel is started up before we try to tell it we - // are ready for input - listener.WaitForEventForBroadcasterWithType (UINT32_MAX, - *m_io_channel_ap, - IOChannel::eBroadcastBitThreadDidStart, - event); - // If we were asked to attach, then do that here: - // I'm going to use the command string rather than directly - // calling the API's because then I don't have to recode the - // event handling here. - if (!m_option_data.m_process_name.empty() - || m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID) + m_debugger.HandleCommand ("settings clear target.run-args"); + char arg_cstr[1024]; + for (size_t arg_idx = 1; arg_idx < num_args; ++arg_idx) { - std::string command_str("process attach "); - if (m_option_data.m_process_pid != LLDB_INVALID_PROCESS_ID) - { - command_str.append("-p "); - char pid_buffer[32]; - ::snprintf (pid_buffer, sizeof(pid_buffer), "%" PRIu64, m_option_data.m_process_pid); - command_str.append(pid_buffer); - } - else - { - command_str.append("-n \""); - command_str.append(m_option_data.m_process_name); - command_str.push_back('\"'); - if (m_option_data.m_wait_for) - command_str.append(" -w"); - } - - if (m_debugger.GetOutputFileHandle()) - ::fprintf (m_debugger.GetOutputFileHandle(), - "Attaching to process with:\n %s\n", - command_str.c_str()); - - // Force the attach to be synchronous: - bool orig_async = m_debugger.GetAsync(); - m_debugger.SetAsync(true); - m_debugger.HandleCommand(command_str.c_str()); - m_debugger.SetAsync(orig_async); + ::snprintf (arg_cstr, + sizeof(arg_cstr), + "settings append target.run-args \"%s\"", + m_option_data.m_args[arg_idx].c_str()); + m_debugger.HandleCommand (arg_cstr); } - - ReadyForCommand (); - - while (!GetIsDone()) - { - listener.WaitForEvent (UINT32_MAX, event); - if (event.IsValid()) - { - if (event.GetBroadcaster().IsValid()) - { - uint32_t event_type = event.GetType(); - if (event.BroadcasterMatchesRef (*m_io_channel_ap)) - { - if ((event_type & IOChannel::eBroadcastBitThreadShouldExit) || - (event_type & IOChannel::eBroadcastBitThreadDidExit)) - { - SetIsDone(); - if (event_type & IOChannel::eBroadcastBitThreadDidExit) - iochannel_thread_exited = true; - } - else - { - if (HandleIOEvent (event)) - SetIsDone(); - } - } - else if (SBProcess::EventIsProcessEvent (event)) - { - HandleProcessEvent (event); - } - else if (SBBreakpoint::EventIsBreakpointEvent (event)) - { - HandleBreakpointEvent (event); - } - else if (SBThread::EventIsThreadEvent (event)) - { - HandleThreadEvent (event); - } - else if (event.BroadcasterMatchesRef (sb_interpreter.GetBroadcaster())) - { - // TODO: deprecate the eBroadcastBitQuitCommandReceived event - // now that we have SBCommandInterpreter::SetCommandOverrideCallback() - // that can take over a command - if (event_type & SBCommandInterpreter::eBroadcastBitQuitCommandReceived) - { - SetIsDone(); - } - else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousErrorData) - { - const char *data = SBEvent::GetCStringFromEvent (event); - m_io_channel_ap->ErrWrite (data, strlen(data), ASYNC); - } - else if (event_type & SBCommandInterpreter::eBroadcastBitAsynchronousOutputData) - { - const char *data = SBEvent::GetCStringFromEvent (event); - m_io_channel_ap->OutWrite (data, strlen(data), ASYNC); - } - } - } - } - } - - master_out_comm.SetReadThreadBytesReceivedCallback(NULL, NULL); - master_out_comm.Disconnect(); - master_out_comm.ReadThreadStop(); - -#if !defined(_MSC_VER) - out_comm_2.SetReadThreadBytesReceivedCallback(NULL, NULL); - out_comm_2.Disconnect(); - out_comm_2.ReadThreadStop(); -#endif - - editline_output_pty.CloseMasterFileDescriptor(); - reset_stdin_termios(); - fclose (stdin); - - CloseIOChannelFile (); - - if (!iochannel_thread_exited) - { - event.Clear(); - listener.GetNextEventForBroadcasterWithType (*m_io_channel_ap, - IOChannel::eBroadcastBitThreadDidExit, - event); - if (!event.IsValid()) - { - // Send end EOF to the driver file descriptor - m_io_channel_ap->Stop(); - } - } - - SBDebugger::Destroy (m_debugger); } } -} + else if (!core_file_spec.empty()) + { + ::snprintf (command_string, + sizeof(command_string), + "target create %s", + core_file_spec.c_str()); + m_debugger.HandleCommand (command_string);; + } + else if (!m_option_data.m_process_name.empty()) + { + ::snprintf (command_string, + sizeof(command_string), + "process attach --name '%s'%s", + m_option_data.m_process_name.c_str(), + m_option_data.m_wait_for ? " --waitfor" : ""); + m_debugger.HandleCommand (command_string); + } + else if (LLDB_INVALID_PROCESS_ID != m_option_data.m_process_pid) + { + ::snprintf (command_string, + sizeof(command_string), + "process attach --pid %" PRIu64, + m_option_data.m_process_pid); + m_debugger.HandleCommand (command_string); + } + ExecuteInitialCommands(false); -void -Driver::ReadyForCommand () -{ - if (m_waiting_for_command == false) + // Now that all option parsing is done, we try and parse the .lldbinit + // file in the current working directory + sb_interpreter.SourceInitFileInCurrentWorkingDirectory (result); + if (GetDebugMode()) { - m_waiting_for_command = true; - BroadcastEventByType (Driver::eBroadcastBitReadyForInput, true); + result.PutError(m_debugger.GetErrorFileHandle()); + result.PutOutput(m_debugger.GetOutputFileHandle()); } + + bool handle_events = true; + bool spawn_thread = false; + m_debugger.RunCommandInterpreter(handle_events, spawn_thread); + + reset_stdin_termios(); + fclose (stdin); + + SBDebugger::Destroy (m_debugger); } + void Driver::ResizeWindow (unsigned short col) { GetDebugger().SetTerminalWidth (col); - if (m_io_channel_ap.get() != NULL) - { - m_io_channel_ap->ElResize(); - } } void diff --git a/tools/driver/Driver.h b/tools/driver/Driver.h index dcfd5ed11cd1..699244685d06 100644 --- a/tools/driver/Driver.h +++ b/tools/driver/Driver.h @@ -22,27 +22,15 @@ #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBDebugger.h" #include "lldb/API/SBError.h" -#include "lldb/API/SBInputReader.h" #define ASYNC true #define NO_ASYNC false class IOChannel; -namespace lldb -{ - class SBInputReader; -} - - class Driver : public lldb::SBBroadcaster { public: - enum { - eBroadcastBitReadyForInput = (1 << 0), - eBroadcastBitThreadShouldExit = (1 << 1) - }; - Driver (); virtual @@ -51,24 +39,6 @@ public: void MainLoop (); - void - PutSTDIN (const char *src, size_t src_len); - - void - GetFromMaster (const char *src, size_t src_len); - - bool - HandleIOEvent (const lldb::SBEvent &event); - - void - HandleProcessEvent (const lldb::SBEvent &event); - - void - HandleBreakpointEvent (const lldb::SBEvent &event); - - void - HandleThreadEvent (const lldb::SBEvent &event); - lldb::SBError ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &do_exit); @@ -137,66 +107,16 @@ public: return m_debugger; } - bool - EditlineReaderIsTop () - { - return m_debugger.InputReaderIsTopReader (m_editline_reader); - } - - bool - GetIsDone () const - { - return m_done; - } - - void - SetIsDone () - { - m_done = true; - } - void ResizeWindow (unsigned short col); private: lldb::SBDebugger m_debugger; - lldb_utility::PseudoTerminal m_editline_pty; - FILE *m_editline_slave_fh; - lldb::SBInputReader m_editline_reader; - std::unique_ptr<IOChannel> m_io_channel_ap; OptionData m_option_data; - bool m_executing_user_command; - bool m_waiting_for_command; - bool m_done; void ResetOptionValues (); - size_t - GetProcessSTDOUT (); - - size_t - GetProcessSTDERR (); - - void - UpdateSelectedThread (); - - void - CloseIOChannelFile (); - - static size_t - EditLineInputReaderCallback (void *baton, - lldb::SBInputReader *reader, - lldb::InputReaderAction notification, - const char *bytes, - size_t bytes_len); - - static void - ReadThreadBytesReceived (void *baton, const void *src, size_t src_len); - - static void - MasterThreadBytesReceived (void *baton, const void *src, size_t src_len); - void ReadyForCommand (); }; diff --git a/tools/driver/ELWrapper.cpp b/tools/driver/ELWrapper.cpp deleted file mode 100644 index 258f47e5169c..000000000000 --- a/tools/driver/ELWrapper.cpp +++ /dev/null @@ -1,422 +0,0 @@ -//===-- ELWrapper.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// this file is only relevant for Visual C++ -#if defined( _MSC_VER ) - -#include "lldb/Host/windows/windows.h" - -#include "ELWrapper.h" -#include <vector> -#include <assert.h> - -// index one of the variable arguments -// presuming "(EditLine *el, ..." is first in the argument list -#define GETARG( X ) ( (void* ) *( ( (int**) &el ) + ((X) + 2) ) ) - -// edit line EL_ADDFN function pointer type -typedef unsigned char (*el_addfn_func)(EditLine *e, int ch); - -// edit line wrapper binding container -struct el_binding -{ - // - const char *name; - const char *help; - // function pointer to callback routine - el_addfn_func func; - // ascii key this function is bound to - const char *key; -}; - -// stored key bindings -static std::vector<el_binding*> _bindings; - -//TODO: this should infact be related to the exact edit line context we create -static void *clientData = NULL; - -// store the current prompt string -// default to what we expect to receive anyway -static const char *_prompt = "(lldb) "; - -#if !defined( _WIP_INPUT_METHOD ) - -static char * -el_get_s (char *buffer, int chars) -{ - return gets_s(buffer, chars); -} -#else - -static void -con_output (char _in) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get the cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // output this char - WriteConsoleOutputCharacterA( hout, &_in, 1, info.dwCursorPosition, &written ); - // advance cursor position - info.dwCursorPosition.X++; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); -} - -static void -con_backspace (void) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // nudge cursor backwards - info.dwCursorPosition.X--; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); - // blank out the last character - WriteConsoleOutputCharacterA( hout, " ", 1, info.dwCursorPosition, &written ); -} - -static void -con_return (void) -{ - HANDLE hout = GetStdHandle( STD_OUTPUT_HANDLE ); - DWORD written = 0; - // get cursor position - CONSOLE_SCREEN_BUFFER_INFO info; - GetConsoleScreenBufferInfo( hout, &info ); - // move onto the new line - info.dwCursorPosition.X = 0; - info.dwCursorPosition.Y++; - SetConsoleCursorPosition( hout, info.dwCursorPosition ); -} - -static bool -runBind (char _key) -{ - for ( int i=0; i<_bindings.size(); i++ ) - { - el_binding *bind = _bindings[i]; - if ( bind->key[0] == _key ) - { - bind->func( (EditLine*) -1, _key ); - return true; - } - } - return false; -} - -// replacement get_s which is EL_BIND aware -static char * -el_get_s (char *buffer, int chars) -{ - // - char *head = buffer; - // - for ( ;; Sleep( 10 ) ) - { - // - INPUT_RECORD _record; - // - DWORD _read = 0; - if ( ReadConsoleInputA( GetStdHandle( STD_INPUT_HANDLE ), &_record, 1, &_read ) == FALSE ) - break; - // if we didnt read a key - if ( _read == 0 ) - continue; - // only interested in key events - if ( _record.EventType != KEY_EVENT ) - continue; - // is the key down - if (! _record.Event.KeyEvent.bKeyDown ) - continue; - // read the ascii key character - char _key = _record.Event.KeyEvent.uChar.AsciiChar; - // non ascii conformant key press - if ( _key == 0 ) - { - // check the scan code - // if VK_UP scroll back through history - // if VK_DOWN scroll forward through history - continue; - } - // try to execute any bind this key may have - if ( runBind( _key ) ) - continue; - // if we read a return key - if ( _key == '\n' || _key == '\r' ) - { - con_return( ); - break; - } - // key is backspace - if ( _key == 0x8 ) - { - // avoid deleting past beginning - if ( head > buffer ) - { - con_backspace( ); - head--; - } - continue; - } - - // add this key to the input buffer - if ( (head-buffer) < (chars-1) ) - { - con_output( _key ); - *(head++) = _key; - } - } - // insert end of line character - *head = '\0'; - - return buffer; -} -#endif - -// edit line initalise -EditLine * -el_init (const char *, FILE *, FILE *, FILE *) -{ - // - SetConsoleTitleA( "lldb" ); - // return dummy handle - return (EditLine*) -1; -} - -const char * -el_gets (EditLine *el, int *length) -{ - // print the prompt if we have one - if ( _prompt != NULL ) - printf( _prompt ); - // create a buffer for the user input - char *buffer = new char[ MAX_PATH ]; - // try to get user input string - if ( el_get_s( buffer, MAX_PATH ) ) - { - // get the string length in 'length' - while ( buffer[ *length ] != '\0' ) - (*length)++; - // return the input buffer - // remember that this memory has the be free'd somewhere - return buffer; - } - else - { - // on error - delete [] buffer; - return NULL; - } -} - -int -el_set (EditLine *el, int code, ...) -{ - int **arg = (int**) ⪙ - // - switch ( code ) - { - // edit line set prompt message - case ( EL_PROMPT ): - { - // EL_PROMPT, char *(*f)( EditLine *) - // define a prompt printing function as 'f', which is to return a string that - // contains the prompt. - - // get the function pointer from the arg list - void *func_vp = (void*) *(arg+2); - // cast to suitable prototype - const char* (*func_fp)(EditLine*) = (const char*(*)(EditLine *)) func_vp; - // call to get the prompt as a string - _prompt = func_fp( el ); - } - break; - case ( EL_EDITOR ): - { - // EL_EDITOR, const char *mode - // set editing mode to "emacs" or "vi" - } - break; - case ( EL_HIST ): - { - // EL_HIST, History *(*fun)(History *, int op, ... ), const char *ptr - // defines which histroy function to use, which is usualy history(). Ptr should be the - // value returned by history_init(). - } - break; - case ( EL_ADDFN ): - { - // EL_ADDFN, const char *name, const char *help, unsigned char (*func)(EditLine *e, int ch) - // add a user defined function, func), referred to as 'name' which is invoked when a key which is bound to 'name' is - // entered. 'help' is a description of 'name'. at involcation time, 'ch' is the key which caused the invocation. the - // return value of 'func()' should be one of: - // CC_NORM add a normal character - // CC_NEWLINE end of line was entered - // CC_EOF EOF was entered - // CC_ARGHACK expecting further command input as arguments, do nothing visually. - // CC_REFRESH refresh display. - // CC_REFRESH_BEEP refresh display and beep. - // CC_CURSOR cursor moved so update and perform CC_REFRESH - // CC_REDISPLAY redisplay entire input line. this is usefull if a key binding outputs extra information. - // CC_ERROR an error occured. beep and flush tty. - // CC_FATAL fatal error, reset tty to known state. - - el_binding *binding = new el_binding; - binding->name = (const char *) GETARG( 0 ); - binding->help = (const char *) GETARG( 1 ); - binding->func = (el_addfn_func) GETARG( 2 ); - binding->key = 0; - // add this to the bindings list - _bindings.push_back( binding ); - } - break; - case ( EL_BIND ): - { - // EL_BIND, const char *, ..., NULL - // perform the BIND buildin command. Refer to editrc(5) for more information. - - const char *name = (const char*) GETARG( 1 ); - - for ( int i=0; i<_bindings.size(); i++ ) - { - el_binding *bind = _bindings[i]; - if ( strcmp( bind->name, name ) == 0 ) - { - bind->key = (const char *) GETARG( 0 ); - break; - } - } - - } - break; - case ( EL_CLIENTDATA ): - { - clientData = GETARG( 0 ); - } - break; - default: - assert( !"Not Implemented!" ); - } - return 0; -} - -void -el_end (EditLine *el) -{ - assert( !"Not implemented!" ); -} - -void -el_reset (EditLine *) -{ - assert( !"Not implemented!" ); -} - -int -el_getc (EditLine *, char *) -{ - assert( !"Not implemented!" ); - return 0; -} - -void -el_push (EditLine *, char *) -{ - assert( !"Not implemented!" ); -} - -void -el_beep (EditLine *) -{ - Beep( 1000, 500 ); -} - -int -el_parse (EditLine *, int, const char **) -{ - assert( !"Not implemented!" ); - return 0; -} - -int -el_get (EditLine *el, int code, ...) -{ - switch ( code ) - { - case ( EL_CLIENTDATA ): - { - void **dout = (void**) GETARG( 0 ); - *dout = clientData; - } - break; - default: - assert( !"Not implemented!" ); - } - return 0; -} - -int -el_source (EditLine *el, const char *file) -{ - // init edit line by reading the contents of 'file' - // nothing to do here on windows... - return 0; -} - -void -el_resize (EditLine *) -{ - assert( !"Not implemented!" ); -} - -const LineInfo * -el_line (EditLine *el) -{ - assert( !"Not implemented!" ); - return 0; -} - -int -el_insertstr (EditLine *, const char *) -{ - assert( !"Not implemented!" ); - return 0; -} - -void -el_deletestr (EditLine *, int) -{ - assert( !"Not implemented!" ); -} - -History * -history_init (void) -{ - // return dummy handle - return (History*) -1; -} - -void -history_end (History *) -{ - assert( !"Not implemented!" ); -} - -int -history (History *, HistEvent *, int op, ...) -{ - // perform operation 'op' on the history list with optional argumetns as needed by - // the operation. - return 0; -} - -#endif diff --git a/tools/driver/ELWrapper.h b/tools/driver/ELWrapper.h deleted file mode 100644 index a30182d948b1..000000000000 --- a/tools/driver/ELWrapper.h +++ /dev/null @@ -1,122 +0,0 @@ -//===-- ELWrapper.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#pragma once - -#include <stdio.h> - -// EditLine editor function return codes. -// For user-defined function interface -#define CC_NORM 0 -#define CC_NEWLINE 1 -#define CC_EOF 2 -#define CC_ARGHACK 3 -#define CC_REFRESH 4 -#define CC_CURSOR 5 -#define CC_ERROR 6 -#define CC_FATAL 7 -#define CC_REDISPLAY 8 -#define CC_REFRESH_BEEP 9 - -// el_set/el_get parameters -#define EL_PROMPT 0 // , el_pfunc_t -#define EL_TERMINAL 1 // , const char * -#define EL_EDITOR 2 // , const char * -#define EL_SIGNAL 3 // , int); -#define EL_BIND 4 // , const char *, ..., NULL -#define EL_TELLTC 5 // , const char *, ..., NULL -#define EL_SETTC 6 // , const char *, ..., NULL -#define EL_ECHOTC 7 // , const char *, ..., NULL -#define EL_SETTY 8 // , const char *, ..., NULL -#define EL_ADDFN 9 // , const char *, const char *, el_func_t -#define EL_HIST 10 // , hist_fun_t, const char * -#define EL_EDITMODE 11 // , int -#define EL_RPROMPT 12 // , el_pfunc_t -#define EL_GETCFN 13 // , el_rfunc_t -#define EL_CLIENTDATA 14 // , void * -#define EL_UNBUFFERED 15 // , int -#define EL_PREP_TERM 16 // , int -#define EL_GETTC 17 // , const char *, ..., NULL -#define EL_GETFP 18 // , int, FILE ** -#define EL_SETFP 19 // , int, FILE * -#define EL_REFRESH 20 // , void - -#define EL_BUILTIN_GETCFN (NULL) - -// history defines -#define H_FUNC 0 // , UTSL -#define H_SETSIZE 1 // , const int -#define H_GETSIZE 2 // , void -#define H_FIRST 3 // , void -#define H_LAST 4 // , void -#define H_PREV 5 // , void -#define H_NEXT 6 // , void -#define H_CURR 8 // , const int -#define H_SET 7 // , int -#define H_ADD 9 // , const char * -#define H_ENTER 10 // , const char * -#define H_APPEND 11 // , const char * -#define H_END 12 // , void -#define H_NEXT_STR 13 // , const char * -#define H_PREV_STR 14 // , const char * -#define H_NEXT_EVENT 15 // , const int -#define H_PREV_EVENT 16 // , const int -#define H_LOAD 17 // , const char * -#define H_SAVE 18 // , const char * -#define H_CLEAR 19 // , void -#define H_SETUNIQUE 20 // , int -#define H_GETUNIQUE 21 // , void -#define H_DEL 22 // , int - -struct EditLine -{ -}; - -struct LineInfo -{ - const char *buffer; - const char *cursor; - const char *lastchar; -}; - -struct History -{ -}; - -struct HistEvent -{ - int num; - const char *str; -}; - -extern "C" -{ - // edit line API - EditLine *el_init ( const char *, FILE *, FILE *, FILE * ); - const char *el_gets ( EditLine *, int * ); - int el_set ( EditLine *, int, ... ); - - void el_end ( EditLine * ); - void el_reset ( EditLine * ); - int el_getc ( EditLine *, char * ); - void el_push ( EditLine *, char * ); - void el_beep ( EditLine * ); - int el_parse ( EditLine *, int, const char ** ); - int el_get ( EditLine *, int, ... ); - int el_source ( EditLine *, const char * ); - void el_resize ( EditLine * ); - const LineInfo *el_line ( EditLine * ); - int el_insertstr( EditLine *, const char * ); - void el_deletestr( EditLine *, int ); - - // history API - History *history_init( void ); - void history_end ( History * ); - int history ( History *, HistEvent *, int, ... ); -};
\ No newline at end of file diff --git a/tools/driver/GetOptWrapper.cpp b/tools/driver/GetOptWrapper.cpp deleted file mode 100644 index e7cdfd786c6e..000000000000 --- a/tools/driver/GetOptWrapper.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- GetOptWrapper.cpp ---------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// this file is only relevant for Visual C++ -#if defined( _MSC_VER ) - -#include "GetOptWrapper.h" - -/* - -// already defined in lldbHostCommon.lib due to 'getopt.inc' - -extern int -getopt_long_only -( - int ___argc, - char *const *___argv, - const char *__shortopts, - const struct option *__longopts, - int *__longind -) -{ - return -1; -} -*/ - -#endif
\ No newline at end of file diff --git a/tools/driver/GetOptWrapper.h b/tools/driver/GetOptWrapper.h deleted file mode 100644 index 9c9cf03d7626..000000000000 --- a/tools/driver/GetOptWrapper.h +++ /dev/null @@ -1,49 +0,0 @@ -//===-- GetOptWrapper.h -----------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_GetOptWrapper_h_ -#define lldb_GetOptWrapper_h_ - -// from getopt.h -#define no_argument 0 -#define required_argument 1 -#define optional_argument 2 - -// defined int unistd.h -extern int optreset; - -// from getopt.h -extern char *optarg; -extern int optind; -extern int opterr; -extern int optopt; - -// option structure -struct option -{ - const char *name; - // has_arg can't be an enum because some compilers complain about - // type mismatches in all the code that assumes it is an int. - int has_arg; - int *flag; - int val; -}; - -// -extern int -getopt_long_only -( - int ___argc, - char *const *___argv, - const char *__shortopts, - const struct option *__longopts, - int *__longind -); - -#endif // lldb_GetOptWrapper_h_
\ No newline at end of file diff --git a/tools/driver/IOChannel.cpp b/tools/driver/IOChannel.cpp deleted file mode 100644 index 7cba73aaae8c..000000000000 --- a/tools/driver/IOChannel.cpp +++ /dev/null @@ -1,656 +0,0 @@ -//===-- IOChannel.cpp -------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Platform.h" -#include "IOChannel.h" - -#include <map> - -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBEvent.h" -#include "lldb/API/SBFileSpec.h" -#include "lldb/API/SBHostOS.h" -#include "lldb/API/SBListener.h" -#include "lldb/API/SBStringList.h" - -#include <string.h> -#include <limits.h> - -using namespace lldb; - -typedef std::map<EditLine *, std::string> PromptMap; -const char *g_default_prompt = "(lldb) "; -PromptMap g_prompt_map; - -// Printing the following string causes libedit to back up to the beginning of the line & blank it out. -const char undo_prompt_string[4] = { (char) 13, (char) 27, (char) 91, (char) 75}; - -static const char* -el_prompt(EditLine *el) -{ - PromptMap::const_iterator pos = g_prompt_map.find (el); - if (pos == g_prompt_map.end()) - return g_default_prompt; - return pos->second.c_str(); -} - -const char * -IOChannel::GetPrompt () -{ - PromptMap::const_iterator pos = g_prompt_map.find (m_edit_line); - if (pos == g_prompt_map.end()) - return g_default_prompt; - return pos->second.c_str(); -} - -bool -IOChannel::EditLineHasCharacters () -{ - const LineInfo *line_info = el_line(m_edit_line); - if (line_info) - { - // Sometimes we get called after the user has submitted the line, but before editline has - // cleared the buffer. In that case the cursor will be pointing at the newline. That's - // equivalent to having no characters on the line, since it has already been submitted. - if (*line_info->cursor == '\n') - return false; - else - return line_info->cursor != line_info->buffer; - } - else - return false; -} - - -void -IOChannel::EraseCharsBeforeCursor () -{ - const LineInfo *line_info = el_line(m_edit_line); - if (line_info != NULL) - el_deletestr(m_edit_line, line_info->cursor - line_info->buffer); -} - -unsigned char -IOChannel::ElCompletionFn (EditLine *e, int ch) -{ - IOChannel *io_channel; - if (el_get(e, EL_CLIENTDATA, &io_channel) == 0) - { - return io_channel->HandleCompletion (e, ch); - } - else - { - return CC_ERROR; - } -} - -void -IOChannel::ElResize() -{ - el_resize(m_edit_line); -} - -unsigned char -IOChannel::HandleCompletion (EditLine *e, int ch) -{ - assert (e == m_edit_line); - - const LineInfo *line_info = el_line(m_edit_line); - SBStringList completions; - int page_size = 40; - - int num_completions = m_driver->GetDebugger().GetCommandInterpreter().HandleCompletion (line_info->buffer, - line_info->cursor, - line_info->lastchar, - 0, - -1, - completions); - - if (num_completions == -1) - { - el_insertstr (m_edit_line, m_completion_key); - return CC_REDISPLAY; - } - else if (num_completions == -2) - { - el_deletestr (m_edit_line, line_info->cursor - line_info->buffer); - el_insertstr (m_edit_line, completions.GetStringAtIndex(0)); - return CC_REDISPLAY; - } - - // If we get a longer match display that first. - const char *completion_str = completions.GetStringAtIndex(0); - if (completion_str != NULL && *completion_str != '\0') - { - el_insertstr (m_edit_line, completion_str); - return CC_REDISPLAY; - } - - if (num_completions > 1) - { - const char *comment = "\nAvailable completions:"; - - int num_elements = num_completions + 1; - OutWrite(comment, strlen (comment), NO_ASYNC); - if (num_completions < page_size) - { - for (int i = 1; i < num_elements; i++) - { - completion_str = completions.GetStringAtIndex(i); - OutWrite("\n\t", 2, NO_ASYNC); - OutWrite(completion_str, strlen (completion_str), NO_ASYNC); - } - OutWrite ("\n", 1, NO_ASYNC); - } - else - { - int cur_pos = 1; - char reply; - int got_char; - while (cur_pos < num_elements) - { - int endpoint = cur_pos + page_size; - if (endpoint > num_elements) - endpoint = num_elements; - for (; cur_pos < endpoint; cur_pos++) - { - completion_str = completions.GetStringAtIndex(cur_pos); - OutWrite("\n\t", 2, NO_ASYNC); - OutWrite(completion_str, strlen (completion_str), NO_ASYNC); - } - - if (cur_pos >= num_elements) - { - OutWrite("\n", 1, NO_ASYNC); - break; - } - - OutWrite("\nMore (Y/n/a): ", strlen ("\nMore (Y/n/a): "), NO_ASYNC); - reply = 'n'; - got_char = el_getc(m_edit_line, &reply); - if (got_char == -1 || reply == 'n') - break; - if (reply == 'a') - page_size = num_elements - cur_pos; - } - } - - } - - if (num_completions == 0) - return CC_REFRESH_BEEP; - else - return CC_REDISPLAY; -} - -IOChannel::IOChannel -( - FILE *editline_in, - FILE *editline_out, - FILE *out, - FILE *err, - Driver *driver -) : - SBBroadcaster ("IOChannel"), - m_output_mutex (), - m_enter_elgets_time (), - m_driver (driver), - m_read_thread (LLDB_INVALID_HOST_THREAD), - m_read_thread_should_exit (false), - m_out_file (out), - m_err_file (err), - m_editline_out (editline_out), - m_command_queue (), - m_completion_key ("\t"), - m_edit_line (::el_init (SBHostOS::GetProgramFileSpec().GetFilename(), editline_in, editline_out, editline_out)), - m_history (history_init()), - m_history_event(), - m_getting_command (false), - m_expecting_prompt (false), - m_prompt_str (), - m_refresh_request_pending (false) -{ - assert (m_edit_line); - el_set (m_edit_line, EL_PROMPT, el_prompt); - el_set (m_edit_line, EL_EDITOR, "emacs"); - el_set (m_edit_line, EL_HIST, history, m_history); - el_set (m_edit_line, EL_ADDFN, "lldb_complete", "LLDB completion function", IOChannel::ElCompletionFn); - el_set (m_edit_line, EL_BIND, m_completion_key, "lldb_complete", NULL); - el_set (m_edit_line, EL_BIND, "^r", "em-inc-search-prev", NULL); // Cycle through backwards search, entering string - el_set (m_edit_line, EL_BIND, "^w", "ed-delete-prev-word", NULL); // Delete previous word, behave like bash does. - el_set (m_edit_line, EL_BIND, "\033[3~", "ed-delete-next-char", NULL); // Fix the delete key. - el_set (m_edit_line, EL_CLIENTDATA, this); - - // Source $PWD/.editrc then $HOME/.editrc - el_source (m_edit_line, NULL); - - assert (m_history); - history (m_history, &m_history_event, H_SETSIZE, 800); - history (m_history, &m_history_event, H_SETUNIQUE, 1); - // Load history - HistorySaveLoad (false); - - // Initialize time that ::el_gets was last called. - m_enter_elgets_time.tv_sec = 0; - m_enter_elgets_time.tv_usec = 0; - - // set the initial state to non flushed - m_output_flushed = false; -} - -IOChannel::~IOChannel () -{ - // Save history - HistorySaveLoad (true); - - if (m_history != NULL) - { - ::history_end (m_history); - m_history = NULL; - } - - if (m_edit_line != NULL) - { - ::el_end (m_edit_line); - m_edit_line = NULL; - } -} - -void -IOChannel::HistorySaveLoad (bool save) -{ - if (m_history != NULL) - { - char history_path[PATH_MAX]; - ::snprintf (history_path, sizeof(history_path), "~/.%s-history", SBHostOS::GetProgramFileSpec().GetFilename()); - if ((size_t)SBFileSpec::ResolvePath (history_path, history_path, sizeof(history_path)) < sizeof(history_path) - 1) - { - const char *path_ptr = history_path; - if (save) - ::history (m_history, &m_history_event, H_SAVE, path_ptr); - else - ::history (m_history, &m_history_event, H_LOAD, path_ptr); - } - } -} - -void -IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len) -{ - IOChannel *io_channel = (IOChannel *) baton; - std::lock_guard<std::recursive_mutex> locker(io_channel->m_output_mutex); - const char *bytes = (const char *) src; - - bool flush = false; - - // See if we have a 'flush' synchronization point in there. - // this is performed from 'fputc ('\0', m_editline_out);' in LibeditGetInput() - if (src_len > 0 && bytes[src_len-1] == '\0') - { - src_len--; - flush = true; - } - - if (io_channel->IsGettingCommand() && io_channel->m_expecting_prompt) - { - io_channel->m_prompt_str.append (bytes, src_len); - // Log this to make sure the prompt is really what you think it is. - if (io_channel->m_prompt_str.find (el_prompt(io_channel->m_edit_line)) == 0) - { - io_channel->m_expecting_prompt = false; - io_channel->m_refresh_request_pending = false; - io_channel->OutWrite (io_channel->m_prompt_str.c_str(), - io_channel->m_prompt_str.size(), NO_ASYNC); - io_channel->m_prompt_str.clear(); - } - } - else - { - if (io_channel->m_prompt_str.size() > 0) - io_channel->m_prompt_str.clear(); - std::string tmp_str (bytes, src_len); - if (tmp_str.find (el_prompt (io_channel->m_edit_line)) == 0) - io_channel->m_refresh_request_pending = false; - io_channel->OutWrite (bytes, src_len, NO_ASYNC); - } - -#if !defined (_MSC_VER) - if (flush) - { - io_channel->m_output_flushed = true; - io_channel->m_output_cond.notify_all(); - } -#endif - -} - -IOChannel::LibeditGetInputResult -IOChannel::LibeditGetInput (std::string &new_line) -{ - IOChannel::LibeditGetInputResult retval = IOChannel::eLibeditGetInputResultUnknown; - if (m_edit_line != NULL) - { - int line_len = 0; - - // Set boolean indicating whether or not el_gets is trying to get input (i.e. whether or not to attempt - // to refresh the prompt after writing data). - SetGettingCommand (true); - m_expecting_prompt = true; - - // Call el_gets to prompt the user and read the user's input. - const char *line = ::el_gets (m_edit_line, &line_len); - -#if !defined (_MSC_VER) - // Force the piped output from el_gets to finish processing. - // el_gets does an fflush internally, which is not sufficient here; it only - // writes the data into m_editline_out, but doesn't affect whether our worker - // thread will read that data yet. So we block here manually. - { - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - m_output_flushed = false; - - // Write a synchronization point into the stream, so we can guarantee - // LibeditOutputBytesReceived has processed everything up till that mark. - fputc ('\0', m_editline_out); - - while (!m_output_flushed) - { - // wait until the condition variable is signaled - m_output_cond.wait(m_output_mutex); - } - } -#endif - - // Re-set the boolean indicating whether or not el_gets is trying to get input. - SetGettingCommand (false); - - if (line) - { - retval = IOChannel::eLibeditGetInputValid; - // strip any newlines off the end of the string... - while (line_len > 0 && (line[line_len - 1] == '\n' || line[line_len - 1] == '\r')) - --line_len; - if (line_len > 0) - { - ::history (m_history, &m_history_event, H_ENTER, line); - new_line.assign (line, line_len); // Omit the newline - } - else - { - retval = IOChannel::eLibeditGetInputEmpty; - // Someone just hit ENTER, return the empty string - new_line.clear(); - } - // Return true to indicate success even if a string is empty - return retval; - } - else - { - retval = (line_len == 0 ? IOChannel::eLibeditGetInputEOF : IOChannel::eLibeditGetInputResultError); - } - } - // Return false to indicate failure. This can happen when the file handle - // is closed (EOF). - new_line.clear(); - return retval; -} - -thread_result_t -IOChannel::IOReadThread (void *ptr) -{ - IOChannel *myself = static_cast<IOChannel *> (ptr); - myself->Run(); - return NULL; -} - -void -IOChannel::Run () -{ - SBListener listener("IOChannel::Run"); - std::string new_line; - - SBBroadcaster interpreter_broadcaster (m_driver->GetDebugger().GetCommandInterpreter().GetBroadcaster()); - listener.StartListeningForEvents (interpreter_broadcaster, - SBCommandInterpreter::eBroadcastBitResetPrompt | - SBCommandInterpreter::eBroadcastBitThreadShouldExit | - SBCommandInterpreter::eBroadcastBitQuitCommandReceived); - - listener.StartListeningForEvents (*this, - IOChannel::eBroadcastBitThreadShouldExit); - - listener.StartListeningForEvents (*m_driver, - Driver::eBroadcastBitReadyForInput | - Driver::eBroadcastBitThreadShouldExit); - - // Let anyone know that the IO channel is up and listening and ready for events - BroadcastEventByType (eBroadcastBitThreadDidStart); - bool done = false; - while (!done) - { - SBEvent event; - - listener.WaitForEvent (UINT32_MAX, event); - if (!event.IsValid()) - continue; - - const uint32_t event_type = event.GetType(); - - if (event.GetBroadcaster().IsValid()) - { - if (event.BroadcasterMatchesPtr (m_driver)) - { - if (event_type & Driver::eBroadcastBitReadyForInput) - { - std::string line; - - if (CommandQueueIsEmpty()) - { - IOChannel::LibeditGetInputResult getline_result = LibeditGetInput(line); - if (getline_result == IOChannel::eLibeditGetInputEOF) - { - // EOF occurred - // pretend that a quit was typed so the user gets a potential - // chance to confirm - line.assign("quit"); - } - else if (getline_result == IOChannel::eLibeditGetInputResultError || getline_result == IOChannel::eLibeditGetInputResultUnknown) - { - // some random error occurred, exit and don't ask because the state might be corrupt - done = true; - continue; - } - } - else - { - GetCommandFromQueue (line); - } - - // TO BE DONE: FIGURE OUT WHICH COMMANDS SHOULD NOT BE REPEATED IF USER PRESSES PLAIN 'RETURN' - // AND TAKE CARE OF THAT HERE. - - SBEvent line_event(IOChannel::eBroadcastBitHasUserInput, - line.c_str(), - line.size()); - BroadcastEvent (line_event); - } - else if (event_type & Driver::eBroadcastBitThreadShouldExit) - { - done = true; - continue; - } - } - else if (event.BroadcasterMatchesRef (interpreter_broadcaster)) - { - switch (event_type) - { - case SBCommandInterpreter::eBroadcastBitResetPrompt: - { - const char *new_prompt = SBEvent::GetCStringFromEvent (event); - if (new_prompt) - g_prompt_map[m_edit_line] = new_prompt; - } - break; - - case SBCommandInterpreter::eBroadcastBitThreadShouldExit: - case SBCommandInterpreter::eBroadcastBitQuitCommandReceived: - done = true; - break; - } - } - else if (event.BroadcasterMatchesPtr (this)) - { - if (event_type & IOChannel::eBroadcastBitThreadShouldExit) - { - done = true; - continue; - } - } - } - } - BroadcastEventByType (IOChannel::eBroadcastBitThreadDidExit); - m_driver = NULL; - m_read_thread = 0; -} - -bool -IOChannel::Start () -{ - if (IS_VALID_LLDB_HOST_THREAD(m_read_thread)) - return true; - - m_read_thread = SBHostOS::ThreadCreate("<lldb.driver.commandline_io>", (lldb::thread_func_t) IOChannel::IOReadThread, this, NULL); - - return (IS_VALID_LLDB_HOST_THREAD(m_read_thread)); -} - -bool -IOChannel::Stop () -{ - if (!IS_VALID_LLDB_HOST_THREAD(m_read_thread)) - return true; - - BroadcastEventByType (eBroadcastBitThreadShouldExit); - - // Don't call Host::ThreadCancel since el_gets won't respond to this - // function call -- the thread will just die and all local variables in - // IOChannel::Run() won't get destructed down which is bad since there is - // a local listener holding onto broadcasters... To ensure proper shutdown, - // a ^D (control-D) sequence (0x04) should be written to other end of the - // the "in" file handle that was passed into the contructor as closing the - // file handle doesn't seem to make el_gets() exit.... - return SBHostOS::ThreadJoin (m_read_thread, NULL, NULL); -} - -void -IOChannel::RefreshPrompt () -{ - // If we are not in the middle of getting input from the user, there is no need to - // refresh the prompt. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (! IsGettingCommand()) - return; - - // If we haven't finished writing the prompt, there's no need to refresh it. - if (m_expecting_prompt) - return; - - if (m_refresh_request_pending) - return; - - ::el_set (m_edit_line, EL_REFRESH); - m_refresh_request_pending = true; -} - -void -IOChannel::OutWrite (const char *buffer, size_t len, bool asynchronous) -{ - if (len == 0 || buffer == NULL) - return; - - // We're in the process of exiting -- IOChannel::Run() has already completed - // and set m_driver to NULL - it is time for us to leave now. We might not - // print the final ^D to stdout in this case. We need to do some re-work on - // how the I/O streams are managed at some point. - if (m_driver == NULL) - { - return; - } - - // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (m_driver->EditlineReaderIsTop() && asynchronous) - ::fwrite (undo_prompt_string, 1, 4, m_out_file); - ::fwrite (buffer, 1, len, m_out_file); - if (asynchronous) - m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten); -} - -void -IOChannel::ErrWrite (const char *buffer, size_t len, bool asynchronous) -{ - if (len == 0 || buffer == NULL) - return; - - // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output. - std::lock_guard<std::recursive_mutex> locker(m_output_mutex); - if (asynchronous) - ::fwrite (undo_prompt_string, 1, 4, m_err_file); - ::fwrite (buffer, 1, len, m_err_file); - if (asynchronous) - m_driver->GetDebugger().NotifyTopInputReader (eInputReaderAsynchronousOutputWritten); -} - -void -IOChannel::AddCommandToQueue (const char *command) -{ - m_command_queue.push (std::string(command)); -} - -bool -IOChannel::GetCommandFromQueue (std::string &cmd) -{ - if (m_command_queue.empty()) - return false; - cmd.swap(m_command_queue.front()); - m_command_queue.pop (); - return true; -} - -int -IOChannel::CommandQueueSize () const -{ - return m_command_queue.size(); -} - -void -IOChannel::ClearCommandQueue () -{ - while (!m_command_queue.empty()) - m_command_queue.pop(); -} - -bool -IOChannel::CommandQueueIsEmpty () const -{ - return m_command_queue.empty(); -} - -bool -IOChannel::IsGettingCommand () const -{ - return m_getting_command; -} - -void -IOChannel::SetGettingCommand (bool new_value) -{ - m_getting_command = new_value; -} diff --git a/tools/driver/IOChannel.h b/tools/driver/IOChannel.h deleted file mode 100644 index 3788673da972..000000000000 --- a/tools/driver/IOChannel.h +++ /dev/null @@ -1,154 +0,0 @@ -//===-- IOChannel.h ---------------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef lldb_IOChannel_h_ -#define lldb_IOChannel_h_ - -#include <thread> -#include <mutex> -#include <atomic> -#include <condition_variable> - -#include <string> -#include <queue> -#include "Driver.h" - -class IOChannel : public lldb::SBBroadcaster -{ -public: - enum { - eBroadcastBitHasUserInput = (1 << 0), - eBroadcastBitUserInterrupt = (1 << 1), - eBroadcastBitThreadShouldExit = (1 << 2), - eBroadcastBitThreadDidExit = (1 << 3), - eBroadcastBitThreadDidStart = (1 << 4), - eBroadcastBitsSTDOUT = (1 << 5), - eBroadcastBitsSTDERR = (1 << 6), - eBroadcastBitsSTDIN = (1 << 7), - eAllEventBits = 0xffffffff - }; - - enum LibeditGetInputResult - { - eLibeditGetInputEOF = 0, - eLibeditGetInputValid = 1, - eLibeditGetInputEmpty = 2, - eLibeditGetInputResultError = 4, - eLibeditGetInputResultUnknown = 0xffffffff - }; - - IOChannel (FILE *editline_in, - FILE *editline_out, - FILE *out, - FILE *err, - Driver *driver = NULL); - - virtual - ~IOChannel (); - - bool - Start (); - - bool - Stop (); - - static lldb::thread_result_t - IOReadThread (void *); - - void - Run (); - - void - OutWrite (const char *buffer, size_t len, bool asynchronous); - - void - ErrWrite (const char *buffer, size_t len, bool asynchronous); - - LibeditGetInputResult - LibeditGetInput (std::string &); - - static void - LibeditOutputBytesReceived (void *baton, const void *src,size_t src_len); - - void - SetPrompt (); - - void - RefreshPrompt (); - - void - AddCommandToQueue (const char *command); - - bool - GetCommandFromQueue (std::string &cmd); - - int - CommandQueueSize () const; - - void - ClearCommandQueue (); - - bool - CommandQueueIsEmpty () const; - - const char * - GetPrompt (); - - bool - EditLineHasCharacters (); - - void - EraseCharsBeforeCursor (); - - static unsigned char - ElCompletionFn (EditLine *e, int ch); - - void - ElResize(); - -protected: - - bool - IsGettingCommand () const; - - void - SetGettingCommand (bool new_value); - -private: - - std::recursive_mutex m_output_mutex; - std::condition_variable_any m_output_cond; - struct timeval m_enter_elgets_time; - - Driver *m_driver; - lldb::thread_t m_read_thread; - bool m_read_thread_should_exit; - FILE *m_out_file; - FILE *m_err_file; - FILE *m_editline_out; - std::queue<std::string> m_command_queue; - const char *m_completion_key; - - EditLine *m_edit_line; - History *m_history; - HistEvent m_history_event; - bool m_getting_command; - bool m_expecting_prompt; - bool m_output_flushed; - std::string m_prompt_str; // for accumlating the prompt as it gets written out by editline - bool m_refresh_request_pending; - - void - HistorySaveLoad (bool save); - - unsigned char - HandleCompletion (EditLine *e, int ch); -}; - -#endif // lldb_IOChannel_h_ diff --git a/tools/driver/Platform.h b/tools/driver/Platform.h index f1fe1e4aac18..faa2991bf6f3 100644 --- a/tools/driver/Platform.h +++ b/tools/driver/Platform.h @@ -18,9 +18,8 @@ #include <io.h> #include <eh.h> #include <inttypes.h> - #include "ELWrapper.h" #include "lldb/Host/windows/Windows.h" - #include "GetOptWrapper.h" + #include "lldb/Host/HostGetOpt.h" struct timeval { |