Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.

As part of this it introduces a new Stream class,
StreamAsynchronousIO.  A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast.  When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string.  When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.

Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.

I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired.  I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).

llvm-svn: 130721
  • Loading branch information
Caroline Tice committed May 2, 2011
1 parent f897d3b commit 969ed3d
Show file tree
Hide file tree
Showing 25 changed files with 351 additions and 119 deletions.
4 changes: 3 additions & 1 deletion lldb/include/lldb/API/SBCommandInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ class SBCommandInterpreter
{
eBroadcastBitThreadShouldExit = (1 << 0),
eBroadcastBitResetPrompt = (1 << 1),
eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
eBroadcastBitAsynchronousOutputData = (1 << 3),
eBroadcastBitAsynchronousErrorData = (1 << 4)
};

SBCommandInterpreter (const lldb::SBCommandInterpreter &rhs);
Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/API/SBDebugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ class SBDebugger
void
PushInputReader (lldb::SBInputReader &reader);

void
NotifyTopInputReader (lldb::InputReaderAction notification);

const char *
GetInstanceName ();

Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Core/Debugger.h
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,9 @@ class Debugger :
bool
PopInputReader (const lldb::InputReaderSP& reader_sp);

void
NotifyTopInputReader (lldb::InputReaderAction notification);

static lldb::DebuggerSP
FindDebuggerWithID (lldb::user_id_t id);

Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Core/Event.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class EventDataBytes : public EventData

void
SetBytes (const void *src, size_t src_len);

void
SwapBytes (std::string &new_bytes);

void
SetBytesFromCString (const char *cstr);
Expand Down
42 changes: 42 additions & 0 deletions lldb/include/lldb/Core/StreamAsynchronousIO.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===-- StreamAsynchronousIO.h -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#ifndef liblldb_StreamAsynchronousIO_h_
#define liblldb_StreamAsynchronousIO_h_

#include <string>

#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamString.h"

namespace lldb_private {

class StreamAsynchronousIO :
public Stream
{
public:
StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type);

virtual ~StreamAsynchronousIO ();

virtual void
Flush ();

virtual int
Write (const void *src, size_t src_len);


private:
Broadcaster &m_broadcaster;
uint32_t m_broadcast_event_type;
StreamString m_accumulated_data;
};

} // namespace lldb_private
#endif // #ifndef liblldb_StreamAsynchronousIO_h
4 changes: 3 additions & 1 deletion lldb/include/lldb/Interpreter/CommandInterpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ class CommandInterpreter : public Broadcaster
{
eBroadcastBitThreadShouldExit = (1 << 0),
eBroadcastBitResetPrompt = (1 << 1),
eBroadcastBitQuitCommandReceived = (1 << 2) // User entered quit
eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
eBroadcastBitAsynchronousOutputData = (1 << 3),
eBroadcastBitAsynchronousErrorData = (1 << 4)
};

void
Expand Down
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ namespace lldb {
typedef enum InputReaderAction
{
eInputReaderActivate, // reader is newly pushed onto the reader stack
eInputReaderAsynchronousOutputWritten, // an async output event occurred; the reader may want to do something
eInputReaderReactivate, // reader is on top of the stack again after another reader was popped off
eInputReaderDeactivate, // another reader was pushed on the stack
eInputReaderGotToken, // reader got one of its tokens (granularity)
Expand Down
12 changes: 10 additions & 2 deletions lldb/lldb.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,8 @@
9A357673116E7B6400E8ED2F /* SBStringList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A357672116E7B6400E8ED2F /* SBStringList.cpp */; };
9A3576A8116E9AB700E8ED2F /* SBHostOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A3576A7116E9AB700E8ED2F /* SBHostOS.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A3576AA116E9AC700E8ED2F /* SBHostOS.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A3576A9116E9AC700E8ED2F /* SBHostOS.cpp */; };
9A4F35101368A51A00823F52 /* StreamAsynchronousIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */; };
9A4F35121368A54100823F52 /* StreamAsynchronousIO.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */; };
9AA69DA61188F52100D753A0 /* PseudoTerminal.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */; };
9AA69DAF118A023300D753A0 /* SBInputReader.h in Headers */ = {isa = PBXBuildFile; fileRef = 9AA69DAE118A023300D753A0 /* SBInputReader.h */; settings = {ATTRIBUTES = (Public, ); }; };
9AA69DB1118A024600D753A0 /* SBInputReader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9AA69DB0118A024600D753A0 /* SBInputReader.cpp */; };
Expand Down Expand Up @@ -1192,6 +1194,8 @@
9A4633DA11F65D8600955CE1 /* UserSettingsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UserSettingsController.h; path = include/lldb/Core/UserSettingsController.h; sourceTree = "<group>"; };
9A4633DC11F65D9A00955CE1 /* UserSettingsController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserSettingsController.cpp; path = source/Core/UserSettingsController.cpp; sourceTree = "<group>"; };
9A48A3A7124AAA5A00922451 /* python-extensions.swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "python-extensions.swig"; sourceTree = "<group>"; };
9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamAsynchronousIO.cpp; path = source/Core/StreamAsynchronousIO.cpp; sourceTree = "<group>"; };
9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamAsynchronousIO.h; path = include/lldb/Core/StreamAsynchronousIO.h; sourceTree = "<group>"; };
9A633FE7112DCE3C001A7E43 /* SBFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFrame.cpp; path = source/API/SBFrame.cpp; sourceTree = "<group>"; };
9A633FE8112DCE3C001A7E43 /* SBFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFrame.h; path = include/lldb/API/SBFrame.h; sourceTree = "<group>"; };
9A82010B10FFB49800182560 /* ScriptInterpreter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ScriptInterpreter.cpp; path = source/Interpreter/ScriptInterpreter.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1327,7 +1331,6 @@
26BC7E7510F1B85900F91463 /* lldb-log.cpp */,
26BC7C2A10F1B3BC00F91463 /* lldb-private.h */,
26217932133BCB850083B112 /* lldb-private-enumerations.h */,
26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */,
26BC7D5D10F1B77400F91463 /* lldb-private-log.h */,
26217930133BC8640083B112 /* lldb-private-types.h */,
262D3190111B4341004E6F88 /* API */,
Expand Down Expand Up @@ -1977,6 +1980,8 @@
26BC7D7810F1B77400F91463 /* STLUtils.h */,
26BC7D7910F1B77400F91463 /* Stream.h */,
26BC7E9110F1B85900F91463 /* Stream.cpp */,
9A4F35111368A54100823F52 /* StreamAsynchronousIO.h */,
9A4F350F1368A51A00823F52 /* StreamAsynchronousIO.cpp */,
26BC7D7A10F1B77400F91463 /* StreamFile.h */,
26BC7E9210F1B85900F91463 /* StreamFile.cpp */,
26BC7D7B10F1B77400F91463 /* StreamString.h */,
Expand Down Expand Up @@ -2176,6 +2181,7 @@
26BC7DBE10F1B78200F91463 /* Expression */ = {
isa = PBXGroup;
children = (
26BC7C2810F1B3BC00F91463 /* lldb-private-interfaces.h */,
49D7072611B5AD03001AD875 /* ClangASTSource.h */,
49D7072811B5AD11001AD875 /* ClangASTSource.cpp */,
26BC7DC010F1B79500F91463 /* ClangExpression.h */,
Expand Down Expand Up @@ -2677,6 +2683,7 @@
2671A0CE134825F6003A87BB /* ConnectionMachPort.h in Headers */,
4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */,
4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */,
9A4F35121368A54100823F52 /* StreamAsynchronousIO.h in Headers */,
4C2FAE2F135E3A70001EDE44 /* SharedCluster.h in Headers */,
2692BA16136610C100F9E14D /* UnwindAssemblyInstEmulation.h in Headers */,
);
Expand Down Expand Up @@ -3246,6 +3253,7 @@
26A7A035135E6E4200FB369E /* NamedOptionValue.cpp in Sources */,
9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */,
9A22A163135E30370024DDC3 /* EmulationStateARM.cpp in Sources */,
9A4F35101368A51A00823F52 /* StreamAsynchronousIO.cpp in Sources */,
2630BFAF1365F3220070C534 /* ArchDefaultUnwindPlan.cpp in Sources */,
2630BFB01365F3220070C534 /* ArchVolatileRegs.cpp in Sources */,
2692BA15136610C100F9E14D /* UnwindAssemblyInstEmulation.cpp in Sources */,
Expand Down Expand Up @@ -3336,7 +3344,7 @@
__STDC_LIMIT_MACROS,
LLDB_CONFIGURATION_DEBUG,
);
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_VERSION = 4.2;
GCC_WARN_64_TO_32_BIT_CONVERSION = NO;
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
Expand Down
12 changes: 12 additions & 0 deletions lldb/source/API/SBDebugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,18 @@ SBDebugger::PushInputReader (SBInputReader &reader)
}
}

void
SBDebugger::NotifyTopInputReader (InputReaderAction notification)
{
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));

if (log)
log->Printf ("SBDebugger(%p)::NotifyTopInputReader (%d)", m_opaque_sp.get(), notification);

if (m_opaque_sp)
m_opaque_sp->NotifyTopInputReader (notification);
}

void
SBDebugger::reset (const DebuggerSP &debugger_sp)
{
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Commands/CommandObjectBreakpointCommand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,9 @@ CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback
}
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
if (bytes && bytes_len && baton)
{
Expand Down
5 changes: 4 additions & 1 deletion lldb/source/Commands/CommandObjectCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,10 @@ CommandObjectCommandsAddRegex::InputReaderCallback (void *baton,

case eInputReaderDeactivate:
break;


case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
while (bytes_len > 0 && (bytes[bytes_len-1] == '\r' || bytes[bytes_len-1] == '\n'))
--bytes_len;
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Commands/CommandObjectExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ CommandObjectExpression::MultiLineExpressionCallback
case eInputReaderDeactivate:
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
++cmd_object_expr->m_expr_line_count;
if (bytes && bytes_len)
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Commands/CommandObjectTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,6 +1032,9 @@ class CommandObjectTargetStopHookAdd : public CommandObject
}
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
if (bytes && bytes_len && baton)
{
Expand Down
14 changes: 14 additions & 0 deletions lldb/source/Core/Debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,20 @@ Debugger::CleanUpInputReaders ()
}
}

void
Debugger::NotifyTopInputReader (InputReaderAction notification)
{
InputReaderSP reader_sp (GetCurrentInputReader());
if (reader_sp)
{
reader_sp->Notify (notification);

// Flush out any input readers that are done.
while (CheckIfTopInputReaderIsDone ())
/* Do nothing. */;
}
}

void
Debugger::WriteToDefaultReader (const char *bytes, size_t bytes_len)
{
Expand Down
7 changes: 7 additions & 0 deletions lldb/source/Core/Event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,10 @@ EventDataBytes::GetEventDataFromEvent (const Event *event_ptr)
return NULL;
}

void
EventDataBytes::SwapBytes (std::string &new_bytes)
{
m_bytes.swap (new_bytes);
}


3 changes: 3 additions & 0 deletions lldb/source/Core/InputReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,9 @@ InputReader::Notify (InputReaderAction notification)
m_active = false;
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderInterrupt:
case eInputReaderEndOfFile:
break;
Expand Down
52 changes: 52 additions & 0 deletions lldb/source/Core/StreamAsynchronousIO.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===-- StreamBroadcast.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include <stdio.h>

#include "lldb/lldb-private.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/StreamAsynchronousIO.h"

using namespace lldb;
using namespace lldb_private;


StreamAsynchronousIO::StreamAsynchronousIO (Broadcaster &broadcaster, uint32_t broadcast_event_type) :
Stream (0, 4, eByteOrderBig),
m_broadcaster (broadcaster),
m_broadcast_event_type (broadcast_event_type),
m_accumulated_data ()
{
}

StreamAsynchronousIO::~StreamAsynchronousIO ()
{
}

void
StreamAsynchronousIO::Flush ()
{
if (m_accumulated_data.GetSize() > 0)
{
std::auto_ptr<EventDataBytes> data_bytes_ap (new EventDataBytes);
// Let's swap the bytes to avoid LARGE string copies.
data_bytes_ap->SwapBytes (m_accumulated_data.GetString());
EventSP new_event_sp (new Event (m_broadcast_event_type, data_bytes_ap.release()));
m_broadcaster.BroadcastEvent (new_event_sp);
m_accumulated_data.Clear();
}
}

int
StreamAsynchronousIO::Write (const void *s, size_t length)
{
m_accumulated_data.Write (s, length);
return length;
}
11 changes: 10 additions & 1 deletion lldb/source/Interpreter/CommandInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,10 @@ CommandInterpreter::GetConfirmationInputReaderCallback
out_file.Flush ();
}
break;


case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
if (bytes_len == 0)
{
Expand Down Expand Up @@ -1642,6 +1645,12 @@ CommandInterpreter::HandleCommands (const StringList &commands,
}
}

if (result.GetImmediateOutputStream())
result.GetImmediateOutputStream()->Flush();

if (result.GetImmediateErrorStream())
result.GetImmediateErrorStream()->Flush();

// N.B. Can't depend on DidChangeProcessState, because the state coming into the command execution
// could be running (for instance in Breakpoint Commands.
// So we check the return value to see if it is has running in it.
Expand Down
6 changes: 6 additions & 0 deletions lldb/source/Interpreter/ScriptInterpreterPython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,6 +639,9 @@ ScriptInterpreterPython::InputReaderCallback
script_interpreter->EnterSession ();
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderInterrupt:
::write (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor(), "raise KeyboardInterrupt\n", 24);
break;
Expand Down Expand Up @@ -1047,6 +1050,9 @@ ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
}
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
{
std::string temp_string (bytes, bytes_len);
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3183,6 +3183,9 @@ Process::ProcessInputReaderCallback (void *baton,
case eInputReaderReactivate:
break;

case eInputReaderAsynchronousOutputWritten:
break;

case eInputReaderGotToken:
{
Error error;
Expand Down
Loading

0 comments on commit 969ed3d

Please sign in to comment.