Skip to content

Commit be265d2

Browse files
committed
[lldb] Add support for specifying a log handler
This patch adds a new flag to `log enable`, allowing the user to specify a custom log handler. In addition to the default (stream) handler, this allows using the circular log handler (which logs to a fixed size, in-memory circular buffer) as well as the system log handler (which logs to the operating system log). Differential revision: https://reviews.llvm.org/D128323
1 parent 7ae92a6 commit be265d2

File tree

9 files changed

+93
-12
lines changed

9 files changed

+93
-12
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
245245
bool EnableLog(llvm::StringRef channel,
246246
llvm::ArrayRef<const char *> categories,
247247
llvm::StringRef log_file, uint32_t log_options,
248-
size_t buffer_size, llvm::raw_ostream &error_stream);
248+
size_t buffer_size, LogHandlerKind log_handler_kind,
249+
llvm::raw_ostream &error_stream);
249250

250251
void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);
251252

lldb/include/lldb/lldb-enumerations.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ enum CommandArgumentType {
602602
eArgTypeColumnNum,
603603
eArgTypeModuleUUID,
604604
eArgTypeSaveCoreStyle,
605+
eArgTypeLogHandler,
605606
eArgTypeLastArg // Always keep this entry as the last entry in this
606607
// enumeration!!
607608
};

lldb/include/lldb/lldb-private-enumerations.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,14 @@ enum StatisticKind {
222222
StatisticMax = 4
223223
};
224224

225+
// Enumeration that can be used to specify a log handler.
226+
enum LogHandlerKind {
227+
eLogHandlerStream,
228+
eLogHandlerCallback,
229+
eLogHandlerCircular,
230+
eLogHandlerSystem,
231+
eLogHandlerDefault = eLogHandlerStream,
232+
};
225233

226234
inline std::string GetStatDescription(lldb_private::StatisticKind K) {
227235
switch (K) {

lldb/source/API/SBDebugger.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,8 @@ bool SBDebugger::EnableLog(const char *channel, const char **categories) {
16211621
std::string error;
16221622
llvm::raw_string_ostream error_stream(error);
16231623
return m_opaque_sp->EnableLog(channel, GetCategoryArray(categories), "",
1624-
log_options, /*buffer_size=*/0, error_stream);
1624+
log_options, /*buffer_size=*/0,
1625+
eLogHandlerStream, error_stream);
16251626
} else
16261627
return false;
16271628
}

lldb/source/Commands/CommandObjectLog.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "lldb/Host/OptionParser.h"
1212
#include "lldb/Interpreter/CommandReturnObject.h"
1313
#include "lldb/Interpreter/OptionArgParser.h"
14+
#include "lldb/Interpreter/OptionValueEnumeration.h"
1415
#include "lldb/Interpreter/OptionValueUInt64.h"
1516
#include "lldb/Interpreter/Options.h"
1617
#include "lldb/Utility/Args.h"
@@ -22,6 +23,36 @@
2223
using namespace lldb;
2324
using namespace lldb_private;
2425

26+
static constexpr OptionEnumValueElement g_log_handler_type[] = {
27+
{
28+
eLogHandlerDefault,
29+
"default",
30+
"Use the default (stream) log handler",
31+
},
32+
{
33+
eLogHandlerStream,
34+
"stream",
35+
"Write log messages to the debugger output stream or to a file if one "
36+
"is specified. A buffer size (in bytes) can be specified with -b. If "
37+
"no buffer size is specified the output is unbuffered.",
38+
},
39+
{
40+
eLogHandlerCircular,
41+
"circular",
42+
"Write log messages to a fixed size circular buffer. A buffer size "
43+
"(number of messages) must be specified with -b.",
44+
},
45+
{
46+
eLogHandlerSystem,
47+
"os",
48+
"Write log messages to the operating system log.",
49+
},
50+
};
51+
52+
static constexpr OptionEnumValues LogHandlerType() {
53+
return OptionEnumValues(g_log_handler_type);
54+
}
55+
2556
#define LLDB_OPTIONS_log_enable
2657
#include "CommandOptions.inc"
2758

@@ -90,6 +121,14 @@ class CommandObjectLogEnable : public CommandObjectParsed {
90121
log_file.SetFile(option_arg, FileSpec::Style::native);
91122
FileSystem::Instance().Resolve(log_file);
92123
break;
124+
case 'h':
125+
handler = (LogHandlerKind)OptionArgParser::ToOptionEnum(
126+
option_arg, GetDefinitions()[option_idx].enum_values, 0, error);
127+
if (!error.Success())
128+
error.SetErrorStringWithFormat(
129+
"unrecognized value for log handler '%s'",
130+
option_arg.str().c_str());
131+
break;
93132
case 'b':
94133
error =
95134
buffer_size.SetValueFromString(option_arg, eVarSetOperationAssign);
@@ -128,6 +167,7 @@ class CommandObjectLogEnable : public CommandObjectParsed {
128167
void OptionParsingStarting(ExecutionContext *execution_context) override {
129168
log_file.Clear();
130169
buffer_size.Clear();
170+
handler = eLogHandlerStream;
131171
log_options = 0;
132172
}
133173

@@ -137,6 +177,7 @@ class CommandObjectLogEnable : public CommandObjectParsed {
137177

138178
FileSpec log_file;
139179
OptionValueUInt64 buffer_size;
180+
LogHandlerKind handler = eLogHandlerStream;
140181
uint32_t log_options = 0;
141182
};
142183

@@ -155,6 +196,13 @@ class CommandObjectLogEnable : public CommandObjectParsed {
155196
return false;
156197
}
157198

199+
if (m_options.handler == eLogHandlerCircular &&
200+
m_options.buffer_size.GetCurrentValue() == 0) {
201+
result.AppendError(
202+
"the circular buffer handler requires a non-zero buffer size.\n");
203+
return false;
204+
}
205+
158206
// Store into a std::string since we're about to shift the channel off.
159207
const std::string channel = std::string(args[0].ref());
160208
args.Shift(); // Shift off the channel
@@ -168,7 +216,8 @@ class CommandObjectLogEnable : public CommandObjectParsed {
168216
llvm::raw_string_ostream error_stream(error);
169217
bool success = GetDebugger().EnableLog(
170218
channel, args.GetArgumentArrayRef(), log_file, m_options.log_options,
171-
m_options.buffer_size.GetCurrentValue(), error_stream);
219+
m_options.buffer_size.GetCurrentValue(), m_options.handler,
220+
error_stream);
172221
result.GetErrorStream() << error_stream.str();
173222

174223
if (success)

lldb/source/Commands/Options.td

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,8 +431,10 @@ let Command = "history" in {
431431
let Command = "log enable" in {
432432
def log_file : Option<"file", "f">, Group<1>, Arg<"Filename">,
433433
Desc<"Set the destination file to log to.">;
434+
def log_handler : Option<"log-handler", "h">, Group<1>,
435+
EnumArg<"LogHandler", "LogHandlerType()">, Desc<"Specify a log handler which determines where log messages are written.">;
434436
def log_buffer_size : Option<"buffer", "b">, Group<1>, Arg<"UnsignedInteger">,
435-
Desc<"Set the log to be buffered, using the specified buffer size.">;
437+
Desc<"Set the log to be buffered, using the specified buffer size, if supported by the log handler.">;
436438
def log_verbose : Option<"verbose", "v">, Group<1>,
437439
Desc<"Enable verbose logging.">;
438440
def log_sequence : Option<"sequence", "s">, Group<1>,

lldb/source/Core/Debugger.cpp

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,11 +1406,27 @@ void Debugger::ReportError(std::string message,
14061406
debugger_id, once);
14071407
}
14081408

1409+
static std::shared_ptr<LogHandler>
1410+
CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
1411+
size_t buffer_size) {
1412+
switch (log_handler_kind) {
1413+
case eLogHandlerStream:
1414+
return std::make_shared<StreamLogHandler>(fd, should_close, buffer_size);
1415+
case eLogHandlerCircular:
1416+
return std::make_shared<RotatingLogHandler>(buffer_size);
1417+
case eLogHandlerSystem:
1418+
return std::make_shared<SystemLogHandler>();
1419+
case eLogHandlerCallback:
1420+
return {};
1421+
}
1422+
return {};
1423+
}
1424+
14091425
bool Debugger::EnableLog(llvm::StringRef channel,
14101426
llvm::ArrayRef<const char *> categories,
14111427
llvm::StringRef log_file, uint32_t log_options,
1412-
size_t buffer_size, llvm::raw_ostream &error_stream) {
1413-
const bool should_close = true;
1428+
size_t buffer_size, LogHandlerKind log_handler_kind,
1429+
llvm::raw_ostream &error_stream) {
14141430

14151431
std::shared_ptr<LogHandler> log_handler_sp;
14161432
if (m_callback_handler_sp) {
@@ -1419,8 +1435,9 @@ bool Debugger::EnableLog(llvm::StringRef channel,
14191435
log_options |=
14201436
LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME;
14211437
} else if (log_file.empty()) {
1422-
log_handler_sp = std::make_shared<StreamLogHandler>(
1423-
GetOutputFile().GetDescriptor(), !should_close, buffer_size);
1438+
log_handler_sp =
1439+
CreateLogHandler(log_handler_kind, GetOutputFile().GetDescriptor(),
1440+
/*should_close=*/false, buffer_size);
14241441
} else {
14251442
auto pos = m_stream_handlers.find(log_file);
14261443
if (pos != m_stream_handlers.end())
@@ -1440,8 +1457,9 @@ bool Debugger::EnableLog(llvm::StringRef channel,
14401457
return false;
14411458
}
14421459

1443-
log_handler_sp = std::make_shared<StreamLogHandler>(
1444-
(*file)->GetDescriptor(), should_close, buffer_size);
1460+
log_handler_sp =
1461+
CreateLogHandler(log_handler_kind, (*file)->GetDescriptor(),
1462+
/*should_close=*/true, buffer_size);
14451463
m_stream_handlers[log_file] = log_handler_sp;
14461464
}
14471465
}

lldb/source/Interpreter/CommandObject.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1126,7 +1126,8 @@ CommandObject::ArgumentTableEntry CommandObject::g_arguments_data[] = {
11261126
{ eArgTypeCommand, "command", CommandCompletions::eNoCompletion, { nullptr, false }, "An LLDB Command line command element." },
11271127
{ eArgTypeColumnNum, "column", CommandCompletions::eNoCompletion, { nullptr, false }, "Column number in a source file." },
11281128
{ eArgTypeModuleUUID, "module-uuid", CommandCompletions::eModuleUUIDCompletion, { nullptr, false }, "A module UUID value." },
1129-
{ eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." }
1129+
{ eArgTypeSaveCoreStyle, "corefile-style", CommandCompletions::eNoCompletion, { nullptr, false }, "The type of corefile that lldb will try to create, dependant on this target's capabilities." },
1130+
{ eArgTypeLogHandler, "log-handler", CommandCompletions::eNoCompletion, { nullptr, false }, "The log handle that will be used to write out log messages." },
11301131
// clang-format on
11311132
};
11321133

lldb/tools/lldb-test/lldb-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1120,7 +1120,7 @@ int main(int argc, const char *argv[]) {
11201120
/*add_to_history*/ eLazyBoolNo, Result);
11211121

11221122
if (!opts::Log.empty())
1123-
Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, 0, errs());
1123+
Dbg->EnableLog("lldb", {"all"}, opts::Log, 0, 0, eLogHandlerStream, errs());
11241124

11251125
if (opts::BreakpointSubcommand)
11261126
return opts::breakpoint::evaluateBreakpoints(*Dbg);

0 commit comments

Comments
 (0)