| //===-- StackFrame.h --------------------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef liblldb_StackFrame_h_ |
| #define liblldb_StackFrame_h_ |
| |
| // C Includes |
| // C++ Includes |
| #include <memory> |
| #include <mutex> |
| |
| // Other libraries and framework includes |
| // Project includes |
| #include "lldb/Utility/Flags.h" |
| |
| #include "lldb/Core/Scalar.h" |
| #include "lldb/Core/ValueObjectList.h" |
| #include "lldb/Symbol/SymbolContext.h" |
| #include "lldb/Target/ExecutionContextScope.h" |
| #include "lldb/Target/StackID.h" |
| #include "lldb/Utility/Status.h" |
| #include "lldb/Utility/StreamString.h" |
| #include "lldb/Utility/UserID.h" |
| |
| namespace lldb_private { |
| |
| /// @class StackFrame StackFrame.h "lldb/Target/StackFrame.h" |
| /// |
| /// This base class provides an interface to stack frames. |
| /// |
| /// StackFrames may have a Canonical Frame Address (CFA) or not. |
| /// A frame may have a plain pc value or it may have a pc value + stop_id |
| /// to indicate a specific point in the debug session so the correct section |
| /// load list is used for symbolication. |
| /// |
| /// Local variables may be available, or not. A register context may be |
| /// available, or not. |
| |
| class StackFrame : public ExecutionContextScope, |
| public std::enable_shared_from_this<StackFrame> { |
| public: |
| enum ExpressionPathOption { |
| eExpressionPathOptionCheckPtrVsMember = (1u << 0), |
| eExpressionPathOptionsNoFragileObjcIvar = (1u << 1), |
| eExpressionPathOptionsNoSyntheticChildren = (1u << 2), |
| eExpressionPathOptionsNoSyntheticArrayRange = (1u << 3), |
| eExpressionPathOptionsAllowDirectIVarAccess = (1u << 4), |
| eExpressionPathOptionsInspectAnonymousUnions = (1u << 5) |
| }; |
| |
| //------------------------------------------------------------------ |
| /// Construct a StackFrame object without supplying a RegisterContextSP. |
| /// |
| /// This is the one constructor that doesn't take a RegisterContext |
| /// parameter. This ctor may be called when creating a history StackFrame; |
| /// these are used if we've collected a stack trace of pc addresses at some |
| /// point in the past. We may only have pc values. We may have pc values |
| /// and the stop_id when the stack trace was recorded. We may have a CFA, |
| /// or more likely, we won't. |
| /// |
| /// @param [in] thread_sp |
| /// The Thread that this frame belongs to. |
| /// |
| /// @param [in] frame_idx |
| /// This StackFrame's frame index number in the Thread. If inlined stack |
| /// frames are being created, this may differ from the concrete_frame_idx |
| /// which is the frame index without any inlined stack frames. |
| /// |
| /// @param [in] concrete_frame_idx |
| /// The StackFrame's frame index number in the Thread without any inlined |
| /// stack frames being included in the index. |
| /// |
| /// @param [in] cfa |
| /// The Canonical Frame Address (this terminology from DWARF) for this |
| /// stack frame. The CFA for a stack frame does not change over the |
| /// span of the stack frame's existence. It is often the value of the |
| /// caller's stack pointer before the call instruction into this frame's |
| /// function. It is usually not the same as the frame pointer register's |
| /// value. |
| /// |
| /// @param [in] cfa_is_valid |
| /// A history stack frame may not have a CFA value collected. We want to |
| /// distinguish between "no CFA available" and a CFA of |
| /// LLDB_INVALID_ADDRESS. |
| /// |
| /// @param [in] pc |
| /// The current pc value of this stack frame. |
| /// |
| /// @param [in] stop_id |
| /// The stop_id which should be used when looking up symbols for the pc |
| /// value, |
| /// if appropriate. This argument is ignored if stop_id_is_valid is false. |
| /// |
| /// @param [in] stop_id_is_valid |
| /// If the stop_id argument provided is not needed for this StackFrame, this |
| /// should be false. If this is a history stack frame and we know the |
| /// stop_id |
| /// when the pc value was collected, that stop_id should be provided and |
| /// this |
| /// will be true. |
| /// |
| /// @param [in] is_history_frame |
| /// If this is a historical stack frame -- possibly without CFA or registers |
| /// or |
| /// local variables -- then this should be set to true. |
| /// |
| /// @param [in] sc_ptr |
| /// Optionally seed the StackFrame with the SymbolContext information that |
| /// has |
| /// already been discovered. |
| //------------------------------------------------------------------ |
| StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, |
| lldb::user_id_t concrete_frame_idx, lldb::addr_t cfa, |
| bool cfa_is_valid, lldb::addr_t pc, uint32_t stop_id, |
| bool stop_id_is_valid, bool is_history_frame, |
| const SymbolContext *sc_ptr); |
| |
| StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, |
| lldb::user_id_t concrete_frame_idx, |
| const lldb::RegisterContextSP ®_context_sp, lldb::addr_t cfa, |
| lldb::addr_t pc, const SymbolContext *sc_ptr); |
| |
| StackFrame(const lldb::ThreadSP &thread_sp, lldb::user_id_t frame_idx, |
| lldb::user_id_t concrete_frame_idx, |
| const lldb::RegisterContextSP ®_context_sp, lldb::addr_t cfa, |
| const Address &pc, const SymbolContext *sc_ptr); |
| |
| ~StackFrame() override; |
| |
| lldb::ThreadSP GetThread() const { return m_thread_wp.lock(); } |
| |
| StackID &GetStackID(); |
| |
| //------------------------------------------------------------------ |
| /// Get an Address for the current pc value in this StackFrame. |
| /// |
| /// May not be the same as the actual PC value for inlined stack frames. |
| /// |
| /// @return |
| /// The Address object set to the current PC value. |
| //------------------------------------------------------------------ |
| const Address &GetFrameCodeAddress(); |
| |
| //------------------------------------------------------------------ |
| /// Change the pc value for a given thread. |
| /// |
| /// Change the current pc value for the frame on this thread. |
| /// |
| /// @param[in] pc |
| /// The load address that the pc will be set to. |
| /// |
| /// @return |
| /// true if the pc was changed. false if this failed -- possibly |
| /// because this frame is not a live StackFrame. |
| //------------------------------------------------------------------ |
| bool ChangePC(lldb::addr_t pc); |
| |
| //------------------------------------------------------------------ |
| /// Provide a SymbolContext for this StackFrame's current pc value. |
| /// |
| /// The StackFrame maintains this SymbolContext and adds additional |
| /// information to it on an as-needed basis. This helps to avoid different |
| /// functions looking up symbolic information for a given pc value multiple |
| /// times. |
| /// |
| /// @params [in] resolve_scope |
| /// Flags from the SymbolContextItem enumerated type which specify what |
| /// type of symbol context is needed by this caller. |
| /// |
| /// @return |
| /// A SymbolContext reference which includes the types of information |
| /// requested by resolve_scope, if they are available. |
| //------------------------------------------------------------------ |
| const SymbolContext &GetSymbolContext(uint32_t resolve_scope); |
| |
| //------------------------------------------------------------------ |
| /// Return the Canonical Frame Address (DWARF term) for this frame. |
| /// |
| /// The CFA is typically the value of the stack pointer register before the |
| /// call invocation is made. It will not change during the lifetime of a |
| /// stack frame. It is often not the same thing as the frame pointer |
| /// register value. |
| /// |
| /// Live StackFrames will always have a CFA but other types of frames may |
| /// not be able to supply one. |
| /// |
| /// @param [out] value |
| /// The address of the CFA for this frame, if available. |
| /// |
| /// @param [out] error_ptr |
| /// If there is an error determining the CFA address, this may contain a |
| /// string explaining the failure. |
| /// |
| /// @return |
| /// Returns true if the CFA value was successfully set in value. Some |
| /// frames may be unable to provide this value; they will return false. |
| //------------------------------------------------------------------ |
| bool GetFrameBaseValue(Scalar &value, Status *error_ptr); |
| |
| //------------------------------------------------------------------ |
| /// Get the DWARFExpression corresponding to the Canonical Frame Address. |
| /// |
| /// Often a register (bp), but sometimes a register + offset. |
| /// |
| /// @param [out] error_ptr |
| /// If there is an error determining the CFA address, this may contain a |
| /// string explaining the failure. |
| /// |
| /// @return |
| /// Returns the corresponding DWARF expression, or NULL. |
| //------------------------------------------------------------------ |
| DWARFExpression *GetFrameBaseExpression(Status *error_ptr); |
| |
| //------------------------------------------------------------------ |
| /// Get the current lexical scope block for this StackFrame, if possible. |
| /// |
| /// If debug information is available for this stack frame, return a pointer |
| /// to the innermost lexical Block that the frame is currently executing. |
| /// |
| /// @return |
| /// A pointer to the current Block. nullptr is returned if this can |
| /// not be provided. |
| //------------------------------------------------------------------ |
| Block *GetFrameBlock(); |
| |
| //------------------------------------------------------------------ |
| /// Get the RegisterContext for this frame, if possible. |
| /// |
| /// Returns a shared pointer to the RegisterContext for this stack frame. |
| /// Only a live StackFrame object will be able to return a RegisterContext - |
| /// callers must be prepared for an empty shared pointer being returned. |
| /// |
| /// Even a live StackFrame RegisterContext may not be able to provide all |
| /// registers. Only the currently executing frame (frame 0) can reliably |
| /// provide every register in the register context. |
| /// |
| /// @return |
| /// The RegisterContext shared point for this frame. |
| //------------------------------------------------------------------ |
| lldb::RegisterContextSP GetRegisterContext(); |
| |
| const lldb::RegisterContextSP &GetRegisterContextSP() const { |
| return m_reg_context_sp; |
| } |
| |
| //------------------------------------------------------------------ |
| /// Retrieve the list of variables that are in scope at this StackFrame's |
| /// pc. |
| /// |
| /// A frame that is not live may return an empty VariableList for a given |
| /// pc value even though variables would be available at this point if it |
| /// were a live stack frame. |
| /// |
| /// @param[in] get_file_globals |
| /// Whether to also retrieve compilation-unit scoped variables |
| /// that are visible to the entire compilation unit (e.g. file |
| /// static in C, globals that are homed in this CU). |
| /// |
| /// @return |
| /// A pointer to a list of variables. |
| //------------------------------------------------------------------ |
| VariableList *GetVariableList(bool get_file_globals); |
| |
| //------------------------------------------------------------------ |
| /// Retrieve the list of variables that are in scope at this StackFrame's |
| /// pc. |
| /// |
| /// A frame that is not live may return an empty VariableListSP for a |
| /// given pc value even though variables would be available at this point if |
| /// it were a live stack frame. |
| /// |
| /// @param[in] get_file_globals |
| /// Whether to also retrieve compilation-unit scoped variables |
| /// that are visible to the entire compilation unit (e.g. file |
| /// static in C, globals that are homed in this CU). |
| /// |
| /// @return |
| /// A pointer to a list of variables. |
| //------------------------------------------------------------------ |
| lldb::VariableListSP |
| GetInScopeVariableList(bool get_file_globals, |
| bool must_have_valid_location = false); |
| |
| //------------------------------------------------------------------ |
| /// Create a ValueObject for a variable name / pathname, possibly including |
| /// simple dereference/child selection syntax. |
| /// |
| /// @param[in] var_expr |
| /// The string specifying a variable to base the VariableObject off |
| /// of. |
| /// |
| /// @param[in] use_dynamic |
| /// Whether the correct dynamic type of an object pointer should be |
| /// determined before creating the object, or if the static type is |
| /// sufficient. One of the DynamicValueType enumerated values. |
| /// |
| /// @param[in] options |
| /// An unsigned integer of flags, values from |
| /// StackFrame::ExpressionPathOption |
| /// enum. |
| /// @param[in] var_sp |
| /// A VariableSP that will be set to the variable described in the |
| /// var_expr path. |
| /// |
| /// @param[in] error |
| /// Record any errors encountered while evaluating var_expr. |
| /// |
| /// @return |
| /// A shared pointer to the ValueObject described by var_expr. |
| //------------------------------------------------------------------ |
| lldb::ValueObjectSP GetValueForVariableExpressionPath( |
| llvm::StringRef var_expr, lldb::DynamicValueType use_dynamic, |
| uint32_t options, lldb::VariableSP &var_sp, Status &error); |
| |
| //------------------------------------------------------------------ |
| /// Determine whether this StackFrame has debug information available or not |
| /// |
| /// @return |
| // true if debug information is available for this frame (function, |
| // compilation unit, block, etc.) |
| //------------------------------------------------------------------ |
| bool HasDebugInformation(); |
| |
| //------------------------------------------------------------------ |
| /// Return the disassembly for the instructions of this StackFrame's |
| /// function as a single C string. |
| /// |
| /// @return |
| // C string with the assembly instructions for this function. |
| //------------------------------------------------------------------ |
| const char *Disassemble(); |
| |
| //------------------------------------------------------------------ |
| /// Print a description for this frame using the frame-format formatter |
| /// settings. |
| /// |
| /// @param [in] strm |
| /// The Stream to print the description to. |
| /// |
| /// @param [in] show_unique |
| /// Whether to print the function arguments or not for backtrace unique. |
| /// |
| /// @param [in] frame_marker |
| /// Optional string that will be prepended to the frame output description. |
| //------------------------------------------------------------------ |
| void DumpUsingSettingsFormat(Stream *strm, bool show_unique = false, |
| const char *frame_marker = nullptr); |
| |
| //------------------------------------------------------------------ |
| /// Print a description for this frame using a default format. |
| /// |
| /// @param [in] strm |
| /// The Stream to print the description to. |
| /// |
| /// @param [in] show_frame_index |
| /// Whether to print the frame number or not. |
| /// |
| /// @param [in] show_fullpaths |
| /// Whether to print the full source paths or just the file base name. |
| //------------------------------------------------------------------ |
| void Dump(Stream *strm, bool show_frame_index, bool show_fullpaths); |
| |
| //------------------------------------------------------------------ |
| /// Print a description of this stack frame and/or the source |
| /// context/assembly for this stack frame. |
| /// |
| /// @param[in] strm |
| /// The Stream to send the output to. |
| /// |
| /// @param[in] show_frame_info |
| /// If true, print the frame info by calling DumpUsingSettingsFormat(). |
| /// |
| /// @param[in] show_source |
| /// If true, print source or disassembly as per the user's settings. |
| /// |
| /// @param[in] show_unique |
| /// If true, print using backtrace unique style, without function |
| /// arguments as per the user's settings. |
| /// |
| /// @param[in] frame_marker |
| /// Passed to DumpUsingSettingsFormat() for the frame info printing. |
| /// |
| /// @return |
| /// Returns true if successful. |
| //------------------------------------------------------------------ |
| bool GetStatus(Stream &strm, bool show_frame_info, bool show_source, |
| bool show_unique = false, const char *frame_marker = nullptr); |
| |
| //------------------------------------------------------------------ |
| /// Query whether this frame is a concrete frame on the call stack, or if it |
| /// is an inlined frame derived from the debug information and presented by |
| /// the debugger. |
| /// |
| /// @return |
| /// true if this is an inlined frame. |
| //------------------------------------------------------------------ |
| bool IsInlined(); |
| |
| //------------------------------------------------------------------ |
| /// Query this frame to find what frame it is in this Thread's |
| /// StackFrameList. |
| /// |
| /// @return |
| /// StackFrame index 0 indicates the currently-executing function. Inline |
| /// frames are included in this frame index count. |
| //------------------------------------------------------------------ |
| uint32_t GetFrameIndex() const; |
| |
| //------------------------------------------------------------------ |
| /// Query this frame to find what frame it is in this Thread's |
| /// StackFrameList, not counting inlined frames. |
| /// |
| /// @return |
| /// StackFrame index 0 indicates the currently-executing function. Inline |
| /// frames are not included in this frame index count; their concrete |
| /// frame index will be the same as the concrete frame that they are |
| /// derived from. |
| //------------------------------------------------------------------ |
| uint32_t GetConcreteFrameIndex() const { return m_concrete_frame_index; } |
| |
| //------------------------------------------------------------------ |
| /// Create a ValueObject for a given Variable in this StackFrame. |
| /// |
| /// @params [in] variable_sp |
| /// The Variable to base this ValueObject on |
| /// |
| /// @params [in] use_dynamic |
| /// Whether the correct dynamic type of the variable should be |
| /// determined before creating the ValueObject, or if the static type |
| /// is sufficient. One of the DynamicValueType enumerated values. |
| /// |
| /// @return |
| // A ValueObject for this variable. |
| //------------------------------------------------------------------ |
| lldb::ValueObjectSP |
| GetValueObjectForFrameVariable(const lldb::VariableSP &variable_sp, |
| lldb::DynamicValueType use_dynamic); |
| |
| //------------------------------------------------------------------ |
| /// Add an arbitrary Variable object (e.g. one that specifics a global or |
| /// static) to a StackFrame's list of ValueObjects. |
| /// |
| /// @params [in] variable_sp |
| /// The Variable to base this ValueObject on |
| /// |
| /// @params [in] use_dynamic |
| /// Whether the correct dynamic type of the variable should be |
| /// determined before creating the ValueObject, or if the static type |
| /// is sufficient. One of the DynamicValueType enumerated values. |
| /// |
| /// @return |
| // A ValueObject for this variable. |
| //------------------------------------------------------------------ |
| lldb::ValueObjectSP TrackGlobalVariable(const lldb::VariableSP &variable_sp, |
| lldb::DynamicValueType use_dynamic); |
| |
| //------------------------------------------------------------------ |
| /// Query this frame to determine what the default language should be when |
| /// parsing expressions given the execution context. |
| /// |
| /// @return |
| /// The language of the frame if known, else lldb::eLanguageTypeUnknown. |
| //------------------------------------------------------------------ |
| lldb::LanguageType GetLanguage(); |
| |
| // similar to GetLanguage(), but is allowed to take a potentially incorrect |
| // guess if exact information is not available |
| lldb::LanguageType GuessLanguage(); |
| |
| //------------------------------------------------------------------ |
| /// Attempt to econstruct the ValueObject for a given raw address touched by |
| /// the current instruction. The ExpressionPath should indicate how to get |
| /// to this value using "frame variable." |
| /// |
| /// @params [in] addr |
| /// The raw address. |
| /// |
| /// @return |
| /// The ValueObject if found. If valid, it has a valid ExpressionPath. |
| //------------------------------------------------------------------ |
| lldb::ValueObjectSP GuessValueForAddress(lldb::addr_t addr); |
| |
| //------------------------------------------------------------------ |
| /// Attempt to reconstruct the ValueObject for the address contained in a |
| /// given register plus an offset. The ExpressionPath should indicate how |
| /// to get to this value using "frame variable." |
| /// |
| /// @params [in] reg |
| /// The name of the register. |
| /// |
| /// @params [in] offset |
| /// The offset from the register. Particularly important for sp... |
| /// |
| /// @return |
| /// The ValueObject if found. If valid, it has a valid ExpressionPath. |
| //------------------------------------------------------------------ |
| lldb::ValueObjectSP GuessValueForRegisterAndOffset(ConstString reg, |
| int64_t offset); |
| |
| //------------------------------------------------------------------ |
| // lldb::ExecutionContextScope pure virtual functions |
| //------------------------------------------------------------------ |
| lldb::TargetSP CalculateTarget() override; |
| |
| lldb::ProcessSP CalculateProcess() override; |
| |
| lldb::ThreadSP CalculateThread() override; |
| |
| lldb::StackFrameSP CalculateStackFrame() override; |
| |
| void CalculateExecutionContext(ExecutionContext &exe_ctx) override; |
| |
| protected: |
| friend class StackFrameList; |
| |
| void SetSymbolContextScope(SymbolContextScope *symbol_scope); |
| |
| void UpdateCurrentFrameFromPreviousFrame(StackFrame &prev_frame); |
| |
| void UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame); |
| |
| bool HasCachedData() const; |
| |
| private: |
| //------------------------------------------------------------------ |
| // For StackFrame only |
| //------------------------------------------------------------------ |
| lldb::ThreadWP m_thread_wp; |
| uint32_t m_frame_index; |
| uint32_t m_concrete_frame_index; |
| lldb::RegisterContextSP m_reg_context_sp; |
| StackID m_id; |
| Address m_frame_code_addr; // The frame code address (might not be the same as |
| // the actual PC for inlined frames) as a |
| // section/offset address |
| SymbolContext m_sc; |
| Flags m_flags; |
| Scalar m_frame_base; |
| Status m_frame_base_error; |
| bool m_cfa_is_valid; // Does this frame have a CFA? Different from CFA == |
| // LLDB_INVALID_ADDRESS |
| uint32_t m_stop_id; |
| bool m_stop_id_is_valid; // Does this frame have a stop_id? Use it when |
| // referring to the m_frame_code_addr. |
| bool m_is_history_frame; |
| lldb::VariableListSP m_variable_list_sp; |
| ValueObjectList m_variable_list_value_objects; // Value objects for each |
| // variable in |
| // m_variable_list_sp |
| StreamString m_disassembly; |
| std::recursive_mutex m_mutex; |
| |
| DISALLOW_COPY_AND_ASSIGN(StackFrame); |
| }; |
| |
| } // namespace lldb_private |
| |
| #endif // liblldb_StackFrame_h_ |