2010-06-08 16:52:24 +00:00
//===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2012-12-05 00:20:57 +00:00
# include "lldb/lldb-python.h"
2010-06-08 16:52:24 +00:00
// C Includes
# include <errno.h>
# include <spawn.h>
2011-03-25 18:16:28 +00:00
# include <stdlib.h>
2012-07-19 18:07:36 +00:00
# include <netinet/in.h>
2011-05-14 01:50:35 +00:00
# include <sys/mman.h> // for mmap
2010-06-08 16:52:24 +00:00
# include <sys/stat.h>
2011-05-14 01:50:35 +00:00
# include <sys/types.h>
2011-03-30 00:12:40 +00:00
# include <time.h>
2010-06-08 16:52:24 +00:00
// C++ Includes
# include <algorithm>
# include <map>
// Other libraries and framework includes
2011-10-14 00:42:25 +00:00
# include "lldb/Breakpoint/Watchpoint.h"
2010-06-15 19:49:27 +00:00
# include "lldb/Interpreter/Args.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/ArchSpec.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/ConnectionFileDescriptor.h"
2011-02-08 05:05:52 +00:00
# include "lldb/Host/FileSpec.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/InputReader.h"
# include "lldb/Core/Module.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-29 21:13:06 +00:00
# include "lldb/Core/ModuleSpec.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/PluginManager.h"
# include "lldb/Core/State.h"
2012-04-13 21:24:18 +00:00
# include "lldb/Core/StreamFile.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/StreamString.h"
# include "lldb/Core/Timer.h"
2011-05-15 01:25:55 +00:00
# include "lldb/Core/Value.h"
2012-09-29 08:03:33 +00:00
# include "lldb/Host/Symbols.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Host/TimeValue.h"
2012-10-15 22:42:16 +00:00
# include "lldb/Interpreter/CommandInterpreter.h"
2012-10-19 22:22:57 +00:00
# include "lldb/Interpreter/CommandObject.h"
# include "lldb/Interpreter/CommandObjectMultiword.h"
2012-10-15 22:42:16 +00:00
# include "lldb/Interpreter/CommandReturnObject.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Symbol/ObjectFile.h"
# include "lldb/Target/DynamicLoader.h"
# include "lldb/Target/Target.h"
# include "lldb/Target/TargetList.h"
2011-05-14 01:50:35 +00:00
# include "lldb/Target/ThreadPlanCallFunction.h"
2010-06-09 21:28:42 +00:00
# include "lldb/Utility/PseudoTerminal.h"
2010-06-08 16:52:24 +00:00
// Project includes
# include "lldb/Host/Host.h"
2011-06-03 20:40:38 +00:00
# include "Plugins/Process/Utility/InferiorCallPOSIX.h"
2012-07-25 03:40:06 +00:00
# include "Plugins/Process/Utility/StopInfoMachException.h"
2012-07-04 00:35:43 +00:00
# include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
2010-07-09 20:39:50 +00:00
# include "Utility/StringExtractorGDBRemote.h"
2010-06-08 16:52:24 +00:00
# include "GDBRemoteRegisterContext.h"
# include "ProcessGDBRemote.h"
# include "ProcessGDBRemoteLog.h"
# include "ThreadGDBRemote.h"
2010-08-04 01:40:35 +00:00
2012-10-03 01:29:34 +00:00
2012-04-09 22:46:21 +00:00
namespace lldb
{
// Provide a function that can easily dump the packet history if we know a
// ProcessGDBRemote * value (which we can get from logs or from debugging).
// We need the function in the lldb namespace so it makes it into the final
// executable since the LLDB shared library only exports stuff in the lldb
// namespace. This allows you to attach with a debugger and call this
// function and get the packet history dumped to a file.
void
DumpProcessGDBRemotePacketHistory ( void * p , const char * path )
{
2012-04-13 21:24:18 +00:00
lldb_private : : StreamFile strm ;
lldb_private : : Error error ( strm . GetFile ( ) . Open ( path , lldb_private : : File : : eOpenOptionWrite | lldb_private : : File : : eOpenOptionCanCreate ) ) ;
if ( error . Success ( ) )
( ( ProcessGDBRemote * ) p ) - > GetGDBRemote ( ) . DumpHistory ( strm ) ;
2012-04-09 22:46:21 +00:00
}
2012-05-23 16:27:09 +00:00
}
2010-06-08 16:52:24 +00:00
# define DEBUGSERVER_BASENAME "debugserver"
using namespace lldb ;
using namespace lldb_private ;
2011-03-29 21:45:47 +00:00
static bool rand_initialized = false ;
2012-07-19 18:07:36 +00:00
// TODO Randomly assigning a port is unsafe. We should get an unused
// ephemeral port from the kernel and make sure we reserve it before passing
// it to debugserver.
# if defined (__APPLE__)
# define LOW_PORT (IPPORT_RESERVED)
# define HIGH_PORT (IPPORT_HIFIRSTAUTO)
# else
# define LOW_PORT (1024u)
# define HIGH_PORT (49151u)
# endif
2010-06-08 16:52:24 +00:00
static inline uint16_t
get_random_port ( )
{
2011-03-29 21:45:47 +00:00
if ( ! rand_initialized )
{
2011-03-30 00:12:40 +00:00
time_t seed = time ( NULL ) ;
2011-03-29 21:45:47 +00:00
rand_initialized = true ;
2011-03-30 00:12:40 +00:00
srand ( seed ) ;
2011-03-29 21:45:47 +00:00
}
2012-07-19 18:07:36 +00:00
return ( rand ( ) % ( HIGH_PORT - LOW_PORT ) ) + LOW_PORT ;
2010-06-08 16:52:24 +00:00
}
const char *
ProcessGDBRemote : : GetPluginNameStatic ( )
{
2011-03-19 01:12:21 +00:00
return " gdb-remote " ;
2010-06-08 16:52:24 +00:00
}
const char *
ProcessGDBRemote : : GetPluginDescriptionStatic ( )
{
return " GDB Remote protocol based debugging plug-in. " ;
}
void
ProcessGDBRemote : : Terminate ( )
{
PluginManager : : UnregisterPlugin ( ProcessGDBRemote : : CreateInstance ) ;
}
2012-02-09 06:16:32 +00:00
lldb : : ProcessSP
ProcessGDBRemote : : CreateInstance ( Target & target , Listener & listener , const FileSpec * crash_file_path )
2010-06-08 16:52:24 +00:00
{
2012-02-09 06:16:32 +00:00
lldb : : ProcessSP process_sp ;
if ( crash_file_path = = NULL )
process_sp . reset ( new ProcessGDBRemote ( target , listener ) ) ;
return process_sp ;
2010-06-08 16:52:24 +00:00
}
bool
2011-07-17 20:36:25 +00:00
ProcessGDBRemote : : CanDebug ( Target & target , bool plugin_specified_by_name )
2010-06-08 16:52:24 +00:00
{
2011-10-21 21:41:45 +00:00
if ( plugin_specified_by_name )
return true ;
2010-06-08 16:52:24 +00:00
// For now we are just making sure the file exists for a given module
2011-08-11 02:48:45 +00:00
Module * exe_module = target . GetExecutableModulePointer ( ) ;
if ( exe_module )
2012-02-09 06:16:32 +00:00
{
ObjectFile * exe_objfile = exe_module - > GetObjectFile ( ) ;
// We can't debug core files...
switch ( exe_objfile - > GetType ( ) )
{
case ObjectFile : : eTypeInvalid :
case ObjectFile : : eTypeCoreFile :
case ObjectFile : : eTypeDebugInfo :
case ObjectFile : : eTypeObjectFile :
case ObjectFile : : eTypeSharedLibrary :
case ObjectFile : : eTypeStubLibrary :
return false ;
case ObjectFile : : eTypeExecutable :
case ObjectFile : : eTypeDynamicLinker :
case ObjectFile : : eTypeUnknown :
break ;
}
2011-08-11 02:48:45 +00:00
return exe_module - > GetFileSpec ( ) . Exists ( ) ;
2012-02-09 06:16:32 +00:00
}
2010-08-09 23:31:02 +00:00
// However, if there is no executable module, we return true since we might be preparing to attach.
return true ;
2010-06-08 16:52:24 +00:00
}
//----------------------------------------------------------------------
// ProcessGDBRemote constructor
//----------------------------------------------------------------------
ProcessGDBRemote : : ProcessGDBRemote ( Target & target , Listener & listener ) :
Process ( target , listener ) ,
m_flags ( 0 ) ,
2011-04-12 05:54:46 +00:00
m_gdb_comm ( false ) ,
2010-06-08 16:52:24 +00:00
m_debugserver_pid ( LLDB_INVALID_PROCESS_ID ) ,
2010-07-09 20:39:50 +00:00
m_last_stop_packet ( ) ,
2011-12-06 04:51:14 +00:00
m_last_stop_packet_mutex ( Mutex : : eMutexTypeNormal ) ,
2010-06-08 16:52:24 +00:00
m_register_info ( ) ,
2012-02-16 06:50:00 +00:00
m_async_broadcaster ( NULL , " lldb.process.gdb-remote.async-broadcaster " ) ,
2010-06-08 16:52:24 +00:00
m_async_thread ( LLDB_INVALID_HOST_THREAD ) ,
2012-11-01 01:15:33 +00:00
m_async_thread_state ( eAsyncThreadNotStarted ) ,
m_async_thread_state_mutex ( Mutex : : eMutexTypeRecursive ) ,
2012-04-10 02:25:43 +00:00
m_thread_ids ( ) ,
2011-02-12 06:28:37 +00:00
m_continue_c_tids ( ) ,
m_continue_C_tids ( ) ,
m_continue_s_tids ( ) ,
m_continue_S_tids ( ) ,
2010-06-08 16:52:24 +00:00
m_dispatch_queue_offsets_addr ( LLDB_INVALID_ADDRESS ) ,
2010-07-09 20:39:50 +00:00
m_max_memory_size ( 512 ) ,
2012-05-15 02:33:01 +00:00
m_addr_to_mmap_size ( ) ,
m_thread_create_bp_sp ( ) ,
2012-07-04 00:35:43 +00:00
m_waiting_for_attach ( false ) ,
2012-10-03 01:29:34 +00:00
m_destroy_tried_resuming ( false ) ,
m_dyld_plugin_name ( ) ,
2012-10-13 02:07:45 +00:00
m_command_sp ( )
2010-06-08 16:52:24 +00:00
{
2011-04-01 00:29:43 +00:00
m_async_broadcaster . SetEventName ( eBroadcastBitAsyncThreadShouldExit , " async thread should exit " ) ;
m_async_broadcaster . SetEventName ( eBroadcastBitAsyncContinue , " async thread continue " ) ;
2012-04-12 18:49:31 +00:00
m_async_broadcaster . SetEventName ( eBroadcastBitAsyncThreadDidExit , " async thread did exit " ) ;
2010-06-08 16:52:24 +00:00
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ProcessGDBRemote : : ~ ProcessGDBRemote ( )
{
// m_mach_process.UnregisterNotificationCallbacks (this);
Clear ( ) ;
2011-10-01 00:45:15 +00:00
// We need to call finalize on the process before destroying ourselves
// to make sure all of the broadcaster cleanup goes as planned. If we
// destruct this class, then Process::~Process() might have problems
// trying to fully destroy the broadcaster.
Finalize ( ) ;
2012-11-01 01:15:33 +00:00
// The general Finalize is going to try to destroy the process and that SHOULD
// shut down the async thread. However, if we don't kill it it will get stranded and
// its connection will go away so when it wakes up it will crash. So kill it for sure here.
StopAsyncThread ( ) ;
KillDebugserverProcess ( ) ;
2010-06-08 16:52:24 +00:00
}
//----------------------------------------------------------------------
// PluginInterface
//----------------------------------------------------------------------
const char *
ProcessGDBRemote : : GetPluginName ( )
{
return " Process debugging plug-in that uses the GDB remote protocol " ;
}
const char *
ProcessGDBRemote : : GetShortPluginName ( )
{
return GetPluginNameStatic ( ) ;
}
uint32_t
ProcessGDBRemote : : GetPluginVersion ( )
{
return 1 ;
}
void
2011-01-29 07:10:55 +00:00
ProcessGDBRemote : : BuildDynamicRegisterInfo ( bool force )
2010-06-08 16:52:24 +00:00
{
2011-01-29 07:10:55 +00:00
if ( ! force & & m_register_info . GetNumRegisters ( ) > 0 )
return ;
char packet [ 128 ] ;
2010-06-08 16:52:24 +00:00
m_register_info . Clear ( ) ;
uint32_t reg_offset = 0 ;
uint32_t reg_num = 0 ;
2012-07-17 03:23:13 +00:00
for ( StringExtractorGDBRemote : : ResponseType response_type = StringExtractorGDBRemote : : eResponse ;
2011-03-22 04:00:09 +00:00
response_type = = StringExtractorGDBRemote : : eResponse ;
+ + reg_num )
2010-06-08 16:52:24 +00:00
{
2011-01-29 07:10:55 +00:00
const int packet_len = : : snprintf ( packet , sizeof ( packet ) , " qRegisterInfo%x " , reg_num ) ;
assert ( packet_len < sizeof ( packet ) ) ;
2010-06-08 16:52:24 +00:00
StringExtractorGDBRemote response ;
2011-03-10 02:26:48 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( packet , packet_len , response , false ) )
2010-06-08 16:52:24 +00:00
{
2011-03-22 04:00:09 +00:00
response_type = response . GetResponseType ( ) ;
if ( response_type = = StringExtractorGDBRemote : : eResponse )
2010-06-08 16:52:24 +00:00
{
std : : string name ;
std : : string value ;
ConstString reg_name ;
ConstString alt_name ;
ConstString set_name ;
2013-01-21 22:17:50 +00:00
std : : vector < uint32_t > value_regs ;
std : : vector < uint32_t > invalidate_regs ;
2010-06-08 16:52:24 +00:00
RegisterInfo reg_info = { NULL , // Name
NULL , // Alt name
0 , // byte size
reg_offset , // offset
eEncodingUint , // encoding
eFormatHex , // formate
{
LLDB_INVALID_REGNUM , // GCC reg num
LLDB_INVALID_REGNUM , // DWARF reg num
LLDB_INVALID_REGNUM , // generic reg num
2010-09-10 07:49:16 +00:00
reg_num , // GDB reg num
reg_num // native register number
2012-02-29 19:27:27 +00:00
} ,
NULL ,
NULL
2010-06-08 16:52:24 +00:00
} ;
while ( response . GetNameColonValue ( name , value ) )
{
if ( name . compare ( " name " ) = = 0 )
{
reg_name . SetCString ( value . c_str ( ) ) ;
}
else if ( name . compare ( " alt-name " ) = = 0 )
{
alt_name . SetCString ( value . c_str ( ) ) ;
}
else if ( name . compare ( " bitsize " ) = = 0 )
{
reg_info . byte_size = Args : : StringToUInt32 ( value . c_str ( ) , 0 , 0 ) / CHAR_BIT ;
}
else if ( name . compare ( " offset " ) = = 0 )
{
uint32_t offset = Args : : StringToUInt32 ( value . c_str ( ) , UINT32_MAX , 0 ) ;
2010-06-11 23:44:18 +00:00
if ( reg_offset ! = offset )
2010-06-08 16:52:24 +00:00
{
reg_offset = offset ;
}
}
else if ( name . compare ( " encoding " ) = = 0 )
{
2012-08-24 01:42:50 +00:00
const Encoding encoding = Args : : StringToEncoding ( value . c_str ( ) ) ;
if ( encoding ! = eEncodingInvalid )
reg_info . encoding = encoding ;
2010-06-08 16:52:24 +00:00
}
else if ( name . compare ( " format " ) = = 0 )
{
2012-08-24 01:42:50 +00:00
Format format = eFormatInvalid ;
if ( Args : : StringToFormat ( value . c_str ( ) , format , NULL ) . Success ( ) )
reg_info . format = format ;
else if ( value . compare ( " binary " ) = = 0 )
2010-06-08 16:52:24 +00:00
reg_info . format = eFormatBinary ;
else if ( value . compare ( " decimal " ) = = 0 )
reg_info . format = eFormatDecimal ;
else if ( value . compare ( " hex " ) = = 0 )
reg_info . format = eFormatHex ;
else if ( value . compare ( " float " ) = = 0 )
reg_info . format = eFormatFloat ;
else if ( value . compare ( " vector-sint8 " ) = = 0 )
reg_info . format = eFormatVectorOfSInt8 ;
else if ( value . compare ( " vector-uint8 " ) = = 0 )
reg_info . format = eFormatVectorOfUInt8 ;
else if ( value . compare ( " vector-sint16 " ) = = 0 )
reg_info . format = eFormatVectorOfSInt16 ;
else if ( value . compare ( " vector-uint16 " ) = = 0 )
reg_info . format = eFormatVectorOfUInt16 ;
else if ( value . compare ( " vector-sint32 " ) = = 0 )
reg_info . format = eFormatVectorOfSInt32 ;
else if ( value . compare ( " vector-uint32 " ) = = 0 )
reg_info . format = eFormatVectorOfUInt32 ;
else if ( value . compare ( " vector-float32 " ) = = 0 )
reg_info . format = eFormatVectorOfFloat32 ;
else if ( value . compare ( " vector-uint128 " ) = = 0 )
reg_info . format = eFormatVectorOfUInt128 ;
}
else if ( name . compare ( " set " ) = = 0 )
{
set_name . SetCString ( value . c_str ( ) ) ;
}
else if ( name . compare ( " gcc " ) = = 0 )
{
reg_info . kinds [ eRegisterKindGCC ] = Args : : StringToUInt32 ( value . c_str ( ) , LLDB_INVALID_REGNUM , 0 ) ;
}
else if ( name . compare ( " dwarf " ) = = 0 )
{
reg_info . kinds [ eRegisterKindDWARF ] = Args : : StringToUInt32 ( value . c_str ( ) , LLDB_INVALID_REGNUM , 0 ) ;
}
else if ( name . compare ( " generic " ) = = 0 )
{
2012-08-24 01:42:50 +00:00
reg_info . kinds [ eRegisterKindGeneric ] = Args : : StringToGenericRegister ( value . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
}
2013-01-21 22:17:50 +00:00
else if ( name . compare ( " container-regs " ) = = 0 )
{
std : : pair < llvm : : StringRef , llvm : : StringRef > value_pair ;
value_pair . second = value ;
do
{
value_pair = value_pair . second . split ( ' , ' ) ;
if ( ! value_pair . first . empty ( ) )
{
2013-01-21 23:32:42 +00:00
uint32_t reg = Args : : StringToUInt32 ( value_pair . first . str ( ) . c_str ( ) , LLDB_INVALID_REGNUM , 16 ) ;
if ( reg ! = LLDB_INVALID_REGNUM )
value_regs . push_back ( reg ) ;
2013-01-21 22:17:50 +00:00
}
} while ( ! value_pair . second . empty ( ) ) ;
}
else if ( name . compare ( " invalidate-regs " ) = = 0 )
{
std : : pair < llvm : : StringRef , llvm : : StringRef > value_pair ;
value_pair . second = value ;
do
{
value_pair = value_pair . second . split ( ' , ' ) ;
if ( ! value_pair . first . empty ( ) )
{
2013-01-21 23:32:42 +00:00
uint32_t reg = Args : : StringToUInt32 ( value_pair . first . str ( ) . c_str ( ) , LLDB_INVALID_REGNUM , 16 ) ;
if ( reg ! = LLDB_INVALID_REGNUM )
invalidate_regs . push_back ( reg ) ;
2013-01-21 22:17:50 +00:00
}
} while ( ! value_pair . second . empty ( ) ) ;
}
2010-06-08 16:52:24 +00:00
}
2010-06-11 23:44:18 +00:00
reg_info . byte_offset = reg_offset ;
2010-06-08 16:52:24 +00:00
assert ( reg_info . byte_size ! = 0 ) ;
reg_offset + = reg_info . byte_size ;
2013-01-21 22:17:50 +00:00
if ( ! value_regs . empty ( ) )
{
value_regs . push_back ( LLDB_INVALID_REGNUM ) ;
reg_info . value_regs = value_regs . data ( ) ;
}
if ( ! invalidate_regs . empty ( ) )
{
invalidate_regs . push_back ( LLDB_INVALID_REGNUM ) ;
reg_info . invalidate_regs = invalidate_regs . data ( ) ;
}
2010-06-08 16:52:24 +00:00
m_register_info . AddRegister ( reg_info , reg_name , alt_name , set_name ) ;
}
}
else
{
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-30 18:16:51 +00:00
break ;
2010-06-08 16:52:24 +00:00
}
}
2012-05-14 18:44:23 +00:00
// We didn't get anything if the accumulated reg_num is zero. See if we are
// debugging ARM and fill with a hard coded register set until we can get an
// updated debugserver down on the devices.
// On the other hand, if the accumulated reg_num is positive, see if we can
// add composite registers to the existing primordial ones.
bool from_scratch = ( reg_num = = 0 ) ;
const ArchSpec & target_arch = GetTarget ( ) . GetArchitecture ( ) ;
2012-12-19 02:54:03 +00:00
const ArchSpec & remote_host_arch = m_gdb_comm . GetHostArchitecture ( ) ;
const ArchSpec & remote_process_arch = m_gdb_comm . GetProcessArchitecture ( ) ;
// Use the process' architecture instead of the host arch, if available
ArchSpec remote_arch ;
if ( remote_process_arch . IsValid ( ) )
remote_arch = remote_process_arch ;
else
remote_arch = remote_host_arch ;
2012-05-14 18:44:23 +00:00
if ( ! target_arch . IsValid ( ) )
2010-06-08 16:52:24 +00:00
{
2012-05-14 18:44:23 +00:00
if ( remote_arch . IsValid ( )
& & remote_arch . GetMachine ( ) = = llvm : : Triple : : arm
& & remote_arch . GetTriple ( ) . getVendor ( ) = = llvm : : Triple : : Apple )
m_register_info . HardcodeARMRegisters ( from_scratch ) ;
2010-06-08 16:52:24 +00:00
}
2012-05-14 18:44:23 +00:00
else if ( target_arch . GetMachine ( ) = = llvm : : Triple : : arm )
{
m_register_info . HardcodeARMRegisters ( from_scratch ) ;
}
// At this point, we can finalize our register info.
2010-06-08 16:52:24 +00:00
m_register_info . Finalize ( ) ;
}
Error
ProcessGDBRemote : : WillLaunch ( Module * module )
{
return WillLaunchOrAttach ( ) ;
}
Error
2010-11-18 05:57:03 +00:00
ProcessGDBRemote : : WillAttachToProcessWithID ( lldb : : pid_t pid )
2010-06-08 16:52:24 +00:00
{
return WillLaunchOrAttach ( ) ;
}
Error
2010-11-18 05:57:03 +00:00
ProcessGDBRemote : : WillAttachToProcessWithName ( const char * process_name , bool wait_for_launch )
2010-06-08 16:52:24 +00:00
{
return WillLaunchOrAttach ( ) ;
}
2011-02-04 01:58:07 +00:00
Error
2012-09-29 04:02:01 +00:00
ProcessGDBRemote : : DoConnectRemote ( Stream * strm , const char * remote_url )
2011-02-04 01:58:07 +00:00
{
Error error ( WillLaunchOrAttach ( ) ) ;
if ( error . Fail ( ) )
return error ;
2011-04-30 01:09:13 +00:00
error = ConnectToDebugserver ( remote_url ) ;
2011-02-04 01:58:07 +00:00
if ( error . Fail ( ) )
return error ;
StartAsyncThread ( ) ;
2011-03-10 02:26:48 +00:00
lldb : : pid_t pid = m_gdb_comm . GetCurrentProcessID ( ) ;
2011-02-04 01:58:07 +00:00
if ( pid = = LLDB_INVALID_PROCESS_ID )
{
// We don't have a valid process ID, so note that we are connected
// and could now request to launch or attach, or get remote process
// listings...
SetPrivateState ( eStateConnected ) ;
}
else
{
// We have a valid process
SetID ( pid ) ;
2011-08-22 02:49:39 +00:00
GetThreadList ( ) ;
2011-06-02 22:22:38 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( " ? " , 1 , m_last_stop_packet , false ) )
2011-02-04 01:58:07 +00:00
{
2011-06-02 22:22:38 +00:00
const StateType state = SetThreadStopInfo ( m_last_stop_packet ) ;
2011-02-04 01:58:07 +00:00
if ( state = = eStateStopped )
{
SetPrivateState ( state ) ;
}
else
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " Process % " PRIu64 " was reported after connecting to '%s', but state was not stopped: %s " , pid , remote_url , StateAsCString ( state ) ) ;
2011-02-04 01:58:07 +00:00
}
else
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " Process % " PRIu64 " was reported after connecting to '%s', but no stop reply packet was received " , pid , remote_url ) ;
2011-02-04 01:58:07 +00:00
}
2012-05-03 22:37:30 +00:00
if ( error . Success ( )
& & ! GetTarget ( ) . GetArchitecture ( ) . IsValid ( )
& & m_gdb_comm . GetHostArchitecture ( ) . IsValid ( ) )
{
2012-12-19 02:54:03 +00:00
// Prefer the *process'* architecture over that of the *host*, if available.
if ( m_gdb_comm . GetProcessArchitecture ( ) . IsValid ( ) )
GetTarget ( ) . SetArchitecture ( m_gdb_comm . GetProcessArchitecture ( ) ) ;
else
GetTarget ( ) . SetArchitecture ( m_gdb_comm . GetHostArchitecture ( ) ) ;
2012-05-03 22:37:30 +00:00
}
2011-02-04 01:58:07 +00:00
return error ;
}
2010-06-08 16:52:24 +00:00
Error
ProcessGDBRemote : : WillLaunchOrAttach ( )
{
Error error ;
m_stdio_communication . Clear ( ) ;
return error ;
}
//----------------------------------------------------------------------
// Process Control
//----------------------------------------------------------------------
Error
2011-11-03 21:22:33 +00:00
ProcessGDBRemote : : DoLaunch ( Module * exe_module , const ProcessLaunchInfo & launch_info )
2010-06-08 16:52:24 +00:00
{
2010-09-30 21:49:03 +00:00
Error error ;
2011-11-03 21:22:33 +00:00
uint32_t launch_flags = launch_info . GetFlags ( ) . Get ( ) ;
const char * stdin_path = NULL ;
const char * stdout_path = NULL ;
const char * stderr_path = NULL ;
const char * working_dir = launch_info . GetWorkingDirectory ( ) ;
const ProcessLaunchInfo : : FileAction * file_action ;
file_action = launch_info . GetFileActionForFD ( STDIN_FILENO ) ;
if ( file_action )
{
if ( file_action - > GetAction ( ) = = ProcessLaunchInfo : : FileAction : : eFileActionOpen )
stdin_path = file_action - > GetPath ( ) ;
}
file_action = launch_info . GetFileActionForFD ( STDOUT_FILENO ) ;
if ( file_action )
{
if ( file_action - > GetAction ( ) = = ProcessLaunchInfo : : FileAction : : eFileActionOpen )
stdout_path = file_action - > GetPath ( ) ;
}
file_action = launch_info . GetFileActionForFD ( STDERR_FILENO ) ;
if ( file_action )
{
if ( file_action - > GetAction ( ) = = ProcessLaunchInfo : : FileAction : : eFileActionOpen )
stderr_path = file_action - > GetPath ( ) ;
}
2010-06-08 16:52:24 +00:00
// ::LogSetBitMask (GDBR_LOG_DEFAULT);
// ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
// ::LogSetLogFile ("/dev/stdout");
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
2011-11-03 21:22:33 +00:00
ObjectFile * object_file = exe_module - > GetObjectFile ( ) ;
2010-06-08 16:52:24 +00:00
if ( object_file )
{
char host_port [ 128 ] ;
snprintf ( host_port , sizeof ( host_port ) , " localhost:%u " , get_random_port ( ) ) ;
2011-02-04 01:58:07 +00:00
char connect_url [ 128 ] ;
snprintf ( connect_url , sizeof ( connect_url ) , " connect://%s " , host_port ) ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
// Make sure we aren't already connected?
if ( ! m_gdb_comm . IsConnected ( ) )
2010-06-08 16:52:24 +00:00
{
2012-02-25 01:07:38 +00:00
error = StartDebugserverProcess ( host_port , launch_info ) ;
2010-06-08 16:52:24 +00:00
if ( error . Fail ( ) )
2011-08-09 05:20:29 +00:00
{
2011-08-09 18:56:45 +00:00
if ( log )
log - > Printf ( " failed to start debugserver process: %s " , error . AsCString ( ) ) ;
2010-06-08 16:52:24 +00:00
return error ;
2011-08-09 05:20:29 +00:00
}
2010-06-08 16:52:24 +00:00
2011-02-04 01:58:07 +00:00
error = ConnectToDebugserver ( connect_url ) ;
2011-02-24 22:24:29 +00:00
}
if ( error . Success ( ) )
{
lldb_utility : : PseudoTerminal pty ;
const bool disable_stdio = ( launch_flags & eLaunchFlagDisableSTDIO ) ! = 0 ;
2011-03-02 21:34:46 +00:00
// If the debugserver is local and we aren't disabling STDIO, lets use
// a pseudo terminal to instead of relying on the 'O' packets for stdio
// since 'O' packets can really slow down debugging if the inferior
// does a lot of output.
2011-06-24 22:32:10 +00:00
PlatformSP platform_sp ( m_target . GetPlatform ( ) ) ;
if ( platform_sp & & platform_sp - > IsHost ( ) & & ! disable_stdio )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
const char * slave_name = NULL ;
if ( stdin_path = = NULL | | stdout_path = = NULL | | stderr_path = = NULL )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
if ( pty . OpenFirstAvailableMaster ( O_RDWR | O_NOCTTY , NULL , 0 ) )
slave_name = pty . GetSlaveName ( NULL , 0 ) ;
2010-06-08 16:52:24 +00:00
}
2011-02-24 22:24:29 +00:00
if ( stdin_path = = NULL )
stdin_path = slave_name ;
if ( stdout_path = = NULL )
stdout_path = slave_name ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
if ( stderr_path = = NULL )
stderr_path = slave_name ;
}
2011-03-02 21:34:46 +00:00
// Set STDIN to /dev/null if we want STDIO disabled or if either
// STDOUT or STDERR have been set to something and STDIN hasn't
if ( disable_stdio | | ( stdin_path = = NULL & & ( stdout_path | | stderr_path ) ) )
2011-02-24 22:24:29 +00:00
stdin_path = " /dev/null " ;
2011-03-02 21:34:46 +00:00
// Set STDOUT to /dev/null if we want STDIO disabled or if either
// STDIN or STDERR have been set to something and STDOUT hasn't
if ( disable_stdio | | ( stdout_path = = NULL & & ( stdin_path | | stderr_path ) ) )
2011-02-24 22:24:29 +00:00
stdout_path = " /dev/null " ;
2011-03-02 21:34:46 +00:00
// Set STDERR to /dev/null if we want STDIO disabled or if either
// STDIN or STDOUT have been set to something and STDERR hasn't
if ( disable_stdio | | ( stderr_path = = NULL & & ( stdin_path | | stdout_path ) ) )
2011-02-24 22:24:29 +00:00
stderr_path = " /dev/null " ;
if ( stdin_path )
m_gdb_comm . SetSTDIN ( stdin_path ) ;
if ( stdout_path )
m_gdb_comm . SetSTDOUT ( stdout_path ) ;
if ( stderr_path )
m_gdb_comm . SetSTDERR ( stderr_path ) ;
m_gdb_comm . SetDisableASLR ( launch_flags & eLaunchFlagDisableASLR ) ;
2011-05-08 04:53:50 +00:00
m_gdb_comm . SendLaunchArchPacket ( m_target . GetArchitecture ( ) . GetArchitectureName ( ) ) ;
2011-02-24 22:24:29 +00:00
if ( working_dir & & working_dir [ 0 ] )
{
m_gdb_comm . SetWorkingDir ( working_dir ) ;
}
// Send the environment and the program + arguments after we connect
2011-11-03 21:22:33 +00:00
const Args & environment = launch_info . GetEnvironmentEntries ( ) ;
if ( environment . GetArgumentCount ( ) )
2011-02-24 22:24:29 +00:00
{
2011-11-03 21:22:33 +00:00
size_t num_environment_entries = environment . GetArgumentCount ( ) ;
for ( size_t i = 0 ; i < num_environment_entries ; + + i )
2010-08-03 00:35:52 +00:00
{
2011-11-03 21:22:33 +00:00
const char * env_entry = environment . GetArgumentAtIndex ( i ) ;
if ( env_entry = = NULL | | m_gdb_comm . SendEnvironmentPacket ( env_entry ) ! = 0 )
2011-02-24 22:24:29 +00:00
break ;
2010-08-03 00:35:52 +00:00
}
2011-02-24 22:24:29 +00:00
}
2010-08-03 00:35:52 +00:00
2011-03-10 02:26:48 +00:00
const uint32_t old_packet_timeout = m_gdb_comm . SetPacketTimeout ( 10 ) ;
2011-11-03 21:22:33 +00:00
int arg_packet_err = m_gdb_comm . SendArgumentsPacket ( launch_info . GetArguments ( ) . GetConstArgumentVector ( ) ) ;
2011-02-24 22:24:29 +00:00
if ( arg_packet_err = = 0 )
{
std : : string error_str ;
2011-03-10 02:26:48 +00:00
if ( m_gdb_comm . GetLaunchSuccess ( error_str ) )
2010-06-08 16:52:24 +00:00
{
2011-03-10 02:26:48 +00:00
SetID ( m_gdb_comm . GetCurrentProcessID ( ) ) ;
2010-06-08 16:52:24 +00:00
}
else
{
2011-02-24 22:24:29 +00:00
error . SetErrorString ( error_str . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
}
2011-02-24 22:24:29 +00:00
}
else
{
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " 'A' packet returned an error: %i " , arg_packet_err ) ;
2011-02-24 22:24:29 +00:00
}
2011-08-10 22:05:39 +00:00
m_gdb_comm . SetPacketTimeout ( old_packet_timeout ) ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
if ( GetID ( ) = = LLDB_INVALID_PROCESS_ID )
{
2011-08-09 18:56:45 +00:00
if ( log )
log - > Printf ( " failed to connect to debugserver: %s " , error . AsCString ( ) ) ;
2011-02-24 22:24:29 +00:00
KillDebugserverProcess ( ) ;
return error ;
2010-06-08 16:52:24 +00:00
}
2011-06-02 22:22:38 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( " ? " , 1 , m_last_stop_packet , false ) )
2011-02-24 22:24:29 +00:00
{
2011-06-02 22:22:38 +00:00
SetPrivateState ( SetThreadStopInfo ( m_last_stop_packet ) ) ;
2011-02-24 22:24:29 +00:00
if ( ! disable_stdio )
{
if ( pty . GetMasterFileDescriptor ( ) ! = lldb_utility : : PseudoTerminal : : invalid_fd )
2011-11-17 22:14:31 +00:00
SetSTDIOFileDescriptor ( pty . ReleaseMasterFileDescriptor ( ) ) ;
2011-02-24 22:24:29 +00:00
}
}
2010-06-08 16:52:24 +00:00
}
2011-08-09 05:20:29 +00:00
else
{
2011-08-09 18:56:45 +00:00
if ( log )
log - > Printf ( " failed to connect to debugserver: %s " , error . AsCString ( ) ) ;
2011-08-09 05:20:29 +00:00
}
2010-06-08 16:52:24 +00:00
}
else
{
// Set our user ID to an invalid process ID.
SetID ( LLDB_INVALID_PROCESS_ID ) ;
2011-11-03 21:22:33 +00:00
error . SetErrorStringWithFormat ( " failed to get object file from '%s' for arch %s " ,
exe_module - > GetFileSpec ( ) . GetFilename ( ) . AsCString ( ) ,
exe_module - > GetArchitecture ( ) . GetArchitectureName ( ) ) ;
2010-06-08 16:52:24 +00:00
}
return error ;
2010-09-30 21:49:03 +00:00
2010-06-08 16:52:24 +00:00
}
Error
2011-02-04 01:58:07 +00:00
ProcessGDBRemote : : ConnectToDebugserver ( const char * connect_url )
2010-06-08 16:52:24 +00:00
{
Error error ;
// Sleep and wait a bit for debugserver to start to listen...
2013-04-18 22:45:39 +00:00
std : : unique_ptr < ConnectionFileDescriptor > conn_ap ( new ConnectionFileDescriptor ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( conn_ap . get ( ) )
{
const uint32_t max_retry_count = 50 ;
uint32_t retry_count = 0 ;
while ( ! m_gdb_comm . IsConnected ( ) )
{
2011-02-04 01:58:07 +00:00
if ( conn_ap - > Connect ( connect_url , & error ) = = eConnectionStatusSuccess )
2010-06-08 16:52:24 +00:00
{
m_gdb_comm . SetConnection ( conn_ap . release ( ) ) ;
break ;
}
retry_count + + ;
if ( retry_count > = max_retry_count )
break ;
usleep ( 100000 ) ;
}
}
if ( ! m_gdb_comm . IsConnected ( ) )
{
if ( error . Success ( ) )
error . SetErrorString ( " not connected to remote gdb server " ) ;
return error ;
}
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-30 18:16:51 +00:00
// We always seem to be able to open a connection to a local port
// so we need to make sure we can then send data to it. If we can't
// then we aren't actually connected to anything, so try and do the
// handshake with the remote GDB server and make sure that goes
// alright.
if ( ! m_gdb_comm . HandshakeWithServer ( NULL ) )
2010-06-08 16:52:24 +00:00
{
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-30 18:16:51 +00:00
m_gdb_comm . Disconnect ( ) ;
if ( error . Success ( ) )
error . SetErrorString ( " not connected to remote gdb server " ) ;
return error ;
2010-06-08 16:52:24 +00:00
}
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-30 18:16:51 +00:00
m_gdb_comm . ResetDiscoverableSettings ( ) ;
m_gdb_comm . QueryNoAckModeSupported ( ) ;
m_gdb_comm . GetThreadSuffixSupported ( ) ;
2012-04-10 03:22:03 +00:00
m_gdb_comm . GetListThreadsInStopReplySupported ( ) ;
Many improvements to the Platform base class and subclasses. The base Platform
class now implements the Host functionality for a lot of things that make
sense by default so that subclasses can check:
int
PlatformSubclass::Foo ()
{
if (IsHost())
return Platform::Foo (); // Let the platform base class do the host specific stuff
// Platform subclass specific code...
int result = ...
return result;
}
Added new functions to the platform:
virtual const char *Platform::GetUserName (uint32_t uid);
virtual const char *Platform::GetGroupName (uint32_t gid);
The user and group names are cached locally so that remote platforms can avoid
sending packets multiple times to resolve this information.
Added the parent process ID to the ProcessInfo class.
Added a new ProcessInfoMatch class which helps us to match processes up
and changed the Host layer over to using this new class. The new class allows
us to search for processs:
1 - by name (equal to, starts with, ends with, contains, and regex)
2 - by pid
3 - And further check for parent pid == value, uid == value, gid == value,
euid == value, egid == value, arch == value, parent == value.
This is all hookup up to the "platform process list" command which required
adding dumping routines to dump process information. If the Host class
implements the process lookup routines, you can now lists processes on
your local machine:
machine1.foo.com % lldb
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
94727 244 username usergroup username usergroup x86_64-apple-darwin Xcode
92742 92710 username usergroup username usergroup i386-apple-darwin debugserver
This of course also works remotely with the lldb-platform:
machine1.foo.com % lldb-platform --listen 1234
machine2.foo.com % lldb
(lldb) platform create remote-macosx
Platform: remote-macosx
Connected: no
(lldb) platform connect connect://localhost:1444
Platform: remote-macosx
Triple: x86_64-apple-darwin
OS Version: 10.6.7 (10J869)
Kernel: Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386
Hostname: machine1.foo.com
Connected: yes
(lldb) platform process list
PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE NAME
====== ====== ========== ========== ========== ========== ======================== ============================
99556 244 username usergroup username usergroup x86_64-apple-darwin trustevaluation
99548 65539 username usergroup username usergroup x86_64-apple-darwin lldb
99538 1 username usergroup username usergroup x86_64-apple-darwin FileMerge
94943 1 username usergroup username usergroup x86_64-apple-darwin mdworker
94852 244 username usergroup username usergroup x86_64-apple-darwin Safari
The lldb-platform implements everything with the Host:: layer, so this should
"just work" for linux. I will probably be adding more stuff to the Host layer
for launching processes and attaching to processes so that this support should
eventually just work as well.
Modified the target to be able to be created with an architecture that differs
from the main executable. This is needed for iOS debugging since we can have
an "armv6" binary which can run on an "armv7" machine, so we want to be able
to do:
% lldb
(lldb) platform create remote-ios
(lldb) file --arch armv7 a.out
Where "a.out" is an armv6 executable. The platform then can correctly decide
to open all "armv7" images for all dependent shared libraries.
Modified the disassembly to show the current PC value. Example output:
(lldb) disassemble --frame
a.out`main:
0x1eb7: pushl %ebp
0x1eb8: movl %esp, %ebp
0x1eba: pushl %ebx
0x1ebb: subl $20, %esp
0x1ebe: calll 0x1ec3 ; main + 12 at test.c:18
0x1ec3: popl %ebx
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
0x1edb: leal 213(%ebx), %eax
0x1ee1: movl %eax, (%esp)
0x1ee4: calll 0x1f1e ; puts
0x1ee9: calll 0x1f0c ; getchar
0x1eee: movl $20, (%esp)
0x1ef5: calll 0x1e6a ; sleep_loop at test.c:6
0x1efa: movl $12, %eax
0x1eff: addl $20, %esp
0x1f02: popl %ebx
0x1f03: leave
0x1f04: ret
This can be handy when dealing with the new --line options that was recently
added:
(lldb) disassemble --line
a.out`main + 13 at test.c:19
18 {
-> 19 printf("Process: %i\n\n", getpid());
20 puts("Press any key to continue..."); getchar();
-> 0x1ec4: calll 0x1f12 ; getpid
0x1ec9: movl %eax, 4(%esp)
0x1ecd: leal 199(%ebx), %eax
0x1ed3: movl %eax, (%esp)
0x1ed6: calll 0x1f18 ; printf
Modified the ModuleList to have a lookup based solely on a UUID. Since the
UUID is typically the MD5 checksum of a binary image, there is no need
to give the path and architecture when searching for a pre-existing
image in an image list.
Now that we support remote debugging a bit better, our lldb_private::Module
needs to be able to track what the original path for file was as the platform
knows it, as well as where the file is locally. The module has the two
following functions to retrieve both paths:
const FileSpec &Module::GetFileSpec () const;
const FileSpec &Module::GetPlatformFileSpec () const;
llvm-svn: 128563
2011-03-30 18:16:51 +00:00
m_gdb_comm . GetHostInfo ( ) ;
m_gdb_comm . GetVContSupported ( ' c ' ) ;
2012-07-20 21:37:13 +00:00
m_gdb_comm . GetVAttachOrWaitSupported ( ) ;
2012-07-02 05:40:07 +00:00
size_t num_cmds = GetExtraStartupCommands ( ) . GetArgumentCount ( ) ;
for ( size_t idx = 0 ; idx < num_cmds ; idx + + )
{
StringExtractorGDBRemote response ;
m_gdb_comm . SendPacketAndWaitForResponse ( GetExtraStartupCommands ( ) . GetArgumentAtIndex ( idx ) , response , false ) ;
}
2010-06-08 16:52:24 +00:00
return error ;
}
void
ProcessGDBRemote : : DidLaunchOrAttach ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2011-02-05 02:25:06 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::DidLaunch() " ) ;
2011-02-16 04:46:07 +00:00
if ( GetID ( ) ! = LLDB_INVALID_PROCESS_ID )
2010-06-08 16:52:24 +00:00
{
m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS ;
2011-01-29 07:10:55 +00:00
BuildDynamicRegisterInfo ( false ) ;
2010-11-18 05:57:03 +00:00
2010-06-08 16:52:24 +00:00
// See if the GDB server supports the qHostInfo information
2011-03-23 00:09:55 +00:00
2012-12-19 02:54:03 +00:00
ArchSpec gdb_remote_arch = m_gdb_comm . GetHostArchitecture ( ) ;
// See if the GDB server supports the qProcessInfo packet, if so
// prefer that over the Host information as it will be more specific
// to our process.
if ( m_gdb_comm . GetProcessArchitecture ( ) . IsValid ( ) )
gdb_remote_arch = m_gdb_comm . GetProcessArchitecture ( ) ;
2011-03-23 00:09:55 +00:00
if ( gdb_remote_arch . IsValid ( ) )
2010-06-08 16:52:24 +00:00
{
2011-03-23 00:09:55 +00:00
ArchSpec & target_arch = GetTarget ( ) . GetArchitecture ( ) ;
if ( target_arch . IsValid ( ) )
{
// If the remote host is ARM and we have apple as the vendor, then
// ARM executables and shared libraries can have mixed ARM architectures.
// You can have an armv6 executable, and if the host is armv7, then the
// system will load the best possible architecture for all shared libraries
// it has, so we really need to take the remote host architecture as our
// defacto architecture in this case.
if ( gdb_remote_arch . GetMachine ( ) = = llvm : : Triple : : arm & &
gdb_remote_arch . GetTriple ( ) . getVendor ( ) = = llvm : : Triple : : Apple )
{
target_arch = gdb_remote_arch ;
}
else
{
// Fill in what is missing in the triple
const llvm : : Triple & remote_triple = gdb_remote_arch . GetTriple ( ) ;
llvm : : Triple & target_triple = target_arch . GetTriple ( ) ;
2011-05-15 01:25:55 +00:00
if ( target_triple . getVendorName ( ) . size ( ) = = 0 )
{
2011-03-23 00:09:55 +00:00
target_triple . setVendor ( remote_triple . getVendor ( ) ) ;
2011-05-15 01:25:55 +00:00
if ( target_triple . getOSName ( ) . size ( ) = = 0 )
{
target_triple . setOS ( remote_triple . getOS ( ) ) ;
2011-03-23 00:09:55 +00:00
2011-05-15 01:25:55 +00:00
if ( target_triple . getEnvironmentName ( ) . size ( ) = = 0 )
target_triple . setEnvironment ( remote_triple . getEnvironment ( ) ) ;
}
}
2011-03-23 00:09:55 +00:00
}
}
else
{
// The target doesn't have a valid architecture yet, set it from
// the architecture we got from the remote GDB server
target_arch = gdb_remote_arch ;
}
2010-06-08 16:52:24 +00:00
}
}
}
void
ProcessGDBRemote : : DidLaunch ( )
{
DidLaunchOrAttach ( ) ;
}
Error
2010-07-09 20:39:50 +00:00
ProcessGDBRemote : : DoAttachToProcessWithID ( lldb : : pid_t attach_pid )
2012-02-25 01:07:38 +00:00
{
ProcessAttachInfo attach_info ;
return DoAttachToProcessWithID ( attach_pid , attach_info ) ;
}
Error
ProcessGDBRemote : : DoAttachToProcessWithID ( lldb : : pid_t attach_pid , const ProcessAttachInfo & attach_info )
2010-06-08 16:52:24 +00:00
{
Error error ;
// Clear out and clean up from any current state
Clear ( ) ;
if ( attach_pid ! = LLDB_INVALID_PROCESS_ID )
{
2011-02-24 22:24:29 +00:00
// Make sure we aren't already connected?
if ( ! m_gdb_comm . IsConnected ( ) )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
char host_port [ 128 ] ;
snprintf ( host_port , sizeof ( host_port ) , " localhost:%u " , get_random_port ( ) ) ;
char connect_url [ 128 ] ;
snprintf ( connect_url , sizeof ( connect_url ) , " connect://%s " , host_port ) ;
2012-02-25 01:07:38 +00:00
error = StartDebugserverProcess ( host_port , attach_info ) ;
2011-02-24 22:24:29 +00:00
if ( error . Fail ( ) )
{
const char * error_string = error . AsCString ( ) ;
if ( error_string = = NULL )
error_string = " unable to launch " DEBUGSERVER_BASENAME ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
SetExitStatus ( - 1 , error_string ) ;
}
else
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
error = ConnectToDebugserver ( connect_url ) ;
2010-06-08 16:52:24 +00:00
}
}
2011-02-24 22:24:29 +00:00
if ( error . Success ( ) )
{
char packet [ 64 ] ;
2012-11-29 21:49:15 +00:00
const int packet_len = : : snprintf ( packet , sizeof ( packet ) , " vAttach;% " PRIx64 , attach_pid ) ;
2011-11-19 02:11:30 +00:00
SetID ( attach_pid ) ;
2011-02-24 22:24:29 +00:00
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncContinue , new EventDataBytes ( packet , packet_len ) ) ;
}
2010-06-08 16:52:24 +00:00
}
return error ;
}
size_t
ProcessGDBRemote : : AttachInputReaderCallback
(
void * baton ,
InputReader * reader ,
lldb : : InputReaderAction notification ,
const char * bytes ,
size_t bytes_len
)
{
if ( notification = = eInputReaderGotToken )
{
ProcessGDBRemote * gdb_process = ( ProcessGDBRemote * ) baton ;
if ( gdb_process - > m_waiting_for_attach )
gdb_process - > m_waiting_for_attach = false ;
reader - > SetIsDone ( true ) ;
return 1 ;
}
return 0 ;
}
Error
2012-02-25 01:07:38 +00:00
ProcessGDBRemote : : DoAttachToProcessWithName ( const char * process_name , bool wait_for_launch , const ProcessAttachInfo & attach_info )
2010-06-08 16:52:24 +00:00
{
Error error ;
// Clear out and clean up from any current state
Clear ( ) ;
if ( process_name & & process_name [ 0 ] )
{
2011-02-24 22:24:29 +00:00
// Make sure we aren't already connected?
if ( ! m_gdb_comm . IsConnected ( ) )
{
char host_port [ 128 ] ;
snprintf ( host_port , sizeof ( host_port ) , " localhost:%u " , get_random_port ( ) ) ;
char connect_url [ 128 ] ;
snprintf ( connect_url , sizeof ( connect_url ) , " connect://%s " , host_port ) ;
2010-06-08 16:52:24 +00:00
2012-02-25 01:07:38 +00:00
error = StartDebugserverProcess ( host_port , attach_info ) ;
2011-02-24 22:24:29 +00:00
if ( error . Fail ( ) )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
const char * error_string = error . AsCString ( ) ;
if ( error_string = = NULL )
error_string = " unable to launch " DEBUGSERVER_BASENAME ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
SetExitStatus ( - 1 , error_string ) ;
}
else
{
error = ConnectToDebugserver ( connect_url ) ;
2010-06-08 16:52:24 +00:00
}
}
2011-02-24 22:24:29 +00:00
if ( error . Success ( ) )
{
StreamString packet ;
if ( wait_for_launch )
2012-07-20 21:37:13 +00:00
{
if ( ! m_gdb_comm . GetVAttachOrWaitSupported ( ) )
{
packet . PutCString ( " vAttachWait " ) ;
}
else
{
if ( attach_info . GetIgnoreExisting ( ) )
packet . PutCString ( " vAttachWait " ) ;
else
packet . PutCString ( " vAttachOrWait " ) ;
}
}
2011-02-24 22:24:29 +00:00
else
packet . PutCString ( " vAttachName " ) ;
packet . PutChar ( ' ; ' ) ;
packet . PutBytesAsRawHex8 ( process_name , strlen ( process_name ) , lldb : : endian : : InlHostByteOrder ( ) , lldb : : endian : : InlHostByteOrder ( ) ) ;
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncContinue , new EventDataBytes ( packet . GetData ( ) , packet . GetSize ( ) ) ) ;
}
2010-06-08 16:52:24 +00:00
}
return error ;
}
void
ProcessGDBRemote : : DidAttach ( )
{
2011-02-04 01:58:07 +00:00
DidLaunchOrAttach ( ) ;
2010-06-08 16:52:24 +00:00
}
2012-12-05 00:16:59 +00:00
void
ProcessGDBRemote : : DoDidExec ( )
{
// The process exec'ed itself, figure out the dynamic loader, etc...
BuildDynamicRegisterInfo ( true ) ;
m_gdb_comm . ResetDiscoverableSettings ( ) ;
DidLaunchOrAttach ( ) ;
}
2010-06-08 16:52:24 +00:00
Error
ProcessGDBRemote : : WillResume ( )
{
2011-02-12 06:28:37 +00:00
m_continue_c_tids . clear ( ) ;
m_continue_C_tids . clear ( ) ;
m_continue_s_tids . clear ( ) ;
m_continue_S_tids . clear ( ) ;
2010-06-08 16:52:24 +00:00
return Error ( ) ;
}
Error
ProcessGDBRemote : : DoResume ( )
{
2010-11-17 02:32:00 +00:00
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2011-02-05 02:25:06 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::Resume() " ) ;
2010-12-03 06:02:24 +00:00
Listener listener ( " gdb-remote.resume-packet-sent " ) ;
if ( listener . StartListeningForEvents ( & m_gdb_comm , GDBRemoteCommunication : : eBroadcastBitRunPacketSent ) )
{
2012-04-12 18:49:31 +00:00
listener . StartListeningForEvents ( & m_async_broadcaster , ProcessGDBRemote : : eBroadcastBitAsyncThreadDidExit ) ;
2013-04-20 00:27:58 +00:00
const size_t num_threads = GetThreadList ( ) . GetSize ( ) ;
2011-02-12 06:28:37 +00:00
StreamString continue_packet ;
bool continue_packet_error = false ;
if ( m_gdb_comm . HasAnyVContSupport ( ) )
{
2013-04-20 00:27:58 +00:00
if ( m_continue_c_tids . size ( ) = = num_threads )
2011-02-12 06:28:37 +00:00
{
2013-04-20 00:27:58 +00:00
// All threads are continuing, just send a "c" packet
continue_packet . PutCString ( " c " ) ;
2011-02-12 06:28:37 +00:00
}
2013-04-20 00:27:58 +00:00
else
2011-02-12 06:28:37 +00:00
{
2013-04-20 00:27:58 +00:00
continue_packet . PutCString ( " vCont " ) ;
if ( ! m_continue_c_tids . empty ( ) )
{
if ( m_gdb_comm . GetVContSupported ( ' c ' ) )
{
for ( tid_collection : : const_iterator t_pos = m_continue_c_tids . begin ( ) , t_end = m_continue_c_tids . end ( ) ; t_pos ! = t_end ; + + t_pos )
continue_packet . Printf ( " ;c:%4.4 " PRIx64 , * t_pos ) ;
}
else
continue_packet_error = true ;
}
if ( ! continue_packet_error & & ! m_continue_C_tids . empty ( ) )
2011-02-12 06:28:37 +00:00
{
2013-04-20 00:27:58 +00:00
if ( m_gdb_comm . GetVContSupported ( ' C ' ) )
{
for ( tid_sig_collection : : const_iterator s_pos = m_continue_C_tids . begin ( ) , s_end = m_continue_C_tids . end ( ) ; s_pos ! = s_end ; + + s_pos )
continue_packet . Printf ( " ;C%2.2x:%4.4 " PRIx64 , s_pos - > second , s_pos - > first ) ;
}
else
continue_packet_error = true ;
2011-02-12 06:28:37 +00:00
}
2013-04-20 00:27:58 +00:00
if ( ! continue_packet_error & & ! m_continue_s_tids . empty ( ) )
2011-02-12 06:28:37 +00:00
{
2013-04-20 00:27:58 +00:00
if ( m_gdb_comm . GetVContSupported ( ' s ' ) )
{
for ( tid_collection : : const_iterator t_pos = m_continue_s_tids . begin ( ) , t_end = m_continue_s_tids . end ( ) ; t_pos ! = t_end ; + + t_pos )
continue_packet . Printf ( " ;s:%4.4 " PRIx64 , * t_pos ) ;
}
else
continue_packet_error = true ;
2011-02-12 06:28:37 +00:00
}
2013-04-20 00:27:58 +00:00
if ( ! continue_packet_error & & ! m_continue_S_tids . empty ( ) )
2011-02-12 06:28:37 +00:00
{
2013-04-20 00:27:58 +00:00
if ( m_gdb_comm . GetVContSupported ( ' S ' ) )
{
for ( tid_sig_collection : : const_iterator s_pos = m_continue_S_tids . begin ( ) , s_end = m_continue_S_tids . end ( ) ; s_pos ! = s_end ; + + s_pos )
continue_packet . Printf ( " ;S%2.2x:%4.4 " PRIx64 , s_pos - > second , s_pos - > first ) ;
}
else
continue_packet_error = true ;
2011-02-12 06:28:37 +00:00
}
2013-04-20 00:27:58 +00:00
if ( continue_packet_error )
continue_packet . GetString ( ) . clear ( ) ;
2011-02-12 06:28:37 +00:00
}
}
else
continue_packet_error = true ;
if ( continue_packet_error )
{
// Either no vCont support, or we tried to use part of the vCont
// packet that wasn't supported by the remote GDB server.
// We need to try and make a simple packet that can do our continue
const size_t num_continue_c_tids = m_continue_c_tids . size ( ) ;
const size_t num_continue_C_tids = m_continue_C_tids . size ( ) ;
const size_t num_continue_s_tids = m_continue_s_tids . size ( ) ;
const size_t num_continue_S_tids = m_continue_S_tids . size ( ) ;
if ( num_continue_c_tids > 0 )
{
if ( num_continue_c_tids = = num_threads )
{
// All threads are resuming...
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( - 1 ) ;
2011-06-24 03:21:43 +00:00
continue_packet . PutChar ( ' c ' ) ;
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
}
else if ( num_continue_c_tids = = 1 & &
num_continue_C_tids = = 0 & &
num_continue_s_tids = = 0 & &
num_continue_S_tids = = 0 )
{
// Only one thread is continuing
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( m_continue_c_tids . front ( ) ) ;
2011-02-12 06:28:37 +00:00
continue_packet . PutChar ( ' c ' ) ;
2011-06-24 03:21:43 +00:00
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
}
}
2011-06-24 03:21:43 +00:00
if ( continue_packet_error & & num_continue_C_tids > 0 )
2011-02-12 06:28:37 +00:00
{
2011-06-24 03:21:43 +00:00
if ( ( num_continue_C_tids + num_continue_c_tids ) = = num_threads & &
num_continue_C_tids > 0 & &
num_continue_s_tids = = 0 & &
num_continue_S_tids = = 0 )
2011-02-12 06:28:37 +00:00
{
const int continue_signo = m_continue_C_tids . front ( ) . second ;
2011-06-24 03:21:43 +00:00
// Only one thread is continuing
2011-02-12 06:28:37 +00:00
if ( num_continue_C_tids > 1 )
{
2011-06-24 03:21:43 +00:00
// More that one thread with a signal, yet we don't have
// vCont support and we are being asked to resume each
// thread with a signal, we need to make sure they are
// all the same signal, or we can't issue the continue
// accurately with the current support...
if ( num_continue_C_tids > 1 )
2011-02-12 06:28:37 +00:00
{
2011-06-24 03:21:43 +00:00
continue_packet_error = false ;
for ( size_t i = 1 ; i < m_continue_C_tids . size ( ) ; + + i )
{
if ( m_continue_C_tids [ i ] . second ! = continue_signo )
continue_packet_error = true ;
}
2011-02-12 06:28:37 +00:00
}
2011-06-24 03:21:43 +00:00
if ( ! continue_packet_error )
m_gdb_comm . SetCurrentThreadForRun ( - 1 ) ;
}
else
{
// Set the continue thread ID
continue_packet_error = false ;
m_gdb_comm . SetCurrentThreadForRun ( m_continue_C_tids . front ( ) . first ) ;
2011-02-12 06:28:37 +00:00
}
if ( ! continue_packet_error )
{
// Add threads continuing with the same signo...
continue_packet . Printf ( " C%2.2x " , continue_signo ) ;
}
}
}
2011-06-24 03:21:43 +00:00
if ( continue_packet_error & & num_continue_s_tids > 0 )
2011-02-12 06:28:37 +00:00
{
if ( num_continue_s_tids = = num_threads )
{
// All threads are resuming...
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( - 1 ) ;
2011-06-24 03:21:43 +00:00
continue_packet . PutChar ( ' s ' ) ;
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
}
else if ( num_continue_c_tids = = 0 & &
num_continue_C_tids = = 0 & &
num_continue_s_tids = = 1 & &
num_continue_S_tids = = 0 )
{
// Only one thread is stepping
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( m_continue_s_tids . front ( ) ) ;
2011-02-12 06:28:37 +00:00
continue_packet . PutChar ( ' s ' ) ;
2011-06-24 03:21:43 +00:00
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
}
}
if ( ! continue_packet_error & & num_continue_S_tids > 0 )
{
if ( num_continue_S_tids = = num_threads )
{
const int step_signo = m_continue_S_tids . front ( ) . second ;
// Are all threads trying to step with the same signal?
2011-06-24 03:21:43 +00:00
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
if ( num_continue_S_tids > 1 )
{
for ( size_t i = 1 ; i < num_threads ; + + i )
{
if ( m_continue_S_tids [ i ] . second ! = step_signo )
continue_packet_error = true ;
}
}
if ( ! continue_packet_error )
{
// Add threads stepping with the same signo...
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( - 1 ) ;
2011-02-12 06:28:37 +00:00
continue_packet . Printf ( " S%2.2x " , step_signo ) ;
}
}
else if ( num_continue_c_tids = = 0 & &
num_continue_C_tids = = 0 & &
num_continue_s_tids = = 0 & &
num_continue_S_tids = = 1 )
{
// Only one thread is stepping with signal
2011-04-12 05:54:46 +00:00
m_gdb_comm . SetCurrentThreadForRun ( m_continue_S_tids . front ( ) . first ) ;
2011-02-12 06:28:37 +00:00
continue_packet . Printf ( " S%2.2x " , m_continue_S_tids . front ( ) . second ) ;
2011-06-24 03:21:43 +00:00
continue_packet_error = false ;
2011-02-12 06:28:37 +00:00
}
}
}
if ( continue_packet_error )
{
error . SetErrorString ( " can't make continue packet for this resume " ) ;
}
else
{
EventSP event_sp ;
TimeValue timeout ;
timeout = TimeValue : : Now ( ) ;
timeout . OffsetWithSeconds ( 5 ) ;
2012-04-12 18:49:31 +00:00
if ( ! IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
{
error . SetErrorString ( " Trying to resume but the async thread is dead. " ) ;
if ( log )
log - > Printf ( " ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead. " ) ;
return error ;
}
2011-02-12 06:28:37 +00:00
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncContinue , new EventDataBytes ( continue_packet . GetData ( ) , continue_packet . GetSize ( ) ) ) ;
if ( listener . WaitForEvent ( & timeout , event_sp ) = = false )
2012-04-12 18:49:31 +00:00
{
2011-02-12 06:28:37 +00:00
error . SetErrorString ( " Resume timed out. " ) ;
2012-04-12 18:49:31 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::DoResume: Resume timed out. " ) ;
}
else if ( event_sp - > BroadcasterIs ( & m_async_broadcaster ) )
{
error . SetErrorString ( " Broadcast continue, but the async thread was killed before we got an ack back. " ) ;
if ( log )
log - > Printf ( " ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back. " ) ;
return error ;
}
2011-02-12 06:28:37 +00:00
}
2010-12-03 06:02:24 +00:00
}
2010-11-17 02:32:00 +00:00
return error ;
2010-06-08 16:52:24 +00:00
}
2012-04-10 02:25:43 +00:00
void
ProcessGDBRemote : : ClearThreadIDList ( )
{
2013-05-07 18:35:34 +00:00
Mutex : : Locker locker ( m_thread_list_real . GetMutex ( ) ) ;
2012-04-10 02:25:43 +00:00
m_thread_ids . clear ( ) ;
}
bool
ProcessGDBRemote : : UpdateThreadIDList ( )
{
2013-05-07 18:35:34 +00:00
Mutex : : Locker locker ( m_thread_list_real . GetMutex ( ) ) ;
2012-04-10 02:25:43 +00:00
bool sequence_mutex_unavailable = false ;
m_gdb_comm . GetCurrentThreadIDs ( m_thread_ids , sequence_mutex_unavailable ) ;
if ( sequence_mutex_unavailable )
{
return false ; // We just didn't get the list
}
return true ;
}
2012-04-10 00:18:59 +00:00
bool
2011-08-22 02:49:39 +00:00
ProcessGDBRemote : : UpdateThreadList ( ThreadList & old_thread_list , ThreadList & new_thread_list )
2010-06-08 16:52:24 +00:00
{
// locker will keep a mutex locked until it goes out of scope
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_THREAD ) ) ;
2010-10-27 03:32:59 +00:00
if ( log & & log - > GetMask ( ) . Test ( GDBR_LOG_VERBOSE ) )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (pid = % " PRIu64 " ) " , __FUNCTION__ , GetID ( ) ) ;
2012-04-10 02:25:43 +00:00
size_t num_thread_ids = m_thread_ids . size ( ) ;
// The "m_thread_ids" thread ID list should always be updated after each stop
// reply packet, but in case it isn't, update it here.
if ( num_thread_ids = = 0 )
{
if ( ! UpdateThreadIDList ( ) )
return false ;
num_thread_ids = m_thread_ids . size ( ) ;
}
2010-06-08 16:52:24 +00:00
2013-01-08 22:10:01 +00:00
ThreadList old_thread_list_copy ( old_thread_list ) ;
2011-08-22 02:49:39 +00:00
if ( num_thread_ids > 0 )
2010-06-08 16:52:24 +00:00
{
2011-08-22 02:49:39 +00:00
for ( size_t i = 0 ; i < num_thread_ids ; + + i )
2010-06-08 16:52:24 +00:00
{
2012-04-10 02:25:43 +00:00
tid_t tid = m_thread_ids [ i ] ;
2013-05-01 21:54:04 +00:00
ThreadSP thread_sp ( old_thread_list_copy . RemoveThreadByProtocolID ( tid , false ) ) ;
2011-08-22 02:49:39 +00:00
if ( ! thread_sp )
2012-10-10 18:32:14 +00:00
thread_sp . reset ( new ThreadGDBRemote ( * this , tid ) ) ;
2011-08-22 02:49:39 +00:00
new_thread_list . AddThread ( thread_sp ) ;
2011-05-20 23:38:13 +00:00
}
2010-06-08 16:52:24 +00:00
}
2013-01-08 22:10:01 +00:00
// Whatever that is left in old_thread_list_copy are not
// present in new_thread_list. Remove non-existent threads from internal id table.
size_t old_num_thread_ids = old_thread_list_copy . GetSize ( false ) ;
for ( size_t i = 0 ; i < old_num_thread_ids ; i + + )
{
ThreadSP old_thread_sp ( old_thread_list_copy . GetThreadAtIndex ( i , false ) ) ;
if ( old_thread_sp )
{
2013-05-01 21:54:04 +00:00
lldb : : tid_t old_thread_id = old_thread_sp - > GetProtocolID ( ) ;
2013-01-08 22:10:01 +00:00
m_thread_id_to_index_id_map . erase ( old_thread_id ) ;
}
}
2012-04-10 00:18:59 +00:00
return true ;
2010-06-08 16:52:24 +00:00
}
StateType
ProcessGDBRemote : : SetThreadStopInfo ( StringExtractor & stop_packet )
{
2011-06-02 22:22:38 +00:00
stop_packet . SetFilePos ( 0 ) ;
2010-06-08 16:52:24 +00:00
const char stop_type = stop_packet . GetChar ( ) ;
switch ( stop_type )
{
case ' T ' :
case ' S ' :
{
2011-02-15 00:19:15 +00:00
if ( GetStopID ( ) = = 0 )
{
// Our first stop, make sure we have a process ID, and also make
// sure we know about our registers
if ( GetID ( ) = = LLDB_INVALID_PROCESS_ID )
{
2011-03-10 02:26:48 +00:00
lldb : : pid_t pid = m_gdb_comm . GetCurrentProcessID ( ) ;
2011-02-15 00:19:15 +00:00
if ( pid ! = LLDB_INVALID_PROCESS_ID )
SetID ( pid ) ;
}
BuildDynamicRegisterInfo ( true ) ;
}
2010-06-08 16:52:24 +00:00
// Stop with signal and thread info
const uint8_t signo = stop_packet . GetHexU8 ( ) ;
std : : string name ;
std : : string value ;
std : : string thread_name ;
2011-06-04 01:26:29 +00:00
std : : string reason ;
std : : string description ;
2010-06-08 16:52:24 +00:00
uint32_t exc_type = 0 ;
2010-07-23 16:45:51 +00:00
std : : vector < addr_t > exc_data ;
2010-06-08 16:52:24 +00:00
addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS ;
2011-01-09 21:07:35 +00:00
ThreadSP thread_sp ;
2013-05-01 21:54:04 +00:00
ThreadGDBRemote * gdb_thread = NULL ;
2011-01-09 21:07:35 +00:00
2010-06-08 16:52:24 +00:00
while ( stop_packet . GetNameColonValue ( name , value ) )
{
if ( name . compare ( " metype " ) = = 0 )
{
// exception type in big endian hex
exc_type = Args : : StringToUInt32 ( value . c_str ( ) , 0 , 16 ) ;
}
else if ( name . compare ( " medata " ) = = 0 )
{
// exception data in big endian hex
exc_data . push_back ( Args : : StringToUInt64 ( value . c_str ( ) , 0 , 16 ) ) ;
}
else if ( name . compare ( " thread " ) = = 0 )
{
// thread in big endian hex
2012-04-10 02:25:43 +00:00
lldb : : tid_t tid = Args : : StringToUInt64 ( value . c_str ( ) , LLDB_INVALID_THREAD_ID , 16 ) ;
2013-05-07 18:35:34 +00:00
// m_thread_list_real does have its own mutex, but we need to
// hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
// and the m_thread_list_real.AddThread(...) so it doesn't change on us
Mutex : : Locker locker ( m_thread_list_real . GetMutex ( ) ) ;
thread_sp = m_thread_list_real . FindThreadByProtocolID ( tid , false ) ;
2013-05-01 21:54:04 +00:00
2013-05-07 18:35:34 +00:00
if ( ! thread_sp )
2011-02-15 00:19:15 +00:00
{
// Create the thread if we need to
2012-10-10 18:32:14 +00:00
thread_sp . reset ( new ThreadGDBRemote ( * this , tid ) ) ;
2013-05-07 18:35:34 +00:00
m_thread_list_real . AddThread ( thread_sp ) ;
2011-02-15 00:19:15 +00:00
}
2013-05-07 18:35:34 +00:00
gdb_thread = static_cast < ThreadGDBRemote * > ( thread_sp . get ( ) ) ;
2010-06-08 16:52:24 +00:00
}
2012-04-10 02:25:43 +00:00
else if ( name . compare ( " threads " ) = = 0 )
{
2013-05-07 18:35:34 +00:00
Mutex : : Locker locker ( m_thread_list_real . GetMutex ( ) ) ;
2012-04-10 02:25:43 +00:00
m_thread_ids . clear ( ) ;
2012-04-10 03:22:03 +00:00
// A comma separated list of all threads in the current
// process that includes the thread for this stop reply
// packet
2012-04-10 02:25:43 +00:00
size_t comma_pos ;
lldb : : tid_t tid ;
while ( ( comma_pos = value . find ( ' , ' ) ) ! = std : : string : : npos )
{
value [ comma_pos ] = ' \0 ' ;
// thread in big endian hex
tid = Args : : StringToUInt64 ( value . c_str ( ) , LLDB_INVALID_THREAD_ID , 16 ) ;
if ( tid ! = LLDB_INVALID_THREAD_ID )
m_thread_ids . push_back ( tid ) ;
value . erase ( 0 , comma_pos + 1 ) ;
}
tid = Args : : StringToUInt64 ( value . c_str ( ) , LLDB_INVALID_THREAD_ID , 16 ) ;
if ( tid ! = LLDB_INVALID_THREAD_ID )
m_thread_ids . push_back ( tid ) ;
}
2011-01-08 03:17:57 +00:00
else if ( name . compare ( " hexname " ) = = 0 )
{
StringExtractor name_extractor ;
// Swap "value" over into "name_extractor"
name_extractor . GetStringRef ( ) . swap ( value ) ;
// Now convert the HEX bytes into a string value
name_extractor . GetHexByteString ( value ) ;
thread_name . swap ( value ) ;
}
2010-06-08 16:52:24 +00:00
else if ( name . compare ( " name " ) = = 0 )
{
thread_name . swap ( value ) ;
}
2010-09-09 06:32:46 +00:00
else if ( name . compare ( " qaddr " ) = = 0 )
2010-06-08 16:52:24 +00:00
{
thread_dispatch_qaddr = Args : : StringToUInt64 ( value . c_str ( ) , 0 , 16 ) ;
}
2011-06-04 01:26:29 +00:00
else if ( name . compare ( " reason " ) = = 0 )
{
reason . swap ( value ) ;
}
else if ( name . compare ( " description " ) = = 0 )
{
StringExtractor desc_extractor ;
// Swap "value" over into "name_extractor"
desc_extractor . GetStringRef ( ) . swap ( value ) ;
// Now convert the HEX bytes into a string value
desc_extractor . GetHexByteString ( thread_name ) ;
}
2011-01-09 21:07:35 +00:00
else if ( name . size ( ) = = 2 & & : : isxdigit ( name [ 0 ] ) & & : : isxdigit ( name [ 1 ] ) )
{
// We have a register number that contains an expedited
// register value. Lets supply this register to our thread
// so it won't have to go and read it.
2013-05-01 21:54:04 +00:00
if ( gdb_thread )
2011-01-09 21:07:35 +00:00
{
uint32_t reg = Args : : StringToUInt32 ( name . c_str ( ) , UINT32_MAX , 16 ) ;
if ( reg ! = UINT32_MAX )
{
StringExtractor reg_value_extractor ;
// Swap "value" over into "reg_value_extractor"
reg_value_extractor . GetStringRef ( ) . swap ( value ) ;
2013-05-01 21:54:04 +00:00
if ( ! gdb_thread - > PrivateSetRegisterValue ( reg , reg_value_extractor ) )
2011-02-15 00:19:15 +00:00
{
Host : : SetCrashDescriptionWithFormat ( " Setting thread register '%s' (decoded to %u (0x%x)) with value '%s' for stop packet: '%s' " ,
name . c_str ( ) ,
reg ,
reg ,
reg_value_extractor . GetStringRef ( ) . c_str ( ) ,
stop_packet . GetStringRef ( ) . c_str ( ) ) ;
}
2011-01-09 21:07:35 +00:00
}
}
}
2010-06-08 16:52:24 +00:00
}
if ( thread_sp )
{
2013-05-07 18:35:34 +00:00
// Clear the stop info just in case we don't set it to anything
thread_sp - > SetStopInfo ( StopInfoSP ( ) ) ;
2010-06-08 16:52:24 +00:00
gdb_thread - > SetThreadDispatchQAddr ( thread_dispatch_qaddr ) ;
2011-01-28 02:23:12 +00:00
gdb_thread - > SetName ( thread_name . empty ( ) ? NULL : thread_name . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( exc_type ! = 0 )
{
2011-01-25 23:55:37 +00:00
const size_t exc_data_size = exc_data . size ( ) ;
2010-08-04 01:40:35 +00:00
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfoMachException : : CreateStopReasonWithMachException ( * thread_sp ,
exc_type ,
exc_data_size ,
exc_data_size > = 1 ? exc_data [ 0 ] : 0 ,
exc_data_size > = 2 ? exc_data [ 1 ] : 0 ,
exc_data_size > = 3 ? exc_data [ 2 ] : 0 ) ) ;
2010-06-08 16:52:24 +00:00
}
2011-06-04 01:26:29 +00:00
else
2010-06-08 16:52:24 +00:00
{
2011-06-04 01:26:29 +00:00
bool handled = false ;
if ( ! reason . empty ( ) )
{
if ( reason . compare ( " trace " ) = = 0 )
{
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonToTrace ( * thread_sp ) ) ;
2011-06-04 01:26:29 +00:00
handled = true ;
}
else if ( reason . compare ( " breakpoint " ) = = 0 )
{
2013-05-01 21:54:04 +00:00
addr_t pc = thread_sp - > GetRegisterContext ( ) - > GetPC ( ) ;
lldb : : BreakpointSiteSP bp_site_sp = thread_sp - > GetProcess ( ) - > GetBreakpointSiteList ( ) . FindByAddress ( pc ) ;
2011-06-04 01:26:29 +00:00
if ( bp_site_sp )
{
// If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
// we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
// will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
2012-07-11 21:41:19 +00:00
handled = true ;
2013-05-01 21:54:04 +00:00
if ( bp_site_sp - > ValidForThisThread ( thread_sp . get ( ) ) )
2011-06-04 01:26:29 +00:00
{
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithBreakpointSiteID ( * thread_sp , bp_site_sp - > GetID ( ) ) ) ;
2012-07-11 21:41:19 +00:00
}
else
{
StopInfoSP invalid_stop_info_sp ;
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( invalid_stop_info_sp ) ;
2011-06-04 01:26:29 +00:00
}
}
}
else if ( reason . compare ( " trap " ) = = 0 )
{
// Let the trap just use the standard signal stop reason below...
}
else if ( reason . compare ( " watchpoint " ) = = 0 )
{
break_id_t watch_id = LLDB_INVALID_WATCH_ID ;
// TODO: locate the watchpoint somehow...
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithWatchpointID ( * thread_sp , watch_id ) ) ;
2011-06-04 01:26:29 +00:00
handled = true ;
}
else if ( reason . compare ( " exception " ) = = 0 )
{
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithException ( * thread_sp , description . c_str ( ) ) ) ;
2011-06-04 01:26:29 +00:00
handled = true ;
}
}
if ( signo )
{
if ( signo = = SIGTRAP )
{
// Currently we are going to assume SIGTRAP means we are either
// hitting a breakpoint or hardware single stepping.
2012-07-11 21:41:19 +00:00
handled = true ;
2013-05-01 21:54:04 +00:00
addr_t pc = thread_sp - > GetRegisterContext ( ) - > GetPC ( ) ;
lldb : : BreakpointSiteSP bp_site_sp = thread_sp - > GetProcess ( ) - > GetBreakpointSiteList ( ) . FindByAddress ( pc ) ;
2012-07-11 21:41:19 +00:00
2011-06-04 01:26:29 +00:00
if ( bp_site_sp )
{
// If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
// we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
// will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
2013-05-01 21:54:04 +00:00
if ( bp_site_sp - > ValidForThisThread ( thread_sp . get ( ) ) )
2011-06-04 01:26:29 +00:00
{
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithBreakpointSiteID ( * thread_sp , bp_site_sp - > GetID ( ) ) ) ;
2012-07-11 21:41:19 +00:00
}
else
{
StopInfoSP invalid_stop_info_sp ;
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( invalid_stop_info_sp ) ;
2011-06-04 01:26:29 +00:00
}
}
2012-07-11 21:41:19 +00:00
else
2011-06-04 01:26:29 +00:00
{
2012-10-27 02:52:04 +00:00
// If we were stepping then assume the stop was the result of the trace. If we were
// not stepping then report the SIGTRAP.
// FIXME: We are still missing the case where we single step over a trap instruction.
2013-05-01 21:54:04 +00:00
if ( thread_sp - > GetTemporaryResumeState ( ) = = eStateStepping )
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonToTrace ( * thread_sp ) ) ;
2012-10-27 02:52:04 +00:00
else
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithSignal ( * thread_sp , signo ) ) ;
2011-06-04 01:26:29 +00:00
}
}
if ( ! handled )
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithSignal ( * thread_sp , signo ) ) ;
2013-04-25 01:33:46 +00:00
}
2011-06-04 01:26:29 +00:00
if ( ! description . empty ( ) )
{
2013-05-01 21:54:04 +00:00
lldb : : StopInfoSP stop_info_sp ( thread_sp - > GetStopInfo ( ) ) ;
2011-06-04 01:26:29 +00:00
if ( stop_info_sp )
{
stop_info_sp - > SetDescription ( description . c_str ( ) ) ;
2011-08-10 02:10:13 +00:00
}
2011-06-04 01:26:29 +00:00
else
{
2013-05-01 21:54:04 +00:00
thread_sp - > SetStopInfo ( StopInfo : : CreateStopReasonWithException ( * thread_sp , description . c_str ( ) ) ) ;
2011-06-04 01:26:29 +00:00
}
}
}
2010-06-08 16:52:24 +00:00
}
return eStateStopped ;
}
break ;
case ' W ' :
// process exited
return eStateExited ;
default :
break ;
}
return eStateInvalid ;
}
void
ProcessGDBRemote : : RefreshStateAfterStop ( )
{
2013-05-07 18:35:34 +00:00
Mutex : : Locker locker ( m_thread_list_real . GetMutex ( ) ) ;
2012-04-10 02:25:43 +00:00
m_thread_ids . clear ( ) ;
// Set the thread stop info. It might have a "threads" key whose value is
// a list of all thread IDs in the current process, so m_thread_ids might
// get set.
SetThreadStopInfo ( m_last_stop_packet ) ;
// Check to see if SetThreadStopInfo() filled in m_thread_ids?
if ( m_thread_ids . empty ( ) )
{
// No, we need to fetch the thread list manually
UpdateThreadIDList ( ) ;
}
2010-06-08 16:52:24 +00:00
// Let all threads recover from stopping and do any clean up based
// on the previous thread state (if any).
2013-05-07 18:35:34 +00:00
m_thread_list_real . RefreshStateAfterStop ( ) ;
2012-04-10 02:25:43 +00:00
2010-06-08 16:52:24 +00:00
}
Error
2010-11-17 02:32:00 +00:00
ProcessGDBRemote : : DoHalt ( bool & caused_stop )
2010-06-08 16:52:24 +00:00
{
Error error ;
2010-11-17 02:32:00 +00:00
2011-01-22 07:12:45 +00:00
bool timed_out = false ;
Mutex : : Locker locker ;
2011-01-29 07:10:55 +00:00
if ( m_public_state . GetValue ( ) = = eStateAttaching )
2010-11-18 05:57:03 +00:00
{
2011-01-29 07:10:55 +00:00
// We are being asked to halt during an attach. We need to just close
// our file handle and debugserver will go away, and we can be done...
m_gdb_comm . Disconnect ( ) ;
}
else
{
2012-03-29 01:55:41 +00:00
if ( ! m_gdb_comm . SendInterrupt ( locker , 2 , timed_out ) )
2011-01-29 07:10:55 +00:00
{
if ( timed_out )
error . SetErrorString ( " timed out sending interrupt packet " ) ;
else
error . SetErrorString ( " unknown error sending interrupt packet " ) ;
}
2012-03-29 01:55:41 +00:00
caused_stop = m_gdb_comm . GetInterruptWasSent ( ) ;
2010-11-18 05:57:03 +00:00
}
2010-06-08 16:52:24 +00:00
return error ;
}
2010-09-27 21:07:38 +00:00
Error
2013-05-02 00:27:30 +00:00
ProcessGDBRemote : : DoDetach ( bool keep_stopped )
2010-09-27 21:07:38 +00:00
{
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-09-27 21:07:38 +00:00
if ( log )
2013-05-02 00:27:30 +00:00
log - > Printf ( " ProcessGDBRemote::DoDetach(keep_stopped: %i) " , keep_stopped ) ;
2010-09-27 21:07:38 +00:00
DisableAllBreakpointSites ( ) ;
2010-10-18 04:14:23 +00:00
m_thread_list . DiscardThreadPlans ( ) ;
2010-09-27 21:07:38 +00:00
2013-05-02 00:27:30 +00:00
error = m_gdb_comm . Detach ( keep_stopped ) ;
2010-10-18 04:14:23 +00:00
if ( log )
2010-09-27 21:07:38 +00:00
{
2013-05-02 00:27:30 +00:00
if ( error . Success ( ) )
2010-10-18 04:14:23 +00:00
log - > PutCString ( " ProcessGDBRemote::DoDetach() detach packet sent successfully " ) ;
else
2013-05-02 00:27:30 +00:00
log - > Printf ( " ProcessGDBRemote::DoDetach() detach packet send failed: %s " , error . AsCString ( ) ? error . AsCString ( ) : " <unknown error> " ) ;
2010-09-27 21:07:38 +00:00
}
2013-05-02 00:27:30 +00:00
if ( ! error . Success ( ) )
return error ;
2010-10-18 04:14:23 +00:00
// Sleep for one second to let the process get all detached...
2010-09-27 21:07:38 +00:00
StopAsyncThread ( ) ;
2010-10-18 04:14:23 +00:00
SetPrivateState ( eStateDetached ) ;
ResumePrivateStateThread ( ) ;
//KillDebugserverProcess ();
2010-09-27 21:07:38 +00:00
return error ;
}
2010-06-08 16:52:24 +00:00
2012-07-04 00:35:43 +00:00
2010-06-08 16:52:24 +00:00
Error
ProcessGDBRemote : : DoDestroy ( )
{
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::DoDestroy() " ) ;
2012-07-04 00:35:43 +00:00
// There is a bug in older iOS debugservers where they don't shut down the process
// they are debugging properly. If the process is sitting at a breakpoint or an exception,
// this can cause problems with restarting. So we check to see if any of our threads are stopped
// at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN
// destroy it again.
//
// Note, we don't have a good way to test the version of debugserver, but I happen to know that
// the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of
// the debugservers with this bug are equal. There really should be a better way to test this!
//
// We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and
// get called here to destroy again and we're still at a breakpoint or exception, then we should
// just do the straight-forward kill.
//
// And of course, if we weren't able to stop the process by the time we get here, it isn't
// necessary (or helpful) to do any of this.
if ( ! m_gdb_comm . GetThreadSuffixSupported ( ) & & m_public_state . GetValue ( ) ! = eStateRunning )
{
PlatformSP platform_sp = GetTarget ( ) . GetPlatform ( ) ;
// FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
if ( platform_sp
& & platform_sp - > GetName ( )
& & strcmp ( platform_sp - > GetName ( ) , PlatformRemoteiOS : : GetShortPluginNameStatic ( ) ) = = 0 )
{
if ( m_destroy_tried_resuming )
{
if ( log )
log - > PutCString ( " ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again. " ) ;
}
else
{
// At present, the plans are discarded and the breakpoints disabled Process::Destroy,
// but we really need it to happen here and it doesn't matter if we do it twice.
m_thread_list . DiscardThreadPlans ( ) ;
DisableAllBreakpointSites ( ) ;
bool stop_looks_like_crash = false ;
ThreadList & threads = GetThreadList ( ) ;
{
2012-09-11 00:08:52 +00:00
Mutex : : Locker locker ( threads . GetMutex ( ) ) ;
2012-07-04 00:35:43 +00:00
size_t num_threads = threads . GetSize ( ) ;
for ( size_t i = 0 ; i < num_threads ; i + + )
{
ThreadSP thread_sp = threads . GetThreadAtIndex ( i ) ;
StopInfoSP stop_info_sp = thread_sp - > GetPrivateStopReason ( ) ;
StopReason reason = eStopReasonInvalid ;
if ( stop_info_sp )
reason = stop_info_sp - > GetStopReason ( ) ;
if ( reason = = eStopReasonBreakpoint
| | reason = = eStopReasonException )
{
if ( log )
2013-05-01 21:54:04 +00:00
log - > Printf ( " ProcessGDBRemote::DoDestroy() - thread: 0x%4.4 " PRIx64 " stopped with reason: %s. " ,
thread_sp - > GetProtocolID ( ) ,
2012-07-04 00:35:43 +00:00
stop_info_sp - > GetDescription ( ) ) ;
stop_looks_like_crash = true ;
break ;
}
}
}
if ( stop_looks_like_crash )
{
if ( log )
log - > PutCString ( " ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill. " ) ;
m_destroy_tried_resuming = true ;
// If we are going to run again before killing, it would be good to suspend all the threads
// before resuming so they won't get into more trouble. Sadly, for the threads stopped with
// the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do
// have to run the risk of letting those threads proceed a bit.
{
2012-09-11 00:08:52 +00:00
Mutex : : Locker locker ( threads . GetMutex ( ) ) ;
2012-07-04 00:35:43 +00:00
size_t num_threads = threads . GetSize ( ) ;
for ( size_t i = 0 ; i < num_threads ; i + + )
{
ThreadSP thread_sp = threads . GetThreadAtIndex ( i ) ;
StopInfoSP stop_info_sp = thread_sp - > GetPrivateStopReason ( ) ;
StopReason reason = eStopReasonInvalid ;
if ( stop_info_sp )
reason = stop_info_sp - > GetStopReason ( ) ;
if ( reason ! = eStopReasonBreakpoint
& & reason ! = eStopReasonException )
{
if ( log )
2013-05-01 21:54:04 +00:00
log - > Printf ( " ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4 " PRIx64 " before running. " ,
thread_sp - > GetProtocolID ( ) ) ;
2012-07-04 00:35:43 +00:00
thread_sp - > SetResumeState ( eStateSuspended ) ;
}
}
}
Resume ( ) ;
return Destroy ( ) ;
}
}
}
}
2010-06-08 16:52:24 +00:00
// Interrupt if our inferior is running...
2012-06-06 00:32:39 +00:00
int exit_status = SIGABRT ;
std : : string exit_string ;
2011-01-22 07:12:45 +00:00
if ( m_gdb_comm . IsConnected ( ) )
2010-06-08 16:52:24 +00:00
{
2011-10-28 01:11:35 +00:00
if ( m_public_state . GetValue ( ) ! = eStateAttaching )
2011-01-22 23:43:18 +00:00
{
2011-01-29 07:10:55 +00:00
StringExtractorGDBRemote response ;
bool send_async = true ;
2012-08-22 13:25:58 +00:00
const uint32_t old_packet_timeout = m_gdb_comm . SetPacketTimeout ( 3 ) ;
2011-03-10 02:26:48 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( " k " , 1 , response , send_async ) )
2011-01-29 07:10:55 +00:00
{
char packet_cmd = response . GetChar ( 0 ) ;
if ( packet_cmd = = ' W ' | | packet_cmd = = ' X ' )
{
2011-12-06 04:51:14 +00:00
SetLastStopPacket ( response ) ;
2012-04-10 02:25:43 +00:00
ClearThreadIDList ( ) ;
2012-06-06 00:32:39 +00:00
exit_status = response . GetHexU8 ( ) ;
}
else
{
if ( log )
log - > Printf ( " ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s " , response . GetStringRef ( ) . c_str ( ) ) ;
exit_string . assign ( " got unexpected response to k packet: " ) ;
exit_string . append ( response . GetStringRef ( ) ) ;
2011-01-29 07:10:55 +00:00
}
}
else
{
2012-06-06 00:32:39 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::DoDestroy - failed to send k packet " ) ;
exit_string . assign ( " failed to send the k packet " ) ;
2011-01-29 07:10:55 +00:00
}
2012-08-22 13:25:58 +00:00
m_gdb_comm . SetPacketTimeout ( old_packet_timeout ) ;
2011-01-22 23:43:18 +00:00
}
2012-06-06 00:32:39 +00:00
else
{
if ( log )
log - > Printf ( " ProcessGDBRemote::DoDestroy - failed to send k packet " ) ;
2012-07-27 23:57:19 +00:00
exit_string . assign ( " killed or interrupted while attaching. " ) ;
2012-06-06 00:32:39 +00:00
}
}
else
{
// If we missed setting the exit status on the way out, do it here.
// NB set exit status can be called multiple times, the first one sets the status.
exit_string . assign ( " destroying when not connected to debugserver " ) ;
2010-06-08 16:52:24 +00:00
}
2012-06-06 00:32:39 +00:00
SetExitStatus ( exit_status , exit_string . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
StopAsyncThread ( ) ;
KillDebugserverProcess ( ) ;
return error ;
}
//------------------------------------------------------------------
// Process Queries
//------------------------------------------------------------------
bool
ProcessGDBRemote : : IsAlive ( )
{
2010-12-08 05:08:21 +00:00
return m_gdb_comm . IsConnected ( ) & & m_private_state . GetValue ( ) ! = eStateExited ;
2010-06-08 16:52:24 +00:00
}
addr_t
ProcessGDBRemote : : GetImageInfoAddress ( )
{
2013-01-30 04:39:32 +00:00
return m_gdb_comm . GetShlibInfoAddr ( ) ;
2010-06-08 16:52:24 +00:00
}
//------------------------------------------------------------------
// Process Memory
//------------------------------------------------------------------
size_t
ProcessGDBRemote : : DoReadMemory ( addr_t addr , void * buf , size_t size , Error & error )
{
if ( size > m_max_memory_size )
{
// Keep memory read sizes down to a sane limit. This function will be
// called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
size = m_max_memory_size ;
}
char packet [ 64 ] ;
2012-11-29 21:49:15 +00:00
const int packet_len = : : snprintf ( packet , sizeof ( packet ) , " m% " PRIx64 " ,% " PRIx64 , ( uint64_t ) addr , ( uint64_t ) size ) ;
2010-06-08 16:52:24 +00:00
assert ( packet_len + 1 < sizeof ( packet ) ) ;
StringExtractorGDBRemote response ;
2011-03-10 02:26:48 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( packet , packet_len , response , true ) )
2010-06-08 16:52:24 +00:00
{
2011-03-22 04:00:09 +00:00
if ( response . IsNormalResponse ( ) )
2010-06-08 16:52:24 +00:00
{
error . Clear ( ) ;
return response . GetHexBytes ( buf , size , ' \xdd ' ) ;
}
2011-03-22 04:00:09 +00:00
else if ( response . IsErrorResponse ( ) )
2012-12-06 22:49:16 +00:00
error . SetErrorStringWithFormat ( " memory read failed for 0x% " PRIx64 , addr ) ;
2011-03-22 04:00:09 +00:00
else if ( response . IsUnsupportedResponse ( ) )
2012-09-19 01:46:31 +00:00
error . SetErrorStringWithFormat ( " GDB server does not support reading memory " ) ;
2010-06-08 16:52:24 +00:00
else
2012-09-19 01:46:31 +00:00
error . SetErrorStringWithFormat ( " unexpected response to GDB server memory read packet '%s': '%s' " , packet , response . GetStringRef ( ) . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
}
else
{
error . SetErrorStringWithFormat ( " failed to sent packet: '%s' " , packet ) ;
}
return 0 ;
}
size_t
ProcessGDBRemote : : DoWriteMemory ( addr_t addr , const void * buf , size_t size , Error & error )
{
2011-05-16 02:35:02 +00:00
if ( size > m_max_memory_size )
{
// Keep memory read sizes down to a sane limit. This function will be
// called multiple times in order to complete the task by
// lldb_private::Process so it is ok to do this.
size = m_max_memory_size ;
}
2010-06-08 16:52:24 +00:00
StreamString packet ;
2012-11-29 21:49:15 +00:00
packet . Printf ( " M% " PRIx64 " ,% " PRIx64 " : " , addr , ( uint64_t ) size ) ;
2011-02-01 01:31:41 +00:00
packet . PutBytesAsRawHex8 ( buf , size , lldb : : endian : : InlHostByteOrder ( ) , lldb : : endian : : InlHostByteOrder ( ) ) ;
2010-06-08 16:52:24 +00:00
StringExtractorGDBRemote response ;
2011-03-10 02:26:48 +00:00
if ( m_gdb_comm . SendPacketAndWaitForResponse ( packet . GetData ( ) , packet . GetSize ( ) , response , true ) )
2010-06-08 16:52:24 +00:00
{
2011-03-22 04:00:09 +00:00
if ( response . IsOKResponse ( ) )
2010-06-08 16:52:24 +00:00
{
error . Clear ( ) ;
return size ;
}
2011-03-22 04:00:09 +00:00
else if ( response . IsErrorResponse ( ) )
2012-12-06 22:49:16 +00:00
error . SetErrorStringWithFormat ( " memory write failed for 0x% " PRIx64 , addr ) ;
2011-03-22 04:00:09 +00:00
else if ( response . IsUnsupportedResponse ( ) )
2012-09-19 01:46:31 +00:00
error . SetErrorStringWithFormat ( " GDB server does not support writing memory " ) ;
2010-06-08 16:52:24 +00:00
else
2012-09-19 01:46:31 +00:00
error . SetErrorStringWithFormat ( " unexpected response to GDB server memory write packet '%s': '%s' " , packet . GetString ( ) . c_str ( ) , response . GetStringRef ( ) . c_str ( ) ) ;
2010-06-08 16:52:24 +00:00
}
else
{
error . SetErrorStringWithFormat ( " failed to sent packet: '%s' " , packet . GetString ( ) . c_str ( ) ) ;
}
return 0 ;
}
lldb : : addr_t
ProcessGDBRemote : : DoAllocateMemory ( size_t size , uint32_t permissions , Error & error )
{
2011-05-14 01:50:35 +00:00
addr_t allocated_addr = LLDB_INVALID_ADDRESS ;
2011-05-15 01:25:55 +00:00
LazyBool supported = m_gdb_comm . SupportsAllocDeallocMemory ( ) ;
2011-05-14 01:50:35 +00:00
switch ( supported )
{
case eLazyBoolCalculate :
case eLazyBoolYes :
allocated_addr = m_gdb_comm . AllocateMemory ( size , permissions ) ;
if ( allocated_addr ! = LLDB_INVALID_ADDRESS | | supported = = eLazyBoolYes )
return allocated_addr ;
case eLazyBoolNo :
2011-06-03 20:40:38 +00:00
// Call mmap() to create memory in the inferior..
unsigned prot = 0 ;
if ( permissions & lldb : : ePermissionsReadable )
prot | = eMmapProtRead ;
if ( permissions & lldb : : ePermissionsWritable )
prot | = eMmapProtWrite ;
if ( permissions & lldb : : ePermissionsExecutable )
prot | = eMmapProtExec ;
if ( InferiorCallMmap ( this , allocated_addr , 0 , size , prot ,
eMmapFlagsAnon | eMmapFlagsPrivate , - 1 , 0 ) )
m_addr_to_mmap_size [ allocated_addr ] = size ;
else
allocated_addr = LLDB_INVALID_ADDRESS ;
2011-05-14 01:50:35 +00:00
break ;
}
2010-06-08 16:52:24 +00:00
if ( allocated_addr = = LLDB_INVALID_ADDRESS )
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " unable to allocate % " PRIu64 " bytes of memory with permissions %s " , ( uint64_t ) size , GetPermissionsAsCString ( permissions ) ) ;
2010-06-08 16:52:24 +00:00
else
error . Clear ( ) ;
return allocated_addr ;
}
2011-11-18 07:03:08 +00:00
Error
ProcessGDBRemote : : GetMemoryRegionInfo ( addr_t load_addr ,
MemoryRegionInfo & region_info )
{
Error error ( m_gdb_comm . GetMemoryRegionInfo ( load_addr , region_info ) ) ;
return error ;
}
2012-05-23 21:09:52 +00:00
Error
ProcessGDBRemote : : GetWatchpointSupportInfo ( uint32_t & num )
{
Error error ( m_gdb_comm . GetWatchpointSupportInfo ( num ) ) ;
return error ;
}
2012-07-13 23:18:48 +00:00
Error
ProcessGDBRemote : : GetWatchpointSupportInfo ( uint32_t & num , bool & after )
{
Error error ( m_gdb_comm . GetWatchpointSupportInfo ( num , after ) ) ;
return error ;
}
2010-06-08 16:52:24 +00:00
Error
ProcessGDBRemote : : DoDeallocateMemory ( lldb : : addr_t addr )
{
Error error ;
2011-05-15 01:25:55 +00:00
LazyBool supported = m_gdb_comm . SupportsAllocDeallocMemory ( ) ;
switch ( supported )
{
case eLazyBoolCalculate :
// We should never be deallocating memory without allocating memory
// first so we should never get eLazyBoolCalculate
error . SetErrorString ( " tried to deallocate memory without ever allocating memory " ) ;
break ;
case eLazyBoolYes :
if ( ! m_gdb_comm . DeallocateMemory ( addr ) )
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " unable to deallocate memory at 0x% " PRIx64 , addr ) ;
2011-05-15 01:25:55 +00:00
break ;
case eLazyBoolNo :
2011-06-03 20:40:38 +00:00
// Call munmap() to deallocate memory in the inferior..
2011-05-15 01:25:55 +00:00
{
MMapMap : : iterator pos = m_addr_to_mmap_size . find ( addr ) ;
2011-06-03 20:40:38 +00:00
if ( pos ! = m_addr_to_mmap_size . end ( ) & &
InferiorCallMunmap ( this , addr , pos - > second ) )
m_addr_to_mmap_size . erase ( pos ) ;
else
2012-11-29 21:49:15 +00:00
error . SetErrorStringWithFormat ( " unable to deallocate memory at 0x% " PRIx64 , addr ) ;
2011-05-15 01:25:55 +00:00
}
break ;
}
2010-06-08 16:52:24 +00:00
return error ;
}
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
size_t
ProcessGDBRemote : : PutSTDIN ( const char * src , size_t src_len , Error & error )
{
if ( m_stdio_communication . IsConnected ( ) )
{
ConnectionStatus status ;
m_stdio_communication . Write ( src , src_len , status , NULL ) ;
}
return 0 ;
}
Error
2013-02-15 02:06:30 +00:00
ProcessGDBRemote : : EnableBreakpointSite ( BreakpointSite * bp_site )
2010-06-08 16:52:24 +00:00
{
Error error ;
assert ( bp_site ! = NULL ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_BREAKPOINTS ) ) ;
2010-06-08 16:52:24 +00:00
user_id_t site_id = bp_site - > GetID ( ) ;
const addr_t addr = bp_site - > GetLoadAddress ( ) ;
if ( log )
2013-02-15 02:06:30 +00:00
log - > Printf ( " ProcessGDBRemote::EnableBreakpointSite (size_id = % " PRIu64 " ) address = 0x% " PRIx64 , site_id , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
if ( bp_site - > IsEnabled ( ) )
{
if ( log )
2013-02-15 02:06:30 +00:00
log - > Printf ( " ProcessGDBRemote::EnableBreakpointSite (size_id = % " PRIu64 " ) address = 0x% " PRIx64 " -- SUCCESS (already enabled) " , site_id , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
return error ;
}
else
{
const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode ( bp_site ) ;
if ( bp_site - > HardwarePreferred ( ) )
{
// Try and set hardware breakpoint, and if that fails, fall through
// and set a software breakpoint?
2011-04-12 05:54:46 +00:00
if ( m_gdb_comm . SupportsGDBStoppointPacket ( eBreakpointHardware ) )
2010-06-08 16:52:24 +00:00
{
2011-04-12 05:54:46 +00:00
if ( m_gdb_comm . SendGDBStoppointTypePacket ( eBreakpointHardware , true , addr , bp_op_size ) = = 0 )
2010-06-08 16:52:24 +00:00
{
bp_site - > SetEnabled ( true ) ;
2011-04-12 05:54:46 +00:00
bp_site - > SetType ( BreakpointSite : : eHardware ) ;
2010-06-08 16:52:24 +00:00
return error ;
}
}
}
2011-04-12 05:54:46 +00:00
if ( m_gdb_comm . SupportsGDBStoppointPacket ( eBreakpointSoftware ) )
2010-06-08 16:52:24 +00:00
{
2011-04-12 05:54:46 +00:00
if ( m_gdb_comm . SendGDBStoppointTypePacket ( eBreakpointSoftware , true , addr , bp_op_size ) = = 0 )
{
bp_site - > SetEnabled ( true ) ;
bp_site - > SetType ( BreakpointSite : : eExternal ) ;
return error ;
}
2010-06-08 16:52:24 +00:00
}
2011-04-12 05:54:46 +00:00
return EnableSoftwareBreakpoint ( bp_site ) ;
2010-06-08 16:52:24 +00:00
}
if ( log )
{
const char * err_string = error . AsCString ( ) ;
2013-02-15 02:06:30 +00:00
log - > Printf ( " ProcessGDBRemote::EnableBreakpointSite () error for breakpoint at 0x%8.8 " PRIx64 " : %s " ,
2010-06-08 16:52:24 +00:00
bp_site - > GetLoadAddress ( ) ,
err_string ? err_string : " NULL " ) ;
}
// We shouldn't reach here on a successful breakpoint enable...
if ( error . Success ( ) )
error . SetErrorToGenericError ( ) ;
return error ;
}
Error
2013-02-15 02:06:30 +00:00
ProcessGDBRemote : : DisableBreakpointSite ( BreakpointSite * bp_site )
2010-06-08 16:52:24 +00:00
{
Error error ;
assert ( bp_site ! = NULL ) ;
addr_t addr = bp_site - > GetLoadAddress ( ) ;
user_id_t site_id = bp_site - > GetID ( ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_BREAKPOINTS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
2013-02-15 02:06:30 +00:00
log - > Printf ( " ProcessGDBRemote::DisableBreakpointSite (site_id = % " PRIu64 " ) addr = 0x%8.8 " PRIx64 , site_id , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
if ( bp_site - > IsEnabled ( ) )
{
const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode ( bp_site ) ;
2011-04-12 05:54:46 +00:00
BreakpointSite : : Type bp_type = bp_site - > GetType ( ) ;
switch ( bp_type )
2010-06-08 16:52:24 +00:00
{
2011-04-12 05:54:46 +00:00
case BreakpointSite : : eSoftware :
error = DisableSoftwareBreakpoint ( bp_site ) ;
break ;
case BreakpointSite : : eHardware :
if ( m_gdb_comm . SendGDBStoppointTypePacket ( eBreakpointSoftware , false , addr , bp_op_size ) )
error . SetErrorToGenericError ( ) ;
break ;
case BreakpointSite : : eExternal :
if ( m_gdb_comm . SendGDBStoppointTypePacket ( eBreakpointSoftware , false , addr , bp_op_size ) )
error . SetErrorToGenericError ( ) ;
break ;
2010-06-08 16:52:24 +00:00
}
2011-04-12 05:54:46 +00:00
if ( error . Success ( ) )
bp_site - > SetEnabled ( false ) ;
2010-06-08 16:52:24 +00:00
}
else
{
if ( log )
2013-02-15 02:06:30 +00:00
log - > Printf ( " ProcessGDBRemote::DisableBreakpointSite (site_id = % " PRIu64 " ) addr = 0x%8.8 " PRIx64 " -- SUCCESS (already disabled) " , site_id , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
return error ;
}
if ( error . Success ( ) )
error . SetErrorToGenericError ( ) ;
return error ;
}
2011-09-06 22:38:36 +00:00
// Pre-requisite: wp != NULL.
static GDBStoppointType
2011-10-14 00:42:25 +00:00
GetGDBStoppointType ( Watchpoint * wp )
2011-09-06 22:38:36 +00:00
{
assert ( wp ) ;
bool watch_read = wp - > WatchpointRead ( ) ;
bool watch_write = wp - > WatchpointWrite ( ) ;
// watch_read and watch_write cannot both be false.
assert ( watch_read | | watch_write ) ;
if ( watch_read & & watch_write )
return eWatchpointReadWrite ;
2011-09-09 20:35:15 +00:00
else if ( watch_read )
2011-09-06 22:38:36 +00:00
return eWatchpointRead ;
2011-09-09 20:35:15 +00:00
else // Must be watch_write, then.
2011-09-06 22:38:36 +00:00
return eWatchpointWrite ;
}
2010-06-08 16:52:24 +00:00
Error
2012-12-18 02:03:49 +00:00
ProcessGDBRemote : : EnableWatchpoint ( Watchpoint * wp , bool notify )
2010-06-08 16:52:24 +00:00
{
Error error ;
if ( wp )
{
user_id_t watchID = wp - > GetID ( ) ;
addr_t addr = wp - > GetLoadAddress ( ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_WATCHPOINTS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::EnableWatchpoint(watchID = % " PRIu64 " ) " , watchID ) ;
2010-06-08 16:52:24 +00:00
if ( wp - > IsEnabled ( ) )
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::EnableWatchpoint(watchID = % " PRIu64 " ) addr = 0x%8.8 " PRIx64 " : watchpoint already enabled. " , watchID , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
return error ;
}
2011-09-06 22:38:36 +00:00
GDBStoppointType type = GetGDBStoppointType ( wp ) ;
// Pass down an appropriate z/Z packet...
if ( m_gdb_comm . SupportsGDBStoppointPacket ( type ) )
2010-06-08 16:52:24 +00:00
{
2011-09-06 22:38:36 +00:00
if ( m_gdb_comm . SendGDBStoppointTypePacket ( type , true , addr , wp - > GetByteSize ( ) ) = = 0 )
{
2012-12-18 02:03:49 +00:00
wp - > SetEnabled ( true , notify ) ;
2011-09-06 22:38:36 +00:00
return error ;
}
else
error . SetErrorString ( " sending gdb watchpoint packet failed " ) ;
2010-06-08 16:52:24 +00:00
}
2011-09-06 22:38:36 +00:00
else
error . SetErrorString ( " watchpoints not supported " ) ;
2010-06-08 16:52:24 +00:00
}
else
{
2011-10-14 00:42:25 +00:00
error . SetErrorString ( " Watchpoint argument was NULL. " ) ;
2010-06-08 16:52:24 +00:00
}
if ( error . Success ( ) )
error . SetErrorToGenericError ( ) ;
return error ;
}
Error
2012-12-18 02:03:49 +00:00
ProcessGDBRemote : : DisableWatchpoint ( Watchpoint * wp , bool notify )
2010-06-08 16:52:24 +00:00
{
Error error ;
if ( wp )
{
user_id_t watchID = wp - > GetID ( ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_WATCHPOINTS ) ) ;
2010-06-08 16:52:24 +00:00
addr_t addr = wp - > GetLoadAddress ( ) ;
2012-12-18 02:03:49 +00:00
2010-06-08 16:52:24 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::DisableWatchpoint (watchID = % " PRIu64 " ) addr = 0x%8.8 " PRIx64 , watchID , ( uint64_t ) addr ) ;
2010-06-08 16:52:24 +00:00
2011-09-06 22:38:36 +00:00
if ( ! wp - > IsEnabled ( ) )
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::DisableWatchpoint (watchID = % " PRIu64 " ) addr = 0x%8.8 " PRIx64 " -- SUCCESS (already disabled) " , watchID , ( uint64_t ) addr ) ;
2012-08-23 22:28:26 +00:00
// See also 'class WatchpointSentry' within StopInfo.cpp.
// This disabling attempt might come from the user-supplied actions, we'll route it in order for
// the watchpoint object to intelligently process this action.
2012-12-18 02:03:49 +00:00
wp - > SetEnabled ( false , notify ) ;
2011-09-06 22:38:36 +00:00
return error ;
}
2010-06-08 16:52:24 +00:00
if ( wp - > IsHardware ( ) )
{
2011-09-06 22:38:36 +00:00
GDBStoppointType type = GetGDBStoppointType ( wp ) ;
2010-06-08 16:52:24 +00:00
// Pass down an appropriate z/Z packet...
2011-09-06 22:38:36 +00:00
if ( m_gdb_comm . SendGDBStoppointTypePacket ( type , false , addr , wp - > GetByteSize ( ) ) = = 0 )
{
2012-12-18 02:03:49 +00:00
wp - > SetEnabled ( false , notify ) ;
2011-09-06 22:38:36 +00:00
return error ;
}
else
error . SetErrorString ( " sending gdb watchpoint packet failed " ) ;
2010-06-08 16:52:24 +00:00
}
// TODO: clear software watchpoints if we implement them
}
else
{
2011-10-14 00:42:25 +00:00
error . SetErrorString ( " Watchpoint argument was NULL. " ) ;
2010-06-08 16:52:24 +00:00
}
if ( error . Success ( ) )
error . SetErrorToGenericError ( ) ;
return error ;
}
void
ProcessGDBRemote : : Clear ( )
{
m_flags = 0 ;
2013-05-07 18:35:34 +00:00
m_thread_list_real . Clear ( ) ;
2010-06-08 16:52:24 +00:00
m_thread_list . Clear ( ) ;
}
Error
ProcessGDBRemote : : DoSignal ( int signo )
{
Error error ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::DoSignal (signal = %d) " , signo ) ;
if ( ! m_gdb_comm . SendAsyncSignal ( signo ) )
error . SetErrorStringWithFormat ( " failed to send signal %i " , signo ) ;
return error ;
}
Error
2012-02-25 01:07:38 +00:00
ProcessGDBRemote : : StartDebugserverProcess ( const char * debugserver_url )
{
ProcessLaunchInfo launch_info ;
return StartDebugserverProcess ( debugserver_url , launch_info ) ;
}
Error
ProcessGDBRemote : : StartDebugserverProcess ( const char * debugserver_url , const ProcessInfo & process_info ) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
2010-06-08 16:52:24 +00:00
{
Error error ;
if ( m_debugserver_pid = = LLDB_INVALID_PROCESS_ID )
{
// If we locate debugserver, keep that located version around
static FileSpec g_debugserver_file_spec ;
2012-02-25 01:07:38 +00:00
ProcessLaunchInfo debugserver_launch_info ;
2010-06-08 16:52:24 +00:00
char debugserver_path [ PATH_MAX ] ;
2012-02-25 01:07:38 +00:00
FileSpec & debugserver_file_spec = debugserver_launch_info . GetExecutableFile ( ) ;
2010-06-08 16:52:24 +00:00
// Always check to see if we have an environment override for the path
// to the debugserver to use and use it if we do.
const char * env_debugserver_path = getenv ( " LLDB_DEBUGSERVER_PATH " ) ;
if ( env_debugserver_path )
2010-10-20 20:54:39 +00:00
debugserver_file_spec . SetFile ( env_debugserver_path , false ) ;
2010-06-08 16:52:24 +00:00
else
debugserver_file_spec = g_debugserver_file_spec ;
bool debugserver_exists = debugserver_file_spec . Exists ( ) ;
if ( ! debugserver_exists )
{
// The debugserver binary is in the LLDB.framework/Resources
// directory.
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-17 22:03:32 +00:00
if ( Host : : GetLLDBPath ( ePathTypeSupportExecutableDir , debugserver_file_spec ) )
2010-06-08 16:52:24 +00:00
{
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-17 22:03:32 +00:00
debugserver_file_spec . GetFilename ( ) . SetCString ( DEBUGSERVER_BASENAME ) ;
2010-06-08 16:52:24 +00:00
debugserver_exists = debugserver_file_spec . Exists ( ) ;
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-17 22:03:32 +00:00
if ( debugserver_exists )
{
g_debugserver_file_spec = debugserver_file_spec ;
}
else
{
g_debugserver_file_spec . Clear ( ) ;
debugserver_file_spec . Clear ( ) ;
}
2010-06-08 16:52:24 +00:00
}
}
if ( debugserver_exists )
{
debugserver_file_spec . GetPath ( debugserver_path , sizeof ( debugserver_path ) ) ;
m_stdio_communication . Clear ( ) ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
2012-02-25 01:07:38 +00:00
Args & debugserver_args = debugserver_launch_info . GetArguments ( ) ;
2010-06-08 16:52:24 +00:00
char arg_cstr [ PATH_MAX ] ;
// Start args with "debugserver /file/path -r --"
debugserver_args . AppendArgument ( debugserver_path ) ;
debugserver_args . AppendArgument ( debugserver_url ) ;
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-17 22:03:32 +00:00
// use native registers, not the GDB registers
debugserver_args . AppendArgument ( " --native-regs " ) ;
// make debugserver run in its own session so signals generated by
// special terminal key sequences (^C) don't affect debugserver
debugserver_args . AppendArgument ( " --setsid " ) ;
2010-06-08 16:52:24 +00:00
const char * env_debugserver_log_file = getenv ( " LLDB_DEBUGSERVER_LOG_FILE " ) ;
if ( env_debugserver_log_file )
{
: : snprintf ( arg_cstr , sizeof ( arg_cstr ) , " --log-file=%s " , env_debugserver_log_file ) ;
debugserver_args . AppendArgument ( arg_cstr ) ;
}
const char * env_debugserver_log_flags = getenv ( " LLDB_DEBUGSERVER_LOG_FLAGS " ) ;
if ( env_debugserver_log_flags )
{
: : snprintf ( arg_cstr , sizeof ( arg_cstr ) , " --log-flags=%s " , env_debugserver_log_flags ) ;
debugserver_args . AppendArgument ( arg_cstr ) ;
}
2012-10-03 22:31:30 +00:00
// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
// debugserver_args.AppendArgument("--log-flags=0x802e0e");
2010-06-08 16:52:24 +00:00
2011-04-12 05:54:46 +00:00
// We currently send down all arguments, attach pids, or attach
// process names in dedicated GDB server packets, so we don't need
// to pass them as arguments. This is currently because of all the
// things we need to setup prior to launching: the environment,
// current working dir, file actions, etc.
#if 0
2010-06-08 16:52:24 +00:00
// Now append the program arguments
2011-02-24 22:24:29 +00:00
if ( inferior_argv )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
// Terminate the debugserver args so we can now append the inferior args
debugserver_args . AppendArgument ( " -- " ) ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
for ( int i = 0 ; inferior_argv [ i ] ! = NULL ; + + i )
debugserver_args . AppendArgument ( inferior_argv [ i ] ) ;
2010-06-08 16:52:24 +00:00
}
else if ( attach_pid ! = LLDB_INVALID_PROCESS_ID )
{
: : snprintf ( arg_cstr , sizeof ( arg_cstr ) , " --attach=%u " , attach_pid ) ;
debugserver_args . AppendArgument ( arg_cstr ) ;
}
else if ( attach_name & & attach_name [ 0 ] )
{
if ( wait_for_launch )
debugserver_args . AppendArgument ( " --waitfor " ) ;
else
debugserver_args . AppendArgument ( " --attach " ) ;
debugserver_args . AppendArgument ( attach_name ) ;
}
# endif
2011-04-12 05:54:46 +00:00
ProcessLaunchInfo : : FileAction file_action ;
// Close STDIN, STDOUT and STDERR. We might need to redirect them
// to "/dev/null" if we run into any problems.
file_action . Close ( STDIN_FILENO ) ;
2012-02-25 01:07:38 +00:00
debugserver_launch_info . AppendFileAction ( file_action ) ;
2011-04-12 05:54:46 +00:00
file_action . Close ( STDOUT_FILENO ) ;
2012-02-25 01:07:38 +00:00
debugserver_launch_info . AppendFileAction ( file_action ) ;
2011-04-12 05:54:46 +00:00
file_action . Close ( STDERR_FILENO ) ;
2012-02-25 01:07:38 +00:00
debugserver_launch_info . AppendFileAction ( file_action ) ;
2010-06-08 16:52:24 +00:00
if ( log )
{
StreamString strm ;
debugserver_args . Dump ( & strm ) ;
log - > Printf ( " %s arguments: \n %s " , debugserver_args . GetArgumentAtIndex ( 0 ) , strm . GetData ( ) ) ;
}
2012-02-25 01:07:38 +00:00
debugserver_launch_info . SetMonitorProcessCallback ( MonitorDebugserverProcess , this , false ) ;
debugserver_launch_info . SetUserID ( process_info . GetUserID ( ) ) ;
2011-11-16 05:37:56 +00:00
2012-02-25 01:07:38 +00:00
error = Host : : LaunchProcess ( debugserver_launch_info ) ;
2010-07-02 01:29:13 +00:00
2011-04-12 05:54:46 +00:00
if ( error . Success ( ) )
2012-02-25 01:07:38 +00:00
m_debugserver_pid = debugserver_launch_info . GetProcessID ( ) ;
2011-04-12 05:54:46 +00:00
else
2010-06-08 16:52:24 +00:00
m_debugserver_pid = LLDB_INVALID_PROCESS_ID ;
if ( error . Fail ( ) | | log )
2013-03-27 23:08:40 +00:00
error . PutToLog ( log , " Host::LaunchProcess (launch_info) => pid=% " PRIu64 " , path='%s' " , m_debugserver_pid , debugserver_path ) ;
2010-06-08 16:52:24 +00:00
}
else
{
2011-10-26 00:56:27 +00:00
error . SetErrorStringWithFormat ( " unable to locate " DEBUGSERVER_BASENAME ) ;
2010-06-08 16:52:24 +00:00
}
if ( m_debugserver_pid ! = LLDB_INVALID_PROCESS_ID )
StartAsyncThread ( ) ;
}
return error ;
}
bool
ProcessGDBRemote : : MonitorDebugserverProcess
(
void * callback_baton ,
lldb : : pid_t debugserver_pid ,
2011-11-16 05:37:56 +00:00
bool exited , // True if the process did exit
2010-06-08 16:52:24 +00:00
int signo , // Zero for no signal
int exit_status // Exit value of process if signal is zero
)
{
2011-11-16 05:37:56 +00:00
// The baton is a "ProcessGDBRemote *". Now this class might be gone
// and might not exist anymore, so we need to carefully try to get the
// target for this process first since we have a race condition when
// we are done running between getting the notice that the inferior
// process has died and the debugserver that was debugging this process.
// In our test suite, we are also continually running process after
// process, so we must be very careful to make sure:
// 1 - process object hasn't been deleted already
// 2 - that a new process object hasn't been recreated in its place
2010-06-08 16:52:24 +00:00
// "debugserver_pid" argument passed in is the process ID for
// debugserver that we are tracking...
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
2010-08-21 02:22:51 +00:00
ProcessGDBRemote * process = ( ProcessGDBRemote * ) callback_baton ;
2011-01-22 23:43:18 +00:00
2011-11-16 05:37:56 +00:00
// Get a shared pointer to the target that has a matching process pointer.
// This target could be gone, or the target could already have a new process
// object inside of it
TargetSP target_sp ( Debugger : : FindTargetWithProcess ( process ) ) ;
2011-01-22 23:43:18 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=% " PRIu64 " , signo=%i (0x%x), exit_status=%i) " , callback_baton , debugserver_pid , signo , signo , exit_status ) ;
2011-01-22 23:43:18 +00:00
2011-11-16 05:37:56 +00:00
if ( target_sp )
2010-06-08 16:52:24 +00:00
{
2011-11-16 05:37:56 +00:00
// We found a process in a target that matches, but another thread
// might be in the process of launching a new process that will
// soon replace it, so get a shared pointer to the process so we
// can keep it alive.
ProcessSP process_sp ( target_sp - > GetProcessSP ( ) ) ;
// Now we have a shared pointer to the process that can't go away on us
// so we now make sure it was the same as the one passed in, and also make
// sure that our previous "process *" didn't get deleted and have a new
// "process *" created in its place with the same pointer. To verify this
// we make sure the process has our debugserver process ID. If we pass all
// of these tests, then we are sure that this process is the one we were
// looking for.
if ( process_sp & & process = = process_sp . get ( ) & & process - > m_debugserver_pid = = debugserver_pid )
2010-06-08 16:52:24 +00:00
{
2011-11-16 05:37:56 +00:00
// 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.
const StateType state = process - > GetState ( ) ;
if ( process - > m_debugserver_pid ! = LLDB_INVALID_PROCESS_ID & &
state ! = eStateInvalid & &
state ! = eStateUnloaded & &
state ! = eStateExited & &
state ! = eStateDetached )
2010-06-08 16:52:24 +00:00
{
2011-11-16 05:37:56 +00:00
char error_str [ 1024 ] ;
if ( 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 signal %i " , signo ) ;
}
2010-06-08 16:52:24 +00:00
else
2011-11-16 05:37:56 +00:00
{
: : snprintf ( error_str , sizeof ( error_str ) , DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x " , exit_status ) ;
}
2010-08-21 02:22:51 +00:00
2011-11-16 05:37:56 +00:00
process - > SetExitStatus ( - 1 , error_str ) ;
}
// 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 ;
2010-08-21 02:22:51 +00:00
}
2010-06-08 16:52:24 +00:00
}
return true ;
}
void
ProcessGDBRemote : : KillDebugserverProcess ( )
{
if ( m_debugserver_pid ! = LLDB_INVALID_PROCESS_ID )
{
: : kill ( m_debugserver_pid , SIGINT ) ;
m_debugserver_pid = LLDB_INVALID_PROCESS_ID ;
}
}
void
ProcessGDBRemote : : Initialize ( )
{
static bool g_initialized = false ;
if ( g_initialized = = false )
{
g_initialized = true ;
PluginManager : : RegisterPlugin ( GetPluginNameStatic ( ) ,
GetPluginDescriptionStatic ( ) ,
CreateInstance ) ;
Log : : Callbacks log_callbacks = {
ProcessGDBRemoteLog : : DisableLog ,
ProcessGDBRemoteLog : : EnableLog ,
ProcessGDBRemoteLog : : ListLogCategories
} ;
Log : : RegisterLogChannel ( ProcessGDBRemote : : GetPluginNameStatic ( ) , log_callbacks ) ;
}
}
bool
ProcessGDBRemote : : StartAsyncThread ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::%s () " , __FUNCTION__ ) ;
2012-11-01 01:15:33 +00:00
Mutex : : Locker start_locker ( m_async_thread_state_mutex ) ;
if ( m_async_thread_state = = eAsyncThreadNotStarted )
{
// Create a thread that watches our internal state and controls which
// events make it to clients (into the DCProcess event queue).
m_async_thread = Host : : ThreadCreate ( " <lldb.process.gdb-remote.async> " , ProcessGDBRemote : : AsyncThread , this , NULL ) ;
if ( IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
{
m_async_thread_state = eAsyncThreadRunning ;
return true ;
}
else
return false ;
}
else
{
// Somebody tried to start the async thread while it was either being started or stopped. If the former, and
// it started up successfully, then say all's well. Otherwise it is an error, since we aren't going to restart it.
if ( log )
log - > Printf ( " ProcessGDBRemote::%s () - Called when Async thread was in state: %d. " , __FUNCTION__ , m_async_thread_state ) ;
if ( m_async_thread_state = = eAsyncThreadRunning )
return true ;
else
return false ;
}
2010-06-08 16:52:24 +00:00
}
void
ProcessGDBRemote : : StopAsyncThread ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::%s () " , __FUNCTION__ ) ;
2012-11-01 01:15:33 +00:00
Mutex : : Locker start_locker ( m_async_thread_state_mutex ) ;
if ( m_async_thread_state = = eAsyncThreadRunning )
{
m_async_broadcaster . BroadcastEvent ( eBroadcastBitAsyncThreadShouldExit ) ;
// This will shut down the async thread.
m_gdb_comm . Disconnect ( ) ; // Disconnect from the debug server.
2010-06-08 16:52:24 +00:00
2012-11-01 01:15:33 +00:00
// Stop the stdio thread
if ( IS_VALID_LLDB_HOST_THREAD ( m_async_thread ) )
{
Host : : ThreadJoin ( m_async_thread , NULL , NULL ) ;
}
m_async_thread_state = eAsyncThreadDone ;
}
else
2010-06-08 16:52:24 +00:00
{
2012-11-01 01:15:33 +00:00
if ( log )
log - > Printf ( " ProcessGDBRemote::%s () - Called when Async thread was in state: %d. " , __FUNCTION__ , m_async_thread_state ) ;
2010-06-08 16:52:24 +00:00
}
}
void *
ProcessGDBRemote : : AsyncThread ( void * arg )
{
ProcessGDBRemote * process = ( ProcessGDBRemote * ) arg ;
2013-03-27 23:08:40 +00:00
Log * log ( ProcessGDBRemoteLog : : GetLogIfAllCategoriesSet ( GDBR_LOG_PROCESS ) ) ;
2010-06-08 16:52:24 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) thread starting... " , __FUNCTION__ , arg , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
Listener listener ( " ProcessGDBRemote::AsyncThread " ) ;
EventSP event_sp ;
const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
eBroadcastBitAsyncThreadShouldExit ;
if ( listener . StartListeningForEvents ( & process - > m_async_broadcaster , desired_event_mask ) = = desired_event_mask )
{
2011-02-24 22:24:29 +00:00
listener . StartListeningForEvents ( & process - > m_gdb_comm , Communication : : eBroadcastBitReadThreadDidExit ) ;
2010-06-08 16:52:24 +00:00
bool done = false ;
while ( ! done )
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) listener.WaitForEvent (NULL, event_sp)... " , __FUNCTION__ , arg , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
if ( listener . WaitForEvent ( NULL , event_sp ) )
{
const uint32_t event_type = event_sp - > GetType ( ) ;
2011-02-24 22:24:29 +00:00
if ( event_sp - > BroadcasterIs ( & process - > m_async_broadcaster ) )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) Got an event of type: %d... " , __FUNCTION__ , arg , process - > GetID ( ) , event_type ) ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
switch ( event_type )
{
case eBroadcastBitAsyncContinue :
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
const EventDataBytes * continue_packet = EventDataBytes : : GetEventDataFromEvent ( event_sp . get ( ) ) ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
if ( continue_packet )
2010-06-08 16:52:24 +00:00
{
2011-02-24 22:24:29 +00:00
const char * continue_cstr = ( const char * ) continue_packet - > GetBytes ( ) ;
const size_t continue_cstr_len = continue_packet - > GetByteSize ( ) ;
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) got eBroadcastBitAsyncContinue: %s " , __FUNCTION__ , arg , process - > GetID ( ) , continue_cstr ) ;
2011-02-24 22:24:29 +00:00
if ( : : strstr ( continue_cstr , " vAttach " ) = = NULL )
process - > SetPrivateState ( eStateRunning ) ;
StringExtractorGDBRemote response ;
StateType stop_state = process - > GetGDBRemote ( ) . SendContinuePacketAndWaitForResponse ( process , continue_cstr , continue_cstr_len , response ) ;
2012-05-16 02:48:06 +00:00
// We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
// The thread ID list might be contained within the "response", or the stop reply packet that
// caused the stop. So clear it now before we give the stop reply packet to the process
// using the process->SetLastStopPacket()...
process - > ClearThreadIDList ( ) ;
2011-02-24 22:24:29 +00:00
switch ( stop_state )
{
case eStateStopped :
case eStateCrashed :
case eStateSuspended :
2011-12-06 04:51:14 +00:00
process - > SetLastStopPacket ( response ) ;
2011-02-24 22:24:29 +00:00
process - > SetPrivateState ( stop_state ) ;
break ;
case eStateExited :
2011-12-06 04:51:14 +00:00
process - > SetLastStopPacket ( response ) ;
2012-04-10 02:25:43 +00:00
process - > ClearThreadIDList ( ) ;
2011-02-24 22:24:29 +00:00
response . SetFilePos ( 1 ) ;
process - > SetExitStatus ( response . GetHexU8 ( ) , NULL ) ;
done = true ;
break ;
case eStateInvalid :
process - > SetExitStatus ( - 1 , " lost connection " ) ;
break ;
default :
process - > SetPrivateState ( stop_state ) ;
break ;
}
2010-06-08 16:52:24 +00:00
}
}
2011-02-24 22:24:29 +00:00
break ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
case eBroadcastBitAsyncThreadShouldExit :
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) got eBroadcastBitAsyncThreadShouldExit... " , __FUNCTION__ , arg , process - > GetID ( ) ) ;
2011-02-24 22:24:29 +00:00
done = true ;
break ;
2010-06-08 16:52:24 +00:00
2011-02-24 22:24:29 +00:00
default :
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) got unknown event 0x%8.8x " , __FUNCTION__ , arg , process - > GetID ( ) , event_type ) ;
2011-02-24 22:24:29 +00:00
done = true ;
break ;
}
}
else if ( event_sp - > BroadcasterIs ( & process - > m_gdb_comm ) )
{
if ( event_type & Communication : : eBroadcastBitReadThreadDidExit )
{
process - > SetExitStatus ( - 1 , " lost connection " ) ;
2010-06-08 16:52:24 +00:00
done = true ;
2011-02-24 22:24:29 +00:00
}
2010-06-08 16:52:24 +00:00
}
}
else
{
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) listener.WaitForEvent (NULL, event_sp) => false " , __FUNCTION__ , arg , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
done = true ;
}
}
}
if ( log )
2012-11-29 21:49:15 +00:00
log - > Printf ( " ProcessGDBRemote::%s (arg = %p, pid = % " PRIu64 " ) thread exiting... " , __FUNCTION__ , arg , process - > GetID ( ) ) ;
2010-06-08 16:52:24 +00:00
process - > m_async_thread = LLDB_INVALID_HOST_THREAD ;
return NULL ;
}
const char *
ProcessGDBRemote : : GetDispatchQueueNameForThread
(
addr_t thread_dispatch_qaddr ,
std : : string & dispatch_queue_name
)
{
dispatch_queue_name . clear ( ) ;
if ( thread_dispatch_qaddr ! = 0 & & thread_dispatch_qaddr ! = LLDB_INVALID_ADDRESS )
{
// Cache the dispatch_queue_offsets_addr value so we don't always have
// to look it up
if ( m_dispatch_queue_offsets_addr = = LLDB_INVALID_ADDRESS )
{
2010-10-12 17:33:06 +00:00
static ConstString g_dispatch_queue_offsets_symbol_name ( " dispatch_queue_offsets " ) ;
const Symbol * dispatch_queue_offsets_symbol = NULL ;
2012-02-26 05:51:37 +00:00
ModuleSpec libSystem_module_spec ( FileSpec ( " libSystem.B.dylib " , false ) ) ;
ModuleSP module_sp ( GetTarget ( ) . GetImages ( ) . FindFirstModule ( libSystem_module_spec ) ) ;
2010-10-12 17:33:06 +00:00
if ( module_sp )
dispatch_queue_offsets_symbol = module_sp - > FindFirstSymbolWithNameAndType ( g_dispatch_queue_offsets_symbol_name , eSymbolTypeData ) ;
if ( dispatch_queue_offsets_symbol = = NULL )
{
2012-02-26 05:51:37 +00:00
ModuleSpec libdispatch_module_spec ( FileSpec ( " libdispatch.dylib " , false ) ) ;
module_sp = GetTarget ( ) . GetImages ( ) . FindFirstModule ( libdispatch_module_spec ) ;
2010-10-12 17:33:06 +00:00
if ( module_sp )
dispatch_queue_offsets_symbol = module_sp - > FindFirstSymbolWithNameAndType ( g_dispatch_queue_offsets_symbol_name , eSymbolTypeData ) ;
}
2010-06-08 16:52:24 +00:00
if ( dispatch_queue_offsets_symbol )
2012-03-07 21:03:09 +00:00
m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol - > GetAddress ( ) . GetLoadAddress ( & m_target ) ;
2010-06-08 16:52:24 +00:00
if ( m_dispatch_queue_offsets_addr = = LLDB_INVALID_ADDRESS )
return NULL ;
}
uint8_t memory_buffer [ 8 ] ;
2011-02-15 21:59:32 +00:00
DataExtractor data ( memory_buffer ,
sizeof ( memory_buffer ) ,
m_target . GetArchitecture ( ) . GetByteOrder ( ) ,
m_target . GetArchitecture ( ) . GetAddressByteSize ( ) ) ;
2010-06-08 16:52:24 +00:00
// Excerpt from src/queue_private.h
struct dispatch_queue_offsets_s
{
uint16_t dqo_version ;
2012-11-10 06:54:30 +00:00
uint16_t dqo_label ; // in version 1-3, offset to string; in version 4+, offset to a pointer to a string
uint16_t dqo_label_size ; // in version 1-3, length of string; in version 4+, size of a (void*) in this process
2010-06-08 16:52:24 +00:00
} dispatch_queue_offsets ;
Error error ;
if ( ReadMemory ( m_dispatch_queue_offsets_addr , memory_buffer , sizeof ( dispatch_queue_offsets ) , error ) = = sizeof ( dispatch_queue_offsets ) )
{
2013-01-25 18:06:21 +00:00
lldb : : offset_t data_offset = 0 ;
2010-06-08 16:52:24 +00:00
if ( data . GetU16 ( & data_offset , & dispatch_queue_offsets . dqo_version , sizeof ( dispatch_queue_offsets ) / sizeof ( uint16_t ) ) )
{
if ( ReadMemory ( thread_dispatch_qaddr , & memory_buffer , data . GetAddressByteSize ( ) , error ) = = data . GetAddressByteSize ( ) )
{
data_offset = 0 ;
lldb : : addr_t queue_addr = data . GetAddress ( & data_offset ) ;
2012-11-10 06:54:30 +00:00
if ( dispatch_queue_offsets . dqo_version > = 4 )
{
// libdispatch versions 4+, pointer to dispatch name is in the
// queue structure.
lldb : : addr_t pointer_to_label_address = queue_addr + dispatch_queue_offsets . dqo_label ;
if ( ReadMemory ( pointer_to_label_address , & memory_buffer , data . GetAddressByteSize ( ) , error ) = = data . GetAddressByteSize ( ) )
{
data_offset = 0 ;
lldb : : addr_t label_addr = data . GetAddress ( & data_offset ) ;
ReadCStringFromMemory ( label_addr , dispatch_queue_name , error ) ;
}
}
else
{
// libdispatch versions 1-3, dispatch name is a fixed width char array
// in the queue structure.
lldb : : addr_t label_addr = queue_addr + dispatch_queue_offsets . dqo_label ;
dispatch_queue_name . resize ( dispatch_queue_offsets . dqo_label_size , ' \0 ' ) ;
size_t bytes_read = ReadMemory ( label_addr , & dispatch_queue_name [ 0 ] , dispatch_queue_offsets . dqo_label_size , error ) ;
if ( bytes_read < dispatch_queue_offsets . dqo_label_size )
dispatch_queue_name . erase ( bytes_read ) ;
}
2010-06-08 16:52:24 +00:00
}
}
}
}
if ( dispatch_queue_name . empty ( ) )
return NULL ;
return dispatch_queue_name . c_str ( ) ;
}
2011-03-08 22:40:15 +00:00
//uint32_t
//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
//{
// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver
// // process and ask it for the list of processes. But if we are local, we can let the Host do it.
// if (m_local_debugserver)
// {
// return Host::ListProcessesMatchingName (name, matches, pids);
// }
// else
// {
// // FIXME: Implement talking to the remote debugserver.
// return 0;
// }
//
//}
//
2011-01-22 01:33:44 +00:00
bool
ProcessGDBRemote : : NewThreadNotifyBreakpointHit ( void * baton ,
lldb_private : : StoppointCallbackContext * context ,
lldb : : user_id_t break_id ,
lldb : : user_id_t break_loc_id )
{
// I don't think I have to do anything here, just make sure I notice the new thread when it starts to
// run so I can stop it if that's what I want to do.
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
2011-01-22 01:33:44 +00:00
if ( log )
log - > Printf ( " Hit New Thread Notification breakpoint. " ) ;
return false ;
}
bool
ProcessGDBRemote : : StartNoticingNewThreads ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
2012-05-15 02:33:01 +00:00
if ( m_thread_create_bp_sp )
2011-01-22 01:33:44 +00:00
{
2012-05-15 02:33:01 +00:00
if ( log & & log - > GetVerbose ( ) )
log - > Printf ( " Enabled noticing new thread breakpoint. " ) ;
m_thread_create_bp_sp - > SetEnabled ( true ) ;
2011-01-22 01:33:44 +00:00
}
2012-05-15 02:33:01 +00:00
else
2011-01-22 01:33:44 +00:00
{
2012-05-15 02:33:01 +00:00
PlatformSP platform_sp ( m_target . GetPlatform ( ) ) ;
if ( platform_sp )
2011-01-22 01:33:44 +00:00
{
2012-05-15 02:33:01 +00:00
m_thread_create_bp_sp = platform_sp - > SetThreadCreationBreakpoint ( m_target ) ;
if ( m_thread_create_bp_sp )
2011-01-22 01:33:44 +00:00
{
2011-10-15 00:21:37 +00:00
if ( log & & log - > GetVerbose ( ) )
2012-05-15 02:33:01 +00:00
log - > Printf ( " Successfully created new thread notification breakpoint %i " , m_thread_create_bp_sp - > GetID ( ) ) ;
m_thread_create_bp_sp - > SetCallback ( ProcessGDBRemote : : NewThreadNotifyBreakpointHit , this , true ) ;
2011-01-22 01:33:44 +00:00
}
else
{
if ( log )
log - > Printf ( " Failed to create new thread notification breakpoint. " ) ;
}
}
}
2012-05-15 02:33:01 +00:00
return m_thread_create_bp_sp . get ( ) ! = NULL ;
2011-01-22 01:33:44 +00:00
}
bool
ProcessGDBRemote : : StopNoticingNewThreads ( )
{
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_STEP ) ) ;
2011-10-15 00:21:37 +00:00
if ( log & & log - > GetVerbose ( ) )
2011-02-08 05:19:01 +00:00
log - > Printf ( " Disabling new thread notification breakpoint. " ) ;
2012-05-15 02:33:01 +00:00
if ( m_thread_create_bp_sp )
m_thread_create_bp_sp - > SetEnabled ( false ) ;
2011-01-22 01:33:44 +00:00
return true ;
}
2012-10-03 01:29:34 +00:00
lldb_private : : DynamicLoader *
ProcessGDBRemote : : GetDynamicLoader ( )
{
if ( m_dyld_ap . get ( ) = = NULL )
m_dyld_ap . reset ( DynamicLoader : : FindPlugin ( this , m_dyld_plugin_name . empty ( ) ? NULL : m_dyld_plugin_name . c_str ( ) ) ) ;
return m_dyld_ap . get ( ) ;
}
2011-01-22 01:33:44 +00:00
2012-10-13 02:07:45 +00:00
2012-10-15 22:42:16 +00:00
class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
2012-10-13 02:07:45 +00:00
{
private :
public :
2012-10-15 22:42:16 +00:00
CommandObjectProcessGDBRemotePacketHistory ( CommandInterpreter & interpreter ) :
2012-10-13 02:07:45 +00:00
CommandObjectParsed ( interpreter ,
2012-10-15 22:42:16 +00:00
" process plugin packet history " ,
" Dumps the packet history buffer. " ,
2012-10-13 02:07:45 +00:00
NULL )
{
}
2012-10-15 22:42:16 +00:00
~ CommandObjectProcessGDBRemotePacketHistory ( )
2012-10-13 02:07:45 +00:00
{
}
bool
DoExecute ( Args & command , CommandReturnObject & result )
{
2012-10-15 22:42:16 +00:00
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc = = 0 )
{
ProcessGDBRemote * process = ( ProcessGDBRemote * ) m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
if ( process )
{
process - > GetGDBRemote ( ) . DumpHistory ( result . GetOutputStream ( ) ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
return true ;
}
}
else
{
result . AppendErrorWithFormat ( " '%s' takes no arguments " , m_cmd_name . c_str ( ) ) ;
}
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
} ;
class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
{
private :
public :
CommandObjectProcessGDBRemotePacketSend ( CommandInterpreter & interpreter ) :
CommandObjectParsed ( interpreter ,
" process plugin packet send " ,
" Send a custom packet through the GDB remote protocol and print the answer. "
" The packet header and footer will automatically be added to the packet prior to sending and stripped from the result. " ,
NULL )
{
}
~ CommandObjectProcessGDBRemotePacketSend ( )
{
}
bool
DoExecute ( Args & command , CommandReturnObject & result )
{
const size_t argc = command . GetArgumentCount ( ) ;
if ( argc = = 0 )
{
result . AppendErrorWithFormat ( " '%s' takes a one or more packet content arguments " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ProcessGDBRemote * process = ( ProcessGDBRemote * ) m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
if ( process )
{
2012-11-26 20:42:03 +00:00
for ( size_t i = 0 ; i < argc ; + + i )
2012-10-15 22:42:16 +00:00
{
2012-11-26 20:42:03 +00:00
const char * packet_cstr = command . GetArgumentAtIndex ( 0 ) ;
bool send_async = true ;
StringExtractorGDBRemote response ;
process - > GetGDBRemote ( ) . SendPacketAndWaitForResponse ( packet_cstr , response , send_async ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
Stream & output_strm = result . GetOutputStream ( ) ;
output_strm . Printf ( " packet: %s \n " , packet_cstr ) ;
2013-01-18 23:11:53 +00:00
std : : string & response_str = response . GetStringRef ( ) ;
if ( strcmp ( packet_cstr , " qGetProfileData " ) = = 0 )
{
response_str = process - > GetGDBRemote ( ) . HarmonizeThreadIdsForProfileData ( process , response ) ;
}
2012-11-26 20:42:03 +00:00
if ( response_str . empty ( ) )
output_strm . PutCString ( " response: \n error: UNIMPLEMENTED \n " ) ;
else
output_strm . Printf ( " response: %s \n " , response . GetStringRef ( ) . c_str ( ) ) ;
2012-10-15 22:42:16 +00:00
}
}
2012-10-13 02:07:45 +00:00
return true ;
}
} ;
2013-02-01 23:03:47 +00:00
class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw
{
private :
public :
CommandObjectProcessGDBRemotePacketMonitor ( CommandInterpreter & interpreter ) :
CommandObjectRaw ( interpreter ,
" process plugin packet monitor " ,
2013-02-14 18:39:30 +00:00
" Send a qRcmd packet through the GDB remote protocol and print the response. "
" The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed. " ,
2013-02-01 23:03:47 +00:00
NULL )
{
}
~ CommandObjectProcessGDBRemotePacketMonitor ( )
{
}
bool
DoExecute ( const char * command , CommandReturnObject & result )
{
if ( command = = NULL | | command [ 0 ] = = ' \0 ' )
{
result . AppendErrorWithFormat ( " '%s' takes a command string argument " , m_cmd_name . c_str ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
return false ;
}
ProcessGDBRemote * process = ( ProcessGDBRemote * ) m_interpreter . GetExecutionContext ( ) . GetProcessPtr ( ) ;
if ( process )
{
StreamString packet ;
2013-02-14 18:39:30 +00:00
packet . PutCString ( " qRcmd, " ) ;
2013-02-01 23:03:47 +00:00
packet . PutBytesAsRawHex8 ( command , strlen ( command ) ) ;
const char * packet_cstr = packet . GetString ( ) . c_str ( ) ;
bool send_async = true ;
StringExtractorGDBRemote response ;
process - > GetGDBRemote ( ) . SendPacketAndWaitForResponse ( packet_cstr , response , send_async ) ;
result . SetStatus ( eReturnStatusSuccessFinishResult ) ;
Stream & output_strm = result . GetOutputStream ( ) ;
output_strm . Printf ( " packet: %s \n " , packet_cstr ) ;
const std : : string & response_str = response . GetStringRef ( ) ;
if ( response_str . empty ( ) )
output_strm . PutCString ( " response: \n error: UNIMPLEMENTED \n " ) ;
else
output_strm . Printf ( " response: %s \n " , response . GetStringRef ( ) . c_str ( ) ) ;
}
return true ;
}
} ;
2012-10-15 22:42:16 +00:00
class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword
{
private :
public :
CommandObjectProcessGDBRemotePacket ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" process plugin packet " ,
" Commands that deal with GDB remote packets. " ,
NULL )
{
LoadSubCommand ( " history " , CommandObjectSP ( new CommandObjectProcessGDBRemotePacketHistory ( interpreter ) ) ) ;
LoadSubCommand ( " send " , CommandObjectSP ( new CommandObjectProcessGDBRemotePacketSend ( interpreter ) ) ) ;
2013-02-01 23:03:47 +00:00
LoadSubCommand ( " monitor " , CommandObjectSP ( new CommandObjectProcessGDBRemotePacketMonitor ( interpreter ) ) ) ;
2012-10-15 22:42:16 +00:00
}
~ CommandObjectProcessGDBRemotePacket ( )
{
}
} ;
2012-10-13 02:07:45 +00:00
class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword
{
public :
CommandObjectMultiwordProcessGDBRemote ( CommandInterpreter & interpreter ) :
CommandObjectMultiword ( interpreter ,
" process plugin " ,
" A set of commands for operating on a ProcessGDBRemote process. " ,
" process plugin <subcommand> [<subcommand-options>] " )
{
LoadSubCommand ( " packet " , CommandObjectSP ( new CommandObjectProcessGDBRemotePacket ( interpreter ) ) ) ;
}
~ CommandObjectMultiwordProcessGDBRemote ( )
{
}
} ;
CommandObject *
ProcessGDBRemote : : GetPluginCommandObject ( )
{
if ( ! m_command_sp )
m_command_sp . reset ( new CommandObjectMultiwordProcessGDBRemote ( GetTarget ( ) . GetDebugger ( ) . GetCommandInterpreter ( ) ) ) ;
return m_command_sp . get ( ) ;
}