66//
77// ===----------------------------------------------------------------------===//
88
9+ #include < limits>
910#include < memory>
1011#include < stdlib.h>
1112#include < string>
3132#include " Commands/CommandObjectQuit.h"
3233#include " Commands/CommandObjectRegister.h"
3334#include " Commands/CommandObjectReproducer.h"
35+ #include " Commands/CommandObjectSession.h"
3436#include " Commands/CommandObjectSettings.h"
3537#include " Commands/CommandObjectSource.h"
3638#include " Commands/CommandObjectStats.h"
5254#if LLDB_ENABLE_LIBEDIT
5355#include " lldb/Host/Editline.h"
5456#endif
57+ #include " lldb/Host/File.h"
58+ #include " lldb/Host/FileCache.h"
5559#include " lldb/Host/Host.h"
5660#include " lldb/Host/HostInfo.h"
5761
7478#include " llvm/Support/FormatAdapters.h"
7579#include " llvm/Support/Path.h"
7680#include " llvm/Support/PrettyStackTrace.h"
81+ #include " llvm/Support/ScopedPrinter.h"
7782
7883using namespace lldb ;
7984using namespace lldb_private ;
@@ -116,7 +121,7 @@ CommandInterpreter::CommandInterpreter(Debugger &debugger,
116121 m_skip_lldbinit_files(false ), m_skip_app_init_files(false ),
117122 m_command_io_handler_sp(), m_comment_char(' #' ),
118123 m_batch_command_mode(false ), m_truncation_warning(eNoTruncation),
119- m_command_source_depth(0 ), m_result() {
124+ m_command_source_depth(0 ), m_result(), m_transcript_stream() {
120125 SetEventName (eBroadcastBitThreadShouldExit, " thread-should-exit" );
121126 SetEventName (eBroadcastBitResetPrompt, " reset-prompt" );
122127 SetEventName (eBroadcastBitQuitCommandReceived, " quit" );
@@ -142,6 +147,17 @@ void CommandInterpreter::SetPromptOnQuit(bool enable) {
142147 m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr , idx, enable);
143148}
144149
150+ bool CommandInterpreter::GetSaveSessionOnQuit () const {
151+ const uint32_t idx = ePropertySaveSessionOnQuit;
152+ return m_collection_sp->GetPropertyAtIndexAsBoolean (
153+ nullptr , idx, g_interpreter_properties[idx].default_uint_value != 0 );
154+ }
155+
156+ void CommandInterpreter::SetSaveSessionOnQuit (bool enable) {
157+ const uint32_t idx = ePropertySaveSessionOnQuit;
158+ m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr , idx, enable);
159+ }
160+
145161bool CommandInterpreter::GetEchoCommands () const {
146162 const uint32_t idx = ePropertyEchoCommands;
147163 return m_collection_sp->GetPropertyAtIndexAsBoolean (
@@ -496,6 +512,7 @@ void CommandInterpreter::LoadCommandDictionary() {
496512 CommandObjectSP (new CommandObjectReproducer (*this ));
497513 m_command_dict[" script" ] =
498514 CommandObjectSP (new CommandObjectScript (*this , script_language));
515+ m_command_dict[" session" ] = std::make_shared<CommandObjectSession>(*this );
499516 m_command_dict[" settings" ] =
500517 CommandObjectSP (new CommandObjectMultiwordSettings (*this ));
501518 m_command_dict[" source" ] =
@@ -1672,6 +1689,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
16721689 else
16731690 add_to_history = (lazy_add_to_history == eLazyBoolYes);
16741691
1692+ m_transcript_stream << " (lldb) " << command_line << ' \n ' ;
1693+
16751694 bool empty_command = false ;
16761695 bool comment_command = false ;
16771696 if (command_string.empty ())
@@ -1804,6 +1823,9 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
18041823 LLDB_LOGF (log, " HandleCommand, command %s" ,
18051824 (result.Succeeded () ? " succeeded" : " did not succeed" ));
18061825
1826+ m_transcript_stream << result.GetOutputData ();
1827+ m_transcript_stream << result.GetErrorData ();
1828+
18071829 return result.Succeeded ();
18081830}
18091831
@@ -2882,6 +2904,51 @@ bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
28822904 return false ;
28832905}
28842906
2907+ bool CommandInterpreter::SaveTranscript (
2908+ CommandReturnObject &result, llvm::Optional<std::string> output_file) {
2909+ if (output_file == llvm::None || output_file->empty ()) {
2910+ std::string now = llvm::to_string (std::chrono::system_clock::now ());
2911+ std::replace (now.begin (), now.end (), ' ' , ' _' );
2912+ const std::string file_name = " lldb_session_" + now + " .log" ;
2913+ FileSpec tmp = HostInfo::GetGlobalTempDir ();
2914+ tmp.AppendPathComponent (file_name);
2915+ output_file = tmp.GetPath ();
2916+ }
2917+
2918+ auto error_out = [&](llvm::StringRef error_message, std::string description) {
2919+ LLDB_LOG (GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS), " {0} ({1}:{2})" ,
2920+ error_message, output_file, description);
2921+ result.AppendErrorWithFormatv (
2922+ " Failed to save session's transcripts to {0}!" , *output_file);
2923+ return false ;
2924+ };
2925+
2926+ File::OpenOptions flags = File::eOpenOptionWrite |
2927+ File::eOpenOptionCanCreate |
2928+ File::eOpenOptionTruncate;
2929+
2930+ auto opened_file = FileSystem::Instance ().Open (FileSpec (*output_file), flags);
2931+
2932+ if (!opened_file)
2933+ return error_out (" Unable to create file" ,
2934+ llvm::toString (opened_file.takeError ()));
2935+
2936+ FileUP file = std::move (opened_file.get ());
2937+
2938+ size_t byte_size = m_transcript_stream.GetSize ();
2939+
2940+ Status error = file->Write (m_transcript_stream.GetData (), byte_size);
2941+
2942+ if (error.Fail () || byte_size != m_transcript_stream.GetSize ())
2943+ return error_out (" Unable to write to destination file" ,
2944+ " Bytes written do not match transcript size." );
2945+
2946+ result.AppendMessageWithFormat (" Session's transcripts saved to %s\n " ,
2947+ output_file->c_str ());
2948+
2949+ return true ;
2950+ }
2951+
28852952void CommandInterpreter::GetLLDBCommandsFromIOHandler (
28862953 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
28872954 Debugger &debugger = GetDebugger ();
0 commit comments