Index: lldb/include/lldb/Target/Thread.h =================================================================== --- lldb/include/lldb/Target/Thread.h +++ lldb/include/lldb/Target/Thread.h @@ -126,6 +126,7 @@ // bit of data. lldb::StopInfoSP stop_info_sp; // You have to restore the stop info or you // might continue with the wrong signals. + std::vector m_completed_plan_stack; lldb::RegisterCheckpointSP register_backup_sp; // You need to restore the registers, of course... uint32_t current_inlined_depth; Index: lldb/include/lldb/Target/ThreadPlan.h =================================================================== --- lldb/include/lldb/Target/ThreadPlan.h +++ lldb/include/lldb/Target/ThreadPlan.h @@ -40,9 +40,10 @@ // The thread maintaining a thread plan stack, and you program the actions of a // particular thread // by pushing plans onto the plan stack. -// There is always a "Current" plan, which is the head of the plan stack, +// There is always a "Current" plan, which is the top of the plan stack, // though in some cases -// a plan may defer to plans higher in the stack for some piece of information. +// a plan may defer to plans higher in the stack for some piece of information +// (let us define that the plan stack grows downwards). // // The plan stack is never empty, there is always a Base Plan which persists // through the life @@ -109,6 +110,15 @@ // plans in the time between when // your plan gets unshipped and the next resume. // +// Thread State Checkpoint: +// +// Note that calling functions on target process (ThreadPlanCallFunction) changes +// current thread state. The function can be called either by direct user demand or +// internally, for example lldb allocates memory on device to calculate breakpoint +// condition expression - on Linux it is performed by calling mmap on device. +// ThreadStateCheckpoint saves Thread state (stop info and completed +// plan stack) to restore it after completing function call. +// // Over the lifetime of the plan, various methods of the ThreadPlan are then // called in response to changes of state in // the process we are debugging as follows: @@ -149,7 +159,7 @@ // If the Current plan answers "true" then it is asked if the stop should // percolate all the way to the // user by calling the ShouldStop method. If the current plan doesn't explain -// the stop, then we query down +// the stop, then we query up // the plan stack for a plan that does explain the stop. The plan that does // explain the stop then needs to // figure out what to do about the plans below it in the stack. If the stop is @@ -241,9 +251,9 @@ // // When the process stops, the thread is given a StopReason, in the form of a // StopInfo object. If there is a completed -// plan corresponding to the stop, then the "actual" stop reason will be +// plan corresponding to the stop, then the "actual" stop reason can be // suppressed, and instead a StopInfoThreadPlan -// object will be cons'ed up from the highest completed plan in the stack. +// object will be cons'ed up from the top completed plan in the stack. // However, if the plan doesn't want to be // the stop reason, then it can call SetPlanComplete and pass in "false" for // the "success" parameter. In that case, Index: lldb/source/Target/Thread.cpp =================================================================== --- lldb/source/Target/Thread.cpp +++ lldb/source/Target/Thread.cpp @@ -540,7 +540,8 @@ if (process_sp) saved_state.orig_stop_id = process_sp->GetStopID(); saved_state.current_inlined_depth = GetCurrentInlinedDepth(); - + saved_state.m_completed_plan_stack = m_completed_plan_stack; + return true; } @@ -573,6 +574,7 @@ SetStopInfo(saved_state.stop_info_sp); GetStackFrameList()->SetCurrentInlinedDepth( saved_state.current_inlined_depth); + m_completed_plan_stack = saved_state.m_completed_plan_stack; return true; }