Index: include/lldb/Core/Debugger.h =================================================================== --- include/lldb/Core/Debugger.h +++ include/lldb/Core/Debugger.h @@ -192,8 +192,9 @@ void SetCloseInputOnEOF(bool b); - bool EnableLog(const char *channel, const char **categories, - const char *log_file, uint32_t log_options, + bool EnableLog(llvm::StringRef channel, + llvm::ArrayRef categories, + llvm::StringRef log_file, uint32_t log_options, Stream &error_stream); void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); Index: include/lldb/Core/Log.h =================================================================== --- include/lldb/Core/Log.h +++ include/lldb/Core/Log.h @@ -100,10 +100,12 @@ static bool EnableLogChannel(const std::shared_ptr &log_stream_sp, uint32_t log_options, llvm::StringRef channel, - const char **categories, Stream &error_stream); + llvm::ArrayRef categories, + Stream &error_stream); static bool DisableLogChannel(llvm::StringRef channel, - const char **categories, Stream &error_stream); + llvm::ArrayRef categories, + Stream &error_stream); static bool ListChannelCategories(llvm::StringRef channel, Stream &stream); Index: include/lldb/Interpreter/Args.h =================================================================== --- include/lldb/Interpreter/Args.h +++ include/lldb/Interpreter/Args.h @@ -193,6 +193,15 @@ const char **GetConstArgumentVector() const; //------------------------------------------------------------------ + /// Gets the argument as an ArrayRef. Note that the return value does *not* + /// have a nullptr const char * at the end, as the size of the list is + /// embedded in the ArrayRef object. + //------------------------------------------------------------------ + llvm::ArrayRef GetArgumentArrayRef() const { + return llvm::makeArrayRef(m_argv).drop_back(); + } + + //------------------------------------------------------------------ /// Appends a new argument to the end of the list argument list. /// /// @param[in] arg_cstr Index: source/API/SBDebugger.cpp =================================================================== --- source/API/SBDebugger.cpp +++ source/API/SBDebugger.cpp @@ -1120,13 +1120,22 @@ } #endif // LLDB_DISABLE_PYTHON +static llvm::ArrayRef GetCategoryArray(const char **categories) { + if (categories == nullptr) + return {}; + size_t len = 0; + while (categories[len] != nullptr) + ++len; + return llvm::makeArrayRef(categories, len); +} + bool SBDebugger::EnableLog(const char *channel, const char **categories) { if (m_opaque_sp) { uint32_t log_options = LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; StreamString errors; - return m_opaque_sp->EnableLog(channel, categories, nullptr, log_options, - errors); + return m_opaque_sp->EnableLog(channel, GetCategoryArray(categories), "", + log_options, errors); } else return false; } Index: source/Commands/CommandObjectLog.cpp =================================================================== --- source/Commands/CommandObjectLog.cpp +++ source/Commands/CommandObjectLog.cpp @@ -172,8 +172,8 @@ else log_file[0] = '\0'; bool success = m_interpreter.GetDebugger().EnableLog( - channel.c_str(), args.GetConstArgumentVector(), log_file, - m_options.log_options, result.GetErrorStream()); + channel, args.GetArgumentArrayRef(), log_file, m_options.log_options, + result.GetErrorStream()); if (success) result.SetStatus(eReturnStatusSuccessFinishNoResult); else @@ -233,7 +233,7 @@ Log::DisableAllLogChannels(&result.GetErrorStream()); result.SetStatus(eReturnStatusSuccessFinishNoResult); } else { - if (Log::DisableLogChannel(channel, args.GetConstArgumentVector(), + if (Log::DisableLogChannel(channel, args.GetArgumentArrayRef(), result.GetErrorStream())) result.SetStatus(eReturnStatusSuccessFinishNoResult); } Index: source/Core/Debugger.cpp =================================================================== --- source/Core/Debugger.cpp +++ source/Core/Debugger.cpp @@ -1239,8 +1239,9 @@ m_log_callback_stream_sp.reset(new StreamCallback(log_callback, baton)); } -bool Debugger::EnableLog(const char *channel, const char **categories, - const char *log_file, uint32_t log_options, +bool Debugger::EnableLog(llvm::StringRef channel, + llvm::ArrayRef categories, + llvm::StringRef log_file, uint32_t log_options, Stream &error_stream) { const bool should_close = true; const bool unbuffered = true; @@ -1251,7 +1252,7 @@ // For now when using the callback mode you always get thread & timestamp. log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; - } else if (log_file == nullptr || *log_file == '\0') { + } else if (log_file.empty()) { log_stream_sp = std::make_shared( GetOutputFile()->GetFile().GetDescriptor(), !should_close, unbuffered); } else { Index: source/Core/Log.cpp =================================================================== --- source/Core/Log.cpp +++ source/Core/Log.cpp @@ -59,27 +59,26 @@ } static uint32_t GetFlags(Stream &stream, const ChannelMap::value_type &entry, - const char **categories) { + llvm::ArrayRef categories) { bool list_categories = false; uint32_t flags = 0; - for (size_t i = 0; categories[i]; ++i) { - if (llvm::StringRef("all").equals_lower(categories[i])) { + for (const char *category : categories) { + if (llvm::StringRef("all").equals_lower(category)) { flags |= UINT32_MAX; continue; } - if (llvm::StringRef("default").equals_lower(categories[i])) { + if (llvm::StringRef("default").equals_lower(category)) { flags |= entry.second.channel.default_flags; continue; } - auto cat = llvm::find_if(entry.second.channel.categories, - [&](const Log::Category &c) { - return c.name.equals_lower(categories[i]); - }); + auto cat = llvm::find_if( + entry.second.channel.categories, + [&](const Log::Category &c) { return c.name.equals_lower(category); }); if (cat != entry.second.channel.categories.end()) { flags |= cat->flag; continue; } - stream.Format("error: unrecognized log category '{0}'\n", categories[i]); + stream.Format("error: unrecognized log category '{0}'\n", category); list_categories = true; } if (list_categories) @@ -237,31 +236,32 @@ bool Log::EnableLogChannel( const std::shared_ptr &log_stream_sp, - uint32_t log_options, llvm::StringRef channel, const char **categories, - Stream &error_stream) { + uint32_t log_options, llvm::StringRef channel, + llvm::ArrayRef categories, Stream &error_stream) { auto iter = g_channel_map->find(channel); if (iter == g_channel_map->end()) { error_stream.Format("Invalid log channel '{0}'.\n", channel); return false; } - uint32_t flags = categories && categories[0] - ? GetFlags(error_stream, *iter, categories) - : iter->second.channel.default_flags; + uint32_t flags = categories.empty() + ? iter->second.channel.default_flags + : GetFlags(error_stream, *iter, categories); iter->second.channel.Enable(iter->second.log, log_stream_sp, log_options, flags); return true; } -bool Log::DisableLogChannel(llvm::StringRef channel, const char **categories, +bool Log::DisableLogChannel(llvm::StringRef channel, + llvm::ArrayRef categories, Stream &error_stream) { auto iter = g_channel_map->find(channel); if (iter == g_channel_map->end()) { error_stream.Format("Invalid log channel '{0}'.\n", channel); return false; } - uint32_t flags = categories && categories[0] - ? GetFlags(error_stream, *iter, categories) - : UINT32_MAX; + uint32_t flags = categories.empty() + ? UINT32_MAX + : GetFlags(error_stream, *iter, categories); iter->second.channel.Disable(flags); return true; } Index: tools/lldb-server/LLDBServerUtilities.cpp =================================================================== --- tools/lldb-server/LLDBServerUtilities.cpp +++ tools/lldb-server/LLDBServerUtilities.cpp @@ -52,8 +52,8 @@ channel_then_categories.Shift(); // Shift off the channel bool success = Log::EnableLogChannel( - log_stream_sp, log_options, channel.c_str(), - channel_then_categories.GetConstArgumentVector(), error_stream); + log_stream_sp, log_options, channel, + channel_then_categories.GetArgumentArrayRef(), error_stream); if (!success) { fprintf(stderr, "Unable to open log file '%s' for channel \"%s\"\n", log_file.c_str(), channel_with_categories.str().c_str()); Index: unittests/Core/LogTest.cpp =================================================================== --- unittests/Core/LogTest.cpp +++ unittests/Core/LogTest.cpp @@ -93,7 +93,7 @@ llvm::llvm_shutdown_obj obj; Log::Register("chan", test_channel); EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO)); - const char *cat1[] = {"foo", nullptr}; + const char *cat1[] = {"foo"}; std::string message; std::shared_ptr stream_sp( new llvm::raw_string_ostream(message)); @@ -110,20 +110,20 @@ std::shared_ptr stream_sp( new llvm::raw_string_ostream(message)); StreamString err; - EXPECT_FALSE(Log::EnableLogChannel(stream_sp, 0, "chanchan", nullptr, err)); + EXPECT_FALSE(Log::EnableLogChannel(stream_sp, 0, "chanchan", {}, err)); EXPECT_EQ("Invalid log channel 'chanchan'.\n", err.GetString()); err.Clear(); - EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", nullptr, err)); - EXPECT_EQ("", err.GetString()); + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", {}, err)); + EXPECT_EQ("", err.GetString()) << "err: " << err.GetString().str(); EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO)); EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); - const char *cat2[] = {"bar", nullptr}; + const char *cat2[] = {"bar"}; EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat2, err)); EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR)); - const char *cat3[] = {"baz", nullptr}; + const char *cat3[] = {"baz"}; EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat3, err)); EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'")) << "err: " << err.GetString().str(); @@ -146,7 +146,7 @@ TEST_F(LogChannelTest, Disable) { EXPECT_EQ(nullptr, test_channel.GetLogIfAll(FOO)); - const char *cat12[] = {"foo", "bar", nullptr}; + const char *cat12[] = {"foo", "bar"}; std::string message; std::shared_ptr stream_sp( new llvm::raw_string_ostream(message)); @@ -154,12 +154,12 @@ EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", cat12, err)); EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO | BAR)); - const char *cat2[] = {"bar", nullptr}; + const char *cat2[] = {"bar"}; EXPECT_TRUE(Log::DisableLogChannel("chan", cat2, err)); EXPECT_NE(nullptr, test_channel.GetLogIfAll(FOO)); EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); - const char *cat3[] = {"baz", nullptr}; + const char *cat3[] = {"baz"}; EXPECT_TRUE(Log::DisableLogChannel("chan", cat3, err)); EXPECT_TRUE(err.GetString().contains("unrecognized log category 'baz'")) << "err: " << err.GetString().str(); @@ -167,7 +167,7 @@ EXPECT_EQ(nullptr, test_channel.GetLogIfAll(BAR)); err.Clear(); - EXPECT_TRUE(Log::DisableLogChannel("chan", nullptr, err)); + EXPECT_TRUE(Log::DisableLogChannel("chan", {}, err)); EXPECT_EQ(nullptr, test_channel.GetLogIfAny(FOO | BAR)); } @@ -195,13 +195,13 @@ std::shared_ptr stream_sp( new llvm::raw_string_ostream(message)); StreamString err; - EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", nullptr, err)); + EXPECT_TRUE(Log::EnableLogChannel(stream_sp, 0, "chan", {}, err)); Log *log = test_channel.GetLogIfAll(FOO); // Start logging on one thread. Concurrently, try disabling the log channel. std::thread log_thread([log] { LLDB_LOG(log, "Hello World"); }); - EXPECT_TRUE(Log::DisableLogChannel("chan", nullptr, err)); + EXPECT_TRUE(Log::DisableLogChannel("chan", {}, err)); log_thread.join(); // The log thread either managed to write to the log in time, or it didn't. In Index: unittests/Interpreter/TestArgs.cpp =================================================================== --- unittests/Interpreter/TestArgs.cpp +++ unittests/Interpreter/TestArgs.cpp @@ -169,6 +169,14 @@ EXPECT_STREQ("4", args.GetArgumentAtIndex(3)); } +TEST(ArgsTest, GetArgumentArrayRef) { + Args args("foo bar"); + auto ref = args.GetArgumentArrayRef(); + ASSERT_EQ(2u, ref.size()); + EXPECT_STREQ("foo", ref[0]); + EXPECT_STREQ("bar", ref[1]); +} + TEST(ArgsTest, StringToBoolean) { bool success = false; EXPECT_TRUE(Args::StringToBoolean(llvm::StringRef("true"), false, nullptr));