blob: ce9b16227672635b92a9772c1e86291edb70b372 [file] [log] [blame]
//===-- 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 &reg_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 &reg_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_