[Lldb-commits] [lldb] r192714 - Patch enabling lldb command line driver to run on windows.

Deepak Panickal deepak at codeplay.com
Tue Oct 15 08:46:40 PDT 2013


Author: panickal
Date: Tue Oct 15 10:46:40 2013
New Revision: 192714

URL: http://llvm.org/viewvc/llvm-project?rev=192714&view=rev
Log:
Patch enabling lldb command line driver to run on windows.
CHANGES:
- Thread locking switched from pthreads to C++11 standard library.
- Abstracted platform specific header includes into 'platform.h'.
- Create editline emulator for windows.
- Emulated various platform dependant functions on windows.
TODO:
- User input currently handled by gets_s(), work started on better handler:
    see _WIP_INPUT_METHOD define blocks in 'ELWrapper.cpp'.
    Aim is to handle 'tab' auto completion on windows.
- Tidy up 'getopt.inc' from lldbHostCommon to serve as LLDB Drivers getopt windows implementation.

Added:
    lldb/trunk/tools/driver/ELWrapper.cpp
    lldb/trunk/tools/driver/ELWrapper.h
    lldb/trunk/tools/driver/GetOptWrapper.cpp
    lldb/trunk/tools/driver/GetOptWrapper.h
    lldb/trunk/tools/driver/Platform.cpp
    lldb/trunk/tools/driver/Platform.h
Modified:
    lldb/trunk/tools/CMakeLists.txt
    lldb/trunk/tools/driver/CMakeLists.txt
    lldb/trunk/tools/driver/Driver.cpp
    lldb/trunk/tools/driver/Driver.h
    lldb/trunk/tools/driver/IOChannel.cpp
    lldb/trunk/tools/driver/IOChannel.h

Modified: lldb/trunk/tools/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/CMakeLists.txt?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/CMakeLists.txt (original)
+++ lldb/trunk/tools/CMakeLists.txt Tue Oct 15 10:46:40 2013
@@ -1,7 +1,7 @@
 if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
   add_subdirectory(debugserver)
 endif()
-if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
   add_subdirectory(driver)
+if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
   add_subdirectory(lldb-platform)
 endif()

Modified: lldb/trunk/tools/driver/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/CMakeLists.txt?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/driver/CMakeLists.txt (original)
+++ lldb/trunk/tools/driver/CMakeLists.txt Tue Oct 15 10:46:40 2013
@@ -5,6 +5,9 @@ add_lldb_executable(lldb
   #DriverOptions.cpp
   #DriverPosix.cpp
   IOChannel.cpp
+  ELWrapper.cpp
+  Platform.cpp
+  GetOptWrapper.cpp
   )
 
 target_link_libraries(lldb liblldb)

Modified: lldb/trunk/tools/driver/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Driver.cpp?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/driver/Driver.cpp (original)
+++ lldb/trunk/tools/driver/Driver.cpp Tue Oct 15 10:46:40 2013
@@ -9,19 +9,15 @@
 
 #include "Driver.h"
 
-#include <getopt.h>
-#include <libgen.h>
-#include <sys/ioctl.h>
-#include <termios.h>
-#include <unistd.h>
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <limits.h>
 #include <fcntl.h>
-#include <inttypes.h>
 
 #include <string>
 
+#include <thread>
 #include "IOChannel.h"
 #include "lldb/API/SBBreakpoint.h"
 #include "lldb/API/SBCommandInterpreter.h"
@@ -155,7 +151,9 @@ Driver::CloseIOChannelFile ()
     // Write an End of File sequence to the file descriptor to ensure any
     // read functions can exit.
     char eof_str[] = "\x04";
-    ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
+    int mfd = m_editline_pty.GetMasterFileDescriptor();
+    if (mfd != -1)
+        ::write (m_editline_pty.GetMasterFileDescriptor(), eof_str, strlen(eof_str));
 
     m_editline_pty.CloseMasterFileDescriptor();
 
@@ -569,7 +567,7 @@ Driver::GetDebugMode() const
 // if the user only wanted help or version information.
 
 SBError
-Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exit)
+Driver::ParseArgs (int argc, const char *argv[], FILE *out_fh, bool &exiting)
 {
     ResetOptionValues ();
 
@@ -802,12 +800,12 @@ Driver::ParseArgs (int argc, const char
     if (error.Fail() || m_option_data.m_print_help)
     {
         ShowUsage (out_fh, g_options, m_option_data);
-        exit = true;
+        exiting = true;
     }
     else if (m_option_data.m_print_version)
     {
         ::fprintf (out_fh, "%s\n", m_debugger.GetVersionString());
-        exit = true;
+        exiting = true;
     }
     else if (m_option_data.m_print_python_path)
     {
@@ -825,7 +823,7 @@ Driver::ParseArgs (int argc, const char
         }
         else
             ::fprintf (out_fh, "<COULD NOT FIND PATH>\n");
-        exit = true;
+        exiting = true;
     }
     else if (m_option_data.m_process_name.empty() && m_option_data.m_process_pid == LLDB_INVALID_PROCESS_ID)
     {
@@ -1311,6 +1309,12 @@ Driver::EditLineInputReaderCallback
 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)
     {
@@ -1371,6 +1375,7 @@ Driver::MainLoop ()
             ::setbuf (editline_output_slave_fh, NULL);
         }
     }
+#endif
 
    // struct termios stdin_termios;
 
@@ -1412,6 +1417,7 @@ Driver::MainLoop ()
 
     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);
@@ -1422,6 +1428,7 @@ Driver::MainLoop ()
         ::fprintf (stderr, "error: failed to start libedit output read thread");
         exit (5);
     }
+#endif
 
 
     struct winsize window_size;
@@ -1663,9 +1670,11 @@ Driver::MainLoop ()
             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();
@@ -1780,15 +1789,15 @@ main (int argc, char const *argv[], cons
     {
         Driver driver;
 
-        bool exit = false;
-        SBError error (driver.ParseArgs (argc, argv, stdout, exit));
+        bool exiting = false;
+        SBError error (driver.ParseArgs (argc, argv, stdout, exiting));
         if (error.Fail())
         {
             const char *error_cstr = error.GetCString ();
             if (error_cstr)
                 ::fprintf (stderr, "error: %s\n", error_cstr);
         }
-        else if (!exit)
+        else if (!exiting)
         {
             driver.MainLoop ();
         }

Modified: lldb/trunk/tools/driver/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Driver.h?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/driver/Driver.h (original)
+++ lldb/trunk/tools/driver/Driver.h Tue Oct 15 10:46:40 2013
@@ -10,6 +10,7 @@
 #ifndef lldb_Driver_h_
 #define lldb_Driver_h_
 
+#include "Platform.h"
 #include "lldb/Utility/PseudoTerminal.h"
 
 #include <set>

Added: lldb/trunk/tools/driver/ELWrapper.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/ELWrapper.cpp?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/ELWrapper.cpp (added)
+++ lldb/trunk/tools/driver/ELWrapper.cpp Tue Oct 15 10:46:40 2013
@@ -0,0 +1,422 @@
+//===-- 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[ 64 ];
+    // try to get user input string
+    if ( el_get_s( buffer, 64 ) )
+    {
+        // 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

Added: lldb/trunk/tools/driver/ELWrapper.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/ELWrapper.h?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/ELWrapper.h (added)
+++ lldb/trunk/tools/driver/ELWrapper.h Tue Oct 15 10:46:40 2013
@@ -0,0 +1,122 @@
+//===-- 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

Added: lldb/trunk/tools/driver/GetOptWrapper.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/GetOptWrapper.cpp?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/GetOptWrapper.cpp (added)
+++ lldb/trunk/tools/driver/GetOptWrapper.cpp Tue Oct 15 10:46:40 2013
@@ -0,0 +1,33 @@
+//===-- 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

Added: lldb/trunk/tools/driver/GetOptWrapper.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/GetOptWrapper.h?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/GetOptWrapper.h (added)
+++ lldb/trunk/tools/driver/GetOptWrapper.h Tue Oct 15 10:46:40 2013
@@ -0,0 +1,49 @@
+//===-- 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

Modified: lldb/trunk/tools/driver/IOChannel.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/IOChannel.cpp?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/driver/IOChannel.cpp (original)
+++ lldb/trunk/tools/driver/IOChannel.cpp Tue Oct 15 10:46:40 2013
@@ -7,6 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "Platform.h"
 #include "IOChannel.h"
 
 #include <map>
@@ -73,7 +74,8 @@ void
 IOChannel::EraseCharsBeforeCursor ()
 {
     const LineInfo *line_info  = el_line(m_edit_line);
-    el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
+    if (line_info != NULL)
+        el_deletestr(m_edit_line, line_info->cursor - line_info->buffer);
 }
 
 unsigned char
@@ -213,17 +215,14 @@ IOChannel::IOChannel
     m_history_event(),
     m_getting_command (false),
     m_expecting_prompt (false),
-	m_prompt_str (),
+    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_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.
@@ -231,35 +230,20 @@ IOChannel::IOChannel
     el_set (m_edit_line, EL_CLIENTDATA, this);
 
     // Source $PWD/.editrc then $HOME/.editrc
-    ::el_source (m_edit_line, NULL);
+    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);
+    history (m_history, &m_history_event, H_SETSIZE, 800);
+    history (m_history, &m_history_event, H_SETUNIQUE, 1);
     // Load history
     HistorySaveLoad (false);
 
-    // Set up mutex to make sure OutErr, OutWrite and RefreshPrompt do not interfere
-    // with each other when writing.
-
-    int error;
-    ::pthread_mutexattr_t attr;
-    error = ::pthread_mutexattr_init (&attr);
-    assert (error == 0);
-    error = ::pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
-    assert (error == 0);
-    error = ::pthread_mutex_init (&m_output_mutex, &attr);
-    assert (error == 0);
-    error = ::pthread_mutexattr_destroy (&attr);
-    assert (error == 0);
-
-    error = ::pthread_cond_init (&m_output_cond, NULL);
-    assert (error == 0);
-
     // 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 ()
@@ -278,9 +262,6 @@ IOChannel::~IOChannel ()
         ::el_end (m_edit_line);
         m_edit_line = NULL;
     }
-
-    ::pthread_cond_destroy (&m_output_cond);
-    ::pthread_mutex_destroy (&m_output_mutex);
 }
 
 void
@@ -304,16 +285,15 @@ IOChannel::HistorySaveLoad (bool save)
 void
 IOChannel::LibeditOutputBytesReceived (void *baton, const void *src, size_t src_len)
 {
-	// Make this a member variable.
-    // static std::string prompt_str;
     IOChannel *io_channel = (IOChannel *) baton;
-    IOLocker locker (io_channel->m_output_mutex);
+    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' syncronization point in there.
-    if (src_len > 0 && bytes[src_len-1] == 0)
+    // 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;
@@ -322,7 +302,7 @@ IOChannel::LibeditOutputBytesReceived (v
     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.
+        // 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;
@@ -342,13 +322,14 @@ IOChannel::LibeditOutputBytesReceived (v
         io_channel->OutWrite (bytes, src_len, NO_ASYNC);
     }
 
+#if !defined (_MSC_VER)
     if (flush)
     {
-        // Signal that we have finished all data up to the sync point.
-        IOLocker locker (io_channel->m_output_mutex);
         io_channel->m_output_flushed = true;
-        pthread_cond_signal (&io_channel->m_output_cond);
+        io_channel->m_output_cond.notify_all();
     }
+#endif
+
 }
 
 IOChannel::LibeditGetInputResult
@@ -367,22 +348,27 @@ IOChannel::LibeditGetInput (std::string
         // 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.
         {
-            IOLocker locker (m_output_mutex);
+            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);
+            fputc ('\0', m_editline_out);
 
-            while (!m_output_flushed && pthread_cond_wait (&m_output_cond, &m_output_mutex))
-            { /* wait */ }
+            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);
 
@@ -417,7 +403,7 @@ IOChannel::LibeditGetInput (std::string
     return retval;
 }
 
-void *
+thread_result_t
 IOChannel::IOReadThread (void *ptr)
 {
     IOChannel *myself = static_cast<IOChannel *> (ptr);
@@ -540,8 +526,7 @@ IOChannel::Start ()
     if (IS_VALID_LLDB_HOST_THREAD(m_read_thread))
         return true;
 
-    m_read_thread = SBHostOS::ThreadCreate ("<lldb.driver.commandline_io>", IOChannel::IOReadThread, this,
-                                            NULL);
+    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));
 }
@@ -569,11 +554,11 @@ IOChannel::RefreshPrompt ()
 {
     // If we are not in the middle of getting input from the user, there is no need to 
     // refresh the prompt.
-    IOLocker locker (m_output_mutex);
+    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 we haven't finished writing the prompt, there's no need to refresh it.
     if (m_expecting_prompt)
         return;
 
@@ -600,7 +585,7 @@ IOChannel::OutWrite (const char *buffer,
     }
 
     // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
-    IOLocker locker (m_output_mutex);
+    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);
@@ -615,7 +600,7 @@ IOChannel::ErrWrite (const char *buffer,
         return;
 
     // Use the mutex to make sure OutWrite and ErrWrite do not interfere with each other's output.
-    IOLocker locker (m_output_mutex);
+    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);
@@ -669,17 +654,3 @@ IOChannel::SetGettingCommand (bool new_v
 {
     m_getting_command = new_value;
 }
-
-IOLocker::IOLocker (pthread_mutex_t &mutex) :
-    m_mutex_ptr (&mutex)
-{
-    if (m_mutex_ptr)
-        ::pthread_mutex_lock (m_mutex_ptr);
-        
-}
-
-IOLocker::~IOLocker ()
-{
-    if (m_mutex_ptr)
-        ::pthread_mutex_unlock (m_mutex_ptr);
-}

Modified: lldb/trunk/tools/driver/IOChannel.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/IOChannel.h?rev=192714&r1=192713&r2=192714&view=diff
==============================================================================
--- lldb/trunk/tools/driver/IOChannel.h (original)
+++ lldb/trunk/tools/driver/IOChannel.h Tue Oct 15 10:46:40 2013
@@ -10,18 +10,13 @@
 #ifndef lldb_IOChannel_h_
 #define lldb_IOChannel_h_
 
+#include <thread>
+#include <mutex>
+#include <atomic>
+#include <condition_variable>
+
 #include <string>
 #include <queue>
-
-#if defined(__FreeBSD__) || defined(__NetBSD__)
-#include <readline/readline.h>
-#else
-#include <editline/readline.h>
-#endif
-#include <histedit.h>
-#include <pthread.h>
-#include <sys/time.h>
-
 #include "Driver.h"
 
 class IOChannel : public lldb::SBBroadcaster
@@ -63,7 +58,7 @@ public:
     bool
     Stop ();
 
-    static void *
+    static lldb::thread_result_t
     IOReadThread (void *);
 
     void
@@ -127,8 +122,8 @@ protected:
 
 private:
 
-    pthread_mutex_t m_output_mutex;
-    pthread_cond_t m_output_cond;
+    std::recursive_mutex m_output_mutex;
+    std::condition_variable_any m_output_cond;
     struct timeval m_enter_elgets_time;
 
     Driver *m_driver;
@@ -156,22 +151,4 @@ private:
     HandleCompletion (EditLine *e, int ch);
 };
 
-class IOLocker 
-{
-public:
-
-    IOLocker (pthread_mutex_t &mutex);
-
-    ~IOLocker ();
-
-protected:
-
-    pthread_mutex_t *m_mutex_ptr;
-
-private:
-
-    IOLocker (const IOLocker&);
-    const IOLocker& operator= (const IOLocker&);
-};
-
 #endif  // lldb_IOChannel_h_

Added: lldb/trunk/tools/driver/Platform.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Platform.cpp?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/Platform.cpp (added)
+++ lldb/trunk/tools/driver/Platform.cpp Tue Oct 15 10:46:40 2013
@@ -0,0 +1,111 @@
+//===-- Platform.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 <process.h>
+#include <assert.h>
+
+#include "Platform.h"
+
+// index one of the variable arguments
+//  presuming "(EditLine *el, ..." is first in the argument list
+#define GETARG( Y, X ) ( (void* ) *( ( (int**) &(Y) ) + (X) ) )
+
+// the control handler or SIGINT handler
+static sighandler_t _ctrlHandler = NULL;
+
+// the default console control handler
+BOOL
+WINAPI CtrlHandler (DWORD ctrlType)
+{
+    if ( _ctrlHandler != NULL )
+    {
+        _ctrlHandler( 0 );
+        return TRUE;
+    }
+    return FALSE;
+}
+
+int
+ioctl (int d, int request, ...)
+{
+    switch ( request )
+    {
+    // request the console windows size
+    case ( TIOCGWINSZ ):
+        {
+            // locate the window size structure on stack
+            winsize *ws = (winsize*) GETARG( d, 2 );
+            // get screen buffer information
+            CONSOLE_SCREEN_BUFFER_INFO info;
+            GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ), &info );
+            // fill in the columns
+            ws->ws_col = info.dwMaximumWindowSize.X;
+            //
+            return 0;
+        }
+        break;
+    default:
+        assert( !"Not implemented!" );
+    }
+    return -1;
+}
+
+int
+kill (pid_t pid, int sig)
+{
+    // is the app trying to kill itself
+    if ( pid == getpid( ) )
+        exit( sig );
+    //
+    assert( !"Not implemented!" );
+    return -1;
+}
+
+int
+tcsetattr (int fd, int optional_actions, const struct termios *termios_p)
+{
+    assert( !"Not implemented!" );
+    return -1;
+}
+
+int
+tcgetattr (int fildes, struct termios *termios_p)
+{
+//  assert( !"Not implemented!" );
+    // error return value (0=success)
+    return -1;
+}
+
+sighandler_t
+signal (int sig, sighandler_t sigFunc)
+{
+    switch ( sig )
+    {
+    case ( SIGINT ):
+        {
+            _ctrlHandler = sigFunc;
+            SetConsoleCtrlHandler( CtrlHandler, TRUE );
+        }
+        break;
+    case ( SIGPIPE  ):
+    case ( SIGWINCH ):
+    case ( SIGTSTP  ):
+    case ( SIGCONT  ):
+        // ignore these for now
+        break;
+    default:
+        assert( !"Not implemented!" );
+    }
+    return 0;
+}
+
+#endif
\ No newline at end of file

Added: lldb/trunk/tools/driver/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Platform.h?rev=192714&view=auto
==============================================================================
--- lldb/trunk/tools/driver/Platform.h (added)
+++ lldb/trunk/tools/driver/Platform.h Tue Oct 15 10:46:40 2013
@@ -0,0 +1,120 @@
+//===-- Platform.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_Platform_h_
+#define lldb_Platform_h_
+
+#if defined( _MSC_VER )
+
+    #define PRIu32 "u"
+    #define PRId64 "I64d"
+    #define PRIi64 "I64i"
+    #define PRIo64 "I64o"
+    #define PRIu64 "I64u"
+    #define PRIx64 "I64x"
+    #define PRIX64 "I64X"
+
+    // this will stop signal.h being included
+    #define _INC_SIGNAL
+
+    #include <io.h>
+    #include <eh.h>
+    #include "ELWrapper.h"
+    #include "lldb/Host/windows/Windows.h"
+    #include "GetOptWrapper.h"
+
+    struct timeval
+    {
+        long tv_sec;
+        long tv_usec;
+    };
+
+    struct winsize
+    {
+        long ws_col;
+    };
+
+    typedef unsigned char   cc_t;
+    typedef unsigned int    speed_t;
+    typedef unsigned int    tcflag_t;
+
+    // fcntl.h
+    #define O_NOCTTY 0400
+
+    // ioctls.h
+    #define TIOCGWINSZ 0x5413
+
+    // signal.h
+    #define SIGPIPE  13
+    #define SIGCONT  18
+    #define SIGTSTP  20
+    #define SIGWINCH 28
+
+    // tcsetattr arguments
+    #define TCSANOW 0
+
+    #define NCCS 32
+    struct termios
+    {
+        tcflag_t c_iflag;  // input mode flags
+        tcflag_t c_oflag;  // output mode flags
+        tcflag_t c_cflag;  // control mode flags
+        tcflag_t c_lflag;  // local mode flags
+        cc_t c_line;       // line discipline
+        cc_t c_cc[NCCS];   // control characters
+        speed_t c_ispeed;  // input speed
+        speed_t c_ospeed;  // output speed
+    };
+
+    typedef long pid_t;
+
+    #define STDIN_FILENO 0
+
+    #define PATH_MAX MAX_PATH
+    #define snprintf _snprintf
+
+    extern int  ioctl( int d, int request, ... );
+    extern int  kill ( pid_t pid, int sig      );
+    extern int  tcsetattr( int fd, int optional_actions, const struct termios *termios_p );
+    extern int  tcgetattr( int fildes, struct termios *termios_p );
+
+    // signal handler function pointer type
+    typedef void (*sighandler_t)(int);
+
+    // signal.h
+    #define SIGINT 2
+    // default handler
+    #define SIG_DFL ( (sighandler_t) -1 )
+    // ignored
+    #define SIG_IGN ( (sighandler_t) -2 )
+    extern sighandler_t signal( int sig, sighandler_t );
+
+#else
+
+    #if defined(__FreeBSD__)
+        #include <readline/readline.h>
+    #else
+        #include <editline/readline.h>
+    #endif
+
+    #include <inttypes.h>
+
+    #include <getopt.h>
+    #include <libgen.h>
+    #include <sys/ioctl.h>
+    #include <termios.h>
+    #include <unistd.h>
+
+    #include <histedit.h>
+    #include <pthread.h>
+    #include <sys/time.h>
+
+#endif
+
+#endif // lldb_Platform_h_
\ No newline at end of file





More information about the lldb-commits mailing list