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 (
@@ -493,6 +509,7 @@ void CommandInterpreter::LoadCommandDictionary() {
493509 CommandObjectSP (new CommandObjectReproducer (*this ));
494510 m_command_dict[" script" ] =
495511 CommandObjectSP (new CommandObjectScript (*this , script_language));
512+ m_command_dict[" session" ] = std::make_shared<CommandObjectSession>(*this );
496513 m_command_dict[" settings" ] =
497514 CommandObjectSP (new CommandObjectMultiwordSettings (*this ));
498515 m_command_dict[" source" ] =
@@ -1667,6 +1684,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
16671684 else
16681685 add_to_history = (lazy_add_to_history == eLazyBoolYes);
16691686
1687+ m_transcript_stream << " (lldb) " << command_line << ' \n ' ;
1688+
16701689 bool empty_command = false ;
16711690 bool comment_command = false ;
16721691 if (command_string.empty ())
@@ -1799,6 +1818,9 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
17991818 LLDB_LOGF (log, " HandleCommand, command %s" ,
18001819 (result.Succeeded () ? " succeeded" : " did not succeed" ));
18011820
1821+ m_transcript_stream << result.GetOutputData ();
1822+ m_transcript_stream << result.GetErrorData ();
1823+
18021824 return result.Succeeded ();
18031825}
18041826
@@ -2877,6 +2899,51 @@ bool CommandInterpreter::IOHandlerInterrupt(IOHandler &io_handler) {
28772899 return false ;
28782900}
28792901
2902+ bool CommandInterpreter::SaveTranscript (
2903+ CommandReturnObject &result, llvm::Optional<std::string> output_file) {
2904+ if (output_file == llvm::None || output_file->empty ()) {
2905+ std::string now = llvm::to_string (std::chrono::system_clock::now ());
2906+ std::replace (now.begin (), now.end (), ' ' , ' _' );
2907+ const std::string file_name = " lldb_session_" + now + " .log" ;
2908+ FileSpec tmp = HostInfo::GetGlobalTempDir ();
2909+ tmp.AppendPathComponent (file_name);
2910+ output_file = tmp.GetPath ();
2911+ }
2912+
2913+ auto error_out = [&](llvm::StringRef error_message, std::string description) {
2914+ LLDB_LOG (GetLogIfAllCategoriesSet (LIBLLDB_LOG_COMMANDS), " {0} ({1}:{2})" ,
2915+ error_message, output_file, description);
2916+ result.AppendErrorWithFormatv (
2917+ " Failed to save session's transcripts to {0}!" , *output_file);
2918+ return false ;
2919+ };
2920+
2921+ File::OpenOptions flags = File::eOpenOptionWrite |
2922+ File::eOpenOptionCanCreate |
2923+ File::eOpenOptionTruncate;
2924+
2925+ auto opened_file = FileSystem::Instance ().Open (FileSpec (*output_file), flags);
2926+
2927+ if (!opened_file)
2928+ return error_out (" Unable to create file" ,
2929+ llvm::toString (opened_file.takeError ()));
2930+
2931+ FileUP file = std::move (opened_file.get ());
2932+
2933+ size_t byte_size = m_transcript_stream.GetSize ();
2934+
2935+ Status error = file->Write (m_transcript_stream.GetData (), byte_size);
2936+
2937+ if (error.Fail () || byte_size != m_transcript_stream.GetSize ())
2938+ return error_out (" Unable to write to destination file" ,
2939+ " Bytes written do not match transcript size." );
2940+
2941+ result.AppendMessageWithFormat (" Session's transcripts saved to %s\n " ,
2942+ output_file->c_str ());
2943+
2944+ return true ;
2945+ }
2946+
28802947void CommandInterpreter::GetLLDBCommandsFromIOHandler (
28812948 const char *prompt, IOHandlerDelegate &delegate, void *baton) {
28822949 Debugger &debugger = GetDebugger ();
0 commit comments