Summary:
- Reason of both bugs:
1. For the very first frame, Unwinder doesn't check the validity
of Full UnwindPlan before creating StackFrame from it:
When 'process launch' command is run after setting a breakpoint
in inferior, the Unwinder runs and saves only Frame 0 (the frame
in which breakpoint was set) in thread's StackFrameList i.e.
m_curr_frames_sp. However, it doesn't check the validity of the
Full UnwindPlan for this frame by unwinding 2 more frames further.
2. Unwinder doesn't update the CFA value of Cursor when Full UnwindPlan
fails and FallBack UnwindPlan succeeds in providing valid CFA values
for frames:
Sometimes during unwinding of stack frames, the Full UnwindPlan
inside the RegisterContextLLDB object may fail to provide valid
CFA values for these frames. Then the Fallback UnwindPlan is used
to unwind the frames.
If the Fallback UnwindPlan succeeds, then it provides a valid new
CFA value. The RegisterContextLLDB::m_cfa field of Cursor object
is updated during the Fallback UnwindPlan execution. However,
UnwindLLDB misses the implementation to update the 'cfa' field
of this Cursor with this valid new CFA value.
- This patch fixes both these issues.
- Remove XFAIL in test files corresponding to these 2 Bugs
Change-Id: I932ea407545ceee2d628f946ecc61a4806d4cc86
Signed-off-by: Abhishek Aggarwal <abhishek.a.aggarwal@intel.com>
Reviewers: jingham, lldb-commits, jasonmolenda
Subscribers: lldb-commits, ovyalov, tberghammer
Differential Revision: http://reviews.llvm.org/D14226
llvm-svn: 253026
166 lines
6.0 KiB
C++
166 lines
6.0 KiB
C++
//===-- UnwindLLDB.h --------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef lldb_UnwindLLDB_h_
|
|
#define lldb_UnwindLLDB_h_
|
|
|
|
// C Includes
|
|
// C++ Includes
|
|
#include <vector>
|
|
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/lldb-public.h"
|
|
#include "lldb/Core/ConstString.h"
|
|
#include "lldb/Symbol/FuncUnwinders.h"
|
|
#include "lldb/Symbol/UnwindPlan.h"
|
|
#include "lldb/Target/RegisterContext.h"
|
|
#include "lldb/Target/Unwind.h"
|
|
|
|
namespace lldb_private {
|
|
|
|
class RegisterContextLLDB;
|
|
|
|
class UnwindLLDB : public lldb_private::Unwind
|
|
{
|
|
public:
|
|
UnwindLLDB (lldb_private::Thread &thread);
|
|
|
|
~UnwindLLDB() override = default;
|
|
|
|
enum RegisterSearchResult
|
|
{
|
|
eRegisterFound = 0,
|
|
eRegisterNotFound,
|
|
eRegisterIsVolatile
|
|
};
|
|
|
|
protected:
|
|
friend class lldb_private::RegisterContextLLDB;
|
|
|
|
struct RegisterLocation {
|
|
enum RegisterLocationTypes
|
|
{
|
|
eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable
|
|
eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location)
|
|
eRegisterInRegister, // register is available in a (possible other) register (register_number)
|
|
eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space
|
|
eRegisterValueInferred, // register val was computed (and is in inferred_value)
|
|
eRegisterInLiveRegisterContext // register value is in a live (stack frame #0) register
|
|
};
|
|
int type;
|
|
union
|
|
{
|
|
lldb::addr_t target_memory_location;
|
|
uint32_t register_number; // in eRegisterKindLLDB register numbering system
|
|
void* host_memory_location;
|
|
uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset
|
|
} location;
|
|
};
|
|
|
|
void
|
|
DoClear() override
|
|
{
|
|
m_frames.clear();
|
|
m_candidate_frame.reset();
|
|
m_unwind_complete = false;
|
|
}
|
|
|
|
uint32_t
|
|
DoGetFrameCount() override;
|
|
|
|
bool
|
|
DoGetFrameInfoAtIndex(uint32_t frame_idx,
|
|
lldb::addr_t& cfa,
|
|
lldb::addr_t& start_pc) override;
|
|
|
|
lldb::RegisterContextSP
|
|
DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
|
|
|
|
typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP;
|
|
|
|
// Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame 1's RegisterContextLLDB)
|
|
// The RegisterContext for frame_num must already exist or this returns an empty shared pointer.
|
|
RegisterContextLLDBSP
|
|
GetRegisterContextForFrameNum (uint32_t frame_num);
|
|
|
|
// Iterate over the RegisterContextLLDB's in our m_frames vector, look for the first one that
|
|
// has a saved location for this reg.
|
|
bool
|
|
SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation ®loc, uint32_t starting_frame_num, bool pc_register);
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
/// Provide the list of user-specified trap handler functions
|
|
///
|
|
/// The Platform is one source of trap handler function names; that
|
|
/// may be augmented via a setting. The setting needs to be converted
|
|
/// into an array of ConstStrings before it can be used - we only want
|
|
/// to do that once per thread so it's here in the UnwindLLDB object.
|
|
///
|
|
/// @return
|
|
/// Vector of ConstStrings of trap handler function names. May be
|
|
/// empty.
|
|
//------------------------------------------------------------------
|
|
const std::vector<ConstString> &
|
|
GetUserSpecifiedTrapHandlerFunctionNames ()
|
|
{
|
|
return m_user_supplied_trap_handler_functions;
|
|
}
|
|
|
|
private:
|
|
struct Cursor
|
|
{
|
|
lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown
|
|
lldb::addr_t cfa; // The canonical frame address for this stack frame
|
|
lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation
|
|
RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextLLDB's
|
|
|
|
Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx_lldb_sp() { }
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN (Cursor);
|
|
};
|
|
|
|
typedef std::shared_ptr<Cursor> CursorSP;
|
|
std::vector<CursorSP> m_frames;
|
|
CursorSP m_candidate_frame;
|
|
bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the
|
|
// number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
|
|
// is how far we've currently gone.
|
|
|
|
std::vector<ConstString> m_user_supplied_trap_handler_functions;
|
|
|
|
//-----------------------------------------------------------------
|
|
// Check if Full UnwindPlan of First frame is valid or not.
|
|
// If not then try Fallback UnwindPlan of the frame. If Fallback
|
|
// UnwindPlan succeeds then update the Full UnwindPlan with the
|
|
// Fallback UnwindPlan.
|
|
//-----------------------------------------------------------------
|
|
void
|
|
UpdateUnwindPlanForFirstFrameIfInvalid (ABI* abi);
|
|
|
|
CursorSP
|
|
GetOneMoreFrame (ABI* abi);
|
|
|
|
bool
|
|
AddOneMoreFrame (ABI *abi);
|
|
|
|
bool
|
|
AddFirstFrame ();
|
|
|
|
//------------------------------------------------------------------
|
|
// For UnwindLLDB only
|
|
//------------------------------------------------------------------
|
|
DISALLOW_COPY_AND_ASSIGN (UnwindLLDB);
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // lldb_UnwindLLDB_h_
|