blob: f0849c9ac950a60fc83776e5e4945a6973bc558d [file] [log] [blame]
//===-- Debugger.h ----------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_CORE_DEBUGGER_H
#define LLDB_CORE_DEBUGGER_H
#include <cstdint>
#include <memory>
#include <vector>
#include "lldb/Core/FormatEntity.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Host/HostThread.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/TargetList.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/FileSpec.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-private-types.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/DynamicLibrary.h"
#include "llvm/Support/Threading.h"
#include <cassert>
#include <cstddef>
#include <cstdio>
namespace llvm {
class raw_ostream;
}
namespace lldb_private {
class Address;
class CommandInterpreter;
class Process;
class Stream;
class SymbolContext;
class Target;
namespace repro {
class DataRecorder;
}
/// \class Debugger Debugger.h "lldb/Core/Debugger.h"
/// A class to manage flag bits.
///
/// Provides a global root objects for the debugger core.
class Debugger : public std::enable_shared_from_this<Debugger>,
public UserID,
public Properties {
friend class SourceManager; // For GetSourceFileCache.
public:
/// Broadcaster event bits definitions.
enum {
eBroadcastBitProgress = (1 << 0),
};
static ConstString GetStaticBroadcasterClass();
/// Get the public broadcaster for this debugger.
Broadcaster &GetBroadcaster() { return m_broadcaster; }
const Broadcaster &GetBroadcaster() const { return m_broadcaster; }
class ProgressEventData : public EventData {
public:
ProgressEventData(uint64_t progress_id, const std::string &message,
uint64_t completed, uint64_t total,
bool debugger_specific)
: m_message(message), m_id(progress_id), m_completed(completed),
m_total(total), m_debugger_specific(debugger_specific) {}
static ConstString GetFlavorString();
ConstString GetFlavor() const override;
void Dump(Stream *s) const override;
static const ProgressEventData *
GetEventDataFromEvent(const Event *event_ptr);
uint64_t GetID() const { return m_id; }
uint64_t GetCompleted() const { return m_completed; }
uint64_t GetTotal() const { return m_total; }
const std::string &GetMessage() const { return m_message; }
bool IsDebuggerSpecific() const { return m_debugger_specific; }
private:
std::string m_message;
const uint64_t m_id;
uint64_t m_completed;
const uint64_t m_total;
const bool m_debugger_specific;
ProgressEventData(const ProgressEventData &) = delete;
const ProgressEventData &operator=(const ProgressEventData &) = delete;
};
~Debugger() override;
static lldb::DebuggerSP
CreateInstance(lldb::LogOutputCallback log_callback = nullptr,
void *baton = nullptr);
static lldb::TargetSP FindTargetWithProcessID(lldb::pid_t pid);
static lldb::TargetSP FindTargetWithProcess(Process *process);
static void Initialize(LoadPluginCallbackType load_plugin_callback);
static void Terminate();
static void SettingsInitialize();
static void SettingsTerminate();
static void Destroy(lldb::DebuggerSP &debugger_sp);
static lldb::DebuggerSP FindDebuggerWithID(lldb::user_id_t id);
static lldb::DebuggerSP
FindDebuggerWithInstanceName(ConstString instance_name);
static size_t GetNumDebuggers();
static lldb::DebuggerSP GetDebuggerAtIndex(size_t index);
static bool FormatDisassemblerAddress(const FormatEntity::Entry *format,
const SymbolContext *sc,
const SymbolContext *prev_sc,
const ExecutionContext *exe_ctx,
const Address *addr, Stream &s);
void Clear();
bool GetAsyncExecution();
void SetAsyncExecution(bool async);
lldb::FileSP GetInputFileSP() { return m_input_file_sp; }
lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; }
lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; }
File &GetInputFile() { return *m_input_file_sp; }
File &GetOutputFile() { return m_output_stream_sp->GetFile(); }
File &GetErrorFile() { return m_error_stream_sp->GetFile(); }
StreamFile &GetOutputStream() { return *m_output_stream_sp; }
StreamFile &GetErrorStream() { return *m_error_stream_sp; }
repro::DataRecorder *GetInputRecorder();
void SetInputFile(lldb::FileSP file, repro::DataRecorder *recorder = nullptr);
void SetOutputFile(lldb::FileSP file);
void SetErrorFile(lldb::FileSP file);
void SaveInputTerminalState();
void RestoreInputTerminalState();
lldb::StreamSP GetAsyncOutputStream();
lldb::StreamSP GetAsyncErrorStream();
CommandInterpreter &GetCommandInterpreter() {
assert(m_command_interpreter_up.get());
return *m_command_interpreter_up;
}
ScriptInterpreter *
GetScriptInterpreter(bool can_create = true,
llvm::Optional<lldb::ScriptLanguage> language = {});
lldb::ListenerSP GetListener() { return m_listener_sp; }
// This returns the Debugger's scratch source manager. It won't be able to
// look up files in debug information, but it can look up files by absolute
// path and display them to you. To get the target's source manager, call
// GetSourceManager on the target instead.
SourceManager &GetSourceManager();
lldb::TargetSP GetSelectedTarget() {
return m_target_list.GetSelectedTarget();
}
ExecutionContext GetSelectedExecutionContext();
/// Get accessor for the target list.
///
/// The target list is part of the global debugger object. This the single
/// debugger shared instance to control where targets get created and to
/// allow for tracking and searching for targets based on certain criteria.
///
/// \return
/// A global shared target list.
TargetList &GetTargetList() { return m_target_list; }
PlatformList &GetPlatformList() { return m_platform_list; }
void DispatchInputInterrupt();
void DispatchInputEndOfFile();
// If any of the streams are not set, set them to the in/out/err stream of
// the top most input reader to ensure they at least have something
void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in,
lldb::StreamFileSP &out,
lldb::StreamFileSP &err);
/// Run the given IO handler and return immediately.
void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp,
bool cancel_top_handler = true);
/// Run the given IO handler and block until it's complete.
void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp);
/// Remove the given IO handler if it's currently active.
bool RemoveIOHandler(const lldb::IOHandlerSP &reader_sp);
bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp);
bool CheckTopIOHandlerTypes(IOHandler::Type top_type,
IOHandler::Type second_top_type);
void PrintAsync(const char *s, size_t len, bool is_stdout);
ConstString GetTopIOHandlerControlSequence(char ch);
const char *GetIOHandlerCommandPrefix();
const char *GetIOHandlerHelpPrologue();
void ClearIOHandlers();
bool GetCloseInputOnEOF() const;
void SetCloseInputOnEOF(bool b);
bool EnableLog(llvm::StringRef channel,
llvm::ArrayRef<const char *> categories,
llvm::StringRef log_file, uint32_t log_options,
llvm::raw_ostream &error_stream);
void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);
// Properties Functions
enum StopDisassemblyType {
eStopDisassemblyTypeNever = 0,
eStopDisassemblyTypeNoDebugInfo,
eStopDisassemblyTypeNoSource,
eStopDisassemblyTypeAlways
};
Status SetPropertyValue(const ExecutionContext *exe_ctx,
VarSetOperationType op, llvm::StringRef property_path,
llvm::StringRef value) override;
bool GetAutoConfirm() const;
const FormatEntity::Entry *GetDisassemblyFormat() const;
const FormatEntity::Entry *GetFrameFormat() const;
const FormatEntity::Entry *GetFrameFormatUnique() const;
uint32_t GetStopDisassemblyMaxSize() const;
const FormatEntity::Entry *GetThreadFormat() const;
const FormatEntity::Entry *GetThreadStopFormat() const;
lldb::ScriptLanguage GetScriptLanguage() const;
bool SetScriptLanguage(lldb::ScriptLanguage script_lang);
uint32_t GetTerminalWidth() const;
bool SetTerminalWidth(uint32_t term_width);
llvm::StringRef GetPrompt() const;
void SetPrompt(llvm::StringRef p);
void SetPrompt(const char *) = delete;
llvm::StringRef GetReproducerPath() const;
bool GetUseExternalEditor() const;
bool SetUseExternalEditor(bool use_external_editor_p);
bool GetUseColor() const;
bool SetUseColor(bool use_color);
bool GetUseAutosuggestion() const;
bool GetUseSourceCache() const;
bool SetUseSourceCache(bool use_source_cache);
bool GetHighlightSource() const;
lldb::StopShowColumn GetStopShowColumn() const;
llvm::StringRef GetStopShowColumnAnsiPrefix() const;
llvm::StringRef GetStopShowColumnAnsiSuffix() const;
uint32_t GetStopSourceLineCount(bool before) const;
StopDisassemblyType GetStopDisassemblyDisplay() const;
uint32_t GetDisassemblyLineCount() const;
llvm::StringRef GetStopShowLineMarkerAnsiPrefix() const;
llvm::StringRef GetStopShowLineMarkerAnsiSuffix() const;
bool GetAutoOneLineSummaries() const;
bool GetAutoIndent() const;
bool SetAutoIndent(bool b);
bool GetPrintDecls() const;
bool SetPrintDecls(bool b);
uint32_t GetTabSize() const;
bool SetTabSize(uint32_t tab_size);
bool GetEscapeNonPrintables() const;
bool GetNotifyVoid() const;
ConstString GetInstanceName() { return m_instance_name; }
bool LoadPlugin(const FileSpec &spec, Status &error);
void RunIOHandlers();
bool IsForwardingEvents();
void EnableForwardEvents(const lldb::ListenerSP &listener_sp);
void CancelForwardEvents(const lldb::ListenerSP &listener_sp);
bool IsHandlingEvents() const { return m_event_handler_thread.IsJoinable(); }
Status RunREPL(lldb::LanguageType language, const char *repl_options);
// This is for use in the command interpreter, when you either want the
// selected target, or if no target is present you want to prime the dummy
// target with entities that will be copied over to new targets.
Target &GetSelectedOrDummyTarget(bool prefer_dummy = false);
Target &GetDummyTarget() { return *m_dummy_target_sp; }
lldb::BroadcasterManagerSP GetBroadcasterManager() {
return m_broadcaster_manager_sp;
}
protected:
friend class CommandInterpreter;
friend class REPL;
friend class Progress;
/// Report progress events.
///
/// Progress events will be delivered to any debuggers that have listeners
/// for the eBroadcastBitProgress. This function is called by the
/// lldb_private::Progress class to deliver the events to any debuggers that
/// qualify.
///
/// \param [in] progress_id
/// The unique integer identifier for the progress to report.
///
/// \param[in] message
/// The title of the progress dialog to display in the UI.
///
/// \param [in] completed
/// The amount of work completed. If \a completed is zero, then this event
/// is a progress started event. If \a completed is equal to \a total, then
/// this event is a progress end event. Otherwise completed indicates the
/// current progress compare to the total value.
///
/// \param [in] total
/// The total amount of work units that need to be completed. If this value
/// is UINT64_MAX, then an indeterminate progress indicator should be
/// displayed.
///
/// \param [in] debugger_id
/// If this optional parameter has a value, it indicates the unique
/// debugger identifier that this progress should be delivered to. If this
/// optional parameter does not have a value, the progress will be
/// delivered to all debuggers.
static void ReportProgress(uint64_t progress_id, const std::string &message,
uint64_t completed, uint64_t total,
llvm::Optional<lldb::user_id_t> debugger_id);
bool StartEventHandlerThread();
void StopEventHandlerThread();
static lldb::thread_result_t EventHandlerThread(lldb::thread_arg_t arg);
void PushIOHandler(const lldb::IOHandlerSP &reader_sp,
bool cancel_top_handler = true);
bool PopIOHandler(const lldb::IOHandlerSP &reader_sp);
bool HasIOHandlerThread();
bool StartIOHandlerThread();
void StopIOHandlerThread();
void JoinIOHandlerThread();
static lldb::thread_result_t IOHandlerThread(lldb::thread_arg_t arg);
void DefaultEventHandler();
void HandleBreakpointEvent(const lldb::EventSP &event_sp);
void HandleProcessEvent(const lldb::EventSP &event_sp);
void HandleThreadEvent(const lldb::EventSP &event_sp);
// Ensures two threads don't attempt to flush process output in parallel.
std::mutex m_output_flush_mutex;
void FlushProcessOutput(Process &process, bool flush_stdout,
bool flush_stderr);
SourceManager::SourceFileCache &GetSourceFileCache() {
return m_source_file_cache;
}
void InstanceInitialize();
// these should never be NULL
lldb::FileSP m_input_file_sp;
lldb::StreamFileSP m_output_stream_sp;
lldb::StreamFileSP m_error_stream_sp;
/// Used for shadowing the input file when capturing a reproducer.
repro::DataRecorder *m_input_recorder;
lldb::BroadcasterManagerSP m_broadcaster_manager_sp; // The debugger acts as a
// broadcaster manager of
// last resort.
// It needs to get constructed before the target_list or any other member
// that might want to broadcast through the debugger.
TerminalState m_terminal_state;
TargetList m_target_list;
PlatformList m_platform_list;
lldb::ListenerSP m_listener_sp;
std::unique_ptr<SourceManager> m_source_manager_up; // This is a scratch
// source manager that we
// return if we have no
// targets.
SourceManager::SourceFileCache m_source_file_cache; // All the source managers
// for targets created in
// this debugger used this
// shared
// source file cache.
std::unique_ptr<CommandInterpreter> m_command_interpreter_up;
std::recursive_mutex m_script_interpreter_mutex;
std::array<lldb::ScriptInterpreterSP, lldb::eScriptLanguageUnknown>
m_script_interpreters;
IOHandlerStack m_io_handler_stack;
std::recursive_mutex m_io_handler_synchronous_mutex;
llvm::StringMap<std::weak_ptr<llvm::raw_ostream>> m_log_streams;
std::shared_ptr<llvm::raw_ostream> m_log_callback_stream_sp;
ConstString m_instance_name;
static LoadPluginCallbackType g_load_plugin_callback;
typedef std::vector<llvm::sys::DynamicLibrary> LoadedPluginsList;
LoadedPluginsList m_loaded_plugins;
HostThread m_event_handler_thread;
HostThread m_io_handler_thread;
Broadcaster m_sync_broadcaster; ///< Private debugger synchronization.
Broadcaster m_broadcaster; ///< Public Debugger event broadcaster.
lldb::ListenerSP m_forward_listener_sp;
llvm::once_flag m_clear_once;
lldb::TargetSP m_dummy_target_sp;
// Events for m_sync_broadcaster
enum {
eBroadcastBitEventThreadIsListening = (1 << 0),
};
private:
// Use Debugger::CreateInstance() to get a shared pointer to a new debugger
// object
Debugger(lldb::LogOutputCallback m_log_callback, void *baton);
Debugger(const Debugger &) = delete;
const Debugger &operator=(const Debugger &) = delete;
};
} // namespace lldb_private
#endif // LLDB_CORE_DEBUGGER_H