Modified the host process monitor callback function Host::StartMonitoringChildProcess

to spawn a thread for each process that is being monitored. Previously
LLDB would spawn a single thread that would wait for any child process which
isn't ok to do as a shared library (LLDB.framework on Mac OSX, or lldb.so on
linux). The old single thread used to call wait4() with a pid of -1 which 
could cause it to reap child processes that it shouldn't have.

Re-wrote the way Function blocks are handles. Previously I attempted to keep
all blocks in a single memory allocation (in a std::vector). This made the
code somewhat efficient, but hard to work with. I got rid of the old BlockList
class, and went to a straight parent with children relationship. This new 
approach will allow for partial parsing of the blocks within a function.

llvm-svn: 111706
This commit is contained in:
Greg Clayton 2010-08-21 02:22:51 +00:00
parent a94e3d1124
commit 0b76a2c21f
18 changed files with 353 additions and 1156 deletions

View File

@ -66,33 +66,17 @@ public:
/// get called if the child process exits.
///
/// @return
/// A unique handle to the process monitoring information that
/// can be used to stop monitoring a child process.
/// A thread handle that can be used to cancel the thread that
/// was spawned to monitor \a pid.
///
/// @see static void Host::StopMonitoringChildProcess (uint32_t)
//------------------------------------------------------------------
static uint32_t
static lldb::thread_t
StartMonitoringChildProcess (MonitorChildProcessCallback callback,
void *callback_baton,
lldb::pid_t pid,
bool monitor_signals);
//------------------------------------------------------------------
/// Stop monitoring a child process.
///
/// @param[in] handle
/// A unique handle returned from a previous call to
/// Host::StartMonitoringChildProcess(...).
///
/// @return
/// \b true if the the handle was found and disabled, \b false
/// if the monitor map with handle of \a handle was not found.
///
/// @see static int Host::StartMonitoringChildProcess (MonitorChildProcessCallback *, void *, lldb::pid_t, bool)
//------------------------------------------------------------------
static bool
StopMonitoringChildProcess (uint32_t handle);
//------------------------------------------------------------------
/// Get the host page size.
///

View File

@ -43,17 +43,6 @@ class Block :
public SymbolContextScope
{
public:
friend class Function;
friend class BlockList;
//------------------------------------------------------------------
/// Enumeration values for special and invalid Block User ID
/// values.
//------------------------------------------------------------------
enum
{
RootID = LLDB_INVALID_UID - 1, ///< The Block UID for the root block
InvalidID = LLDB_INVALID_UID ///< Invalid Block UID.
};
//------------------------------------------------------------------
/// Construct with a User ID \a uid, \a depth.
@ -79,55 +68,22 @@ public:
///
/// @see BlockList
//------------------------------------------------------------------
Block (lldb::user_id_t uid, uint32_t depth, BlockList* block_list);
//------------------------------------------------------------------
/// Copy constructor.
///
/// Makes a copy of the another Block object \a rhs.
///
/// @param[in] rhs
/// A const Block object reference to copy.
//------------------------------------------------------------------
Block (const Block& rhs);
Block (lldb::user_id_t uid);
//------------------------------------------------------------------
/// Destructor.
//------------------------------------------------------------------
~Block ();
//------------------------------------------------------------------
/// Assignment operator.
///
/// Copies the block value from another Block object \a rhs
/// into \a this object.
///
/// @param[in] rhs
/// A const Block object reference to copy.
///
/// @return
/// A const Block object reference to \a this.
//------------------------------------------------------------------
const Block&
operator= (const Block& rhs);
//------------------------------------------------------------------
/// Add a child to this object.
///
/// @param[in] uid
/// The UID for a given block. This value is given by the
/// SymbolFile plug-in and can be any value that helps the
/// SymbolFile plug-in to match this block back to the debug
/// information data that it parses for further or more in
/// depth parsing. Common values would be the index into a
/// table, or an offset into the debug information.
///
/// @return
/// Returns \a uid if the child was successfully added to this
/// block, or Block::InvalidID on failure.
/// @param[in] child_block_sp
/// A shared pointer to a child block that will get added to
/// this block.
//------------------------------------------------------------------
lldb::user_id_t
AddChild (lldb::user_id_t uid);
void
AddChild (const lldb::BlockSP &child_block_sp);
//------------------------------------------------------------------
/// Add a new offset range to this block.
@ -177,9 +133,6 @@ public:
bool
Contains (const VMRange& range) const;
bool
ContainsBlockWithID (lldb::user_id_t block_id) const;
//------------------------------------------------------------------
/// Dump the block contents.
///
@ -215,40 +168,10 @@ public:
void
GetDescription (Stream *s,
Function *function,
lldb::DescriptionLevel level,
Process *process) const;
//------------------------------------------------------------------
/// Get the parent block's UID.
///
/// @return
/// The UID of the parent block, or Block::InvalidID
/// if this block has no parent.
//------------------------------------------------------------------
lldb::user_id_t
GetParentUID () const;
//------------------------------------------------------------------
/// Get the sibling block's UID.
///
/// @return
/// The UID of the sibling block, or Block::InvalidID
/// if this block has no sibling.
//------------------------------------------------------------------
lldb::user_id_t
GetSiblingUID () const;
//------------------------------------------------------------------
/// Get the first child block's UID.
///
/// @return
/// The UID of the first child block, or Block::InvalidID
/// if this block has no first child.
//------------------------------------------------------------------
lldb::user_id_t
GetFirstChildUID () const;
//------------------------------------------------------------------
/// Get the parent block.
///
@ -260,14 +183,17 @@ public:
GetParent () const;
//------------------------------------------------------------------
/// Get the sibling block.
/// Get the sibling block for this block.
///
/// @return
/// The sibling block pointer, or NULL if this block has no
/// sibling.
//------------------------------------------------------------------
Block *
GetSibling () const;
GetSibling () const
{
return m_sibling;
}
//------------------------------------------------------------------
/// Get the first child block.
@ -387,6 +313,19 @@ public:
const Declaration *decl_ptr,
const Declaration *call_decl_ptr);
void
SetParentScope (SymbolContextScope *parent_scope)
{
m_parent_scope = parent_scope;
}
void
SetSibling (Block *block)
{
m_sibling = block;
}
//------------------------------------------------------------------
/// Set accessor for the variable list.
///
@ -400,358 +339,39 @@ public:
void
SetVariableList (lldb::VariableListSP& variable_list_sp);
protected:
//------------------------------------------------------------------
/// Get accessor for the integer block depth value.
///
/// @return
/// The integer depth of this block in the block hiearchy.
//------------------------------------------------------------------
uint32_t Depth () const;
bool
BlockInfoHasBeenParsed() const
{
return m_parsed_block_info;
}
void
SetBlockInfoHasBeenParsed (bool b, bool set_children);
Block *
FindBlockByID (lldb::user_id_t block_id);
protected:
typedef std::vector<lldb::BlockSP> collection;
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------
BlockList *m_block_list; ///< The block list, one of which is this one
uint32_t m_depth; ///< The depth of this block where zero is the root block
SymbolContextScope *m_parent_scope;
Block *m_sibling;
collection m_children;
VMRange::collection m_ranges; ///< A list of address offset ranges relative to the function's section/offset address.
lldb::InlineFunctionInfoSP m_inlineInfoSP; ///< Inlined function information.
lldb::VariableListSP m_variables; ///< The variable list for all local, static and paramter variables scoped to this block.
// TOOD: add a Type* list
};
//----------------------------------------------------------------------
/// @class BlockList Block.h "lldb/Symbol/Block.h"
/// @brief A class that contains a heirachical collection of lexical
/// block objects where one block is the root.
///
/// A collection of Block objects is managed by this class. All access
/// to the block data is made through the block_uid of each block. This
/// facilitates partial parsing and can enable block specific data to
/// only be parsed when the data is asked for (variables, params, types,
/// etc).
//----------------------------------------------------------------------
class BlockList
{
public:
friend class Block;
typedef std::vector<Block> collection;///< Our block collection type.
//------------------------------------------------------------------
/// Construct with \a function and section offset based address
/// range.
///
/// @param[in] function
/// A const Function object that owns this block list.
///
/// @param[in] range
/// A section offset based address range object.
//------------------------------------------------------------------
BlockList (Function *function, const AddressRange& range);
//------------------------------------------------------------------
/// Destructor.
//------------------------------------------------------------------
~BlockList ();
//------------------------------------------------------------------
/// Add a child block to a parent block.
///
/// Adds a new child to a parent block. The UID values for
/// blocks are created by the SymbolFile plug-ins and should have
/// values that facilitate correlating an existing Block object
/// with information in the debug information file. Typically
/// a table index, or a debug information offset is used.
///
/// @param[in] parent_uid
/// The UID for a the existing parent block that will have
/// a new child, whose UID is \a child_uid, added to its
/// child list.
///
/// @param[in] child_uid
/// The UID for the new child block.
///
/// @return
/// Returns \a child_uid if the child was successfully added
/// to the parent \a parent_uid, or Block::InvalidID on
/// failure (if the parent doesn't exist).
//------------------------------------------------------------------
lldb::user_id_t
AddChild (lldb::user_id_t parent_uid, lldb::user_id_t child_uid);
//------------------------------------------------------------------
/// Add a child block to a parent block.
///
/// Adds a new child to a parent block. The UID values for
/// blocks are created by the SymbolFile plug-ins and should have
/// values that facilitate correlating an existing Block object
/// with information in the debug information file. Typically
/// a table index, or a debug information offset is used.
///
/// @param[in] block_uid
/// The UID for a the existing block that will get the
/// new range.
///
/// @param[in] start_offset
/// An offset into this object's address range that
/// describes the start address of a range for \a block_uid.
///
/// @param[in] end_offset
/// An offset into this object's address range that
/// describes the end address of a range for for \a block_uid.
///
/// @return
/// Returns \b true if the range was successfully added to
/// the block whose UID is \a block_uid, \b false otherwise.
//------------------------------------------------------------------
bool
AddRange (lldb::user_id_t block_uid, lldb::addr_t start_offset, lldb::addr_t end_offset);
// const Block *
// FindDeepestBlockForAddress (const Address &addr);
//------------------------------------------------------------------
/// Get accessor for the section offset based address range.
///
/// All Block objects contained in a BlockList are relative to
/// the base address in this object.
///
/// @return
/// Returns a reference to the section offset based address
/// range object.
//------------------------------------------------------------------
AddressRange &
GetAddressRange ();
//------------------------------------------------------------------
/// Get const accessor for the section offset based address range.
///
/// All Block objects contained in a BlockList are relative to
/// the base address in this object.
///
/// @return
/// Returns a const reference to the section offset based
/// address range object.
//------------------------------------------------------------------
const AddressRange &
GetAddressRange () const;
//------------------------------------------------------------------
/// Dump the block list contents.
///
/// @param[in] s
/// The stream to which to dump the object descripton.
///
/// @param[in] block_uid
/// The UID of the block in the block list to dump. If this
/// value is Block::RootID, then the entire block list will
/// dumped as long as \a depth is set to a large enough value.
///
/// @param[in] depth
/// Limit the number of levels deep that this function should
/// print as the block whose UID is \a block_uid can contain
/// child blocks. Specify INT_MAX to dump all child blocks.
///
/// @param[in] show_context
/// If \b true, variables will dump their context information.
//------------------------------------------------------------------
void
Dump (Stream *s, lldb::user_id_t block_uid, uint32_t depth, bool show_context) const;
//------------------------------------------------------------------
/// Get a block object pointer by block UID.
///
/// @param[in] block_uid
/// The UID of the block to retrieve.
///
/// @return
/// A pointer to the block object, or NULL if \a block_uid
/// doesn't exist in the block list.
//------------------------------------------------------------------
Block *
GetBlockByID (lldb::user_id_t block_uid);
//------------------------------------------------------------------
/// Get a const block object pointer by block UID.
///
/// @param[in] block_uid
/// The UID of the block to retrieve.
///
/// @return
/// A const pointer to the block object, or NULL if \a block_uid
/// doesn't exist in the block list.
//------------------------------------------------------------------
const Block *
GetBlockByID (lldb::user_id_t block_uid) const;
//------------------------------------------------------------------
/// Get a function object pointer for the block list.
///
/// @return
/// A pointer to the function object.
//------------------------------------------------------------------
Function *
GetFunction ();
//------------------------------------------------------------------
/// Get a const function object pointer for the block list.
///
/// @return
/// A const pointer to the function object.
//------------------------------------------------------------------
const Function *
GetFunction () const;
//------------------------------------------------------------------
/// Get the first child block UID for the block whose UID is \a
/// block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to access information for.
///
/// @return
/// The UID of the first child block, or Block::InvalidID
/// if this block has no children, or if \a block_uid is not
/// a valid block ID for this block list.
//------------------------------------------------------------------
lldb::user_id_t
GetFirstChild (lldb::user_id_t block_uid) const;
//------------------------------------------------------------------
/// Get the parent block UID for the block whose UID is \a
/// block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to access information for.
///
/// @return
/// The UID of the parent block, or Block::InvalidID
/// if this block has no parent, or if \a block_uid is not
/// a valid block ID for this block list.
//------------------------------------------------------------------
lldb::user_id_t
GetParent (lldb::user_id_t block_uid) const;
//------------------------------------------------------------------
/// Get the sibling block UID for the block whose UID is \a
/// block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to access information for.
///
/// @return
/// The UID of the sibling block, or Block::InvalidID
/// if this block has no sibling, or if \a block_uid is not
/// a valid block ID for this block list.
//------------------------------------------------------------------
lldb::user_id_t
GetSibling (lldb::user_id_t block_uid) const;
//------------------------------------------------------------------
/// Get the variable list for the block whose UID is \a block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to access information for.
///
/// @param[in] can_create
/// If \b true, the variable list can be parsed on demand. If
/// \b false, the variable list contained in this object will
/// be returned.
///
/// @return
/// The variable list shared pointer which may contain a NULL
/// variable list object.
//------------------------------------------------------------------
lldb::VariableListSP
GetVariableList (lldb::user_id_t block_uid, bool get_child_variables, bool can_create);
//------------------------------------------------------------------
/// Check if the block list is empty.
///
/// @return
/// Returns \b true if the block list is empty, \b false
/// otherwise.
//------------------------------------------------------------------
bool
IsEmpty () const;
//------------------------------------------------------------------
/// Get the memory cost of this object.
///
/// Returns the cost of this object plus any owned objects (address
/// range, and contains Block objects).
///
/// @return
/// The number of bytes that this object occupies in memory.
//------------------------------------------------------------------
size_t
MemorySize () const;
//------------------------------------------------------------------
/// Set the variable list for the block whose UID is \a block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to set information for.
///
/// @param[in] variable_list_sp
/// A shared pointer to list of variables.
///
/// @return
/// Returns \b true if the variable list was successfully added
/// to the block, \b false otherwise.
//------------------------------------------------------------------
bool
SetVariableList (lldb::user_id_t block_uid, lldb::VariableListSP& variable_list_sp);
//------------------------------------------------------------------
/// Set the inlined function info for the block whose UID is \a
/// block_uid.
///
/// @param[in] block_uid
/// The UID of the block we wish to set information for.
///
/// @param[in] name
/// The method name for the inlined function. This value should
/// not be NULL.
///
/// @param[in] mangled
/// The mangled method name for the inlined function. This can
/// be NULL if there is no mangled name for an inlined function
/// or if the name is the same as \a name.
///
/// @param[in] decl_ptr
/// A optional pointer to declaration information for the
/// inlined function information. This value can be NULL to
/// indicate that no declaration information is available.
///
/// @param[in] call_decl_ptr
/// Optional calling location declaration information that
/// describes from where this inlined function was called.
///
/// @return
/// Returns \b true if the inline function info was successfully
/// associated with the block, \b false otherwise.
//------------------------------------------------------------------
bool
SetInlinedFunctionInfo (lldb::user_id_t block_uid, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr);
protected:
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------
Function *m_function; ///< A pointer to the function that owns this block list.
AddressRange m_range; ///< The section offset based address range.
collection m_blocks; ///< A contiguous array of block objects.
bool
BlockContainsBlockWithID (const lldb::user_id_t block_id, const lldb::user_id_t find_block_id) const;
bool m_parsed_block_info:1, ///< Set to true if this block and it's children have all been parsed
m_parsed_block_variables:1,
m_parsed_child_blocks:1;
private:
DISALLOW_COPY_AND_ASSIGN (BlockList);
DISALLOW_COPY_AND_ASSIGN (Block);
};
} // namespace lldb_private
#endif // liblldb_Block_h_

View File

@ -419,8 +419,11 @@ public:
CalculateSymbolContext(SymbolContext* sc);
const AddressRange &
GetAddressRange();
GetAddressRange()
{
return m_range;
}
//------------------------------------------------------------------
/// Find the file and line number of the source location of the start
/// of the function. This will use the declaration if present and fall
@ -450,15 +453,6 @@ public:
void
GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no);
//------------------------------------------------------------------
/// Return whether this Function represents an inlined version of the
/// original function.
///
/// @return
/// \b true if inlined, \b false otherwise.
//------------------------------------------------------------------
bool IsInlined();
//------------------------------------------------------------------
/// Get accessor for the block list.
///
@ -468,8 +462,8 @@ public:
///
/// @see BlockList
//------------------------------------------------------------------
BlockList&
GetBlocks (bool can_create);
Block&
GetBlock (bool can_create);
//------------------------------------------------------------------
/// Get accessor for the compile unit that owns this function.
@ -611,14 +605,15 @@ protected:
//------------------------------------------------------------------
// Member variables.
//------------------------------------------------------------------
CompileUnit *m_comp_unit; ///< The compile unit that owns this function.
CompileUnit *m_comp_unit; ///< The compile unit that owns this function.
lldb::user_id_t m_type_uid; ///< The user ID of for the prototype Type for this function.
Type * m_type; ///< The function prototype type for this function that include the function info (FunctionInfo), return type and parameters.
Mangled m_mangled; ///< The mangled function name if any, if empty, there is no mangled information.
BlockList m_blocks; ///< All lexical blocks contained in this function.
Type * m_type; ///< The function prototype type for this function that include the function info (FunctionInfo), return type and parameters.
Mangled m_mangled; ///< The mangled function name if any, if empty, there is no mangled information.
Block m_block; ///< All lexical blocks contained in this function.
AddressRange m_range; ///< The function address range that covers the widest range needed to contain all blocks
DWARFExpression m_frame_base; ///< The frame base expression for variables that are relative to the frame pointer.
Flags m_flags;
uint32_t m_prologue_byte_size; ///< Compute the prologue size once and cache it
uint32_t m_prologue_byte_size; ///< Compute the prologue size once and cache it
private:
DISALLOW_COPY_AND_ASSIGN(Function);
};

View File

@ -25,7 +25,6 @@ class ArchSpec;
class Args;
class Baton;
class Block;
class BlockList;
class Breakpoint;
class BreakpointID;
class BreakpointIDList;

View File

@ -2791,6 +2791,7 @@
);
LLVM_BUILD_DIR = "$(SRCROOT)/llvm";
LLVM_CONFIGURATION = Release;
ONLY_ACTIVE_ARCH = NO;
OTHER_CFLAGS = (
"-DFOR_DYLD=0",
"-DSUPPORT_REMOTE_UNWINDING",

View File

@ -626,28 +626,21 @@ ClangExpressionDeclMap::FindVariableInScope(const SymbolContext &sym_ctx,
{
Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
Function *function(m_sym_ctx->function);
Block *block(m_sym_ctx->block);
if (!function || !block)
if (m_sym_ctx->function == NULL || m_sym_ctx->block == NULL)
{
if (log)
log->Printf("function = %p, block = %p", function, block);
log->Printf("function = %p, block = %p", m_sym_ctx->function, m_sym_ctx->block);
return NULL;
}
BlockList& blocks(function->GetBlocks(true));
ConstString name_cs(name);
lldb::user_id_t current_block_id;
Block *current_block;
for (current_block_id = block->GetID();
current_block_id != Block::InvalidID;
current_block_id = blocks.GetParent(current_block_id))
{
Block *current_block(blocks.GetBlockByID(current_block_id));
for (current_block = m_sym_ctx->block;
current_block != NULL;
current_block = current_block->GetParent())
{
lldb::VariableListSP var_list = current_block->GetVariableList(false, true);
if (!var_list)

View File

@ -508,102 +508,48 @@ Host::ResolveExecutableInBundle (FileSpec *file)
struct MonitorInfo
{
uint32_t handle;
pthread_t thread;
Host::MonitorChildProcessCallback callback;
void *callback_baton;
bool monitor_signals;
lldb::pid_t pid; // The process ID to monitor
Host::MonitorChildProcessCallback callback; // The callback function to call when "pid" exits or signals
void *callback_baton; // The callback baton for the callback function
bool monitor_signals; // If true, call the callback when "pid" gets signaled.
};
typedef std::multimap<lldb::pid_t, MonitorInfo> MonitorInfoMap;
static pthread_mutex_t g_monitor_map_mutex = PTHREAD_MUTEX_INITIALIZER;
typedef lldb::SharedPtr<MonitorInfoMap>::Type MonitorInfoMapSP;
static MonitorInfoMapSP&
GetMonitorMap (bool can_create)
{
static MonitorInfoMapSP g_monitor_map_sp;
if (can_create && g_monitor_map_sp.get() == NULL)
{
g_monitor_map_sp.reset (new MonitorInfoMap);
}
return g_monitor_map_sp;
}
static Predicate<bool>&
GetChildProcessPredicate ()
{
static Predicate<bool> g_has_child_processes;
return g_has_child_processes;
}
static void *
MonitorChildProcessThreadFunction (void *arg);
static pthread_t g_monitor_thread;
uint32_t
lldb::thread_t
Host::StartMonitoringChildProcess
(
MonitorChildProcessCallback callback,
Host::MonitorChildProcessCallback callback,
void *callback_baton,
lldb::pid_t pid,
bool monitor_signals
)
{
static uint32_t g_handle = 0;
lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
if (callback)
{
Mutex::Locker locker(&g_monitor_map_mutex);
if (!g_monitor_thread)
{
lldb::pid_t wait_pid = -1;
g_monitor_thread = ThreadCreate ("<lldb.host.wait4>",
MonitorChildProcessThreadFunction,
&wait_pid,
NULL);
if (g_monitor_thread)
{
//Host::ThreadDetach (g_monitor_thread, NULL);
}
}
if (g_monitor_thread)
{
MonitorInfo info = { ++g_handle, 0, callback, callback_baton, monitor_signals };
MonitorInfoMapSP monitor_map_sp (GetMonitorMap (true));
if (monitor_map_sp)
{
monitor_map_sp->insert(std::make_pair(pid, info));
GetChildProcessPredicate ().SetValue (true, eBroadcastOnChange);
return info.handle;
}
}
std::auto_ptr<MonitorInfo> info_ap(new MonitorInfo);
info_ap->pid = pid;
info_ap->callback = callback;
info_ap->callback_baton = callback_baton;
info_ap->monitor_signals = monitor_signals;
char thread_name[256];
::snprintf (thread_name, sizeof(thread_name), "<lldb.host.wait4(pid=%i)>", pid);
thread = ThreadCreate (thread_name,
MonitorChildProcessThreadFunction,
info_ap.get(),
NULL);
if (thread != LLDB_INVALID_HOST_THREAD)
info_ap.release();
}
return 0;
return thread;
}
bool
Host::StopMonitoringChildProcess (uint32_t handle)
{
Mutex::Locker locker(&g_monitor_map_mutex);
MonitorInfoMapSP monitor_map_sp (GetMonitorMap (false));
if (monitor_map_sp)
{
MonitorInfoMap::iterator pos, end = monitor_map_sp->end();
for (pos = monitor_map_sp->end(); pos != end; ++pos)
{
if (pos->second.handle == handle)
{
monitor_map_sp->erase(pos);
return true;
}
}
}
return false;
}
//------------------------------------------------------------------
// Scoped class that will disable thread canceling when it is
// constructed, and exception safely restore the previous value it
@ -643,64 +589,37 @@ MonitorChildProcessThreadFunction (void *arg)
if (log)
log->Printf ("%s (arg = %p) thread starting...", function, arg);
const lldb::pid_t wait_pid = -1;//*((pid_t*)arg);
MonitorInfo *info = (MonitorInfo *)arg;
const Host::MonitorChildProcessCallback callback = info->callback;
void * const callback_baton = info->callback_baton;
const lldb::pid_t pid = info->pid;
const bool monitor_signals = info->monitor_signals;
delete info;
int status = -1;
const int options = 0;
struct rusage *rusage = NULL;
while (1)
{
if (log)
log->Printf("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p)...", function, wait_pid, options, rusage);
log->Printf("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p)...", function, pid, options, rusage);
// Wait for all child processes
::pthread_testcancel ();
lldb::pid_t pid = ::wait4 (wait_pid, &status, options, rusage);
const lldb::pid_t wait_pid = ::wait4 (pid, &status, options, rusage);
::pthread_testcancel ();
if (pid < 0)
if (wait_pid == -1)
{
// No child processes to watch wait for the mutex to be cleared
// Scope for "locker"
{
ScopedPThreadCancelDisabler pthread_cancel_disabler;
// First clear out all monitor entries since we have no processes
// to watch.
Mutex::Locker locker(&g_monitor_map_mutex);
// Since we don't have any child processes, we can safely clear
// anyone with a valid pid.
MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
if (monitor_map_sp)
{
MonitorInfoMap::iterator pos = monitor_map_sp->begin();
while (pos != monitor_map_sp->end())
{
// pid value of 0 and -1 are special (see man page on wait4...)
if (pos->first > 0)
{
MonitorInfoMap::iterator next_pos = pos; ++next_pos;
monitor_map_sp->erase (pos, next_pos);
pos = next_pos;
}
else
++pos;
}
}
}
if (log)
log->Printf("%s no child processes, wait for some...", function);
GetChildProcessPredicate ().SetValue (false, eBroadcastNever);
::pthread_testcancel();
GetChildProcessPredicate ().WaitForValueEqualTo (true);
if (log)
log->Printf("%s resuming monitoring of child processes.", function);
if (errno == EINTR)
continue;
else
break;
}
else
else if (wait_pid == pid)
{
ScopedPThreadCancelDisabler pthread_cancel_disabler;
bool exited = false;
int signal = 0;
int exit_status = 0;
@ -728,80 +647,47 @@ MonitorChildProcessThreadFunction (void *arg)
status_cstr = "(???)";
}
if (log)
log->Printf ("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_state = %i",
function,
wait_pid,
options,
rusage,
pid,
status,
status_cstr,
signal,
exit_status);
// Scope for mutex locker
// Scope for pthread_cancel_disabler
{
// Notify anyone listening to this process
Mutex::Locker locker(&g_monitor_map_mutex);
MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
if (monitor_map_sp)
ScopedPThreadCancelDisabler pthread_cancel_disabler;
if (log)
log->Printf ("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_state = %i",
function,
wait_pid,
options,
rusage,
pid,
status,
status_cstr,
signal,
exit_status);
if (exited || (signal != 0 && monitor_signals))
{
std::pair<MonitorInfoMap::iterator, MonitorInfoMap::iterator> range;
range = monitor_map_sp->equal_range(pid);
MonitorInfoMap::iterator pos;
for (pos = range.first; pos != range.second; ++pos)
{
if (exited || (signal != 0 && pos->second.monitor_signals))
{
bool callback_return = pos->second.callback (pos->second.callback_baton, pid, signal, exit_status);
if (exited || callback_return)
{
// Make this entry as needing to be removed by
// setting its handle to zero
pos->second.handle = 0;
}
}
}
// Remove any entries that requested to be removed or any
// entries for child processes that did exit. We know this
// because we changed the handles to an invalid value.
pos = monitor_map_sp->begin();
while (pos != monitor_map_sp->end())
{
if (pos->second.handle == 0)
{
MonitorInfoMap::iterator next_pos = pos; ++next_pos;
monitor_map_sp->erase (pos, next_pos);
pos = next_pos;
}
else
++pos;
}
bool callback_return = callback (callback_baton, pid, signal, exit_status);
// If our process exited, then this thread should exit
if (exited)
break;
// If the callback returns true, it means this process should
// exit
if (callback_return)
break;
}
}
}
}
if (log)
log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
log->Printf ("%s (arg = %p) thread exiting...", __FUNCTION__, arg);
g_monitor_thread = NULL;
return NULL;
}
void
Host::WillTerminate ()
{
if (g_monitor_thread != NULL)
{
ThreadCancel (g_monitor_thread, NULL);
GetChildProcessPredicate ().SetValue (true, eBroadcastAlways);
ThreadJoin(g_monitor_thread, NULL, NULL);
g_monitor_thread = NULL;
}
}
uint32_t

View File

@ -226,6 +226,7 @@ ProcessMacOSX::ProcessMacOSX(Target& target, Listener &listener) :
m_task (this),
m_flags (eFlagsNone),
m_stdio_thread (LLDB_INVALID_HOST_THREAD),
m_monitor_thread (LLDB_INVALID_HOST_THREAD),
m_stdio_mutex (Mutex::eMutexTypeRecursive),
m_stdout_data (),
m_exception_messages (),
@ -244,6 +245,7 @@ ProcessMacOSX::~ProcessMacOSX()
{
// m_mach_process.UnregisterNotificationCallbacks (this);
Clear();
}
//----------------------------------------------------------------------
@ -450,7 +452,7 @@ ProcessMacOSX::DidLaunchOrAttach ()
// Install a signal handler so we can catch when our child process
// dies and set the exit status correctly.
Host::StartMonitoringChildProcess (Process::SetProcessExitStatus, NULL, GetID(), false);
m_monitor_thread = Host::StartMonitoringChildProcess (Process::SetProcessExitStatus, NULL, GetID(), false);
if (m_arch_spec == ArchSpec("arm"))
{
@ -1156,6 +1158,14 @@ ProcessMacOSX::Clear()
m_exception_messages.clear();
}
if (m_monitor_thread != LLDB_INVALID_HOST_THREAD)
{
Host::ThreadCancel (m_monitor_thread, NULL);
thread_result_t thread_result;
Host::ThreadJoin (m_monitor_thread, &thread_result, NULL);
m_monitor_thread = LLDB_INVALID_HOST_THREAD;
}
}
bool

View File

@ -239,6 +239,7 @@ protected:
MachTask m_task; // The mach task for this process
lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
lldb::thread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
lldb::thread_t m_monitor_thread; // Thread ID for the thread that watches for child process stdio
lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
std::string m_stdout_data;
MachException::Message::collection m_exception_messages; // A collection of exception messages caught when listening to the exception port

View File

@ -110,7 +110,7 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
m_byte_order (eByteOrderHost),
m_gdb_comm(),
m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
m_debugserver_monitor (0),
m_debugserver_thread (LLDB_INVALID_HOST_THREAD),
m_last_stop_packet (),
m_register_info (),
m_async_broadcaster ("lldb.process.gdb-remote.async-broadcaster"),
@ -134,6 +134,13 @@ ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
//----------------------------------------------------------------------
ProcessGDBRemote::~ProcessGDBRemote()
{
if (m_debugserver_thread != LLDB_INVALID_HOST_THREAD)
{
Host::ThreadCancel (m_debugserver_thread, NULL);
thread_result_t thread_result;
Host::ThreadJoin (m_debugserver_thread, &thread_result, NULL);
m_debugserver_thread = LLDB_INVALID_HOST_THREAD;
}
// m_mach_process.UnregisterNotificationCallbacks (this);
Clear();
}
@ -535,11 +542,11 @@ ProcessGDBRemote::ConnectToDebugserver (const char *host_port)
m_gdb_comm.SendAck('+');
if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
m_debugserver_monitor = Host::StartMonitoringChildProcess (MonitorDebugserverProcess,
(void*)(intptr_t)GetID(), // Pass the inferior pid in the thread argument (which is a void *)
m_debugserver_pid,
false);
m_debugserver_thread = Host::StartMonitoringChildProcess (MonitorDebugserverProcess,
this,
m_debugserver_pid,
false);
StringExtractorGDBRemote response;
if (m_gdb_comm.SendPacketAndWaitForResponse("QStartNoAckMode", response, 1, false))
{
@ -1907,47 +1914,42 @@ ProcessGDBRemote::MonitorDebugserverProcess
// "debugserver_pid" argument passed in is the process ID for
// debugserver that we are tracking...
lldb::pid_t gdb_remote_pid = (lldb::pid_t)(intptr_t)callback_baton;
TargetSP target_sp(Debugger::FindTargetWithProcessID (gdb_remote_pid));
if (target_sp)
ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton;
if (process)
{
ProcessSP process_sp (target_sp->GetProcessSP());
if (process_sp)
// Sleep for a half a second to make sure our inferior process has
// time to set its exit status before we set it incorrectly when
// both the debugserver and the inferior process shut down.
usleep (500000);
// If our process hasn't yet exited, debugserver might have died.
// If the process did exit, the we are reaping it.
if (process->GetState() != eStateExited)
{
// Sleep for a half a second to make sure our inferior process has
// time to set its exit status before we set it incorrectly when
// both the debugserver and the inferior process shut down.
usleep (500000);
// If our process hasn't yet exited, debugserver might have died.
// If the process did exit, the we are reaping it.
if (process_sp->GetState() != eStateExited)
char error_str[1024];
if (signo)
{
char error_str[1024];
if (signo)
{
const char *signal_cstr = process_sp->GetUnixSignals().GetSignalAsCString (signo);
if (signal_cstr)
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
else
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
}
const char *signal_cstr = process->GetUnixSignals().GetSignalAsCString (signo);
if (signal_cstr)
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
else
{
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
}
process_sp->SetExitStatus (-1, error_str);
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
}
else
{
ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)process_sp.get();
// Debugserver has exited we need to let our ProcessGDBRemote
// know that it no longer has a debugserver instance
gdb_process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
// We are returning true to this function below, so we can
// forget about the monitor handle.
gdb_process->m_debugserver_monitor = 0;
::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
}
process->SetExitStatus (-1, error_str);
}
else
{
// Debugserver has exited we need to let our ProcessGDBRemote
// know that it no longer has a debugserver instance
process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
// We are returning true to this function below, so we can
// forget about the monitor handle.
process->m_debugserver_thread = LLDB_INVALID_HOST_THREAD;
}
}
return true;

View File

@ -324,7 +324,7 @@ protected:
lldb::ByteOrder m_byte_order;
GDBRemoteCommunication m_gdb_comm;
lldb::pid_t m_debugserver_pid;
uint32_t m_debugserver_monitor;
lldb::thread_t m_debugserver_thread;
StringExtractor m_last_stop_packet;
GDBRemoteDynamicRegisterInfo m_register_info;
lldb_private::Broadcaster m_async_broadcaster;

View File

@ -785,8 +785,7 @@ SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx)
static void
AddRangesToBlock
(
BlockList& blocks,
lldb::user_id_t blockID,
Block& block,
DWARFDebugRanges::RangeList& ranges,
addr_t block_base_addr
)
@ -796,7 +795,7 @@ AddRangesToBlock
const DWARFDebugRanges::Range *debug_range;
for (range_idx = 0; (debug_range = ranges.RangeAtIndex(range_idx)) != NULL; range_idx++)
{
blocks.AddRange(blockID, debug_range->begin_offset, debug_range->end_offset);
block.AddRange(debug_range->begin_offset, debug_range->end_offset);
}
}
@ -1129,7 +1128,7 @@ size_t
SymbolFileDWARF::ParseFunctionBlocks
(
const SymbolContext& sc,
lldb::user_id_t parentBlockID,
Block *parent_block,
const DWARFCompileUnit* dwarf_cu,
const DWARFDebugInfoEntry *die,
addr_t subprogram_low_pc,
@ -1151,18 +1150,31 @@ SymbolFileDWARF::ParseFunctionBlocks
DWARFDebugRanges::RangeList ranges;
const char *name = NULL;
const char *mangled_name = NULL;
BlockList& blocks = sc.function->GetBlocks(false);
Block *block = NULL;
if (tag != DW_TAG_subprogram)
{
BlockSP block_sp(new Block (die->GetOffset()));
parent_block->AddChild(block_sp);
block = block_sp.get();
}
else
{
block = parent_block;
}
lldb::user_id_t blockID = blocks.AddChild(parentBlockID, die->GetOffset());
int decl_file = 0;
int decl_line = 0;
int decl_column = 0;
int call_file = 0;
int call_line = 0;
int call_column = 0;
if (die->GetDIENamesAndRanges(this, dwarf_cu, name, mangled_name, ranges,
decl_file, decl_line, decl_column,
call_file, call_line, call_column))
if (die->GetDIENamesAndRanges (this,
dwarf_cu,
name,
mangled_name,
ranges,
decl_file, decl_line, decl_column,
call_file, call_line, call_column))
{
if (tag == DW_TAG_subprogram)
{
@ -1185,7 +1197,7 @@ SymbolFileDWARF::ParseFunctionBlocks
}
}
AddRangesToBlock (blocks, blockID, ranges, subprogram_low_pc);
AddRangesToBlock (*block, ranges, subprogram_low_pc);
if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL))
{
@ -1199,15 +1211,20 @@ SymbolFileDWARF::ParseFunctionBlocks
call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file),
call_line, call_column));
blocks.SetInlinedFunctionInfo(blockID, name, mangled_name, decl_ap.get(), call_ap.get());
block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get());
}
++blocks_added;
if (parse_children && die->HasChildren())
{
blocks_added += ParseFunctionBlocks(sc, blockID, dwarf_cu, die->GetFirstChild(),
subprogram_low_pc, true, true);
blocks_added += ParseFunctionBlocks (sc,
block,
dwarf_cu,
die->GetFirstChild(),
subprogram_low_pc,
true,
true);
}
}
}
@ -1582,12 +1599,12 @@ SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_
if (resolve_scope & eSymbolContextBlock)
{
BlockList& blocks = sc.function->GetBlocks(true);
Block& block = sc.function->GetBlock (true);
if (block_die != NULL)
sc.block = blocks.GetBlockByID(block_die->GetOffset());
sc.block = block.FindBlockByID (block_die->GetOffset());
else
sc.block = blocks.GetBlockByID(function_die->GetOffset());
sc.block = block.FindBlockByID (function_die->GetOffset());
if (sc.block)
resolved |= eSymbolContextBlock;
}
@ -1674,12 +1691,12 @@ SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line,
if (sc.function != NULL)
{
BlockList& blocks = sc.function->GetBlocks(true);
Block& block = sc.function->GetBlock (true);
if (block_die != NULL)
sc.block = blocks.GetBlockByID(block_die->GetOffset());
sc.block = block.FindBlockByID (block_die->GetOffset());
else
sc.block = blocks.GetBlockByID(function_die->GetOffset());
sc.block = block.FindBlockByID (function_die->GetOffset());
}
}
}
@ -3126,7 +3143,7 @@ SymbolFileDWARF::ParseType(const SymbolContext& sc, const DWARFCompileUnit* dwar
}
else if (sc.function != NULL)
{
symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset());
symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die->GetOffset());
if (symbol_context_scope == NULL)
symbol_context_scope = sc.function;
}
@ -3235,7 +3252,7 @@ SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc)
const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset);
if (function_die)
{
ParseFunctionBlocks(sc, Block::RootID, dwarf_cu, function_die, LLDB_INVALID_ADDRESS, false, true);
ParseFunctionBlocks(sc, &sc.function->GetBlock (false), dwarf_cu, function_die, LLDB_INVALID_ADDRESS, false, true);
}
}
@ -3430,7 +3447,7 @@ SymbolFileDWARF::ParseVariableDIE
}
else if (sc.function != NULL)
{
symbol_context_scope = sc.function->GetBlocks(true).GetBlockByID(sc_parent_die->GetOffset());
symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(sc_parent_die->GetOffset());
if (symbol_context_scope == NULL)
symbol_context_scope = sc.function;
}
@ -3495,11 +3512,14 @@ SymbolFileDWARF::ParseVariables
if (sc.function != NULL)
{
// Check to see if we already have parsed the variables for the given scope
variables = sc.function->GetBlocks(true).GetVariableList(sc_parent_die->GetOffset(), false, false);
Block *block = sc.function->GetBlock(true).FindBlockByID(sc_parent_die->GetOffset());
assert (block != NULL);
variables = block->GetVariableList(false, true);
if (variables.get() == NULL)
{
variables.reset(new VariableList());
sc.function->GetBlocks(true).SetVariableList(sc_parent_die->GetOffset(), variables);
block->SetVariableList(variables);
}
}
else

View File

@ -222,7 +222,7 @@ protected:
bool GetFunction (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc);
lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, const DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die);
size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc,
lldb::user_id_t parentBlockID,
lldb_private::Block *parent_block,
const DWARFCompileUnit* dwarf_cu,
const DWARFDebugInfoEntry *die,
lldb::addr_t subprogram_low_pc,

View File

@ -17,47 +17,26 @@
using namespace lldb;
using namespace lldb_private;
Block::Block(user_id_t uid, uint32_t depth, BlockList* blocks) :
Block::Block(lldb::user_id_t uid) :
UserID(uid),
m_block_list(blocks),
m_depth(depth),
m_ranges(),
m_inlineInfoSP(),
m_variables()
m_parent_scope (NULL),
m_sibling (NULL),
m_children (),
m_ranges (),
m_inlineInfoSP (),
m_variables (),
m_parsed_block_info (false),
m_parsed_block_variables (false),
m_parsed_child_blocks (false)
{
}
Block::Block(const Block& rhs) :
UserID(rhs),
m_block_list(rhs.m_block_list),
m_depth(rhs.m_depth),
m_ranges(rhs.m_ranges),
m_inlineInfoSP(rhs.m_inlineInfoSP),
m_variables(rhs.m_variables)
{
}
const Block&
Block::operator= (const Block& rhs)
{
if (this != &rhs)
{
UserID::operator= (rhs);
m_block_list = rhs.m_block_list;
m_depth = rhs.m_depth;
m_ranges = rhs.m_ranges;
m_inlineInfoSP = rhs.m_inlineInfoSP;
m_variables = rhs.m_variables;
}
return *this;
}
Block::~Block ()
{
}
void
Block::GetDescription(Stream *s, lldb::DescriptionLevel level, Process *process) const
Block::GetDescription(Stream *s, Function *function, lldb::DescriptionLevel level, Process *process) const
{
size_t num_ranges = m_ranges.size();
if (num_ranges)
@ -65,9 +44,9 @@ Block::GetDescription(Stream *s, lldb::DescriptionLevel level, Process *process)
addr_t base_addr = LLDB_INVALID_ADDRESS;
if (process)
base_addr = m_block_list->GetAddressRange().GetBaseAddress().GetLoadAddress(process);
base_addr = function->GetAddressRange().GetBaseAddress().GetLoadAddress(process);
if (base_addr == LLDB_INVALID_ADDRESS)
base_addr = m_block_list->GetAddressRange().GetBaseAddress().GetFileAddress();
base_addr = function->GetAddressRange().GetBaseAddress().GetFileAddress();
s->Printf("range%s = ", num_ranges > 1 ? "s" : "");
std::vector<VMRange>::const_iterator pos, end = m_ranges.end();
@ -85,9 +64,13 @@ Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
{
if (depth < 0)
{
// We have a depth that is less than zero, print our parent blocks
// first
m_block_list->Dump(s, GetParentUID(), depth + 1, show_context);
Block *parent = GetParent();
if (parent)
{
// We have a depth that is less than zero, print our parent blocks
// first
parent->Dump(s, base_addr, depth + 1, show_context);
}
}
s->Printf("%.*p: ", (int)sizeof(void*) * 2, this);
@ -126,12 +109,9 @@ Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
m_variables->Dump(s, show_context);
}
uint32_t blockID = m_block_list->GetFirstChild(GetID());
while (blockID != Block::InvalidID)
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
{
m_block_list->Dump(s, blockID, depth - 1, show_context);
blockID = m_block_list->GetSibling(blockID);
child_block->Dump(s, base_addr, depth - 1, show_context);
}
s->IndentLess();
@ -140,11 +120,28 @@ Block::Dump(Stream *s, addr_t base_addr, int32_t depth, bool show_context) const
}
Block *
Block::FindBlockByID (user_id_t block_id)
{
if (block_id == GetID())
return this;
Block *matching_block = NULL;
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
{
matching_block = child_block->FindBlockByID (block_id);
if (matching_block)
break;
}
return matching_block;
}
void
Block::CalculateSymbolContext(SymbolContext* sc)
{
if (m_parent_scope)
m_parent_scope->CalculateSymbolContext(sc);
sc->block = this;
m_block_list->GetFunction()->CalculateSymbolContext(sc);
}
void
@ -196,7 +193,10 @@ Block::DumpStopContext (Stream *s, const SymbolContext *sc)
void
Block::DumpSymbolContext(Stream *s)
{
m_block_list->GetFunction()->DumpSymbolContext(s);
SymbolContext sc;
CalculateSymbolContext(&sc);
if (sc.function)
sc.function->DumpSymbolContext(s);
s->Printf(", Block{0x%8.8x}", GetID());
}
@ -212,37 +212,19 @@ Block::Contains (const VMRange& range) const
return VMRange::ContainsRange(m_ranges, range);
}
bool
BlockList::BlockContainsBlockWithID (const user_id_t block_id, const user_id_t find_block_id) const
Block *
Block::GetParent () const
{
if (block_id == Block::InvalidID)
return false;
if (block_id == find_block_id)
return true;
else
if (m_parent_scope)
{
user_id_t child_block_id = GetFirstChild(block_id);
while (child_block_id != Block::InvalidID)
{
if (BlockContainsBlockWithID (child_block_id, find_block_id))
return true;
child_block_id = GetSibling(child_block_id);
}
SymbolContext sc;
m_parent_scope->CalculateSymbolContext(&sc);
if (sc.block)
return sc.block;
}
return false;
return NULL;
}
bool
Block::ContainsBlockWithID (user_id_t block_id) const
{
return m_block_list->BlockContainsBlockWithID (GetID(), block_id);
}
void
Block::AddRange(addr_t start_offset, addr_t end_offset)
{
@ -275,46 +257,30 @@ Block::MemorySize() const
}
Block *
Block::GetParent () const
{
return m_block_list->GetBlockByID (m_block_list->GetParent(GetID()));
}
Block *
Block::GetSibling () const
{
return m_block_list->GetBlockByID (m_block_list->GetSibling(GetID()));
}
Block *
Block::GetFirstChild () const
{
return m_block_list->GetBlockByID (m_block_list->GetFirstChild(GetID()));
if (m_children.empty())
return NULL;
return m_children.front().get();
}
user_id_t
Block::GetParentUID() const
void
Block::AddChild(const BlockSP &child_block_sp)
{
return m_block_list->GetParent(GetID());
}
if (child_block_sp)
{
Block *block_needs_sibling = NULL;
user_id_t
Block::GetSiblingUID() const
{
return m_block_list->GetSibling(GetID());
}
if (!m_children.empty())
block_needs_sibling = m_children.back().get();
user_id_t
Block::GetFirstChildUID() const
{
return m_block_list->GetFirstChild(GetID());
}
child_block_sp->SetParentScope (this);
m_children.push_back (child_block_sp);
user_id_t
Block::AddChild(user_id_t userID)
{
return m_block_list->AddChild(GetID(), userID);
if (block_needs_sibling)
block_needs_sibling->SetSibling (child_block_sp.get());
}
}
void
@ -329,12 +295,16 @@ VariableListSP
Block::GetVariableList (bool get_child_variables, bool can_create)
{
VariableListSP variable_list_sp;
if (m_variables.get() == NULL && can_create)
if (m_parsed_block_variables == false)
{
SymbolContext sc;
CalculateSymbolContext(&sc);
assert(sc.module_sp);
sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
if (m_variables.get() == NULL && can_create)
{
m_parsed_block_variables = true;
SymbolContext sc;
CalculateSymbolContext(&sc);
assert(sc.module_sp);
sc.module_sp->GetSymbolVendor()->ParseVariablesForContext(sc);
}
}
if (m_variables.get())
@ -387,285 +357,14 @@ Block::SetVariableList(VariableListSP& variables)
m_variables = variables;
}
uint32_t
Block::Depth () const
{
return m_depth;
}
BlockList::BlockList(Function *function, const AddressRange& range) :
m_function(function),
m_range(range),
m_blocks()
{
}
BlockList::~BlockList()
{
}
AddressRange &
BlockList::GetAddressRange()
{
return m_range;
}
const AddressRange &
BlockList::GetAddressRange() const
{
return m_range;
}
void
BlockList::Dump(Stream *s, user_id_t blockID, uint32_t depth, bool show_context) const
Block::SetBlockInfoHasBeenParsed (bool b, bool set_children)
{
const Block* block = GetBlockByID(blockID);
if (block)
block->Dump(s, m_range.GetBaseAddress().GetFileAddress(), depth, show_context);
}
Function *
BlockList::GetFunction()
{
return m_function;
}
const Function *
BlockList::GetFunction() const
{
return m_function;
}
user_id_t
BlockList::GetParent(user_id_t blockID) const
{
collection::const_iterator end = m_blocks.end();
collection::const_iterator begin = m_blocks.begin();
collection::const_iterator pos = std::find_if(begin, end, UserID::IDMatches(blockID));
if (pos != end && pos != begin && pos->Depth() > 0)
m_parsed_block_info = b;
if (set_children)
{
const uint32_t parent_depth = pos->Depth() - 1;
while (--pos >= begin)
{
if (pos->Depth() == parent_depth)
return pos->GetID();
}
m_parsed_child_blocks = true;
for (Block *child_block = GetFirstChild(); child_block != NULL; child_block = child_block->GetSibling())
child_block->SetBlockInfoHasBeenParsed (b, true);
}
return Block::InvalidID;
}
user_id_t
BlockList::GetSibling(user_id_t blockID) const
{
collection::const_iterator end = m_blocks.end();
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
if (pos != end)
{
const uint32_t sibling_depth = pos->Depth();
while (++pos != end)
{
uint32_t depth = pos->Depth();
if (depth == sibling_depth)
return pos->GetID();
if (depth < sibling_depth)
break;
}
}
return Block::InvalidID;
}
user_id_t
BlockList::GetFirstChild(user_id_t blockID) const
{
if (!m_blocks.empty())
{
if (blockID == Block::RootID)
{
return m_blocks.front().GetID();
}
else
{
collection::const_iterator end = m_blocks.end();
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
if (pos != end)
{
collection::const_iterator child_pos = pos + 1;
if (child_pos != end)
{
if (child_pos->Depth() == pos->Depth() + 1)
return child_pos->GetID();
}
}
}
}
return Block::InvalidID;
}
// Return the current number of bytes that this object occupies in memory
size_t
BlockList::MemorySize() const
{
size_t mem_size = sizeof(BlockList);
collection::const_iterator pos, end = m_blocks.end();
for (pos = m_blocks.begin(); pos != end; ++pos)
mem_size += pos->MemorySize(); // Each block can vary in size
return mem_size;
}
user_id_t
BlockList::AddChild (user_id_t parentID, user_id_t childID)
{
bool added = false;
if (parentID == Block::RootID)
{
assert(m_blocks.empty());
Block block(childID, 0, this);
m_blocks.push_back(block);
added = true;
}
else
{
collection::iterator end = m_blocks.end();
collection::iterator parent_pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(parentID));
assert(parent_pos != end);
if (parent_pos != end)
{
const uint32_t parent_sibling_depth = parent_pos->Depth();
collection::iterator insert_pos = parent_pos;
collection::iterator prev_sibling = end;
while (++insert_pos != end)
{
if (insert_pos->Depth() <= parent_sibling_depth)
break;
}
Block child_block(childID, parent_pos->Depth() + 1, this);
collection::iterator child_pos = m_blocks.insert(insert_pos, child_block);
added = true;
}
}
if (added)
return childID;
return Block::InvalidID;
}
const Block *
BlockList::GetBlockByID(user_id_t blockID) const
{
if (m_blocks.empty() || blockID == Block::InvalidID)
return NULL;
if (blockID == Block::RootID)
blockID = m_blocks.front().GetID();
collection::const_iterator end = m_blocks.end();
collection::const_iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
if (pos != end)
return &(*pos);
return NULL;
}
Block *
BlockList::GetBlockByID(user_id_t blockID)
{
if (m_blocks.empty() || blockID == Block::InvalidID)
return NULL;
if (blockID == Block::RootID)
blockID = m_blocks.front().GetID();
collection::iterator end = m_blocks.end();
collection::iterator pos = std::find_if(m_blocks.begin(), end, UserID::IDMatches(blockID));
if (pos != end)
return &(*pos);
return NULL;
}
bool
BlockList::AddRange(user_id_t blockID, addr_t start_offset, addr_t end_offset)
{
Block *block = GetBlockByID(blockID);
if (block)
{
block->AddRange(start_offset, end_offset);
return true;
}
return false;
}
//
//const Block *
//BlockList::FindDeepestBlockForAddress (const Address &addr)
//{
// if (m_range.Contains(addr))
// {
// addr_t block_offset = addr.GetFileAddress() - m_range.GetBaseAddress().GetFileAddress();
// collection::const_iterator pos, end = m_blocks.end();
// collection::const_iterator deepest_match_pos = end;
// for (pos = m_blocks.begin(); pos != end; ++pos)
// {
// if (pos->Contains (block_offset))
// {
// if (deepest_match_pos == end || deepest_match_pos->Depth() < pos->Depth())
// deepest_match_pos = pos;
// }
// }
// if (deepest_match_pos != end)
// return &(*deepest_match_pos);
// }
// return NULL;
//}
//
bool
BlockList::SetInlinedFunctionInfo(user_id_t blockID, const char *name, const char *mangled, const Declaration *decl_ptr, const Declaration *call_decl_ptr)
{
Block *block = GetBlockByID(blockID);
if (block)
{
block->SetInlinedFunctionInfo(name, mangled, decl_ptr, call_decl_ptr);
return true;
}
return false;
}
VariableListSP
BlockList::GetVariableList(user_id_t blockID, bool get_child_variables, bool can_create)
{
VariableListSP variable_list_sp;
Block *block = GetBlockByID(blockID);
if (block)
variable_list_sp = block->GetVariableList(get_child_variables, can_create);
return variable_list_sp;
}
bool
BlockList::IsEmpty() const
{
return m_blocks.empty();
}
bool
BlockList::SetVariableList(user_id_t blockID, VariableListSP& variables)
{
Block *block = GetBlockByID(blockID);
if (block)
{
block->SetVariableList(variables);
return true;
}
return false;
}

View File

@ -191,16 +191,18 @@ Function::Function
Type * type,
const AddressRange& range
) :
UserID(func_uid),
m_comp_unit(comp_unit),
m_type_uid(type_uid),
m_type(type),
m_mangled(mangled),
m_blocks(this, range),
m_frame_base(),
m_flags(),
m_prologue_byte_size(0)
UserID (func_uid),
m_comp_unit (comp_unit),
m_type_uid (type_uid),
m_type (type),
m_mangled (mangled),
m_block (func_uid),
m_range (range),
m_frame_base (),
m_flags (),
m_prologue_byte_size (0)
{
m_block.SetParentScope(this);
assert(comp_unit != NULL);
}
@ -213,16 +215,18 @@ Function::Function
Type *type,
const AddressRange &range
) :
UserID(func_uid),
m_comp_unit(comp_unit),
m_type_uid(type_uid),
m_type(type),
m_mangled(mangled, true),
m_blocks(this, range),
m_frame_base(),
m_flags(),
m_prologue_byte_size(0)
UserID (func_uid),
m_comp_unit (comp_unit),
m_type_uid (type_uid),
m_type (type),
m_mangled (mangled, true),
m_block (func_uid),
m_range (range),
m_frame_base (),
m_flags (),
m_prologue_byte_size (0)
{
m_block.SetParentScope(this);
assert(comp_unit != NULL);
}
@ -231,24 +235,6 @@ Function::~Function()
{
}
const AddressRange &
Function::GetAddressRange()
{
return GetBlocks(true).GetAddressRange();
}
bool
Function::IsInlined()
{
Block *root_block = GetBlocks(true).GetBlockByID(Block::RootID);
if (root_block)
{
if (root_block->InlinedFunctionInfo() != NULL)
return true;
}
return false;
}
void
Function::GetStartLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
{
@ -301,17 +287,18 @@ Function::GetEndLineSourceInfo (FileSpec &source_file, uint32_t &line_no)
}
}
BlockList &
Function::GetBlocks(bool can_create)
Block &
Function::GetBlock (bool can_create)
{
if (m_blocks.IsEmpty() && can_create)
if (!m_block.BlockInfoHasBeenParsed() && can_create)
{
SymbolContext sc;
CalculateSymbolContext(&sc);
assert(sc.module_sp);
sc.module_sp->GetSymbolVendor()->ParseFunctionBlocks(sc);
m_block.SetBlockInfoHasBeenParsed (true, true);
}
return m_blocks;
return m_block;
}
CompileUnit*
@ -358,8 +345,8 @@ Function::Dump(Stream *s, bool show_context) const
s->EOL();
// Dump the root object
if (!m_blocks.IsEmpty())
m_blocks.Dump(s, Block::RootID, INT_MAX, show_context);
if (m_block.BlockInfoHasBeenParsed ())
m_block.Dump(s, m_range.GetBaseAddress().GetFileAddress(), INT_MAX, show_context);
}
@ -380,7 +367,7 @@ Function::DumpSymbolContext(Stream *s)
size_t
Function::MemorySize () const
{
size_t mem_size = sizeof(Function) + m_blocks.MemorySize();
size_t mem_size = sizeof(Function) + m_block.MemorySize();
return mem_size;
}

View File

@ -217,7 +217,7 @@ SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level, Process *
s->Indent(" Blocks: ");
else
s->Indent(" ");
(*pos)->GetDescription(s, level, process);
(*pos)->GetDescription(s, function, level, process);
s->EOL();
}
}

View File

@ -154,7 +154,7 @@ Variable::IsInScope (StackFrame *frame)
SymbolContext variable_sc;
CalculateSymbolContext (&variable_sc);
if (variable_sc.function && variable_sc.block)
return variable_sc.block->ContainsBlockWithID (frame_block->GetID());
return variable_sc.block->FindBlockByID(frame_block->GetID()) != NULL;
}
}
break;

View File

@ -280,7 +280,7 @@ StackFrame::GetVariableList ()
{
bool get_child_variables = true;
bool can_create = true;
m_variable_list_sp = m_sc.function->GetBlocks(can_create).GetVariableList (Block::RootID, get_child_variables, can_create);
m_variable_list_sp = m_sc.function->GetBlock (can_create).GetVariableList (get_child_variables, can_create);
}
}
return m_variable_list_sp.get();