2010-06-08 16:52:24 +00:00
//===-- ObjectFileMachO.cpp -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
2011-12-03 02:30:59 +00:00
# include "llvm/ADT/StringRef.h"
2011-03-07 23:44:08 +00:00
# include "llvm/Support/MachO.h"
2010-06-08 16:52:24 +00:00
# include "ObjectFileMachO.h"
2012-09-05 01:38:55 +00:00
# include "lldb/lldb-private-log.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/ArchSpec.h"
# include "lldb/Core/DataBuffer.h"
2013-04-10 05:58:57 +00:00
# include "lldb/Core/Debugger.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/FileSpecList.h"
2012-09-05 01:38:55 +00:00
# include "lldb/Core/Log.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/Module.h"
2013-04-24 22:29:28 +00:00
# include "lldb/Core/ModuleSpec.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/PluginManager.h"
2012-04-24 03:06:13 +00:00
# include "lldb/Core/RangeMap.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Core/Section.h"
# include "lldb/Core/StreamFile.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Core/Timer.h"
# include "lldb/Core/UUID.h"
2012-01-05 03:57:59 +00:00
# include "lldb/Host/Host.h"
# include "lldb/Host/FileSpec.h"
2011-10-12 02:08:07 +00:00
# include "lldb/Symbol/ClangNamespaceDecl.h"
2013-03-21 03:36:01 +00:00
# include "lldb/Symbol/DWARFCallFrameInfo.h"
2010-06-08 16:52:24 +00:00
# include "lldb/Symbol/ObjectFile.h"
2012-04-18 05:19:20 +00:00
# include "lldb/Target/Platform.h"
2012-02-05 02:38:54 +00:00
# include "lldb/Target/Process.h"
2012-04-18 05:19:20 +00:00
# include "lldb/Target/Target.h"
2012-02-13 23:10:39 +00:00
# include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
# include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
2012-02-09 06:16:32 +00:00
# include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
2010-06-08 16:52:24 +00:00
2013-04-16 06:24:42 +00:00
# if defined (__APPLE__) && defined (__arm__)
// GetLLDBSharedCacheUUID() needs to call dlsym()
# include <dlfcn.h>
# endif
2013-04-17 19:24:22 +00:00
# ifndef __APPLE__
# include "Utility/UuidCompatibility.h"
# endif
2010-06-08 16:52:24 +00:00
using namespace lldb ;
using namespace lldb_private ;
2010-07-21 22:12:05 +00:00
using namespace llvm : : MachO ;
2010-06-08 16:52:24 +00:00
2013-03-06 23:19:17 +00:00
class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64
2012-02-09 06:16:32 +00:00
{
public :
RegisterContextDarwin_x86_64_Mach ( lldb_private : : Thread & thread , const DataExtractor & data ) :
RegisterContextDarwin_x86_64 ( thread , 0 )
{
SetRegisterDataFrom_LC_THREAD ( data ) ;
}
virtual void
InvalidateAllRegisters ( )
{
// Do nothing... registers are always valid...
}
void
SetRegisterDataFrom_LC_THREAD ( const DataExtractor & data )
{
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = 0 ;
2012-02-09 06:16:32 +00:00
SetError ( GPRRegSet , Read , - 1 ) ;
SetError ( FPURegSet , Read , - 1 ) ;
SetError ( EXCRegSet , Read , - 1 ) ;
2012-02-13 23:10:39 +00:00
bool done = false ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
while ( ! done )
2012-02-09 06:16:32 +00:00
{
2012-02-13 23:10:39 +00:00
int flavor = data . GetU32 ( & offset ) ;
if ( flavor = = 0 )
done = true ;
else
2012-02-09 06:16:32 +00:00
{
2012-02-13 23:10:39 +00:00
uint32_t i ;
uint32_t count = data . GetU32 ( & offset ) ;
switch ( flavor )
{
case GPRRegSet :
for ( i = 0 ; i < count ; + + i )
( & gpr . rax ) [ i ] = data . GetU64 ( & offset ) ;
SetError ( GPRRegSet , Read , 0 ) ;
done = true ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
break ;
case FPURegSet :
// TODO: fill in FPU regs....
//SetError (FPURegSet, Read, -1);
done = true ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
break ;
case EXCRegSet :
exc . trapno = data . GetU32 ( & offset ) ;
exc . err = data . GetU32 ( & offset ) ;
exc . faultvaddr = data . GetU64 ( & offset ) ;
SetError ( EXCRegSet , Read , 0 ) ;
done = true ;
break ;
case 7 :
case 8 :
case 9 :
// fancy flavors that encapsulate of the the above
// falvors...
break ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
default :
done = true ;
break ;
}
2012-02-09 06:16:32 +00:00
}
2012-02-13 23:10:39 +00:00
}
}
protected :
virtual int
DoReadGPR ( lldb : : tid_t tid , int flavor , GPR & gpr )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoReadFPU ( lldb : : tid_t tid , int flavor , FPU & fpu )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoReadEXC ( lldb : : tid_t tid , int flavor , EXC & exc )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteGPR ( lldb : : tid_t tid , int flavor , const GPR & gpr )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteFPU ( lldb : : tid_t tid , int flavor , const FPU & fpu )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteEXC ( lldb : : tid_t tid , int flavor , const EXC & exc )
{
return 0 ;
}
} ;
2012-02-09 06:16:32 +00:00
2012-02-13 23:10:39 +00:00
2013-03-06 23:19:17 +00:00
class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386
2012-02-13 23:10:39 +00:00
{
public :
RegisterContextDarwin_i386_Mach ( lldb_private : : Thread & thread , const DataExtractor & data ) :
RegisterContextDarwin_i386 ( thread , 0 )
{
SetRegisterDataFrom_LC_THREAD ( data ) ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual void
InvalidateAllRegisters ( )
{
// Do nothing... registers are always valid...
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
void
SetRegisterDataFrom_LC_THREAD ( const DataExtractor & data )
{
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = 0 ;
2012-02-13 23:10:39 +00:00
SetError ( GPRRegSet , Read , - 1 ) ;
SetError ( FPURegSet , Read , - 1 ) ;
SetError ( EXCRegSet , Read , - 1 ) ;
bool done = false ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
while ( ! done )
{
int flavor = data . GetU32 ( & offset ) ;
if ( flavor = = 0 )
done = true ;
else
2012-02-09 06:16:32 +00:00
{
2012-02-13 23:10:39 +00:00
uint32_t i ;
uint32_t count = data . GetU32 ( & offset ) ;
switch ( flavor )
{
case GPRRegSet :
for ( i = 0 ; i < count ; + + i )
( & gpr . eax ) [ i ] = data . GetU32 ( & offset ) ;
SetError ( GPRRegSet , Read , 0 ) ;
done = true ;
break ;
case FPURegSet :
// TODO: fill in FPU regs....
//SetError (FPURegSet, Read, -1);
done = true ;
break ;
case EXCRegSet :
exc . trapno = data . GetU32 ( & offset ) ;
exc . err = data . GetU32 ( & offset ) ;
exc . faultvaddr = data . GetU32 ( & offset ) ;
SetError ( EXCRegSet , Read , 0 ) ;
done = true ;
break ;
case 7 :
case 8 :
case 9 :
// fancy flavors that encapsulate of the the above
// falvors...
break ;
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
default :
done = true ;
break ;
}
2012-02-09 06:16:32 +00:00
}
}
}
protected :
virtual int
DoReadGPR ( lldb : : tid_t tid , int flavor , GPR & gpr )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-09 06:16:32 +00:00
virtual int
DoReadFPU ( lldb : : tid_t tid , int flavor , FPU & fpu )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-09 06:16:32 +00:00
virtual int
DoReadEXC ( lldb : : tid_t tid , int flavor , EXC & exc )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-09 06:16:32 +00:00
virtual int
DoWriteGPR ( lldb : : tid_t tid , int flavor , const GPR & gpr )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-09 06:16:32 +00:00
virtual int
DoWriteFPU ( lldb : : tid_t tid , int flavor , const FPU & fpu )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-09 06:16:32 +00:00
virtual int
DoWriteEXC ( lldb : : tid_t tid , int flavor , const EXC & exc )
{
return 0 ;
}
} ;
2013-03-06 23:19:17 +00:00
class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm
2012-02-13 23:10:39 +00:00
{
public :
RegisterContextDarwin_arm_Mach ( lldb_private : : Thread & thread , const DataExtractor & data ) :
2012-10-30 23:57:32 +00:00
RegisterContextDarwin_arm ( thread , 0 )
2012-02-13 23:10:39 +00:00
{
SetRegisterDataFrom_LC_THREAD ( data ) ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual void
InvalidateAllRegisters ( )
{
// Do nothing... registers are always valid...
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
void
SetRegisterDataFrom_LC_THREAD ( const DataExtractor & data )
{
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = 0 ;
2012-02-13 23:10:39 +00:00
SetError ( GPRRegSet , Read , - 1 ) ;
SetError ( FPURegSet , Read , - 1 ) ;
SetError ( EXCRegSet , Read , - 1 ) ;
2013-05-14 03:25:58 +00:00
bool done = false ;
while ( ! done )
2012-02-13 23:10:39 +00:00
{
2013-05-14 03:25:58 +00:00
int flavor = data . GetU32 ( & offset ) ;
uint32_t count = data . GetU32 ( & offset ) ;
2013-05-14 04:50:47 +00:00
lldb : : offset_t next_thread_state = offset + ( count * 4 ) ;
2013-05-14 03:25:58 +00:00
switch ( flavor )
{
case GPRRegSet :
for ( uint32_t i = 0 ; i < count ; + + i )
2013-05-14 04:50:47 +00:00
{
2013-05-14 03:25:58 +00:00
gpr . r [ i ] = data . GetU32 ( & offset ) ;
2013-05-14 04:50:47 +00:00
}
// Note that gpr.cpsr is also copied by the above loop; this loop technically extends
// one element past the end of the gpr.r[] array.
2013-05-14 03:25:58 +00:00
SetError ( GPRRegSet , Read , 0 ) ;
2013-05-14 04:50:47 +00:00
offset = next_thread_state ;
2013-05-14 03:25:58 +00:00
break ;
case FPURegSet :
{
2013-05-14 03:52:22 +00:00
uint8_t * fpu_reg_buf = ( uint8_t * ) & fpu . floats . s [ 0 ] ;
const int fpu_reg_buf_size = sizeof ( fpu . floats ) ;
if ( data . ExtractBytes ( offset , fpu_reg_buf_size , eByteOrderLittle , fpu_reg_buf ) = = fpu_reg_buf_size )
2013-05-14 03:25:58 +00:00
{
2013-05-14 03:52:22 +00:00
offset + = fpu_reg_buf_size ;
fpu . fpscr = data . GetU32 ( & offset ) ;
SetError ( FPURegSet , Read , 0 ) ;
}
else
{
done = true ;
2013-05-14 03:25:58 +00:00
}
}
2013-05-14 04:50:47 +00:00
offset = next_thread_state ;
2013-05-14 03:25:58 +00:00
break ;
case EXCRegSet :
2013-05-14 04:50:47 +00:00
if ( count = = 3 )
{
exc . exception = data . GetU32 ( & offset ) ;
exc . fsr = data . GetU32 ( & offset ) ;
exc . far = data . GetU32 ( & offset ) ;
SetError ( EXCRegSet , Read , 0 ) ;
}
2013-05-14 03:25:58 +00:00
done = true ;
2013-05-14 04:50:47 +00:00
offset = next_thread_state ;
2013-05-14 03:25:58 +00:00
break ;
// Unknown register set flavor, stop trying to parse.
default :
done = true ;
}
2012-02-13 23:10:39 +00:00
}
}
protected :
virtual int
DoReadGPR ( lldb : : tid_t tid , int flavor , GPR & gpr )
{
2013-05-14 04:50:47 +00:00
return - 1 ;
2012-02-13 23:10:39 +00:00
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoReadFPU ( lldb : : tid_t tid , int flavor , FPU & fpu )
{
2013-05-14 04:50:47 +00:00
return - 1 ;
2012-02-13 23:10:39 +00:00
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoReadEXC ( lldb : : tid_t tid , int flavor , EXC & exc )
{
2013-05-14 04:50:47 +00:00
return - 1 ;
2012-02-13 23:10:39 +00:00
}
2012-10-30 23:57:32 +00:00
virtual int
DoReadDBG ( lldb : : tid_t tid , int flavor , DBG & dbg )
{
return - 1 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteGPR ( lldb : : tid_t tid , int flavor , const GPR & gpr )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteFPU ( lldb : : tid_t tid , int flavor , const FPU & fpu )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-02-13 23:10:39 +00:00
virtual int
DoWriteEXC ( lldb : : tid_t tid , int flavor , const EXC & exc )
{
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-10-30 23:57:32 +00:00
virtual int
DoWriteDBG ( lldb : : tid_t tid , int flavor , const DBG & dbg )
{
return - 1 ;
}
2012-02-13 23:10:39 +00:00
} ;
2013-05-15 19:52:08 +00:00
static uint32_t
MachHeaderSizeFromMagic ( uint32_t magic )
{
switch ( magic )
{
2013-08-27 05:04:57 +00:00
case MH_MAGIC :
case MH_CIGAM :
2013-05-15 19:52:08 +00:00
return sizeof ( struct mach_header ) ;
2013-08-27 05:04:57 +00:00
case MH_MAGIC_64 :
case MH_CIGAM_64 :
2013-05-15 19:52:08 +00:00
return sizeof ( struct mach_header_64 ) ;
break ;
default :
break ;
}
return 0 ;
}
2011-03-19 01:12:21 +00:00
# define MACHO_NLIST_ARM_SYMBOL_IS_THUMB 0x0008
2010-06-08 16:52:24 +00:00
void
ObjectFileMachO : : Initialize ( )
{
PluginManager : : RegisterPlugin ( GetPluginNameStatic ( ) ,
GetPluginDescriptionStatic ( ) ,
2012-02-05 02:38:54 +00:00
CreateInstance ,
2013-04-24 22:29:28 +00:00
CreateMemoryInstance ,
GetModuleSpecifications ) ;
2010-06-08 16:52:24 +00:00
}
void
ObjectFileMachO : : Terminate ( )
{
PluginManager : : UnregisterPlugin ( CreateInstance ) ;
}
2013-05-10 21:47:16 +00:00
lldb_private : : ConstString
2010-06-08 16:52:24 +00:00
ObjectFileMachO : : GetPluginNameStatic ( )
{
2013-05-10 21:47:16 +00:00
static ConstString g_name ( " mach-o " ) ;
return g_name ;
2010-06-08 16:52:24 +00:00
}
const char *
ObjectFileMachO : : GetPluginDescriptionStatic ( )
{
return " Mach-o object file reader (32 and 64 bit) " ;
}
ObjectFile *
2013-02-06 17:22:03 +00:00
ObjectFileMachO : : CreateInstance ( const lldb : : ModuleSP & module_sp ,
DataBufferSP & data_sp ,
lldb : : offset_t data_offset ,
const FileSpec * file ,
lldb : : offset_t file_offset ,
lldb : : offset_t length )
2010-06-08 16:52:24 +00:00
{
2013-02-06 17:22:03 +00:00
if ( ! data_sp )
2010-06-08 16:52:24 +00:00
{
2013-02-06 17:22:03 +00:00
data_sp = file - > MemoryMapFileContents ( file_offset , length ) ;
data_offset = 0 ;
}
if ( ObjectFileMachO : : MagicBytesMatch ( data_sp , data_offset , length ) )
{
// Update the data to contain the entire file if it doesn't already
if ( data_sp - > GetByteSize ( ) < length )
{
data_sp = file - > MemoryMapFileContents ( file_offset , length ) ;
data_offset = 0 ;
}
2013-04-18 22:45:39 +00:00
std : : unique_ptr < ObjectFile > objfile_ap ( new ObjectFileMachO ( module_sp , data_sp , data_offset , file , file_offset , length ) ) ;
2010-06-08 16:52:24 +00:00
if ( objfile_ap . get ( ) & & objfile_ap - > ParseHeader ( ) )
return objfile_ap . release ( ) ;
}
return NULL ;
}
2012-02-05 02:38:54 +00:00
ObjectFile *
2013-03-06 23:19:17 +00:00
ObjectFileMachO : : CreateMemoryInstance ( const lldb : : ModuleSP & module_sp ,
DataBufferSP & data_sp ,
const ProcessSP & process_sp ,
2012-02-05 02:38:54 +00:00
lldb : : addr_t header_addr )
{
if ( ObjectFileMachO : : MagicBytesMatch ( data_sp , 0 , data_sp - > GetByteSize ( ) ) )
{
2013-04-18 22:45:39 +00:00
std : : unique_ptr < ObjectFile > objfile_ap ( new ObjectFileMachO ( module_sp , data_sp , process_sp , header_addr ) ) ;
2012-02-05 02:38:54 +00:00
if ( objfile_ap . get ( ) & & objfile_ap - > ParseHeader ( ) )
return objfile_ap . release ( ) ;
}
2013-03-06 23:19:17 +00:00
return NULL ;
2012-02-05 02:38:54 +00:00
}
2013-04-24 22:29:28 +00:00
size_t
ObjectFileMachO : : GetModuleSpecifications ( const lldb_private : : FileSpec & file ,
lldb : : DataBufferSP & data_sp ,
lldb : : offset_t data_offset ,
lldb : : offset_t file_offset ,
lldb : : offset_t length ,
lldb_private : : ModuleSpecList & specs )
{
const size_t initial_count = specs . GetSize ( ) ;
if ( ObjectFileMachO : : MagicBytesMatch ( data_sp , 0 , data_sp - > GetByteSize ( ) ) )
{
DataExtractor data ;
data . SetData ( data_sp ) ;
llvm : : MachO : : mach_header header ;
if ( ParseHeader ( data , & data_offset , header ) )
{
if ( header . sizeofcmds > = data_sp - > GetByteSize ( ) )
{
data_sp = file . ReadFileContents ( file_offset , header . sizeofcmds ) ;
2013-07-12 22:07:46 +00:00
data . SetData ( data_sp ) ;
data_offset = MachHeaderSizeFromMagic ( header . magic ) ;
2013-04-24 22:29:28 +00:00
}
if ( data_sp )
{
ModuleSpec spec ;
spec . GetFileSpec ( ) = file ;
spec . GetArchitecture ( ) . SetArchitecture ( eArchTypeMachO ,
header . cputype ,
header . cpusubtype ) ;
2013-08-27 05:04:57 +00:00
if ( header . filetype = = MH_PRELOAD ) // 0x5u
2013-08-27 02:22:06 +00:00
{
// Set OS to "unknown" - this is a standalone binary with no dyld et al
spec . GetArchitecture ( ) . GetTriple ( ) . setOS ( llvm : : Triple : : UnknownOS ) ;
}
2013-04-24 22:29:28 +00:00
if ( spec . GetArchitecture ( ) . IsValid ( ) )
{
GetUUID ( header , data , data_offset , spec . GetUUID ( ) ) ;
specs . Append ( spec ) ;
}
}
}
}
return specs . GetSize ( ) - initial_count ;
}
2012-02-05 02:38:54 +00:00
const ConstString &
ObjectFileMachO : : GetSegmentNameTEXT ( )
{
static ConstString g_segment_name_TEXT ( " __TEXT " ) ;
return g_segment_name_TEXT ;
}
const ConstString &
ObjectFileMachO : : GetSegmentNameDATA ( )
{
static ConstString g_segment_name_DATA ( " __DATA " ) ;
return g_segment_name_DATA ;
}
const ConstString &
ObjectFileMachO : : GetSegmentNameOBJC ( )
{
static ConstString g_segment_name_OBJC ( " __OBJC " ) ;
return g_segment_name_OBJC ;
}
const ConstString &
ObjectFileMachO : : GetSegmentNameLINKEDIT ( )
{
static ConstString g_section_name_LINKEDIT ( " __LINKEDIT " ) ;
return g_section_name_LINKEDIT ;
}
const ConstString &
ObjectFileMachO : : GetSectionNameEHFrame ( )
{
static ConstString g_section_name_eh_frame ( " __eh_frame " ) ;
return g_section_name_eh_frame ;
}
2010-06-08 16:52:24 +00:00
bool
2013-03-06 23:19:17 +00:00
ObjectFileMachO : : MagicBytesMatch ( DataBufferSP & data_sp ,
lldb : : addr_t data_offset ,
2012-01-12 05:25:17 +00:00
lldb : : addr_t data_length )
2010-06-08 16:52:24 +00:00
{
2012-01-12 05:25:17 +00:00
DataExtractor data ;
data . SetData ( data_sp , data_offset , data_length ) ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = 0 ;
2010-06-08 16:52:24 +00:00
uint32_t magic = data . GetU32 ( & offset ) ;
return MachHeaderSizeFromMagic ( magic ) ! = 0 ;
}
2013-02-06 17:22:03 +00:00
ObjectFileMachO : : ObjectFileMachO ( const lldb : : ModuleSP & module_sp ,
DataBufferSP & data_sp ,
lldb : : offset_t data_offset ,
const FileSpec * file ,
lldb : : offset_t file_offset ,
lldb : : offset_t length ) :
ObjectFile ( module_sp , file , file_offset , length , data_sp , data_offset ) ,
2012-02-09 06:16:32 +00:00
m_mach_segments ( ) ,
m_mach_sections ( ) ,
m_entry_point_address ( ) ,
m_thread_context_offsets ( ) ,
m_thread_context_offsets_valid ( false )
2010-06-08 16:52:24 +00:00
{
2011-02-04 21:13:05 +00:00
: : memset ( & m_header , 0 , sizeof ( m_header ) ) ;
: : memset ( & m_dysymtab , 0 , sizeof ( m_dysymtab ) ) ;
2010-06-08 16:52:24 +00:00
}
2012-02-24 01:59:29 +00:00
ObjectFileMachO : : ObjectFileMachO ( const lldb : : ModuleSP & module_sp ,
2012-02-05 02:38:54 +00:00
lldb : : DataBufferSP & header_data_sp ,
const lldb : : ProcessSP & process_sp ,
lldb : : addr_t header_addr ) :
2012-02-24 01:59:29 +00:00
ObjectFile ( module_sp , process_sp , header_addr , header_data_sp ) ,
2012-02-09 06:16:32 +00:00
m_mach_segments ( ) ,
m_mach_sections ( ) ,
m_entry_point_address ( ) ,
m_thread_context_offsets ( ) ,
m_thread_context_offsets_valid ( false )
2012-02-05 02:38:54 +00:00
{
: : memset ( & m_header , 0 , sizeof ( m_header ) ) ;
: : memset ( & m_dysymtab , 0 , sizeof ( m_dysymtab ) ) ;
}
2010-06-08 16:52:24 +00:00
ObjectFileMachO : : ~ ObjectFileMachO ( )
{
}
2013-04-24 22:29:28 +00:00
bool
ObjectFileMachO : : ParseHeader ( DataExtractor & data ,
lldb : : offset_t * data_offset_ptr ,
llvm : : MachO : : mach_header & header )
{
data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
// Leave magic in the original byte order
header . magic = data . GetU32 ( data_offset_ptr ) ;
bool can_parse = false ;
bool is_64_bit = false ;
switch ( header . magic )
{
2013-08-27 05:04:57 +00:00
case MH_MAGIC :
2013-04-24 22:29:28 +00:00
data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
data . SetAddressByteSize ( 4 ) ;
can_parse = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_MAGIC_64 :
2013-04-24 22:29:28 +00:00
data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
data . SetAddressByteSize ( 8 ) ;
can_parse = true ;
is_64_bit = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_CIGAM :
2013-04-24 22:29:28 +00:00
data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) = = eByteOrderBig ? eByteOrderLittle : eByteOrderBig ) ;
data . SetAddressByteSize ( 4 ) ;
can_parse = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_CIGAM_64 :
2013-04-24 22:29:28 +00:00
data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) = = eByteOrderBig ? eByteOrderLittle : eByteOrderBig ) ;
data . SetAddressByteSize ( 8 ) ;
is_64_bit = true ;
can_parse = true ;
break ;
default :
break ;
}
if ( can_parse )
{
data . GetU32 ( data_offset_ptr , & header . cputype , 6 ) ;
if ( is_64_bit )
* data_offset_ptr + = 4 ;
return true ;
}
else
{
memset ( & header , 0 , sizeof ( header ) ) ;
}
return false ;
}
2010-06-08 16:52:24 +00:00
bool
ObjectFileMachO : : ParseHeader ( )
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
bool can_parse = false ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = 0 ;
2011-02-01 01:31:41 +00:00
m_data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
2012-03-13 23:14:29 +00:00
// Leave magic in the original byte order
m_header . magic = m_data . GetU32 ( & offset ) ;
switch ( m_header . magic )
2012-02-05 02:38:54 +00:00
{
2013-08-27 05:04:57 +00:00
case MH_MAGIC :
2012-03-13 23:14:29 +00:00
m_data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
m_data . SetAddressByteSize ( 4 ) ;
can_parse = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_MAGIC_64 :
2012-03-13 23:14:29 +00:00
m_data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) ) ;
m_data . SetAddressByteSize ( 8 ) ;
can_parse = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_CIGAM :
2012-03-13 23:14:29 +00:00
m_data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) = = eByteOrderBig ? eByteOrderLittle : eByteOrderBig ) ;
m_data . SetAddressByteSize ( 4 ) ;
can_parse = true ;
break ;
2013-08-27 05:04:57 +00:00
case MH_CIGAM_64 :
2012-03-13 23:14:29 +00:00
m_data . SetByteOrder ( lldb : : endian : : InlHostByteOrder ( ) = = eByteOrderBig ? eByteOrderLittle : eByteOrderBig ) ;
m_data . SetAddressByteSize ( 8 ) ;
can_parse = true ;
break ;
default :
break ;
}
if ( can_parse )
{
m_data . GetU32 ( & offset , & m_header . cputype , 6 ) ;
ArchSpec mach_arch ( eArchTypeMachO , m_header . cputype , m_header . cpusubtype ) ;
2013-03-06 23:19:17 +00:00
2012-11-16 21:36:10 +00:00
// Check if the module has a required architecture
const ArchSpec & module_arch = module_sp - > GetArchitecture ( ) ;
2012-12-13 22:07:14 +00:00
if ( module_arch . IsValid ( ) & & ! module_arch . IsCompatibleMatch ( mach_arch ) )
2012-11-16 21:36:10 +00:00
return false ;
2012-03-13 23:14:29 +00:00
if ( SetModulesArchitecture ( mach_arch ) )
2012-02-05 02:38:54 +00:00
{
2012-03-13 23:14:29 +00:00
const size_t header_and_lc_size = m_header . sizeofcmds + MachHeaderSizeFromMagic ( m_header . magic ) ;
if ( m_data . GetByteSize ( ) < header_and_lc_size )
2012-02-05 02:38:54 +00:00
{
2012-03-13 23:14:29 +00:00
DataBufferSP data_sp ;
ProcessSP process_sp ( m_process_wp . lock ( ) ) ;
if ( process_sp )
{
2013-02-06 17:22:03 +00:00
data_sp = ReadMemory ( process_sp , m_memory_addr , header_and_lc_size ) ;
2012-03-13 23:14:29 +00:00
}
else
{
// Read in all only the load command data from the file on disk
2013-02-06 17:22:03 +00:00
data_sp = m_file . ReadFileContents ( m_file_offset , header_and_lc_size ) ;
2012-03-13 23:14:29 +00:00
if ( data_sp - > GetByteSize ( ) ! = header_and_lc_size )
return false ;
}
if ( data_sp )
m_data . SetData ( data_sp ) ;
2012-02-05 02:38:54 +00:00
}
}
2012-03-13 23:14:29 +00:00
return true ;
}
else
{
memset ( & m_header , 0 , sizeof ( struct mach_header ) ) ;
2012-02-05 02:38:54 +00:00
}
2010-06-08 16:52:24 +00:00
}
return false ;
}
ByteOrder
ObjectFileMachO : : GetByteOrder ( ) const
{
return m_data . GetByteOrder ( ) ;
}
2010-08-09 23:31:02 +00:00
bool
ObjectFileMachO : : IsExecutable ( ) const
{
2013-08-27 05:04:57 +00:00
return m_header . filetype = = MH_EXECUTE ;
2010-08-09 23:31:02 +00:00
}
2010-06-08 16:52:24 +00:00
2013-01-25 18:06:21 +00:00
uint32_t
2010-06-08 16:52:24 +00:00
ObjectFileMachO : : GetAddressByteSize ( ) const
{
return m_data . GetAddressByteSize ( ) ;
}
2011-03-24 21:19:54 +00:00
AddressClass
2011-03-19 01:12:21 +00:00
ObjectFileMachO : : GetAddressClass ( lldb : : addr_t file_addr )
{
Symtab * symtab = GetSymtab ( ) ;
if ( symtab )
{
Symbol * symbol = symtab - > FindSymbolContainingFileAddress ( file_addr ) ;
if ( symbol )
{
2012-03-07 21:03:09 +00:00
if ( symbol - > ValueIsAddress ( ) )
2011-03-19 01:12:21 +00:00
{
2012-03-07 21:03:09 +00:00
SectionSP section_sp ( symbol - > GetAddress ( ) . GetSection ( ) ) ;
2012-02-24 01:59:29 +00:00
if ( section_sp )
2011-03-19 01:12:21 +00:00
{
2013-08-27 05:04:57 +00:00
const lldb : : SectionType section_type = section_sp - > GetType ( ) ;
2011-03-19 01:12:21 +00:00
switch ( section_type )
{
case eSectionTypeInvalid : return eAddressClassUnknown ;
case eSectionTypeCode :
2013-08-27 05:04:57 +00:00
if ( m_header . cputype = = llvm : : MachO : : CPU_TYPE_ARM )
2011-03-19 01:12:21 +00:00
{
// For ARM we have a bit in the n_desc field of the symbol
// that tells us ARM/Thumb which is bit 0x0008.
if ( symbol - > GetFlags ( ) & MACHO_NLIST_ARM_SYMBOL_IS_THUMB )
return eAddressClassCodeAlternateISA ;
}
return eAddressClassCode ;
case eSectionTypeContainer : return eAddressClassUnknown ;
2011-10-27 17:55:14 +00:00
case eSectionTypeData :
case eSectionTypeDataCString :
case eSectionTypeDataCStringPointers :
case eSectionTypeDataSymbolAddress :
case eSectionTypeData4 :
case eSectionTypeData8 :
case eSectionTypeData16 :
case eSectionTypeDataPointers :
case eSectionTypeZeroFill :
case eSectionTypeDataObjCMessageRefs :
case eSectionTypeDataObjCCFStrings :
return eAddressClassData ;
case eSectionTypeDebug :
case eSectionTypeDWARFDebugAbbrev :
case eSectionTypeDWARFDebugAranges :
case eSectionTypeDWARFDebugFrame :
case eSectionTypeDWARFDebugInfo :
case eSectionTypeDWARFDebugLine :
case eSectionTypeDWARFDebugLoc :
case eSectionTypeDWARFDebugMacInfo :
case eSectionTypeDWARFDebugPubNames :
case eSectionTypeDWARFDebugPubTypes :
case eSectionTypeDWARFDebugRanges :
case eSectionTypeDWARFDebugStr :
case eSectionTypeDWARFAppleNames :
case eSectionTypeDWARFAppleTypes :
case eSectionTypeDWARFAppleNamespaces :
case eSectionTypeDWARFAppleObjC :
return eAddressClassDebug ;
2011-03-19 01:12:21 +00:00
case eSectionTypeEHFrame : return eAddressClassRuntime ;
2013-07-01 19:45:50 +00:00
case eSectionTypeELFSymbolTable :
case eSectionTypeELFDynamicSymbols :
case eSectionTypeELFRelocationEntries :
case eSectionTypeELFDynamicLinkInfo :
2011-03-19 01:12:21 +00:00
case eSectionTypeOther : return eAddressClassUnknown ;
}
}
}
2013-03-06 23:19:17 +00:00
2011-03-24 21:19:54 +00:00
const SymbolType symbol_type = symbol - > GetType ( ) ;
2011-03-19 01:12:21 +00:00
switch ( symbol_type )
{
case eSymbolTypeAny : return eAddressClassUnknown ;
case eSymbolTypeAbsolute : return eAddressClassUnknown ;
2013-03-06 23:19:17 +00:00
2011-03-19 01:12:21 +00:00
case eSymbolTypeCode :
case eSymbolTypeTrampoline :
2013-02-27 21:16:04 +00:00
case eSymbolTypeResolver :
2013-08-27 05:04:57 +00:00
if ( m_header . cputype = = llvm : : MachO : : CPU_TYPE_ARM )
2011-03-19 01:12:21 +00:00
{
// For ARM we have a bit in the n_desc field of the symbol
// that tells us ARM/Thumb which is bit 0x0008.
if ( symbol - > GetFlags ( ) & MACHO_NLIST_ARM_SYMBOL_IS_THUMB )
return eAddressClassCodeAlternateISA ;
}
return eAddressClassCode ;
case eSymbolTypeData : return eAddressClassData ;
case eSymbolTypeRuntime : return eAddressClassRuntime ;
case eSymbolTypeException : return eAddressClassRuntime ;
case eSymbolTypeSourceFile : return eAddressClassDebug ;
case eSymbolTypeHeaderFile : return eAddressClassDebug ;
case eSymbolTypeObjectFile : return eAddressClassDebug ;
case eSymbolTypeCommonBlock : return eAddressClassDebug ;
case eSymbolTypeBlock : return eAddressClassDebug ;
case eSymbolTypeLocal : return eAddressClassData ;
case eSymbolTypeParam : return eAddressClassData ;
case eSymbolTypeVariable : return eAddressClassData ;
case eSymbolTypeVariableType : return eAddressClassDebug ;
case eSymbolTypeLineEntry : return eAddressClassDebug ;
case eSymbolTypeLineHeader : return eAddressClassDebug ;
case eSymbolTypeScopeBegin : return eAddressClassDebug ;
case eSymbolTypeScopeEnd : return eAddressClassDebug ;
case eSymbolTypeAdditional : return eAddressClassUnknown ;
case eSymbolTypeCompiler : return eAddressClassDebug ;
case eSymbolTypeInstrumentation : return eAddressClassDebug ;
case eSymbolTypeUndefined : return eAddressClassUnknown ;
2011-12-03 02:30:59 +00:00
case eSymbolTypeObjCClass : return eAddressClassRuntime ;
case eSymbolTypeObjCMetaClass : return eAddressClassRuntime ;
case eSymbolTypeObjCIVar : return eAddressClassRuntime ;
2013-10-21 18:40:51 +00:00
case eSymbolTypeReExported : return eAddressClassRuntime ;
2011-03-19 01:12:21 +00:00
}
}
}
return eAddressClassUnknown ;
}
2010-06-08 16:52:24 +00:00
Symtab *
2013-07-10 01:23:25 +00:00
ObjectFileMachO : : GetSymtab ( )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
if ( m_symtab_ap . get ( ) = = NULL )
{
m_symtab_ap . reset ( new Symtab ( this ) ) ;
Mutex : : Locker symtab_locker ( m_symtab_ap - > GetMutex ( ) ) ;
2013-07-10 01:23:25 +00:00
ParseSymtab ( ) ;
2012-03-13 23:14:29 +00:00
m_symtab_ap - > Finalize ( ) ;
}
2010-06-08 16:52:24 +00:00
}
return m_symtab_ap . get ( ) ;
}
2013-07-10 01:23:25 +00:00
bool
ObjectFileMachO : : IsStripped ( )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( m_dysymtab . cmd = = 0 )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2012-03-13 23:14:29 +00:00
{
2013-07-10 01:23:25 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
for ( uint32_t i = 0 ; i < m_header . ncmds ; + + i )
2012-05-25 18:09:55 +00:00
{
2013-07-10 01:23:25 +00:00
const lldb : : offset_t load_cmd_offset = offset ;
load_command lc ;
if ( m_data . GetU32 ( & offset , & lc . cmd , 2 ) = = NULL )
break ;
2013-08-27 05:04:57 +00:00
if ( lc . cmd = = LC_DYSYMTAB )
2012-05-25 18:09:55 +00:00
{
2013-07-10 01:23:25 +00:00
m_dysymtab . cmd = lc . cmd ;
m_dysymtab . cmdsize = lc . cmdsize ;
if ( m_data . GetU32 ( & offset , & m_dysymtab . ilocalsym , ( sizeof ( m_dysymtab ) / sizeof ( uint32_t ) ) - 2 ) = = NULL )
{
// Clear m_dysymtab if we were unable to read all items from the load command
: : memset ( & m_dysymtab , 0 , sizeof ( m_dysymtab ) ) ;
}
2012-05-25 18:09:55 +00:00
}
2013-07-10 01:23:25 +00:00
offset = load_cmd_offset + lc . cmdsize ;
2012-05-25 18:09:55 +00:00
}
2012-04-24 03:06:13 +00:00
}
}
2013-07-10 01:23:25 +00:00
if ( m_dysymtab . cmd )
2013-10-11 22:03:48 +00:00
return m_dysymtab . nlocalsym < = 1 ;
2013-07-10 01:23:25 +00:00
return false ;
}
2012-04-24 03:06:13 +00:00
2013-07-10 01:23:25 +00:00
void
ObjectFileMachO : : CreateSections ( SectionList & unified_section_list )
{
if ( ! m_sections_ap . get ( ) )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
m_sections_ap . reset ( new SectionList ( ) ) ;
2013-08-27 05:04:57 +00:00
const bool is_dsym = ( m_header . filetype = = MH_DSYM ) ;
2013-07-10 01:23:25 +00:00
lldb : : user_id_t segID = 0 ;
lldb : : user_id_t sectID = 0 ;
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
uint32_t i ;
const bool is_core = GetType ( ) = = eTypeCoreFile ;
//bool dump_sections = false;
ModuleSP module_sp ( GetModule ( ) ) ;
// First look up any LC_ENCRYPTION_INFO load commands
typedef RangeArray < uint32_t , uint32_t , 8 > EncryptedFileRanges ;
EncryptedFileRanges encrypted_file_ranges ;
encryption_info_command encryption_cmd ;
for ( i = 0 ; i < m_header . ncmds ; + + i )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
const lldb : : offset_t load_cmd_offset = offset ;
if ( m_data . GetU32 ( & offset , & encryption_cmd , 2 ) = = NULL )
break ;
2013-08-27 05:04:57 +00:00
if ( encryption_cmd . cmd = = LC_ENCRYPTION_INFO )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( m_data . GetU32 ( & offset , & encryption_cmd . cryptoff , 3 ) )
2013-04-10 05:58:57 +00:00
{
2013-07-10 01:23:25 +00:00
if ( encryption_cmd . cryptid ! = 0 )
2013-04-16 16:51:19 +00:00
{
2013-07-10 01:23:25 +00:00
EncryptedFileRanges : : Entry entry ;
entry . SetRangeBase ( encryption_cmd . cryptoff ) ;
entry . SetByteSize ( encryption_cmd . cryptsize ) ;
encrypted_file_ranges . Append ( entry ) ;
2013-04-10 05:58:57 +00:00
}
}
2013-07-10 01:23:25 +00:00
}
offset = load_cmd_offset + encryption_cmd . cmdsize ;
}
offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
struct segment_command_64 load_cmd ;
for ( i = 0 ; i < m_header . ncmds ; + + i )
{
const lldb : : offset_t load_cmd_offset = offset ;
if ( m_data . GetU32 ( & offset , & load_cmd , 2 ) = = NULL )
break ;
2013-08-27 05:04:57 +00:00
if ( load_cmd . cmd = = LC_SEGMENT | | load_cmd . cmd = = LC_SEGMENT_64 )
2013-07-10 01:23:25 +00:00
{
if ( m_data . GetU8 ( & offset , ( uint8_t * ) load_cmd . segname , 16 ) )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
bool add_section = true ;
bool add_to_unified = true ;
ConstString const_segname ( load_cmd . segname , std : : min < size_t > ( strlen ( load_cmd . segname ) , sizeof ( load_cmd . segname ) ) ) ;
2013-03-06 23:19:17 +00:00
2013-07-10 01:23:25 +00:00
SectionSP unified_section_sp ( unified_section_list . FindSectionByName ( const_segname ) ) ;
if ( is_dsym & & unified_section_sp )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( const_segname = = GetSegmentNameLINKEDIT ( ) )
{
// We need to keep the __LINKEDIT segment private to this object file only
add_to_unified = false ;
}
else
{
// This is the dSYM file and this section has already been created by
// the object file, no need to create it.
add_section = false ;
}
2010-06-08 16:52:24 +00:00
}
2013-07-10 01:23:25 +00:00
load_cmd . vmaddr = m_data . GetAddress ( & offset ) ;
load_cmd . vmsize = m_data . GetAddress ( & offset ) ;
load_cmd . fileoff = m_data . GetAddress ( & offset ) ;
load_cmd . filesize = m_data . GetAddress ( & offset ) ;
if ( m_length ! = 0 & & load_cmd . filesize ! = 0 )
{
if ( load_cmd . fileoff > m_length )
{
// We have a load command that says it extends past the end of hte file. This is likely
// a corrupt file. We don't have any way to return an error condition here (this method
// was likely invokved from something like ObjectFile::GetSectionList()) -- all we can do
// is null out the SectionList vector and if a process has been set up, dump a message
// to stdout. The most common case here is core file debugging with a truncated file.
2013-08-27 05:04:57 +00:00
const char * lc_segment_name = load_cmd . cmd = = LC_SEGMENT_64 ? " LC_SEGMENT_64 " : " LC_SEGMENT " ;
2013-09-14 05:20:02 +00:00
module_sp - > ReportWarning ( " load command %u %s has a fileoff (0x% " PRIx64 " ) that extends beyond the end of the file (0x% " PRIx64 " ), ignoring this section " ,
2013-08-16 03:20:42 +00:00
i ,
lc_segment_name ,
load_cmd . fileoff ,
m_length ) ;
2013-07-10 01:23:25 +00:00
load_cmd . fileoff = 0 ;
load_cmd . filesize = 0 ;
}
if ( load_cmd . fileoff + load_cmd . filesize > m_length )
{
// We have a load command that says it extends past the end of hte file. This is likely
// a corrupt file. We don't have any way to return an error condition here (this method
// was likely invokved from something like ObjectFile::GetSectionList()) -- all we can do
// is null out the SectionList vector and if a process has been set up, dump a message
// to stdout. The most common case here is core file debugging with a truncated file.
2013-08-27 05:04:57 +00:00
const char * lc_segment_name = load_cmd . cmd = = LC_SEGMENT_64 ? " LC_SEGMENT_64 " : " LC_SEGMENT " ;
2013-09-14 05:20:02 +00:00
GetModule ( ) - > ReportWarning ( " load command %u %s has a fileoff + filesize (0x% " PRIx64 " ) that extends beyond the end of the file (0x% " PRIx64 " ), the segment will be truncated to match " ,
2013-08-27 05:04:57 +00:00
i ,
lc_segment_name ,
load_cmd . fileoff + load_cmd . filesize ,
m_length ) ;
2013-07-10 01:23:25 +00:00
// Tuncase the length
load_cmd . filesize = m_length - load_cmd . fileoff ;
}
}
if ( m_data . GetU32 ( & offset , & load_cmd . maxprot , 4 ) )
2010-06-08 16:52:24 +00:00
{
2013-08-27 05:04:57 +00:00
const bool segment_is_encrypted = ( load_cmd . flags & SG_PROTECTED_VERSION_1 ) ! = 0 ;
2010-06-08 16:52:24 +00:00
2013-07-10 01:23:25 +00:00
// Keep a list of mach segments around in case we need to
2010-06-08 16:52:24 +00:00
// get at data that isn't stored in the abstracted Sections.
2013-07-10 01:23:25 +00:00
m_mach_segments . push_back ( load_cmd ) ;
2010-06-08 16:52:24 +00:00
2013-07-10 01:23:25 +00:00
// Use a segment ID of the segment index shifted left by 8 so they
// never conflict with any of the sections.
SectionSP segment_sp ;
if ( add_section & & ( const_segname | | is_core ) )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
segment_sp . reset ( new Section ( module_sp , // Module to which this section belongs
this , // Object file to which this sections belongs
+ + segID < < 8 , // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
const_segname , // Name of this section
eSectionTypeContainer , // This section is a container of other sections.
load_cmd . vmaddr , // File VM address == addresses as they are found in the object file
load_cmd . vmsize , // VM size in bytes of this section
load_cmd . fileoff , // Offset to the data for this section in the file
load_cmd . filesize , // Size in bytes of this section as found in the the file
load_cmd . flags ) ) ; // Flags for this section
2010-06-28 23:51:11 +00:00
2013-07-10 01:23:25 +00:00
segment_sp - > SetIsEncrypted ( segment_is_encrypted ) ;
m_sections_ap - > AddSection ( segment_sp ) ;
if ( add_to_unified )
unified_section_list . AddSection ( segment_sp ) ;
2010-06-08 16:52:24 +00:00
}
2013-07-10 01:23:25 +00:00
else if ( unified_section_sp )
2010-06-08 16:52:24 +00:00
{
2013-08-16 03:20:42 +00:00
if ( is_dsym & & unified_section_sp - > GetFileAddress ( ) ! = load_cmd . vmaddr )
{
// Check to see if the module was read from memory?
if ( module_sp - > GetObjectFile ( ) - > GetHeaderAddress ( ) . IsValid ( ) )
{
// We have a module that is in memory and needs to have its
// file address adjusted. We need to do this because when we
// load a file from memory, its addresses will be slid already,
// yet the addresses in the new symbol file will still be unslid.
// Since everything is stored as section offset, this shouldn't
// cause any problems.
2013-08-17 03:39:52 +00:00
// Make sure we've parsed the symbol table from the
// ObjectFile before we go around changing its Sections.
module_sp - > GetObjectFile ( ) - > GetSymtab ( ) ;
// eh_frame would present the same problems but we parse that on
// a per-function basis as-needed so it's more difficult to
// remove its use of the Sections. Realistically, the environments
// where this code path will be taken will not have eh_frame sections.
2013-08-16 03:20:42 +00:00
unified_section_sp - > SetFileAddress ( load_cmd . vmaddr ) ;
}
}
2013-07-10 01:23:25 +00:00
m_sections_ap - > AddSection ( unified_section_sp ) ;
2010-06-08 16:52:24 +00:00
}
2013-07-10 01:23:25 +00:00
struct section_64 sect64 ;
: : memset ( & sect64 , 0 , sizeof ( sect64 ) ) ;
// Push a section into our mach sections for the section at
2013-08-27 05:04:57 +00:00
// index zero (NO_SECT) if we don't have any mach sections yet...
2013-07-10 01:23:25 +00:00
if ( m_mach_sections . empty ( ) )
m_mach_sections . push_back ( sect64 ) ;
uint32_t segment_sect_idx ;
const lldb : : user_id_t first_segment_sectID = sectID + 1 ;
2013-08-27 05:04:57 +00:00
const uint32_t num_u32s = load_cmd . cmd = = LC_SEGMENT ? 7 : 8 ;
2013-07-10 01:23:25 +00:00
for ( segment_sect_idx = 0 ; segment_sect_idx < load_cmd . nsects ; + + segment_sect_idx )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( m_data . GetU8 ( & offset , ( uint8_t * ) sect64 . sectname , sizeof ( sect64 . sectname ) ) = = NULL )
2010-10-08 00:21:05 +00:00
break ;
2013-07-10 01:23:25 +00:00
if ( m_data . GetU8 ( & offset , ( uint8_t * ) sect64 . segname , sizeof ( sect64 . segname ) ) = = NULL )
break ;
sect64 . addr = m_data . GetAddress ( & offset ) ;
sect64 . size = m_data . GetAddress ( & offset ) ;
if ( m_data . GetU32 ( & offset , & sect64 . offset , num_u32s ) = = NULL )
break ;
// Keep a list of mach sections around in case we need to
// get at data that isn't stored in the abstracted Sections.
m_mach_sections . push_back ( sect64 ) ;
if ( add_section )
{
ConstString section_name ( sect64 . sectname , std : : min < size_t > ( strlen ( sect64 . sectname ) , sizeof ( sect64 . sectname ) ) ) ;
if ( ! const_segname )
{
// We have a segment with no name so we need to conjure up
// segments that correspond to the section's segname if there
// isn't already such a section. If there is such a section,
// we resize the section so that it spans all sections.
// We also mark these sections as fake so address matches don't
// hit if they land in the gaps between the child sections.
const_segname . SetTrimmedCStringWithLength ( sect64 . segname , sizeof ( sect64 . segname ) ) ;
segment_sp = unified_section_list . FindSectionByName ( const_segname ) ;
if ( segment_sp . get ( ) )
{
Section * segment = segment_sp . get ( ) ;
// Grow the section size as needed.
const lldb : : addr_t sect64_min_addr = sect64 . addr ;
const lldb : : addr_t sect64_max_addr = sect64_min_addr + sect64 . size ;
const lldb : : addr_t curr_seg_byte_size = segment - > GetByteSize ( ) ;
const lldb : : addr_t curr_seg_min_addr = segment - > GetFileAddress ( ) ;
const lldb : : addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size ;
if ( sect64_min_addr > = curr_seg_min_addr )
{
const lldb : : addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr ;
// Only grow the section size if needed
if ( new_seg_byte_size > curr_seg_byte_size )
segment - > SetByteSize ( new_seg_byte_size ) ;
}
else
{
// We need to change the base address of the segment and
// adjust the child section offsets for all existing children.
const lldb : : addr_t slide_amount = sect64_min_addr - curr_seg_min_addr ;
segment - > Slide ( slide_amount , false ) ;
segment - > GetChildren ( ) . Slide ( - slide_amount , false ) ;
segment - > SetByteSize ( curr_seg_max_addr - sect64_min_addr ) ;
}
// Grow the section size as needed.
if ( sect64 . offset )
{
const lldb : : addr_t segment_min_file_offset = segment - > GetFileOffset ( ) ;
const lldb : : addr_t segment_max_file_offset = segment_min_file_offset + segment - > GetFileSize ( ) ;
const lldb : : addr_t section_min_file_offset = sect64 . offset ;
const lldb : : addr_t section_max_file_offset = section_min_file_offset + sect64 . size ;
const lldb : : addr_t new_file_offset = std : : min ( section_min_file_offset , segment_min_file_offset ) ;
const lldb : : addr_t new_file_size = std : : max ( section_max_file_offset , segment_max_file_offset ) - new_file_offset ;
segment - > SetFileOffset ( new_file_offset ) ;
segment - > SetFileSize ( new_file_size ) ;
}
}
else
{
// Create a fake section for the section's named segment
segment_sp . reset ( new Section ( segment_sp , // Parent section
module_sp , // Module to which this section belongs
this , // Object file to which this section belongs
+ + segID < < 8 , // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
const_segname , // Name of this section
eSectionTypeContainer , // This section is a container of other sections.
sect64 . addr , // File VM address == addresses as they are found in the object file
sect64 . size , // VM size in bytes of this section
sect64 . offset , // Offset to the data for this section in the file
sect64 . offset ? sect64 . size : 0 , // Size in bytes of this section as found in the the file
load_cmd . flags ) ) ; // Flags for this section
segment_sp - > SetIsFake ( true ) ;
m_sections_ap - > AddSection ( segment_sp ) ;
if ( add_to_unified )
unified_section_list . AddSection ( segment_sp ) ;
segment_sp - > SetIsEncrypted ( segment_is_encrypted ) ;
}
}
assert ( segment_sp . get ( ) ) ;
2013-08-27 05:04:57 +00:00
uint32_t mach_sect_type = sect64 . flags & SECTION_TYPE ;
2013-07-10 01:23:25 +00:00
static ConstString g_sect_name_objc_data ( " __objc_data " ) ;
static ConstString g_sect_name_objc_msgrefs ( " __objc_msgrefs " ) ;
static ConstString g_sect_name_objc_selrefs ( " __objc_selrefs " ) ;
static ConstString g_sect_name_objc_classrefs ( " __objc_classrefs " ) ;
static ConstString g_sect_name_objc_superrefs ( " __objc_superrefs " ) ;
static ConstString g_sect_name_objc_const ( " __objc_const " ) ;
static ConstString g_sect_name_objc_classlist ( " __objc_classlist " ) ;
static ConstString g_sect_name_cfstring ( " __cfstring " ) ;
static ConstString g_sect_name_dwarf_debug_abbrev ( " __debug_abbrev " ) ;
static ConstString g_sect_name_dwarf_debug_aranges ( " __debug_aranges " ) ;
static ConstString g_sect_name_dwarf_debug_frame ( " __debug_frame " ) ;
static ConstString g_sect_name_dwarf_debug_info ( " __debug_info " ) ;
static ConstString g_sect_name_dwarf_debug_line ( " __debug_line " ) ;
static ConstString g_sect_name_dwarf_debug_loc ( " __debug_loc " ) ;
static ConstString g_sect_name_dwarf_debug_macinfo ( " __debug_macinfo " ) ;
static ConstString g_sect_name_dwarf_debug_pubnames ( " __debug_pubnames " ) ;
static ConstString g_sect_name_dwarf_debug_pubtypes ( " __debug_pubtypes " ) ;
static ConstString g_sect_name_dwarf_debug_ranges ( " __debug_ranges " ) ;
static ConstString g_sect_name_dwarf_debug_str ( " __debug_str " ) ;
static ConstString g_sect_name_dwarf_apple_names ( " __apple_names " ) ;
static ConstString g_sect_name_dwarf_apple_types ( " __apple_types " ) ;
static ConstString g_sect_name_dwarf_apple_namespaces ( " __apple_namespac " ) ;
static ConstString g_sect_name_dwarf_apple_objc ( " __apple_objc " ) ;
static ConstString g_sect_name_eh_frame ( " __eh_frame " ) ;
static ConstString g_sect_name_DATA ( " __DATA " ) ;
static ConstString g_sect_name_TEXT ( " __TEXT " ) ;
2013-08-27 05:04:57 +00:00
lldb : : SectionType sect_type = eSectionTypeOther ;
2013-07-10 01:23:25 +00:00
if ( section_name = = g_sect_name_dwarf_debug_abbrev )
sect_type = eSectionTypeDWARFDebugAbbrev ;
else if ( section_name = = g_sect_name_dwarf_debug_aranges )
sect_type = eSectionTypeDWARFDebugAranges ;
else if ( section_name = = g_sect_name_dwarf_debug_frame )
sect_type = eSectionTypeDWARFDebugFrame ;
else if ( section_name = = g_sect_name_dwarf_debug_info )
sect_type = eSectionTypeDWARFDebugInfo ;
else if ( section_name = = g_sect_name_dwarf_debug_line )
sect_type = eSectionTypeDWARFDebugLine ;
else if ( section_name = = g_sect_name_dwarf_debug_loc )
sect_type = eSectionTypeDWARFDebugLoc ;
else if ( section_name = = g_sect_name_dwarf_debug_macinfo )
sect_type = eSectionTypeDWARFDebugMacInfo ;
else if ( section_name = = g_sect_name_dwarf_debug_pubnames )
sect_type = eSectionTypeDWARFDebugPubNames ;
else if ( section_name = = g_sect_name_dwarf_debug_pubtypes )
sect_type = eSectionTypeDWARFDebugPubTypes ;
else if ( section_name = = g_sect_name_dwarf_debug_ranges )
sect_type = eSectionTypeDWARFDebugRanges ;
else if ( section_name = = g_sect_name_dwarf_debug_str )
sect_type = eSectionTypeDWARFDebugStr ;
else if ( section_name = = g_sect_name_dwarf_apple_names )
sect_type = eSectionTypeDWARFAppleNames ;
else if ( section_name = = g_sect_name_dwarf_apple_types )
sect_type = eSectionTypeDWARFAppleTypes ;
else if ( section_name = = g_sect_name_dwarf_apple_namespaces )
sect_type = eSectionTypeDWARFAppleNamespaces ;
else if ( section_name = = g_sect_name_dwarf_apple_objc )
sect_type = eSectionTypeDWARFAppleObjC ;
else if ( section_name = = g_sect_name_objc_selrefs )
sect_type = eSectionTypeDataCStringPointers ;
else if ( section_name = = g_sect_name_objc_msgrefs )
sect_type = eSectionTypeDataObjCMessageRefs ;
else if ( section_name = = g_sect_name_eh_frame )
sect_type = eSectionTypeEHFrame ;
else if ( section_name = = g_sect_name_cfstring )
sect_type = eSectionTypeDataObjCCFStrings ;
else if ( section_name = = g_sect_name_objc_data | |
section_name = = g_sect_name_objc_classrefs | |
section_name = = g_sect_name_objc_superrefs | |
section_name = = g_sect_name_objc_const | |
section_name = = g_sect_name_objc_classlist )
{
sect_type = eSectionTypeDataPointers ;
}
if ( sect_type = = eSectionTypeOther )
{
switch ( mach_sect_type )
{
// TODO: categorize sections by other flags for regular sections
2013-08-27 05:04:57 +00:00
case S_REGULAR :
2013-07-10 01:23:25 +00:00
if ( segment_sp - > GetName ( ) = = g_sect_name_TEXT )
sect_type = eSectionTypeCode ;
else if ( segment_sp - > GetName ( ) = = g_sect_name_DATA )
sect_type = eSectionTypeData ;
else
sect_type = eSectionTypeOther ;
break ;
2013-08-27 05:04:57 +00:00
case S_ZEROFILL : sect_type = eSectionTypeZeroFill ; break ;
case S_CSTRING_LITERALS : sect_type = eSectionTypeDataCString ; break ; // section with only literal C strings
case S_4BYTE_LITERALS : sect_type = eSectionTypeData4 ; break ; // section with only 4 byte literals
case S_8BYTE_LITERALS : sect_type = eSectionTypeData8 ; break ; // section with only 8 byte literals
case S_LITERAL_POINTERS : sect_type = eSectionTypeDataPointers ; break ; // section with only pointers to literals
case S_NON_LAZY_SYMBOL_POINTERS : sect_type = eSectionTypeDataPointers ; break ; // section with only non-lazy symbol pointers
case S_LAZY_SYMBOL_POINTERS : sect_type = eSectionTypeDataPointers ; break ; // section with only lazy symbol pointers
case S_SYMBOL_STUBS : sect_type = eSectionTypeCode ; break ; // section with only symbol stubs, byte size of stub in the reserved2 field
case S_MOD_INIT_FUNC_POINTERS : sect_type = eSectionTypeDataPointers ; break ; // section with only function pointers for initialization
case S_MOD_TERM_FUNC_POINTERS : sect_type = eSectionTypeDataPointers ; break ; // section with only function pointers for termination
case S_COALESCED : sect_type = eSectionTypeOther ; break ;
case S_GB_ZEROFILL : sect_type = eSectionTypeZeroFill ; break ;
case S_INTERPOSING : sect_type = eSectionTypeCode ; break ; // section with only pairs of function pointers for interposing
case S_16BYTE_LITERALS : sect_type = eSectionTypeData16 ; break ; // section with only 16 byte literals
case S_DTRACE_DOF : sect_type = eSectionTypeDebug ; break ;
case S_LAZY_DYLIB_SYMBOL_POINTERS : sect_type = eSectionTypeDataPointers ; break ;
2013-07-10 01:23:25 +00:00
default : break ;
}
}
SectionSP section_sp ( new Section ( segment_sp ,
module_sp ,
this ,
+ + sectID ,
section_name ,
sect_type ,
sect64 . addr - segment_sp - > GetFileAddress ( ) ,
sect64 . size ,
sect64 . offset ,
sect64 . offset = = 0 ? 0 : sect64 . size ,
sect64 . flags ) ) ;
// Set the section to be encrypted to match the segment
bool section_is_encrypted = false ;
if ( ! segment_is_encrypted & & load_cmd . filesize ! = 0 )
section_is_encrypted = encrypted_file_ranges . FindEntryThatContains ( sect64 . offset ) ! = NULL ;
section_sp - > SetIsEncrypted ( segment_is_encrypted | | section_is_encrypted ) ;
segment_sp - > GetChildren ( ) . AddSection ( section_sp ) ;
if ( segment_sp - > IsFake ( ) )
{
segment_sp . reset ( ) ;
const_segname . Clear ( ) ;
}
2010-06-08 16:52:24 +00:00
}
}
2013-07-10 01:23:25 +00:00
if ( segment_sp & & is_dsym )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( first_segment_sectID < = sectID )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
lldb : : user_id_t sect_uid ;
for ( sect_uid = first_segment_sectID ; sect_uid < = sectID ; + + sect_uid )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
SectionSP curr_section_sp ( segment_sp - > GetChildren ( ) . FindSectionByID ( sect_uid ) ) ;
SectionSP next_section_sp ;
if ( sect_uid + 1 < = sectID )
next_section_sp = segment_sp - > GetChildren ( ) . FindSectionByID ( sect_uid + 1 ) ;
if ( curr_section_sp . get ( ) )
2010-06-08 16:52:24 +00:00
{
2013-07-10 01:23:25 +00:00
if ( curr_section_sp - > GetByteSize ( ) = = 0 )
{
if ( next_section_sp . get ( ) ! = NULL )
curr_section_sp - > SetByteSize ( next_section_sp - > GetFileAddress ( ) - curr_section_sp - > GetFileAddress ( ) ) ;
else
curr_section_sp - > SetByteSize ( load_cmd . vmsize ) ;
}
2010-06-08 16:52:24 +00:00
}
}
}
}
}
}
}
2013-08-27 05:04:57 +00:00
else if ( load_cmd . cmd = = LC_DYSYMTAB )
2013-07-10 01:23:25 +00:00
{
m_dysymtab . cmd = load_cmd . cmd ;
m_dysymtab . cmdsize = load_cmd . cmdsize ;
m_data . GetU32 ( & offset , & m_dysymtab . ilocalsym , ( sizeof ( m_dysymtab ) / sizeof ( uint32_t ) ) - 2 ) ;
}
2010-06-08 16:52:24 +00:00
2013-07-10 01:23:25 +00:00
offset = load_cmd_offset + load_cmd . cmdsize ;
}
// StreamFile s(stdout, false); // REMOVE THIS LINE
// s.Printf ("Sections for %s:\n", m_file.GetPath().c_str());// REMOVE THIS LINE
// m_sections_ap->Dump(&s, NULL, true, UINT32_MAX);// REMOVE THIS LINE
2010-06-08 16:52:24 +00:00
}
}
class MachSymtabSectionInfo
{
public :
MachSymtabSectionInfo ( SectionList * section_list ) :
m_section_list ( section_list ) ,
m_section_infos ( )
{
// Get the number of sections down to a depth of 1 to include
// all segments and their sections, but no other sections that
// may be added for debug map or
m_section_infos . resize ( section_list - > GetNumSections ( 1 ) ) ;
}
2012-02-24 01:59:29 +00:00
SectionSP
2010-06-08 16:52:24 +00:00
GetSection ( uint8_t n_sect , addr_t file_addr )
{
if ( n_sect = = 0 )
2012-02-24 01:59:29 +00:00
return SectionSP ( ) ;
2010-06-08 16:52:24 +00:00
if ( n_sect < m_section_infos . size ( ) )
{
2012-02-24 01:59:29 +00:00
if ( ! m_section_infos [ n_sect ] . section_sp )
2010-06-08 16:52:24 +00:00
{
2012-02-24 01:59:29 +00:00
SectionSP section_sp ( m_section_list - > FindSectionByID ( n_sect ) ) ;
m_section_infos [ n_sect ] . section_sp = section_sp ;
2012-08-09 00:50:26 +00:00
if ( section_sp )
2011-07-10 17:32:33 +00:00
{
2012-02-24 01:59:29 +00:00
m_section_infos [ n_sect ] . vm_range . SetBaseAddress ( section_sp - > GetFileAddress ( ) ) ;
m_section_infos [ n_sect ] . vm_range . SetByteSize ( section_sp - > GetByteSize ( ) ) ;
2011-07-10 17:32:33 +00:00
}
else
{
2012-01-05 03:57:59 +00:00
Host : : SystemLog ( Host : : eSystemLogError , " error: unable to find section for section %u \n " , n_sect ) ;
2011-07-10 17:32:33 +00:00
}
2010-06-08 16:52:24 +00:00
}
if ( m_section_infos [ n_sect ] . vm_range . Contains ( file_addr ) )
2011-08-26 20:01:35 +00:00
{
// Symbol is in section.
2012-02-24 01:59:29 +00:00
return m_section_infos [ n_sect ] . section_sp ;
2011-08-26 20:01:35 +00:00
}
else if ( m_section_infos [ n_sect ] . vm_range . GetByteSize ( ) = = 0 & &
m_section_infos [ n_sect ] . vm_range . GetBaseAddress ( ) = = file_addr )
{
// Symbol is in section with zero size, but has the same start
// address as the section. This can happen with linker symbols
// (symbols that start with the letter 'l' or 'L'.
2012-02-24 01:59:29 +00:00
return m_section_infos [ n_sect ] . section_sp ;
2011-08-26 20:01:35 +00:00
}
2010-06-08 16:52:24 +00:00
}
2012-02-24 01:59:29 +00:00
return m_section_list - > FindSectionContainingFileAddress ( file_addr ) ;
2010-06-08 16:52:24 +00:00
}
protected :
struct SectionInfo
{
SectionInfo ( ) :
vm_range ( ) ,
2012-02-24 01:59:29 +00:00
section_sp ( )
2010-06-08 16:52:24 +00:00
{
}
VMRange vm_range ;
2012-02-24 01:59:29 +00:00
SectionSP section_sp ;
2010-06-08 16:52:24 +00:00
} ;
SectionList * m_section_list ;
std : : vector < SectionInfo > m_section_infos ;
} ;
2013-10-21 18:40:51 +00:00
struct TrieEntry
{
TrieEntry ( ) :
name ( ) ,
address ( LLDB_INVALID_ADDRESS ) ,
flags ( 0 ) ,
other ( 0 ) ,
import_name ( )
{
}
void
Clear ( )
{
name . Clear ( ) ;
address = LLDB_INVALID_ADDRESS ;
flags = 0 ;
other = 0 ;
import_name . Clear ( ) ;
}
void
Dump ( ) const
{
printf ( " 0x%16.16llx 0x%16.16llx 0x%16.16llx \" %s \" " , address , flags , other , name . GetCString ( ) ) ;
if ( import_name )
printf ( " -> \" %s \" \n " , import_name . GetCString ( ) ) ;
else
printf ( " \n " ) ;
}
ConstString name ;
uint64_t address ;
uint64_t flags ;
uint64_t other ;
ConstString import_name ;
} ;
struct TrieEntryWithOffset
{
lldb : : offset_t nodeOffset ;
TrieEntry entry ;
TrieEntryWithOffset ( lldb : : offset_t offset ) :
nodeOffset ( offset ) ,
entry ( )
{
}
void
Dump ( uint32_t idx ) const
{
printf ( " [%3u] 0x%16.16llx: " , idx , nodeOffset ) ;
entry . Dump ( ) ;
}
bool
operator < ( const TrieEntryWithOffset & other ) const
{
return ( nodeOffset < other . nodeOffset ) ;
}
} ;
static void
ParseTrieEntries ( DataExtractor & data ,
lldb : : offset_t offset ,
std : : vector < llvm : : StringRef > & nameSlices ,
std : : set < lldb : : addr_t > & resolver_addresses ,
std : : vector < TrieEntryWithOffset > & output )
{
if ( ! data . ValidOffset ( offset ) )
return ;
const uint64_t terminalSize = data . GetULEB128 ( & offset ) ;
lldb : : offset_t children_offset = offset + terminalSize ;
if ( terminalSize ! = 0 ) {
TrieEntryWithOffset e ( offset ) ;
e . entry . flags = data . GetULEB128 ( & offset ) ;
const char * import_name = NULL ;
if ( e . entry . flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
e . entry . address = 0 ;
e . entry . other = data . GetULEB128 ( & offset ) ; // dylib ordinal
import_name = data . GetCStr ( & offset ) ;
}
else {
e . entry . address = data . GetULEB128 ( & offset ) ;
if ( e . entry . flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
{
2014-01-10 22:55:37 +00:00
//resolver_addresses.insert(e.entry.address);
2013-10-21 18:40:51 +00:00
e . entry . other = data . GetULEB128 ( & offset ) ;
2014-01-10 22:55:37 +00:00
resolver_addresses . insert ( e . entry . other ) ;
2013-10-21 18:40:51 +00:00
}
else
e . entry . other = 0 ;
}
// Only add symbols that are reexport symbols with a valid import name
if ( EXPORT_SYMBOL_FLAGS_REEXPORT & e . entry . flags & & import_name & & import_name [ 0 ] )
{
std : : string name ;
if ( ! nameSlices . empty ( ) )
{
for ( auto name_slice : nameSlices )
name . append ( name_slice . data ( ) , name_slice . size ( ) ) ;
}
if ( name . size ( ) > 1 )
{
// Skip the leading '_'
e . entry . name . SetCStringWithLength ( name . c_str ( ) + 1 , name . size ( ) - 1 ) ;
}
if ( import_name )
{
// Skip the leading '_'
e . entry . import_name . SetCString ( import_name + 1 ) ;
}
output . push_back ( e ) ;
}
}
const uint8_t childrenCount = data . GetU8 ( & children_offset ) ;
for ( uint8_t i = 0 ; i < childrenCount ; + + i ) {
nameSlices . push_back ( data . GetCStr ( & children_offset ) ) ;
lldb : : offset_t childNodeOffset = data . GetULEB128 ( & children_offset ) ;
if ( childNodeOffset )
{
ParseTrieEntries ( data ,
childNodeOffset ,
nameSlices ,
resolver_addresses ,
output ) ;
}
nameSlices . pop_back ( ) ;
}
}
2010-06-08 16:52:24 +00:00
size_t
2013-07-10 01:23:25 +00:00
ObjectFileMachO : : ParseSymtab ( )
2010-06-08 16:52:24 +00:00
{
Timer scoped_timer ( __PRETTY_FUNCTION__ ,
" ObjectFileMachO::ParseSymtab () module = % s " ,
m_file . GetFilename ( ) . AsCString ( " " ) ) ;
2012-03-09 04:26:05 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( ! module_sp )
return 0 ;
struct symtab_command symtab_load_command = { 0 , 0 , 0 , 0 , 0 , 0 } ;
struct linkedit_data_command function_starts_load_command = { 0 , 0 , 0 , 0 } ;
2013-10-21 18:40:51 +00:00
struct dyld_info_command dyld_info = { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } ;
2012-03-09 04:26:05 +00:00
typedef AddressDataArray < lldb : : addr_t , bool , 100 > FunctionStarts ;
FunctionStarts function_starts ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2010-06-08 16:52:24 +00:00
uint32_t i ;
2013-10-21 18:40:51 +00:00
FileSpecList dylib_files ;
2013-03-27 23:08:40 +00:00
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SYMBOLS ) ) ;
2011-12-30 00:32:24 +00:00
2010-06-08 16:52:24 +00:00
for ( i = 0 ; i < m_header . ncmds ; + + i )
{
2013-01-25 18:06:21 +00:00
const lldb : : offset_t cmd_offset = offset ;
2010-06-08 16:52:24 +00:00
// Read in the load command and load command size
2012-03-09 04:26:05 +00:00
struct load_command lc ;
if ( m_data . GetU32 ( & offset , & lc , 2 ) = = NULL )
2010-06-08 16:52:24 +00:00
break ;
// Watch for the symbol table load command
2012-03-09 04:26:05 +00:00
switch ( lc . cmd )
2010-06-08 16:52:24 +00:00
{
2013-08-27 05:04:57 +00:00
case LC_SYMTAB :
2012-03-09 04:26:05 +00:00
symtab_load_command . cmd = lc . cmd ;
symtab_load_command . cmdsize = lc . cmdsize ;
2010-06-08 16:52:24 +00:00
// Read in the rest of the symtab load command
2012-03-09 04:26:05 +00:00
if ( m_data . GetU32 ( & offset , & symtab_load_command . symoff , 4 ) = = 0 ) // fill in symoff, nsyms, stroff, strsize fields
return 0 ;
if ( symtab_load_command . symoff = = 0 )
2010-06-08 16:52:24 +00:00
{
2012-03-09 04:26:05 +00:00
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " LC_SYMTAB.symoff == 0 " ) ;
2012-03-09 04:26:05 +00:00
return 0 ;
}
if ( symtab_load_command . stroff = = 0 )
{
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " LC_SYMTAB.stroff == 0 " ) ;
2012-03-09 04:26:05 +00:00
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
if ( symtab_load_command . nsyms = = 0 )
{
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " LC_SYMTAB.nsyms == 0 " ) ;
2012-03-09 04:26:05 +00:00
return 0 ;
}
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
if ( symtab_load_command . strsize = = 0 )
{
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " LC_SYMTAB.strsize == 0 " ) ;
2012-03-09 04:26:05 +00:00
return 0 ;
}
break ;
2013-10-21 18:40:51 +00:00
case LC_DYLD_INFO :
case LC_DYLD_INFO_ONLY :
if ( m_data . GetU32 ( & offset , & dyld_info . rebase_off , 10 ) )
{
dyld_info . cmd = lc . cmd ;
dyld_info . cmdsize = lc . cmdsize ;
}
else
{
memset ( & dyld_info , 0 , sizeof ( dyld_info ) ) ;
}
break ;
case LC_LOAD_DYLIB :
case LC_LOAD_WEAK_DYLIB :
case LC_REEXPORT_DYLIB :
case LC_LOADFVMLIB :
case LC_LOAD_UPWARD_DYLIB :
{
uint32_t name_offset = cmd_offset + m_data . GetU32 ( & offset ) ;
const char * path = m_data . PeekCStr ( name_offset ) ;
if ( path )
{
FileSpec file_spec ( path , false ) ;
// Strip the path if there is @rpath, @executanble, etc so we just use the basename
if ( path [ 0 ] = = ' @ ' )
file_spec . GetDirectory ( ) . Clear ( ) ;
dylib_files . Append ( file_spec ) ;
}
}
break ;
2013-08-27 05:04:57 +00:00
case LC_FUNCTION_STARTS :
2012-03-09 04:26:05 +00:00
function_starts_load_command . cmd = lc . cmd ;
function_starts_load_command . cmdsize = lc . cmdsize ;
if ( m_data . GetU32 ( & offset , & function_starts_load_command . dataoff , 2 ) = = NULL ) // fill in symoff, nsyms, stroff, strsize fields
2013-08-23 12:44:05 +00:00
memset ( & function_starts_load_command , 0 , sizeof ( function_starts_load_command ) ) ;
2012-03-09 04:26:05 +00:00
break ;
default :
break ;
}
offset = cmd_offset + lc . cmdsize ;
}
if ( symtab_load_command . cmd )
{
Symtab * symtab = m_symtab_ap . get ( ) ;
SectionList * section_list = GetSectionList ( ) ;
if ( section_list = = NULL )
return 0 ;
2013-01-25 18:06:21 +00:00
const uint32_t addr_byte_size = m_data . GetAddressByteSize ( ) ;
const ByteOrder byte_order = m_data . GetByteOrder ( ) ;
2012-03-09 04:26:05 +00:00
bool bit_width_32 = addr_byte_size = = 4 ;
const size_t nlist_byte_size = bit_width_32 ? sizeof ( struct nlist ) : sizeof ( struct nlist_64 ) ;
2013-01-25 18:06:21 +00:00
DataExtractor nlist_data ( NULL , 0 , byte_order , addr_byte_size ) ;
DataExtractor strtab_data ( NULL , 0 , byte_order , addr_byte_size ) ;
DataExtractor function_starts_data ( NULL , 0 , byte_order , addr_byte_size ) ;
2013-02-05 22:31:24 +00:00
DataExtractor indirect_symbol_index_data ( NULL , 0 , byte_order , addr_byte_size ) ;
2013-10-21 18:40:51 +00:00
DataExtractor dyld_trie_data ( NULL , 0 , byte_order , addr_byte_size ) ;
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
const addr_t nlist_data_byte_size = symtab_load_command . nsyms * nlist_byte_size ;
const addr_t strtab_data_byte_size = symtab_load_command . strsize ;
2012-05-18 23:20:01 +00:00
addr_t strtab_addr = LLDB_INVALID_ADDRESS ;
2013-08-13 01:42:25 +00:00
ProcessSP process_sp ( m_process_wp . lock ( ) ) ;
Process * process = process_sp . get ( ) ;
2013-08-13 21:32:34 +00:00
uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete ;
2012-05-18 23:20:01 +00:00
if ( process )
2012-03-09 04:26:05 +00:00
{
2012-05-18 23:20:01 +00:00
Target & target = process - > GetTarget ( ) ;
2013-08-13 01:42:25 +00:00
2013-08-13 21:32:34 +00:00
memory_module_load_level = target . GetMemoryModuleLoadLevel ( ) ;
2013-08-13 01:42:25 +00:00
2012-03-09 04:26:05 +00:00
SectionSP linkedit_section_sp ( section_list - > FindSectionByName ( GetSegmentNameLINKEDIT ( ) ) ) ;
// Reading mach file from memory in a process or core file...
if ( linkedit_section_sp )
{
const addr_t linkedit_load_addr = linkedit_section_sp - > GetLoadBaseAddress ( & target ) ;
const addr_t linkedit_file_offset = linkedit_section_sp - > GetFileOffset ( ) ;
const addr_t symoff_addr = linkedit_load_addr + symtab_load_command . symoff - linkedit_file_offset ;
2012-05-18 23:20:01 +00:00
strtab_addr = linkedit_load_addr + symtab_load_command . stroff - linkedit_file_offset ;
2012-04-18 05:19:20 +00:00
bool data_was_read = false ;
# if defined (__APPLE__) && defined (__arm__)
if ( m_header . flags & 0x80000000u )
2011-12-30 00:32:24 +00:00
{
2012-04-18 05:19:20 +00:00
// This mach-o memory file is in the dyld shared cache. If this
// program is not remote and this is iOS, then this process will
// share the same shared cache as the process we are debugging and
// we can read the entire __LINKEDIT from the address space in this
// process. This is a needed optimization that is used for local iOS
// debugging only since all shared libraries in the shared cache do
// not have corresponding files that exist in the file system of the
// device. They have been combined into a single file. This means we
// always have to load these files from memory. All of the symbol and
// string tables from all of the __LINKEDIT sections from the shared
// libraries in the shared cache have been merged into a single large
// symbol and string table. Reading all of this symbol and string table
// data across can slow down debug launch times, so we optimize this by
// reading the memory for the __LINKEDIT section from this process.
2013-04-16 06:24:42 +00:00
UUID lldb_shared_cache ( GetLLDBSharedCacheUUID ( ) ) ;
UUID process_shared_cache ( GetProcessSharedCacheUUID ( process ) ) ;
bool use_lldb_cache = true ;
if ( lldb_shared_cache . IsValid ( ) & & process_shared_cache . IsValid ( ) & & lldb_shared_cache ! = process_shared_cache )
{
use_lldb_cache = false ;
2013-04-16 21:42:58 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
module_sp - > ReportWarning ( " shared cache in process does not match lldb's own shared cache, startup will be slow. " ) ;
2013-04-16 06:24:42 +00:00
}
2012-04-18 05:19:20 +00:00
PlatformSP platform_sp ( target . GetPlatform ( ) ) ;
2013-04-16 06:24:42 +00:00
if ( platform_sp & & platform_sp - > IsHost ( ) & & use_lldb_cache )
2012-04-18 05:19:20 +00:00
{
data_was_read = true ;
nlist_data . SetData ( ( void * ) symoff_addr , nlist_data_byte_size , eByteOrderLittle ) ;
2012-05-18 23:20:01 +00:00
strtab_data . SetData ( ( void * ) strtab_addr , strtab_data_byte_size , eByteOrderLittle ) ;
2012-04-18 05:19:20 +00:00
if ( function_starts_load_command . cmd )
{
const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command . dataoff - linkedit_file_offset ;
function_starts_data . SetData ( ( void * ) func_start_addr , function_starts_load_command . datasize , eByteOrderLittle ) ;
}
}
}
# endif
if ( ! data_was_read )
{
2013-08-13 01:42:25 +00:00
if ( memory_module_load_level = = eMemoryModuleLoadLevelComplete )
2013-02-05 22:31:24 +00:00
{
2013-08-13 01:42:25 +00:00
DataBufferSP nlist_data_sp ( ReadMemory ( process_sp , symoff_addr , nlist_data_byte_size ) ) ;
if ( nlist_data_sp )
nlist_data . SetData ( nlist_data_sp , 0 , nlist_data_sp - > GetByteSize ( ) ) ;
// Load strings individually from memory when loading from memory since shared cache
// string tables contain strings for all symbols from all shared cached libraries
//DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, strtab_data_byte_size));
//if (strtab_data_sp)
// strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize());
if ( m_dysymtab . nindirectsyms ! = 0 )
{
const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab . indirectsymoff - linkedit_file_offset ;
DataBufferSP indirect_syms_data_sp ( ReadMemory ( process_sp , indirect_syms_addr , m_dysymtab . nindirectsyms * 4 ) ) ;
if ( indirect_syms_data_sp )
indirect_symbol_index_data . SetData ( indirect_syms_data_sp , 0 , indirect_syms_data_sp - > GetByteSize ( ) ) ;
}
2013-02-05 22:31:24 +00:00
}
2013-08-13 01:42:25 +00:00
if ( memory_module_load_level > = eMemoryModuleLoadLevelPartial )
2012-04-18 05:19:20 +00:00
{
2013-08-13 01:42:25 +00:00
if ( function_starts_load_command . cmd )
{
const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command . dataoff - linkedit_file_offset ;
DataBufferSP func_start_data_sp ( ReadMemory ( process_sp , func_start_addr , function_starts_load_command . datasize ) ) ;
if ( func_start_data_sp )
function_starts_data . SetData ( func_start_data_sp , 0 , func_start_data_sp - > GetByteSize ( ) ) ;
}
2012-04-18 05:19:20 +00:00
}
2011-12-30 00:32:24 +00:00
}
2012-03-09 04:26:05 +00:00
}
}
else
{
2013-03-06 23:19:17 +00:00
nlist_data . SetData ( m_data ,
symtab_load_command . symoff ,
2012-03-09 04:26:05 +00:00
nlist_data_byte_size ) ;
strtab_data . SetData ( m_data ,
2013-03-06 23:19:17 +00:00
symtab_load_command . stroff ,
2012-03-09 04:26:05 +00:00
strtab_data_byte_size ) ;
2013-10-21 18:40:51 +00:00
if ( dyld_info . export_size > 0 )
{
dyld_trie_data . SetData ( m_data ,
dyld_info . export_off ,
dyld_info . export_size ) ;
}
2013-02-05 22:31:24 +00:00
if ( m_dysymtab . nindirectsyms ! = 0 )
{
2013-03-06 23:19:17 +00:00
indirect_symbol_index_data . SetData ( m_data ,
m_dysymtab . indirectsymoff ,
2013-02-05 22:31:24 +00:00
m_dysymtab . nindirectsyms * 4 ) ;
}
2012-03-09 04:26:05 +00:00
if ( function_starts_load_command . cmd )
{
function_starts_data . SetData ( m_data ,
function_starts_load_command . dataoff ,
function_starts_load_command . datasize ) ;
}
}
2011-12-30 00:32:24 +00:00
2013-08-13 21:32:34 +00:00
if ( nlist_data . GetByteSize ( ) = = 0 & & memory_module_load_level = = eMemoryModuleLoadLevelComplete )
{
if ( log )
module_sp - > LogMessage ( log , " failed to read nlist data " ) ;
return 0 ;
}
2012-05-25 17:04:00 +00:00
const bool have_strtab_data = strtab_data . GetByteSize ( ) > 0 ;
if ( ! have_strtab_data )
2012-05-18 23:20:01 +00:00
{
2012-05-25 17:04:00 +00:00
if ( process )
{
if ( strtab_addr = = LLDB_INVALID_ADDRESS )
{
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " failed to locate the strtab in memory " ) ;
2012-05-25 17:04:00 +00:00
return 0 ;
}
}
else
2012-05-18 23:20:01 +00:00
{
if ( log )
2013-03-27 23:08:40 +00:00
module_sp - > LogMessage ( log , " failed to read strtab data " ) ;
2012-05-18 23:20:01 +00:00
return 0 ;
}
}
2012-03-09 04:26:05 +00:00
const ConstString & g_segment_name_TEXT = GetSegmentNameTEXT ( ) ;
const ConstString & g_segment_name_DATA = GetSegmentNameDATA ( ) ;
const ConstString & g_segment_name_OBJC = GetSegmentNameOBJC ( ) ;
const ConstString & g_section_name_eh_frame = GetSectionNameEHFrame ( ) ;
SectionSP text_section_sp ( section_list - > FindSectionByName ( g_segment_name_TEXT ) ) ;
SectionSP data_section_sp ( section_list - > FindSectionByName ( g_segment_name_DATA ) ) ;
SectionSP objc_section_sp ( section_list - > FindSectionByName ( g_segment_name_OBJC ) ) ;
SectionSP eh_frame_section_sp ;
if ( text_section_sp . get ( ) )
eh_frame_section_sp = text_section_sp - > GetChildren ( ) . FindSectionByName ( g_section_name_eh_frame ) ;
else
eh_frame_section_sp = section_list - > FindSectionByName ( g_section_name_eh_frame ) ;
2013-08-27 05:04:57 +00:00
const bool is_arm = ( m_header . cputype = = llvm : : MachO : : CPU_TYPE_ARM ) ;
2013-03-21 03:36:01 +00:00
// lldb works best if it knows the start addresss of all functions in a module.
// Linker symbols or debug info are normally the best source of information for start addr / size but
// they may be stripped in a released binary.
2013-04-16 00:18:44 +00:00
// Two additional sources of information exist in Mach-O binaries:
2013-03-21 03:36:01 +00:00
// LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each function's start address in the
// binary, relative to the text section.
// eh_frame - the eh_frame FDEs have the start addr & size of each function
// LC_FUNCTION_STARTS is the fastest source to read in, and is present on all modern binaries.
// Binaries built to run on older releases may need to use eh_frame information.
2012-03-09 04:26:05 +00:00
if ( text_section_sp & & function_starts_data . GetByteSize ( ) )
{
FunctionStarts : : Entry function_start_entry ;
function_start_entry . data = false ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t function_start_offset = 0 ;
2012-03-09 04:26:05 +00:00
function_start_entry . addr = text_section_sp - > GetFileAddress ( ) ;
uint64_t delta ;
while ( ( delta = function_starts_data . GetULEB128 ( & function_start_offset ) ) > 0 )
{
// Now append the current entry
function_start_entry . addr + = delta ;
function_starts . Append ( function_start_entry ) ;
}
2013-04-16 00:18:44 +00:00
}
2013-03-21 03:36:01 +00:00
else
{
2013-03-22 00:38:45 +00:00
// If m_type is eTypeDebugInfo, then this is a dSYM - it will have the load command claiming an eh_frame
// but it doesn't actually have the eh_frame content. And if we have a dSYM, we don't need to do any
// of this fill-in-the-missing-symbols works anyway - the debug info should give us all the functions in
// the module.
if ( text_section_sp . get ( ) & & eh_frame_section_sp . get ( ) & & m_type ! = eTypeDebugInfo )
2013-03-21 03:36:01 +00:00
{
DWARFCallFrameInfo eh_frame ( * this , eh_frame_section_sp , eRegisterKindGCC , true ) ;
DWARFCallFrameInfo : : FunctionAddressAndSizeVector functions ;
eh_frame . GetFunctionAddressAndSizeVector ( functions ) ;
addr_t text_base_addr = text_section_sp - > GetFileAddress ( ) ;
size_t count = functions . GetSize ( ) ;
for ( size_t i = 0 ; i < count ; + + i )
{
const DWARFCallFrameInfo : : FunctionAddressAndSizeVector : : Entry * func = functions . GetEntryAtIndex ( i ) ;
if ( func )
{
FunctionStarts : : Entry function_start_entry ;
function_start_entry . addr = func - > base - text_base_addr ;
function_starts . Append ( function_start_entry ) ;
}
}
}
2012-03-09 04:26:05 +00:00
}
2013-03-06 23:19:17 +00:00
2013-01-25 18:06:21 +00:00
const size_t function_starts_count = function_starts . GetSize ( ) ;
2012-03-09 04:26:05 +00:00
2013-08-27 05:04:57 +00:00
const user_id_t TEXT_eh_frame_sectID = eh_frame_section_sp . get ( ) ? eh_frame_section_sp - > GetID ( ) : NO_SECT ;
2012-03-09 04:26:05 +00:00
2013-01-25 18:06:21 +00:00
lldb : : offset_t nlist_data_offset = 0 ;
2012-03-09 04:26:05 +00:00
uint32_t N_SO_index = UINT32_MAX ;
MachSymtabSectionInfo section_info ( section_list ) ;
std : : vector < uint32_t > N_FUN_indexes ;
std : : vector < uint32_t > N_NSYM_indexes ;
std : : vector < uint32_t > N_INCL_indexes ;
std : : vector < uint32_t > N_BRAC_indexes ;
std : : vector < uint32_t > N_COMM_indexes ;
typedef std : : map < uint64_t , uint32_t > ValueToSymbolIndexMap ;
typedef std : : map < uint32_t , uint32_t > NListIndexToSymbolIndexMap ;
2013-05-14 22:19:37 +00:00
typedef std : : map < const char * , uint32_t > ConstNameToSymbolIndexMap ;
2012-03-09 04:26:05 +00:00
ValueToSymbolIndexMap N_FUN_addr_to_sym_idx ;
ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx ;
2013-05-14 22:19:37 +00:00
ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx ;
2012-03-09 04:26:05 +00:00
// Any symbols that get merged into another will get an entry
// in this map so we know
NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx ;
uint32_t nlist_idx = 0 ;
Symbol * symbol_ptr = NULL ;
uint32_t sym_idx = 0 ;
2012-06-21 01:51:02 +00:00
Symbol * sym = NULL ;
2013-01-25 18:06:21 +00:00
size_t num_syms = 0 ;
2012-05-18 23:20:01 +00:00
std : : string memory_symbol_name ;
2012-06-21 01:51:02 +00:00
uint32_t unmapped_local_symbols_found = 0 ;
2012-03-09 04:26:05 +00:00
2014-01-10 22:55:37 +00:00
std : : vector < TrieEntryWithOffset > trie_entries ;
std : : set < lldb : : addr_t > resolver_addresses ;
if ( dyld_trie_data . GetByteSize ( ) > 0 )
{
std : : vector < llvm : : StringRef > nameSlices ;
ParseTrieEntries ( dyld_trie_data ,
0 ,
nameSlices ,
resolver_addresses ,
trie_entries ) ;
ConstString text_segment_name ( " __TEXT " ) ;
SectionSP text_segment_sp = GetSectionList ( ) - > FindSectionByName ( text_segment_name ) ;
if ( text_segment_sp )
{
const lldb : : addr_t text_segment_file_addr = text_segment_sp - > GetFileAddress ( ) ;
if ( text_segment_file_addr ! = LLDB_INVALID_ADDRESS )
{
for ( auto & e : trie_entries )
e . entry . address + = text_segment_file_addr ;
}
}
}
2012-06-21 01:51:02 +00:00
# if defined (__APPLE__) && defined (__arm__)
// Some recent builds of the dyld_shared_cache (hereafter: DSC) have been optimized by moving LOCAL
// symbols out of the memory mapped portion of the DSC. The symbol information has all been retained,
// but it isn't available in the normal nlist data. However, there *are* duplicate entries of *some*
// LOCAL symbols in the normal nlist data. To handle this situation correctly, we must first attempt
// to parse any DSC unmapped symbol information. If we find any, we set a flag that tells the normal
// nlist parser to ignore all LOCAL symbols.
if ( m_header . flags & 0x80000000u )
{
// Before we can start mapping the DSC, we need to make certain the target process is actually
// using the cache we can find.
// Next we need to determine the correct path for the dyld shared cache.
ArchSpec header_arch ( eArchTypeMachO , m_header . cputype , m_header . cpusubtype ) ;
char dsc_path [ PATH_MAX ] ;
snprintf ( dsc_path , sizeof ( dsc_path ) , " %s%s%s " ,
2013-03-06 23:19:17 +00:00
" /System/Library/Caches/com.apple.dyld/ " , /* IPHONE_DYLD_SHARED_CACHE_DIR */
" dyld_shared_cache_ " , /* DYLD_SHARED_CACHE_BASE_NAME */
2012-06-21 01:51:02 +00:00
header_arch . GetArchitectureName ( ) ) ;
FileSpec dsc_filespec ( dsc_path , false ) ;
// We need definitions of two structures in the on-disk DSC, copy them here manually
2013-04-16 00:18:44 +00:00
struct lldb_copy_dyld_cache_header_v0
2012-09-05 22:30:51 +00:00
{
2013-04-16 00:18:44 +00:00
char magic [ 16 ] ; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
uint32_t mappingOffset ; // file offset to first dyld_cache_mapping_info
uint32_t mappingCount ; // number of dyld_cache_mapping_info entries
uint32_t imagesOffset ;
uint32_t imagesCount ;
uint64_t dyldBaseAddress ;
uint64_t codeSignatureOffset ;
uint64_t codeSignatureSize ;
uint64_t slideInfoOffset ;
uint64_t slideInfoSize ;
uint64_t localSymbolsOffset ; // file offset of where local symbols are stored
uint64_t localSymbolsSize ; // size of local symbols information
} ;
struct lldb_copy_dyld_cache_header_v1
{
char magic [ 16 ] ; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
uint32_t mappingOffset ; // file offset to first dyld_cache_mapping_info
uint32_t mappingCount ; // number of dyld_cache_mapping_info entries
2013-03-06 23:19:17 +00:00
uint32_t imagesOffset ;
uint32_t imagesCount ;
uint64_t dyldBaseAddress ;
uint64_t codeSignatureOffset ;
uint64_t codeSignatureSize ;
uint64_t slideInfoOffset ;
uint64_t slideInfoSize ;
uint64_t localSymbolsOffset ;
uint64_t localSymbolsSize ;
2013-04-16 00:18:44 +00:00
uint8_t uuid [ 16 ] ; // v1 and above, also recorded in dyld_all_image_infos v13 and later
2012-09-05 22:30:51 +00:00
} ;
2013-03-06 23:17:36 +00:00
2013-04-16 00:18:44 +00:00
struct lldb_copy_dyld_cache_mapping_info
{
uint64_t address ;
uint64_t size ;
uint64_t fileOffset ;
uint32_t maxProt ;
uint32_t initProt ;
} ;
2013-03-06 23:17:36 +00:00
2012-09-05 22:30:51 +00:00
struct lldb_copy_dyld_cache_local_symbols_info
{
2013-04-16 00:18:44 +00:00
uint32_t nlistOffset ;
uint32_t nlistCount ;
uint32_t stringsOffset ;
uint32_t stringsSize ;
uint32_t entriesOffset ;
uint32_t entriesCount ;
2012-09-05 22:30:51 +00:00
} ;
struct lldb_copy_dyld_cache_local_symbols_entry
{
2013-04-16 00:18:44 +00:00
uint32_t dylibOffset ;
uint32_t nlistStartIndex ;
uint32_t nlistCount ;
2012-09-05 22:30:51 +00:00
} ;
2012-06-21 01:51:02 +00:00
2012-06-22 03:28:35 +00:00
/* The dyld_cache_header has a pointer to the dyld_cache_local_symbols_info structure (localSymbolsOffset).
The dyld_cache_local_symbols_info structure gives us three things:
1. The start and count of the nlist records in the dyld_shared_cache file
2. The start and size of the strings for these nlist records
3. The start and count of dyld_cache_local_symbols_entry entries
There is one dyld_cache_local_symbols_entry per dylib/framework in the dyld shared cache.
The "dylibOffset" field is the Mach-O header of this dylib/framework in the dyld shared cache.
2013-03-06 23:19:17 +00:00
The dyld_cache_local_symbols_entry also lists the start of this dylib/framework's nlist records
2012-06-22 03:28:35 +00:00
and the count of how many nlist records there are for this dylib/framework.
*/
2012-06-21 01:51:02 +00:00
// Process the dsc header to find the unmapped symbols
//
// Save some VM space, do not map the entire cache in one shot.
2013-03-06 23:17:36 +00:00
DataBufferSP dsc_data_sp ;
dsc_data_sp = dsc_filespec . MemoryMapFileContents ( 0 , sizeof ( struct lldb_copy_dyld_cache_header_v1 ) ) ;
if ( dsc_data_sp )
2012-06-21 01:51:02 +00:00
{
2013-01-25 18:06:21 +00:00
DataExtractor dsc_header_data ( dsc_data_sp , byte_order , addr_byte_size ) ;
2012-06-21 01:51:02 +00:00
2013-03-06 23:17:36 +00:00
char version_str [ 17 ] ;
int version = - 1 ;
lldb : : offset_t offset = 0 ;
memcpy ( version_str , dsc_header_data . GetData ( & offset , 16 ) , 16 ) ;
version_str [ 16 ] = ' \0 ' ;
if ( strncmp ( version_str , " dyld_v " , 6 ) = = 0 & & isdigit ( version_str [ 6 ] ) )
{
int v ;
if ( : : sscanf ( version_str + 6 , " %d " , & v ) = = 1 )
{
version = v ;
}
}
2013-04-16 06:24:42 +00:00
UUID dsc_uuid ;
if ( version > = 1 )
{
offset = offsetof ( struct lldb_copy_dyld_cache_header_v1 , uuid ) ;
uint8_t uuid_bytes [ sizeof ( uuid_t ) ] ;
memcpy ( uuid_bytes , dsc_header_data . GetData ( & offset , sizeof ( uuid_t ) ) , sizeof ( uuid_t ) ) ;
dsc_uuid . SetBytes ( uuid_bytes ) ;
}
bool uuid_match = true ;
if ( dsc_uuid . IsValid ( ) & & process )
{
UUID shared_cache_uuid ( GetProcessSharedCacheUUID ( process ) ) ;
if ( shared_cache_uuid . IsValid ( ) & & dsc_uuid ! = shared_cache_uuid )
{
// The on-disk dyld_shared_cache file is not the same as the one in this
// process' memory, don't use it.
uuid_match = false ;
2013-04-16 21:42:58 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
module_sp - > ReportWarning ( " process shared cache does not match on-disk dyld_shared_cache file, some symbol names will be missing. " ) ;
2013-04-16 06:24:42 +00:00
}
}
2013-03-06 23:19:17 +00:00
offset = offsetof ( struct lldb_copy_dyld_cache_header_v1 , mappingOffset ) ;
2013-03-06 23:17:36 +00:00
2012-06-21 01:51:02 +00:00
uint32_t mappingOffset = dsc_header_data . GetU32 ( & offset ) ;
// If the mappingOffset points to a location inside the header, we've
// opened an old dyld shared cache, and should not proceed further.
2013-04-16 06:24:42 +00:00
if ( uuid_match & & mappingOffset > = sizeof ( struct lldb_copy_dyld_cache_header_v0 ) )
2012-06-21 01:51:02 +00:00
{
2013-03-06 23:17:36 +00:00
DataBufferSP dsc_mapping_info_data_sp = dsc_filespec . MemoryMapFileContents ( mappingOffset , sizeof ( struct lldb_copy_dyld_cache_mapping_info ) ) ;
DataExtractor dsc_mapping_info_data ( dsc_mapping_info_data_sp , byte_order , addr_byte_size ) ;
offset = 0 ;
// The File addresses (from the in-memory Mach-O load commands) for the shared libraries
// in the shared library cache need to be adjusted by an offset to match up with the
// dylibOffset identifying field in the dyld_cache_local_symbol_entry's. This offset is
// recorded in mapping_offset_value.
const uint64_t mapping_offset_value = dsc_mapping_info_data . GetU64 ( & offset ) ;
offset = offsetof ( struct lldb_copy_dyld_cache_header_v1 , localSymbolsOffset ) ;
2012-06-21 01:51:02 +00:00
uint64_t localSymbolsOffset = dsc_header_data . GetU64 ( & offset ) ;
uint64_t localSymbolsSize = dsc_header_data . GetU64 ( & offset ) ;
2013-03-06 23:19:17 +00:00
if ( localSymbolsOffset & & localSymbolsSize )
2012-06-21 01:51:02 +00:00
{
// Map the local symbols
2013-03-06 23:19:17 +00:00
if ( DataBufferSP dsc_local_symbols_data_sp = dsc_filespec . MemoryMapFileContents ( localSymbolsOffset , localSymbolsSize ) )
2012-06-21 01:51:02 +00:00
{
2013-01-25 18:06:21 +00:00
DataExtractor dsc_local_symbols_data ( dsc_local_symbols_data_sp , byte_order , addr_byte_size ) ;
2012-06-21 01:51:02 +00:00
offset = 0 ;
// Read the local_symbols_infos struct in one shot
struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info ;
dsc_local_symbols_data . GetU32 ( & offset , & local_symbols_info . nlistOffset , 6 ) ;
SectionSP text_section_sp ( section_list - > FindSectionByName ( GetSegmentNameTEXT ( ) ) ) ;
2013-03-06 23:17:36 +00:00
uint32_t header_file_offset = ( text_section_sp - > GetFileAddress ( ) - mapping_offset_value ) ;
2012-06-21 01:51:02 +00:00
offset = local_symbols_info . entriesOffset ;
for ( uint32_t entry_index = 0 ; entry_index < local_symbols_info . entriesCount ; entry_index + + )
{
struct lldb_copy_dyld_cache_local_symbols_entry local_symbols_entry ;
local_symbols_entry . dylibOffset = dsc_local_symbols_data . GetU32 ( & offset ) ;
local_symbols_entry . nlistStartIndex = dsc_local_symbols_data . GetU32 ( & offset ) ;
local_symbols_entry . nlistCount = dsc_local_symbols_data . GetU32 ( & offset ) ;
2013-03-06 23:19:17 +00:00
if ( header_file_offset = = local_symbols_entry . dylibOffset )
2012-06-21 01:51:02 +00:00
{
unmapped_local_symbols_found = local_symbols_entry . nlistCount ;
// The normal nlist code cannot correctly size the Symbols array, we need to allocate it here.
sym = symtab - > Resize ( symtab_load_command . nsyms + m_dysymtab . nindirectsyms + unmapped_local_symbols_found - m_dysymtab . nlocalsym ) ;
num_syms = symtab - > GetNumSymbols ( ) ;
nlist_data_offset = local_symbols_info . nlistOffset + ( nlist_byte_size * local_symbols_entry . nlistStartIndex ) ;
uint32_t string_table_offset = local_symbols_info . stringsOffset ;
2013-03-06 23:19:17 +00:00
for ( uint32_t nlist_index = 0 ; nlist_index < local_symbols_entry . nlistCount ; nlist_index + + )
2012-06-21 01:51:02 +00:00
{
/////////////////////////////
{
struct nlist_64 nlist ;
if ( ! dsc_local_symbols_data . ValidOffsetForDataOfSize ( nlist_data_offset , nlist_byte_size ) )
break ;
nlist . n_strx = dsc_local_symbols_data . GetU32_unchecked ( & nlist_data_offset ) ;
nlist . n_type = dsc_local_symbols_data . GetU8_unchecked ( & nlist_data_offset ) ;
nlist . n_sect = dsc_local_symbols_data . GetU8_unchecked ( & nlist_data_offset ) ;
nlist . n_desc = dsc_local_symbols_data . GetU16_unchecked ( & nlist_data_offset ) ;
nlist . n_value = dsc_local_symbols_data . GetAddress_unchecked ( & nlist_data_offset ) ;
SymbolType type = eSymbolTypeInvalid ;
const char * symbol_name = dsc_local_symbols_data . PeekCStr ( string_table_offset + nlist . n_strx ) ;
if ( symbol_name = = NULL )
{
// No symbol should be NULL, even the symbols with no
// string values should have an offset zero which points
// to an empty C-string
Host : : SystemLog ( Host : : eSystemLogError ,
2013-04-29 17:25:54 +00:00
" error: DSC unmapped local symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol \n " ,
2012-06-21 01:51:02 +00:00
entry_index ,
nlist . n_strx ,
2013-04-29 17:25:54 +00:00
module_sp - > GetFileSpec ( ) . GetPath ( ) . c_str ( ) ) ;
2012-06-21 01:51:02 +00:00
continue ;
}
if ( symbol_name [ 0 ] = = ' \0 ' )
symbol_name = NULL ;
const char * symbol_name_non_abi_mangled = NULL ;
SectionSP symbol_section ;
uint32_t symbol_byte_size = 0 ;
bool add_nlist = true ;
2013-08-27 05:04:57 +00:00
bool is_debug = ( ( nlist . n_type & N_STAB ) ! = 0 ) ;
2012-11-27 01:52:16 +00:00
bool demangled_is_synthesized = false ;
2013-05-14 22:19:37 +00:00
bool is_gsym = false ;
2012-06-21 01:51:02 +00:00
assert ( sym_idx < num_syms ) ;
sym [ sym_idx ] . SetDebug ( is_debug ) ;
if ( is_debug )
{
switch ( nlist . n_type )
{
2013-08-27 05:04:57 +00:00
case N_GSYM :
// global symbol: name,,NO_SECT,type,0
2012-06-21 01:51:02 +00:00
// Sometimes the N_GSYM value contains the address.
// FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
// have the same address, but we want to ensure that we always find only the real symbol,
// 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
// symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
// correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
// same address.
if ( symbol_name & & symbol_name [ 0 ] = = ' _ ' & & symbol_name [ 1 ] = = ' O '
& & ( strncmp ( symbol_name , " _OBJC_IVAR_$_ " , strlen ( " _OBJC_IVAR_$_ " ) ) = = 0
| | strncmp ( symbol_name , " _OBJC_CLASS_$_ " , strlen ( " _OBJC_CLASS_$_ " ) ) = = 0
| | strncmp ( symbol_name , " _OBJC_METACLASS_$_ " , strlen ( " _OBJC_METACLASS_$_ " ) ) = = 0 ) )
add_nlist = false ;
else
{
2013-05-14 22:19:37 +00:00
is_gsym = true ;
2012-06-21 01:51:02 +00:00
sym [ sym_idx ] . SetExternal ( true ) ;
if ( nlist . n_value ! = 0 )
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeData ;
}
break ;
2013-08-27 05:04:57 +00:00
case N_FNAME :
// procedure name (f77 kludge): name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_FUN :
// procedure: name,,n_sect,linenumber,address
2012-06-21 01:51:02 +00:00
if ( symbol_name )
{
type = eSymbolTypeCode ;
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
N_FUN_addr_to_sym_idx [ nlist . n_value ] = sym_idx ;
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
N_FUN_indexes . push_back ( sym_idx ) ;
}
else
{
type = eSymbolTypeCompiler ;
if ( ! N_FUN_indexes . empty ( ) )
{
// Copy the size of the function into the original STAB entry so we don't have
// to hunt for it later
symtab - > SymbolAtIndex ( N_FUN_indexes . back ( ) ) - > SetByteSize ( nlist . n_value ) ;
N_FUN_indexes . pop_back ( ) ;
// We don't really need the end function STAB as it contains the size which
// we already placed with the original symbol, so don't add it if we want a
// minimal symbol table
2013-07-10 01:23:25 +00:00
add_nlist = false ;
2012-06-21 01:51:02 +00:00
}
}
break ;
2013-08-27 05:04:57 +00:00
case N_STSYM :
// static symbol: name,,n_sect,type,address
2012-06-21 01:51:02 +00:00
N_STSYM_addr_to_sym_idx [ nlist . n_value ] = sym_idx ;
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeData ;
break ;
2013-08-27 05:04:57 +00:00
case N_LCSYM :
// .lcomm symbol: name,,n_sect,type,address
2012-06-21 01:51:02 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeCommonBlock ;
break ;
2013-08-27 05:04:57 +00:00
case N_BNSYM :
2012-06-21 01:51:02 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
2013-07-10 01:23:25 +00:00
// Skip these if we want minimal symbol tables
add_nlist = false ;
2012-06-21 01:51:02 +00:00
break ;
2013-08-27 05:04:57 +00:00
case N_ENSYM :
2012-06-21 01:51:02 +00:00
// Set the size of the N_BNSYM to the terminating index of this N_ENSYM
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
2013-07-10 01:23:25 +00:00
// Skip these if we want minimal symbol tables
add_nlist = false ;
2012-06-21 01:51:02 +00:00
break ;
2013-08-27 05:04:57 +00:00
case N_OPT :
// emitted with gcc2_compiled and in gcc source
2012-06-21 01:51:02 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_RSYM :
// register sym: name,,NO_SECT,type,register
2012-06-21 01:51:02 +00:00
type = eSymbolTypeVariable ;
break ;
2013-08-27 05:04:57 +00:00
case N_SLINE :
// src line: 0,,n_sect,linenumber,address
2012-06-21 01:51:02 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeLineEntry ;
break ;
2013-08-27 05:04:57 +00:00
case N_SSYM :
// structure elt: name,,NO_SECT,type,struct_offset
2012-06-21 01:51:02 +00:00
type = eSymbolTypeVariableType ;
break ;
2013-08-27 05:04:57 +00:00
case N_SO :
// source file name
2012-06-21 01:51:02 +00:00
type = eSymbolTypeSourceFile ;
if ( symbol_name = = NULL )
{
2013-07-10 01:23:25 +00:00
add_nlist = false ;
2012-06-21 01:51:02 +00:00
if ( N_SO_index ! = UINT32_MAX )
{
// Set the size of the N_SO to the terminating index of this N_SO
// so that we can always skip the entire N_SO if we need to navigate
// more quickly at the source level when parsing STABS
symbol_ptr = symtab - > SymbolAtIndex ( N_SO_index ) ;
2013-07-10 01:23:25 +00:00
symbol_ptr - > SetByteSize ( sym_idx ) ;
2012-06-21 01:51:02 +00:00
symbol_ptr - > SetSizeIsSibling ( true ) ;
}
N_NSYM_indexes . clear ( ) ;
N_INCL_indexes . clear ( ) ;
N_BRAC_indexes . clear ( ) ;
N_COMM_indexes . clear ( ) ;
N_FUN_indexes . clear ( ) ;
N_SO_index = UINT32_MAX ;
}
else
{
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
const bool N_SO_has_full_path = symbol_name [ 0 ] = = ' / ' ;
if ( N_SO_has_full_path )
{
2013-07-10 01:23:25 +00:00
if ( ( N_SO_index = = sym_idx - 1 ) & & ( ( sym_idx - 1 ) < num_syms ) )
2012-06-21 01:51:02 +00:00
{
// We have two consecutive N_SO entries where the first contains a directory
// and the second contains a full path.
2012-07-20 03:35:44 +00:00
sym [ sym_idx - 1 ] . GetMangled ( ) . SetValue ( ConstString ( symbol_name ) , false ) ;
2012-06-21 01:51:02 +00:00
m_nlist_idx_to_sym_idx [ nlist_idx ] = sym_idx - 1 ;
add_nlist = false ;
}
else
{
// This is the first entry in a N_SO that contains a directory or
// a full path to the source file
N_SO_index = sym_idx ;
}
}
2013-07-10 01:23:25 +00:00
else if ( ( N_SO_index = = sym_idx - 1 ) & & ( ( sym_idx - 1 ) < num_syms ) )
2012-06-21 01:51:02 +00:00
{
// This is usually the second N_SO entry that contains just the filename,
// so here we combine it with the first one if we are minimizing the symbol table
const char * so_path = sym [ sym_idx - 1 ] . GetMangled ( ) . GetDemangledName ( ) . AsCString ( ) ;
if ( so_path & & so_path [ 0 ] )
{
std : : string full_so_path ( so_path ) ;
2012-09-07 20:29:13 +00:00
const size_t double_slash_pos = full_so_path . find ( " // " ) ;
if ( double_slash_pos ! = std : : string : : npos )
{
// The linker has been generating bad N_SO entries with doubled up paths
2013-08-27 14:56:58 +00:00
// in the format "%s%s" where the first string in the DW_AT_comp_dir,
2012-09-07 20:29:13 +00:00
// and the second is the directory for the source file so you end up with
// a path that looks like "/tmp/src//tmp/src/"
FileSpec so_dir ( so_path , false ) ;
if ( ! so_dir . Exists ( ) )
{
so_dir . SetFile ( & full_so_path [ double_slash_pos + 1 ] , false ) ;
if ( so_dir . Exists ( ) )
{
// Trim off the incorrect path
full_so_path . erase ( 0 , double_slash_pos + 1 ) ;
}
}
}
2012-06-21 01:51:02 +00:00
if ( * full_so_path . rbegin ( ) ! = ' / ' )
full_so_path + = ' / ' ;
full_so_path + = symbol_name ;
2012-07-20 03:35:44 +00:00
sym [ sym_idx - 1 ] . GetMangled ( ) . SetValue ( ConstString ( full_so_path . c_str ( ) ) , false ) ;
2012-06-21 01:51:02 +00:00
add_nlist = false ;
m_nlist_idx_to_sym_idx [ nlist_idx ] = sym_idx - 1 ;
}
}
2012-09-05 22:30:51 +00:00
else
{
// This could be a relative path to a N_SO
N_SO_index = sym_idx ;
}
2012-06-21 01:51:02 +00:00
}
break ;
2013-08-27 05:04:57 +00:00
case N_OSO :
// object file name: name,,0,0,st_mtime
2012-06-21 01:51:02 +00:00
type = eSymbolTypeObjectFile ;
break ;
2013-08-27 05:04:57 +00:00
case N_LSYM :
// local sym: name,,NO_SECT,type,offset
2012-06-21 01:51:02 +00:00
type = eSymbolTypeLocal ;
break ;
//----------------------------------------------------------------------
// INCL scopes
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_BINCL :
// include file beginning: name,,NO_SECT,0,sum
2012-06-21 01:51:02 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
N_INCL_indexes . push_back ( sym_idx ) ;
type = eSymbolTypeScopeBegin ;
break ;
2013-08-27 05:04:57 +00:00
case N_EINCL :
// include file end: name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
// Set the size of the N_BINCL to the terminating index of this N_EINCL
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
if ( ! N_INCL_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_INCL_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_INCL_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_SOL :
// #included file name: name,,n_sect,0,address
2012-06-21 01:51:02 +00:00
type = eSymbolTypeHeaderFile ;
// We currently don't use the header files on darwin
2013-07-10 01:23:25 +00:00
add_nlist = false ;
2012-06-21 01:51:02 +00:00
break ;
2013-08-27 05:04:57 +00:00
case N_PARAMS :
// compiler parameters: name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_VERSION :
// compiler version: name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_OLEVEL :
// compiler -O level: name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_PSYM :
// parameter: name,,NO_SECT,type,offset
2012-06-21 01:51:02 +00:00
type = eSymbolTypeVariable ;
break ;
2013-08-27 05:04:57 +00:00
case N_ENTRY :
// alternate entry: name,,n_sect,linenumber,address
2012-06-21 01:51:02 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeLineEntry ;
break ;
//----------------------------------------------------------------------
// Left and Right Braces
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_LBRAC :
// left bracket: 0,,NO_SECT,nesting level,address
2012-06-21 01:51:02 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
N_BRAC_indexes . push_back ( sym_idx ) ;
type = eSymbolTypeScopeBegin ;
break ;
2013-08-27 05:04:57 +00:00
case N_RBRAC :
// right bracket: 0,,NO_SECT,nesting level,address
2012-06-21 01:51:02 +00:00
// Set the size of the N_LBRAC to the terminating index of this N_RBRAC
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
if ( ! N_BRAC_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_BRAC_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_BRAC_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_EXCL :
// deleted include file: name,,NO_SECT,0,sum
2012-06-21 01:51:02 +00:00
type = eSymbolTypeHeaderFile ;
break ;
//----------------------------------------------------------------------
// COMM scopes
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_BCOMM :
// begin common: name,,NO_SECT,0,0
2012-06-21 01:51:02 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
type = eSymbolTypeScopeBegin ;
N_COMM_indexes . push_back ( sym_idx ) ;
break ;
2013-08-27 05:04:57 +00:00
case N_ECOML :
// end common (local name): 0,,n_sect,0,address
2012-06-21 01:51:02 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
// Fall through
2013-08-27 05:04:57 +00:00
case N_ECOMM :
// end common: name,,n_sect,0,0
2012-06-21 01:51:02 +00:00
// Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
if ( ! N_COMM_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_COMM_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_COMM_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_LENG :
// second stab entry with length information
2012-06-21 01:51:02 +00:00
type = eSymbolTypeAdditional ;
break ;
default : break ;
}
}
else
{
2013-08-27 05:04:57 +00:00
//uint8_t n_pext = N_PEXT & nlist.n_type;
uint8_t n_type = N_TYPE & nlist . n_type ;
sym [ sym_idx ] . SetExternal ( ( N_EXT & nlist . n_type ) ! = 0 ) ;
2012-06-21 01:51:02 +00:00
switch ( n_type )
{
2013-08-27 05:04:57 +00:00
case N_INDR : // Fall through
case N_PBUD : // Fall through
case N_UNDF :
2012-06-21 01:51:02 +00:00
type = eSymbolTypeUndefined ;
break ;
2013-08-27 05:04:57 +00:00
case N_ABS :
2012-06-21 01:51:02 +00:00
type = eSymbolTypeAbsolute ;
break ;
2013-08-27 05:04:57 +00:00
case N_SECT :
2012-11-27 01:52:16 +00:00
{
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
2012-06-21 01:51:02 +00:00
2012-11-27 01:52:16 +00:00
if ( symbol_section = = NULL )
2012-06-21 01:51:02 +00:00
{
2012-11-27 01:52:16 +00:00
// TODO: warn about this?
add_nlist = false ;
break ;
2012-06-21 01:51:02 +00:00
}
2012-11-27 01:52:16 +00:00
if ( TEXT_eh_frame_sectID = = nlist . n_sect )
2012-06-21 01:51:02 +00:00
{
2012-11-27 01:52:16 +00:00
type = eSymbolTypeException ;
}
else
{
2013-08-27 05:04:57 +00:00
uint32_t section_type = symbol_section - > Get ( ) & SECTION_TYPE ;
2013-03-06 23:19:17 +00:00
2012-11-27 01:52:16 +00:00
switch ( section_type )
2012-06-21 01:51:02 +00:00
{
2013-08-27 05:04:57 +00:00
case S_REGULAR : break ; // regular section
//case S_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section
case S_CSTRING_LITERALS : type = eSymbolTypeData ; break ; // section with only literal C strings
case S_4BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 4 byte literals
case S_8BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 8 byte literals
case S_LITERAL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only pointers to literals
case S_NON_LAZY_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only non-lazy symbol pointers
case S_LAZY_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only lazy symbol pointers
case S_SYMBOL_STUBS : type = eSymbolTypeTrampoline ; break ; // section with only symbol stubs, byte size of stub in the reserved2 field
case S_MOD_INIT_FUNC_POINTERS : type = eSymbolTypeCode ; break ; // section with only function pointers for initialization
case S_MOD_TERM_FUNC_POINTERS : type = eSymbolTypeCode ; break ; // section with only function pointers for termination
//case S_COALESCED: type = eSymbolType; break; // section contains symbols that are to be coalesced
//case S_GB_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section (that can be larger than 4 gigabytes)
case S_INTERPOSING : type = eSymbolTypeTrampoline ; break ; // section with only pairs of function pointers for interposing
case S_16BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 16 byte literals
case S_DTRACE_DOF : type = eSymbolTypeInstrumentation ; break ;
case S_LAZY_DYLIB_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ;
2012-11-27 01:52:16 +00:00
default : break ;
2012-06-21 01:51:02 +00:00
}
2013-03-06 23:19:17 +00:00
2012-11-27 01:52:16 +00:00
if ( type = = eSymbolTypeInvalid )
{
const char * symbol_sect_name = symbol_section - > GetName ( ) . AsCString ( ) ;
if ( symbol_section - > IsDescendant ( text_section_sp . get ( ) ) )
{
2013-08-27 05:04:57 +00:00
if ( symbol_section - > IsClear ( S_ATTR_PURE_INSTRUCTIONS |
S_ATTR_SELF_MODIFYING_CODE |
S_ATTR_SOME_INSTRUCTIONS ) )
2012-11-27 01:52:16 +00:00
type = eSymbolTypeData ;
else
type = eSymbolTypeCode ;
}
else if ( symbol_section - > IsDescendant ( data_section_sp . get ( ) ) )
2012-06-21 01:51:02 +00:00
{
if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __objc " ) = = symbol_sect_name )
{
type = eSymbolTypeRuntime ;
2013-03-06 23:19:17 +00:00
2012-11-27 01:52:16 +00:00
if ( symbol_name & &
symbol_name [ 0 ] = = ' _ ' & &
symbol_name [ 1 ] = = ' O ' & &
2012-06-21 01:51:02 +00:00
symbol_name [ 2 ] = = ' B ' )
{
llvm : : StringRef symbol_name_ref ( symbol_name ) ;
static const llvm : : StringRef g_objc_v2_prefix_class ( " _OBJC_CLASS_$_ " ) ;
static const llvm : : StringRef g_objc_v2_prefix_metaclass ( " _OBJC_METACLASS_$_ " ) ;
static const llvm : : StringRef g_objc_v2_prefix_ivar ( " _OBJC_IVAR_$_ " ) ;
if ( symbol_name_ref . startswith ( g_objc_v2_prefix_class ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_class . size ( ) ;
type = eSymbolTypeObjCClass ;
2012-11-27 01:52:16 +00:00
demangled_is_synthesized = true ;
2012-06-21 01:51:02 +00:00
}
else if ( symbol_name_ref . startswith ( g_objc_v2_prefix_metaclass ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_metaclass . size ( ) ;
type = eSymbolTypeObjCMetaClass ;
2012-11-27 01:52:16 +00:00
demangled_is_synthesized = true ;
2012-06-21 01:51:02 +00:00
}
else if ( symbol_name_ref . startswith ( g_objc_v2_prefix_ivar ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_ivar . size ( ) ;
type = eSymbolTypeObjCIVar ;
2012-11-27 01:52:16 +00:00
demangled_is_synthesized = true ;
2012-06-21 01:51:02 +00:00
}
}
}
2012-11-27 01:52:16 +00:00
else if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __gcc_except_tab " ) = = symbol_sect_name )
2012-06-21 01:51:02 +00:00
{
2012-11-27 01:52:16 +00:00
type = eSymbolTypeException ;
2012-06-21 01:51:02 +00:00
}
else
2012-11-27 01:52:16 +00:00
{
type = eSymbolTypeData ;
}
}
else if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __IMPORT " ) = = symbol_sect_name )
{
type = eSymbolTypeTrampoline ;
}
else if ( symbol_section - > IsDescendant ( objc_section_sp . get ( ) ) )
{
type = eSymbolTypeRuntime ;
if ( symbol_name & & symbol_name [ 0 ] = = ' . ' )
{
llvm : : StringRef symbol_name_ref ( symbol_name ) ;
static const llvm : : StringRef g_objc_v1_prefix_class ( " .objc_class_name_ " ) ;
if ( symbol_name_ref . startswith ( g_objc_v1_prefix_class ) )
2012-06-21 01:51:02 +00:00
{
2012-11-27 01:52:16 +00:00
symbol_name_non_abi_mangled = symbol_name ;
symbol_name = symbol_name + g_objc_v1_prefix_class . size ( ) ;
type = eSymbolTypeObjCClass ;
demangled_is_synthesized = true ;
2012-06-21 01:51:02 +00:00
}
2012-11-27 01:52:16 +00:00
}
}
}
2012-06-21 01:51:02 +00:00
}
}
break ;
2013-03-06 23:19:17 +00:00
}
2012-06-21 01:51:02 +00:00
}
if ( add_nlist )
{
uint64_t symbol_value = nlist . n_value ;
if ( symbol_name_non_abi_mangled )
{
2012-07-20 03:35:44 +00:00
sym [ sym_idx ] . GetMangled ( ) . SetMangledName ( ConstString ( symbol_name_non_abi_mangled ) ) ;
sym [ sym_idx ] . GetMangled ( ) . SetDemangledName ( ConstString ( symbol_name ) ) ;
2012-06-21 01:51:02 +00:00
}
else
{
2013-07-10 01:23:25 +00:00
bool symbol_name_is_mangled = false ;
2012-06-21 01:51:02 +00:00
if ( symbol_name & & symbol_name [ 0 ] = = ' _ ' )
{
symbol_name_is_mangled = symbol_name [ 1 ] = = ' _ ' ;
symbol_name + + ; // Skip the leading underscore
}
2013-03-06 23:19:17 +00:00
2012-06-21 01:51:02 +00:00
if ( symbol_name )
{
2013-05-14 22:19:37 +00:00
ConstString const_symbol_name ( symbol_name ) ;
sym [ sym_idx ] . GetMangled ( ) . SetValue ( const_symbol_name , symbol_name_is_mangled ) ;
2013-07-10 01:23:25 +00:00
if ( is_gsym & & is_debug )
N_GSYM_name_to_sym_idx [ sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) . GetCString ( ) ] = sym_idx ;
2012-06-21 01:51:02 +00:00
}
}
if ( symbol_section )
{
const addr_t section_file_addr = symbol_section - > GetFileAddress ( ) ;
if ( symbol_byte_size = = 0 & & function_starts_count > 0 )
{
addr_t symbol_lookup_file_addr = nlist . n_value ;
// Do an exact address match for non-ARM addresses, else get the closest since
// the symbol might be a thumb symbol which has an address with bit zero set
FunctionStarts : : Entry * func_start_entry = function_starts . FindEntry ( symbol_lookup_file_addr , ! is_arm ) ;
if ( is_arm & & func_start_entry )
{
// Verify that the function start address is the symbol address (ARM)
// or the symbol address + 1 (thumb)
if ( func_start_entry - > addr ! = symbol_lookup_file_addr & &
func_start_entry - > addr ! = ( symbol_lookup_file_addr + 1 ) )
{
// Not the right entry, NULL it out...
func_start_entry = NULL ;
}
}
if ( func_start_entry )
{
func_start_entry - > data = true ;
2013-03-06 23:19:17 +00:00
2012-06-21 01:51:02 +00:00
addr_t symbol_file_addr = func_start_entry - > addr ;
uint32_t symbol_flags = 0 ;
if ( is_arm )
{
if ( symbol_file_addr & 1 )
symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB ;
symbol_file_addr & = 0xfffffffffffffffeull ;
}
2013-03-06 23:19:17 +00:00
2012-06-21 01:51:02 +00:00
const FunctionStarts : : Entry * next_func_start_entry = function_starts . FindNextEntry ( func_start_entry ) ;
const addr_t section_end_file_addr = section_file_addr + symbol_section - > GetByteSize ( ) ;
if ( next_func_start_entry )
{
addr_t next_symbol_file_addr = next_func_start_entry - > addr ;
// Be sure the clear the Thumb address bit when we calculate the size
// from the current and next address
if ( is_arm )
next_symbol_file_addr & = 0xfffffffffffffffeull ;
symbol_byte_size = std : : min < lldb : : addr_t > ( next_symbol_file_addr - symbol_file_addr , section_end_file_addr - symbol_file_addr ) ;
}
else
{
symbol_byte_size = section_end_file_addr - symbol_file_addr ;
}
}
}
symbol_value - = section_file_addr ;
}
2013-03-06 23:19:17 +00:00
2013-05-14 22:19:37 +00:00
if ( is_debug = = false )
{
if ( type = = eSymbolTypeCode )
{
// See if we can find a N_FUN entry for any code symbols.
// If we do find a match, and the name matches, then we
// can merge the two into just the function symbol to avoid
// duplicate entries in the symbol table
ValueToSymbolIndexMap : : const_iterator pos = N_FUN_addr_to_sym_idx . find ( nlist . n_value ) ;
if ( pos ! = N_FUN_addr_to_sym_idx . end ( ) )
{
2013-07-10 01:23:25 +00:00
if ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) = = sym [ pos - > second ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) )
2013-05-14 22:19:37 +00:00
{
m_nlist_idx_to_sym_idx [ nlist_idx ] = pos - > second ;
// We just need the flags from the linker symbol, so put these flags
// into the N_FUN flags to avoid duplicate symbols in the symbol table
2013-10-21 18:40:51 +00:00
sym [ pos - > second ] . SetExternal ( sym [ sym_idx ] . IsExternal ( ) ) ;
2013-05-14 22:19:37 +00:00
sym [ pos - > second ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
2014-01-10 22:55:37 +00:00
if ( resolver_addresses . find ( nlist . n_value ) ! = resolver_adresses . end ( ) )
sym [ pos - > second ] . SetType ( eSymbolTypeResolver ) ;
2013-05-14 22:19:37 +00:00
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
2014-01-10 22:55:37 +00:00
else
{
if ( resolver_addresses . find ( nlist . n_value ) ! = resolver_adresses . end ( ) )
sym [ sym_idx ] . SetType ( eSymbolTypeResolver ) ;
}
2013-05-14 22:19:37 +00:00
}
else if ( type = = eSymbolTypeData )
{
// See if we can find a N_STSYM entry for any data symbols.
// If we do find a match, and the name matches, then we
// can merge the two into just the Static symbol to avoid
// duplicate entries in the symbol table
ValueToSymbolIndexMap : : const_iterator pos = N_STSYM_addr_to_sym_idx . find ( nlist . n_value ) ;
if ( pos ! = N_STSYM_addr_to_sym_idx . end ( ) )
{
2013-07-10 01:23:25 +00:00
if ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) = = sym [ pos - > second ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) )
2013-05-14 22:19:37 +00:00
{
m_nlist_idx_to_sym_idx [ nlist_idx ] = pos - > second ;
// We just need the flags from the linker symbol, so put these flags
// into the N_STSYM flags to avoid duplicate symbols in the symbol table
2013-10-21 18:40:51 +00:00
sym [ pos - > second ] . SetExternal ( sym [ sym_idx ] . IsExternal ( ) ) ;
2013-05-14 22:19:37 +00:00
sym [ pos - > second ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
else
{
// Combine N_GSYM stab entries with the non stab symbol
2013-07-10 01:23:25 +00:00
ConstNameToSymbolIndexMap : : const_iterator pos = N_GSYM_name_to_sym_idx . find ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) . GetCString ( ) ) ;
2013-05-14 22:19:37 +00:00
if ( pos ! = N_GSYM_name_to_sym_idx . end ( ) )
{
const uint32_t GSYM_sym_idx = pos - > second ;
m_nlist_idx_to_sym_idx [ nlist_idx ] = GSYM_sym_idx ;
// Copy the address, because often the N_GSYM address has an invalid address of zero
// when the global is a common symbol
sym [ GSYM_sym_idx ] . GetAddress ( ) . SetSection ( symbol_section ) ;
sym [ GSYM_sym_idx ] . GetAddress ( ) . SetOffset ( symbol_value ) ;
// We just need the flags from the linker symbol, so put these flags
// into the N_STSYM flags to avoid duplicate symbols in the symbol table
sym [ GSYM_sym_idx ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
}
}
2012-06-21 01:51:02 +00:00
sym [ sym_idx ] . SetID ( nlist_idx ) ;
sym [ sym_idx ] . SetType ( type ) ;
sym [ sym_idx ] . GetAddress ( ) . SetSection ( symbol_section ) ;
sym [ sym_idx ] . GetAddress ( ) . SetOffset ( symbol_value ) ;
sym [ sym_idx ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
2013-03-06 23:19:17 +00:00
2012-06-21 01:51:02 +00:00
if ( symbol_byte_size > 0 )
sym [ sym_idx ] . SetByteSize ( symbol_byte_size ) ;
2012-11-27 01:52:16 +00:00
if ( demangled_is_synthesized )
sym [ sym_idx ] . SetDemangledNameIsSynthesized ( true ) ;
2012-06-21 01:51:02 +00:00
+ + sym_idx ;
}
else
{
sym [ sym_idx ] . Clear ( ) ;
}
2013-03-06 23:19:17 +00:00
2012-06-21 01:51:02 +00:00
}
/////////////////////////////
}
break ; // No more entries to consider
}
}
}
}
}
}
}
// Must reset this in case it was mutated above!
nlist_data_offset = 0 ;
# endif
2014-01-10 22:55:37 +00:00
2013-08-13 01:42:25 +00:00
if ( nlist_data . GetByteSize ( ) > 0 )
2012-06-21 01:51:02 +00:00
{
2013-08-13 01:42:25 +00:00
// If the sym array was not created while parsing the DSC unmapped
// symbols, create it now.
if ( sym = = NULL )
2012-05-18 23:20:01 +00:00
{
2013-08-13 01:42:25 +00:00
sym = symtab - > Resize ( symtab_load_command . nsyms + m_dysymtab . nindirectsyms ) ;
num_syms = symtab - > GetNumSymbols ( ) ;
}
2013-03-06 23:19:17 +00:00
2013-08-13 01:42:25 +00:00
if ( unmapped_local_symbols_found )
{
assert ( m_dysymtab . ilocalsym = = 0 ) ;
nlist_data_offset + = ( m_dysymtab . nlocalsym * nlist_byte_size ) ;
nlist_idx = m_dysymtab . nlocalsym ;
2012-03-09 04:26:05 +00:00
}
2012-05-25 17:04:00 +00:00
else
{
2013-08-13 01:42:25 +00:00
nlist_idx = 0 ;
2012-05-25 17:04:00 +00:00
}
2012-03-09 04:26:05 +00:00
2013-08-13 01:42:25 +00:00
for ( ; nlist_idx < symtab_load_command . nsyms ; + + nlist_idx )
2012-03-09 04:26:05 +00:00
{
2013-08-13 01:42:25 +00:00
struct nlist_64 nlist ;
if ( ! nlist_data . ValidOffsetForDataOfSize ( nlist_data_offset , nlist_byte_size ) )
break ;
nlist . n_strx = nlist_data . GetU32_unchecked ( & nlist_data_offset ) ;
nlist . n_type = nlist_data . GetU8_unchecked ( & nlist_data_offset ) ;
nlist . n_sect = nlist_data . GetU8_unchecked ( & nlist_data_offset ) ;
nlist . n_desc = nlist_data . GetU16_unchecked ( & nlist_data_offset ) ;
nlist . n_value = nlist_data . GetAddress_unchecked ( & nlist_data_offset ) ;
SymbolType type = eSymbolTypeInvalid ;
const char * symbol_name = NULL ;
if ( have_strtab_data )
2011-12-30 00:32:24 +00:00
{
2013-08-13 01:42:25 +00:00
symbol_name = strtab_data . PeekCStr ( nlist . n_strx ) ;
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
if ( symbol_name = = NULL )
{
2013-08-13 01:42:25 +00:00
// No symbol should be NULL, even the symbols with no
// string values should have an offset zero which points
// to an empty C-string
Host : : SystemLog ( Host : : eSystemLogError ,
" error: symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol \n " ,
nlist_idx ,
nlist . n_strx ,
module_sp - > GetFileSpec ( ) . GetPath ( ) . c_str ( ) ) ;
continue ;
2012-03-09 04:26:05 +00:00
}
2013-08-13 01:42:25 +00:00
if ( symbol_name [ 0 ] = = ' \0 ' )
symbol_name = NULL ;
2012-03-09 04:26:05 +00:00
}
else
{
2013-08-13 01:42:25 +00:00
const addr_t str_addr = strtab_addr + nlist . n_strx ;
Error str_error ;
if ( process - > ReadCStringFromMemory ( str_addr , memory_symbol_name , str_error ) )
symbol_name = memory_symbol_name . c_str ( ) ;
2012-03-09 04:26:05 +00:00
}
2013-08-13 01:42:25 +00:00
const char * symbol_name_non_abi_mangled = NULL ;
SectionSP symbol_section ;
lldb : : addr_t symbol_byte_size = 0 ;
bool add_nlist = true ;
bool is_gsym = false ;
2013-08-27 05:04:57 +00:00
bool is_debug = ( ( nlist . n_type & N_STAB ) ! = 0 ) ;
2013-08-13 01:42:25 +00:00
bool demangled_is_synthesized = false ;
assert ( sym_idx < num_syms ) ;
sym [ sym_idx ] . SetDebug ( is_debug ) ;
if ( is_debug )
2012-03-09 04:26:05 +00:00
{
2013-08-13 01:42:25 +00:00
switch ( nlist . n_type )
2012-03-09 04:26:05 +00:00
{
2013-08-27 05:04:57 +00:00
case N_GSYM :
// global symbol: name,,NO_SECT,type,0
2013-08-13 01:42:25 +00:00
// Sometimes the N_GSYM value contains the address.
2013-03-06 23:19:17 +00:00
2013-08-13 01:42:25 +00:00
// FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
// have the same address, but we want to ensure that we always find only the real symbol,
// 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
// symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
// correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
// same address.
2012-03-14 01:53:24 +00:00
2013-08-13 01:42:25 +00:00
if ( symbol_name & & symbol_name [ 0 ] = = ' _ ' & & symbol_name [ 1 ] = = ' O '
& & ( strncmp ( symbol_name , " _OBJC_IVAR_$_ " , strlen ( " _OBJC_IVAR_$_ " ) ) = = 0
| | strncmp ( symbol_name , " _OBJC_CLASS_$_ " , strlen ( " _OBJC_CLASS_$_ " ) ) = = 0
| | strncmp ( symbol_name , " _OBJC_METACLASS_$_ " , strlen ( " _OBJC_METACLASS_$_ " ) ) = = 0 ) )
add_nlist = false ;
else
{
is_gsym = true ;
sym [ sym_idx ] . SetExternal ( true ) ;
if ( nlist . n_value ! = 0 )
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeData ;
2012-03-09 04:26:05 +00:00
}
2013-08-13 01:42:25 +00:00
break ;
2013-05-14 22:19:37 +00:00
2013-08-27 05:04:57 +00:00
case N_FNAME :
// procedure name (f77 kludge): name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_FUN :
// procedure: name,,n_sect,linenumber,address
2013-08-13 01:42:25 +00:00
if ( symbol_name )
2013-05-14 22:19:37 +00:00
{
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCode ;
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
N_FUN_addr_to_sym_idx [ nlist . n_value ] = sym_idx ;
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
N_FUN_indexes . push_back ( sym_idx ) ;
2013-05-14 22:19:37 +00:00
}
else
{
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
if ( ! N_FUN_indexes . empty ( ) )
2013-05-14 22:19:37 +00:00
{
2013-08-13 01:42:25 +00:00
// Copy the size of the function into the original STAB entry so we don't have
// to hunt for it later
symtab - > SymbolAtIndex ( N_FUN_indexes . back ( ) ) - > SetByteSize ( nlist . n_value ) ;
N_FUN_indexes . pop_back ( ) ;
// We don't really need the end function STAB as it contains the size which
// we already placed with the original symbol, so don't add it if we want a
// minimal symbol table
add_nlist = false ;
2013-05-14 22:19:37 +00:00
}
}
2013-08-13 01:42:25 +00:00
break ;
2013-08-27 05:04:57 +00:00
case N_STSYM :
// static symbol: name,,n_sect,type,address
2013-08-13 01:42:25 +00:00
N_STSYM_addr_to_sym_idx [ nlist . n_value ] = sym_idx ;
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeData ;
break ;
2013-08-27 05:04:57 +00:00
case N_LCSYM :
// .lcomm symbol: name,,n_sect,type,address
2013-08-13 01:42:25 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeCommonBlock ;
break ;
2013-08-27 05:04:57 +00:00
case N_BNSYM :
2013-08-13 01:42:25 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
// Skip these if we want minimal symbol tables
add_nlist = false ;
break ;
2013-08-27 05:04:57 +00:00
case N_ENSYM :
2013-08-13 01:42:25 +00:00
// Set the size of the N_BNSYM to the terminating index of this N_ENSYM
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
// Skip these if we want minimal symbol tables
add_nlist = false ;
break ;
2013-08-27 05:04:57 +00:00
case N_OPT :
// emitted with gcc2_compiled and in gcc source
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_RSYM :
// register sym: name,,NO_SECT,type,register
2013-08-13 01:42:25 +00:00
type = eSymbolTypeVariable ;
break ;
2013-08-27 05:04:57 +00:00
case N_SLINE :
// src line: 0,,n_sect,linenumber,address
2013-08-13 01:42:25 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeLineEntry ;
break ;
2013-08-27 05:04:57 +00:00
case N_SSYM :
// structure elt: name,,NO_SECT,type,struct_offset
2013-08-13 01:42:25 +00:00
type = eSymbolTypeVariableType ;
break ;
2013-08-27 05:04:57 +00:00
case N_SO :
// source file name
2013-08-13 01:42:25 +00:00
type = eSymbolTypeSourceFile ;
if ( symbol_name = = NULL )
{
add_nlist = false ;
if ( N_SO_index ! = UINT32_MAX )
{
// Set the size of the N_SO to the terminating index of this N_SO
// so that we can always skip the entire N_SO if we need to navigate
// more quickly at the source level when parsing STABS
symbol_ptr = symtab - > SymbolAtIndex ( N_SO_index ) ;
symbol_ptr - > SetByteSize ( sym_idx ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
}
N_NSYM_indexes . clear ( ) ;
N_INCL_indexes . clear ( ) ;
N_BRAC_indexes . clear ( ) ;
N_COMM_indexes . clear ( ) ;
N_FUN_indexes . clear ( ) ;
N_SO_index = UINT32_MAX ;
}
else
{
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
const bool N_SO_has_full_path = symbol_name [ 0 ] = = ' / ' ;
if ( N_SO_has_full_path )
{
if ( ( N_SO_index = = sym_idx - 1 ) & & ( ( sym_idx - 1 ) < num_syms ) )
{
// We have two consecutive N_SO entries where the first contains a directory
// and the second contains a full path.
sym [ sym_idx - 1 ] . GetMangled ( ) . SetValue ( ConstString ( symbol_name ) , false ) ;
m_nlist_idx_to_sym_idx [ nlist_idx ] = sym_idx - 1 ;
add_nlist = false ;
}
else
{
// This is the first entry in a N_SO that contains a directory or
// a full path to the source file
N_SO_index = sym_idx ;
}
}
else if ( ( N_SO_index = = sym_idx - 1 ) & & ( ( sym_idx - 1 ) < num_syms ) )
{
// This is usually the second N_SO entry that contains just the filename,
// so here we combine it with the first one if we are minimizing the symbol table
const char * so_path = sym [ sym_idx - 1 ] . GetMangled ( ) . GetDemangledName ( ) . AsCString ( ) ;
if ( so_path & & so_path [ 0 ] )
{
std : : string full_so_path ( so_path ) ;
const size_t double_slash_pos = full_so_path . find ( " // " ) ;
if ( double_slash_pos ! = std : : string : : npos )
{
// The linker has been generating bad N_SO entries with doubled up paths
2013-08-27 14:56:58 +00:00
// in the format "%s%s" where the first string in the DW_AT_comp_dir,
2013-08-13 01:42:25 +00:00
// and the second is the directory for the source file so you end up with
// a path that looks like "/tmp/src//tmp/src/"
FileSpec so_dir ( so_path , false ) ;
if ( ! so_dir . Exists ( ) )
{
so_dir . SetFile ( & full_so_path [ double_slash_pos + 1 ] , false ) ;
if ( so_dir . Exists ( ) )
{
// Trim off the incorrect path
full_so_path . erase ( 0 , double_slash_pos + 1 ) ;
}
}
}
if ( * full_so_path . rbegin ( ) ! = ' / ' )
full_so_path + = ' / ' ;
full_so_path + = symbol_name ;
sym [ sym_idx - 1 ] . GetMangled ( ) . SetValue ( ConstString ( full_so_path . c_str ( ) ) , false ) ;
add_nlist = false ;
m_nlist_idx_to_sym_idx [ nlist_idx ] = sym_idx - 1 ;
}
}
else
{
// This could be a relative path to a N_SO
N_SO_index = sym_idx ;
}
}
break ;
2013-08-27 05:04:57 +00:00
case N_OSO :
// object file name: name,,0,0,st_mtime
2013-08-13 01:42:25 +00:00
type = eSymbolTypeObjectFile ;
break ;
2013-08-27 05:04:57 +00:00
case N_LSYM :
// local sym: name,,NO_SECT,type,offset
2013-08-13 01:42:25 +00:00
type = eSymbolTypeLocal ;
break ;
//----------------------------------------------------------------------
// INCL scopes
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_BINCL :
// include file beginning: name,,NO_SECT,0,sum
2013-08-13 01:42:25 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
N_INCL_indexes . push_back ( sym_idx ) ;
type = eSymbolTypeScopeBegin ;
break ;
2013-08-27 05:04:57 +00:00
case N_EINCL :
// include file end: name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
// Set the size of the N_BINCL to the terminating index of this N_EINCL
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
if ( ! N_INCL_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_INCL_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_INCL_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_SOL :
// #included file name: name,,n_sect,0,address
2013-08-13 01:42:25 +00:00
type = eSymbolTypeHeaderFile ;
// We currently don't use the header files on darwin
add_nlist = false ;
break ;
2013-08-27 05:04:57 +00:00
case N_PARAMS :
// compiler parameters: name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_VERSION :
// compiler version: name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_OLEVEL :
// compiler -O level: name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
type = eSymbolTypeCompiler ;
break ;
2013-08-27 05:04:57 +00:00
case N_PSYM :
// parameter: name,,NO_SECT,type,offset
2013-08-13 01:42:25 +00:00
type = eSymbolTypeVariable ;
break ;
2013-08-27 05:04:57 +00:00
case N_ENTRY :
// alternate entry: name,,n_sect,linenumber,address
2013-08-13 01:42:25 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
type = eSymbolTypeLineEntry ;
break ;
//----------------------------------------------------------------------
// Left and Right Braces
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_LBRAC :
// left bracket: 0,,NO_SECT,nesting level,address
2013-08-13 01:42:25 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
N_BRAC_indexes . push_back ( sym_idx ) ;
type = eSymbolTypeScopeBegin ;
break ;
2013-08-27 05:04:57 +00:00
case N_RBRAC :
// right bracket: 0,,NO_SECT,nesting level,address
2013-08-13 01:42:25 +00:00
// Set the size of the N_LBRAC to the terminating index of this N_RBRAC
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
if ( ! N_BRAC_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_BRAC_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_BRAC_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_EXCL :
// deleted include file: name,,NO_SECT,0,sum
2013-08-13 01:42:25 +00:00
type = eSymbolTypeHeaderFile ;
break ;
//----------------------------------------------------------------------
// COMM scopes
//----------------------------------------------------------------------
2013-08-27 05:04:57 +00:00
case N_BCOMM :
// begin common: name,,NO_SECT,0,0
2013-08-13 01:42:25 +00:00
// We use the current number of symbols in the symbol table in lieu of
// using nlist_idx in case we ever start trimming entries out
type = eSymbolTypeScopeBegin ;
N_COMM_indexes . push_back ( sym_idx ) ;
break ;
2013-08-27 05:04:57 +00:00
case N_ECOML :
// end common (local name): 0,,n_sect,0,address
2013-08-13 01:42:25 +00:00
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
// Fall through
2013-08-27 05:04:57 +00:00
case N_ECOMM :
// end common: name,,n_sect,0,0
2013-08-13 01:42:25 +00:00
// Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
// so that we can always skip the entire symbol if we need to navigate
// more quickly at the source level when parsing STABS
if ( ! N_COMM_indexes . empty ( ) )
{
symbol_ptr = symtab - > SymbolAtIndex ( N_COMM_indexes . back ( ) ) ;
symbol_ptr - > SetByteSize ( sym_idx + 1 ) ;
symbol_ptr - > SetSizeIsSibling ( true ) ;
N_COMM_indexes . pop_back ( ) ;
}
type = eSymbolTypeScopeEnd ;
break ;
2013-08-27 05:04:57 +00:00
case N_LENG :
// second stab entry with length information
2013-08-13 01:42:25 +00:00
type = eSymbolTypeAdditional ;
break ;
default : break ;
}
}
else
{
2013-08-27 05:04:57 +00:00
//uint8_t n_pext = N_PEXT & nlist.n_type;
uint8_t n_type = N_TYPE & nlist . n_type ;
sym [ sym_idx ] . SetExternal ( ( N_EXT & nlist . n_type ) ! = 0 ) ;
2013-08-13 01:42:25 +00:00
switch ( n_type )
{
2013-08-27 05:04:57 +00:00
case N_INDR : // Fall through
case N_PBUD : // Fall through
case N_UNDF :
2013-08-13 01:42:25 +00:00
type = eSymbolTypeUndefined ;
break ;
2013-08-27 05:04:57 +00:00
case N_ABS :
2013-08-13 01:42:25 +00:00
type = eSymbolTypeAbsolute ;
break ;
2013-08-27 05:04:57 +00:00
case N_SECT :
2013-08-13 01:42:25 +00:00
{
symbol_section = section_info . GetSection ( nlist . n_sect , nlist . n_value ) ;
if ( ! symbol_section )
{
// TODO: warn about this?
add_nlist = false ;
break ;
}
if ( TEXT_eh_frame_sectID = = nlist . n_sect )
{
type = eSymbolTypeException ;
}
else
{
2013-08-27 05:04:57 +00:00
uint32_t section_type = symbol_section - > Get ( ) & SECTION_TYPE ;
2013-08-13 01:42:25 +00:00
switch ( section_type )
{
2013-08-27 05:04:57 +00:00
case S_REGULAR : break ; // regular section
//case S_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section
case S_CSTRING_LITERALS : type = eSymbolTypeData ; break ; // section with only literal C strings
case S_4BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 4 byte literals
case S_8BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 8 byte literals
case S_LITERAL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only pointers to literals
case S_NON_LAZY_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only non-lazy symbol pointers
case S_LAZY_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ; // section with only lazy symbol pointers
case S_SYMBOL_STUBS : type = eSymbolTypeTrampoline ; break ; // section with only symbol stubs, byte size of stub in the reserved2 field
case S_MOD_INIT_FUNC_POINTERS : type = eSymbolTypeCode ; break ; // section with only function pointers for initialization
case S_MOD_TERM_FUNC_POINTERS : type = eSymbolTypeCode ; break ; // section with only function pointers for termination
//case S_COALESCED: type = eSymbolType; break; // section contains symbols that are to be coalesced
//case S_GB_ZEROFILL: type = eSymbolTypeData; break; // zero fill on demand section (that can be larger than 4 gigabytes)
case S_INTERPOSING : type = eSymbolTypeTrampoline ; break ; // section with only pairs of function pointers for interposing
case S_16BYTE_LITERALS : type = eSymbolTypeData ; break ; // section with only 16 byte literals
case S_DTRACE_DOF : type = eSymbolTypeInstrumentation ; break ;
case S_LAZY_DYLIB_SYMBOL_POINTERS : type = eSymbolTypeTrampoline ; break ;
2013-08-13 01:42:25 +00:00
default : break ;
}
if ( type = = eSymbolTypeInvalid )
{
const char * symbol_sect_name = symbol_section - > GetName ( ) . AsCString ( ) ;
if ( symbol_section - > IsDescendant ( text_section_sp . get ( ) ) )
{
2013-08-27 05:04:57 +00:00
if ( symbol_section - > IsClear ( S_ATTR_PURE_INSTRUCTIONS |
S_ATTR_SELF_MODIFYING_CODE |
S_ATTR_SOME_INSTRUCTIONS ) )
2013-08-13 01:42:25 +00:00
type = eSymbolTypeData ;
else
type = eSymbolTypeCode ;
}
else
if ( symbol_section - > IsDescendant ( data_section_sp . get ( ) ) )
{
if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __objc " ) = = symbol_sect_name )
{
type = eSymbolTypeRuntime ;
if ( symbol_name & &
symbol_name [ 0 ] = = ' _ ' & &
symbol_name [ 1 ] = = ' O ' & &
symbol_name [ 2 ] = = ' B ' )
{
llvm : : StringRef symbol_name_ref ( symbol_name ) ;
static const llvm : : StringRef g_objc_v2_prefix_class ( " _OBJC_CLASS_$_ " ) ;
static const llvm : : StringRef g_objc_v2_prefix_metaclass ( " _OBJC_METACLASS_$_ " ) ;
static const llvm : : StringRef g_objc_v2_prefix_ivar ( " _OBJC_IVAR_$_ " ) ;
if ( symbol_name_ref . startswith ( g_objc_v2_prefix_class ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_class . size ( ) ;
type = eSymbolTypeObjCClass ;
demangled_is_synthesized = true ;
}
else if ( symbol_name_ref . startswith ( g_objc_v2_prefix_metaclass ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_metaclass . size ( ) ;
type = eSymbolTypeObjCMetaClass ;
demangled_is_synthesized = true ;
}
else if ( symbol_name_ref . startswith ( g_objc_v2_prefix_ivar ) )
{
symbol_name_non_abi_mangled = symbol_name + 1 ;
symbol_name = symbol_name + g_objc_v2_prefix_ivar . size ( ) ;
type = eSymbolTypeObjCIVar ;
demangled_is_synthesized = true ;
}
}
}
else
if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __gcc_except_tab " ) = = symbol_sect_name )
{
type = eSymbolTypeException ;
}
else
{
type = eSymbolTypeData ;
}
}
else
if ( symbol_sect_name & & : : strstr ( symbol_sect_name , " __IMPORT " ) = = symbol_sect_name )
{
type = eSymbolTypeTrampoline ;
}
else
if ( symbol_section - > IsDescendant ( objc_section_sp . get ( ) ) )
{
type = eSymbolTypeRuntime ;
if ( symbol_name & & symbol_name [ 0 ] = = ' . ' )
{
llvm : : StringRef symbol_name_ref ( symbol_name ) ;
static const llvm : : StringRef g_objc_v1_prefix_class ( " .objc_class_name_ " ) ;
if ( symbol_name_ref . startswith ( g_objc_v1_prefix_class ) )
{
symbol_name_non_abi_mangled = symbol_name ;
symbol_name = symbol_name + g_objc_v1_prefix_class . size ( ) ;
type = eSymbolTypeObjCClass ;
demangled_is_synthesized = true ;
}
}
}
}
}
}
break ;
2013-05-14 22:19:37 +00:00
}
}
2012-03-09 04:26:05 +00:00
2013-08-13 01:42:25 +00:00
if ( add_nlist )
2012-03-09 04:26:05 +00:00
{
2013-08-13 01:42:25 +00:00
uint64_t symbol_value = nlist . n_value ;
if ( symbol_name_non_abi_mangled )
2012-03-09 04:26:05 +00:00
{
2013-08-13 01:42:25 +00:00
sym [ sym_idx ] . GetMangled ( ) . SetMangledName ( ConstString ( symbol_name_non_abi_mangled ) ) ;
sym [ sym_idx ] . GetMangled ( ) . SetDemangledName ( ConstString ( symbol_name ) ) ;
}
else
{
bool symbol_name_is_mangled = false ;
if ( symbol_name & & symbol_name [ 0 ] = = ' _ ' )
2012-03-09 04:26:05 +00:00
{
2013-08-13 01:42:25 +00:00
symbol_name_is_mangled = symbol_name [ 1 ] = = ' _ ' ;
symbol_name + + ; // Skip the leading underscore
}
if ( symbol_name )
{
ConstString const_symbol_name ( symbol_name ) ;
sym [ sym_idx ] . GetMangled ( ) . SetValue ( const_symbol_name , symbol_name_is_mangled ) ;
if ( is_gsym & & is_debug )
{
N_GSYM_name_to_sym_idx [ sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) . GetCString ( ) ] = sym_idx ;
}
}
}
if ( symbol_section )
{
const addr_t section_file_addr = symbol_section - > GetFileAddress ( ) ;
if ( symbol_byte_size = = 0 & & function_starts_count > 0 )
{
addr_t symbol_lookup_file_addr = nlist . n_value ;
// Do an exact address match for non-ARM addresses, else get the closest since
// the symbol might be a thumb symbol which has an address with bit zero set
FunctionStarts : : Entry * func_start_entry = function_starts . FindEntry ( symbol_lookup_file_addr , ! is_arm ) ;
if ( is_arm & & func_start_entry )
{
// Verify that the function start address is the symbol address (ARM)
// or the symbol address + 1 (thumb)
if ( func_start_entry - > addr ! = symbol_lookup_file_addr & &
func_start_entry - > addr ! = ( symbol_lookup_file_addr + 1 ) )
{
// Not the right entry, NULL it out...
func_start_entry = NULL ;
}
}
if ( func_start_entry )
{
func_start_entry - > data = true ;
addr_t symbol_file_addr = func_start_entry - > addr ;
if ( is_arm )
symbol_file_addr & = 0xfffffffffffffffeull ;
const FunctionStarts : : Entry * next_func_start_entry = function_starts . FindNextEntry ( func_start_entry ) ;
const addr_t section_end_file_addr = section_file_addr + symbol_section - > GetByteSize ( ) ;
if ( next_func_start_entry )
{
addr_t next_symbol_file_addr = next_func_start_entry - > addr ;
// Be sure the clear the Thumb address bit when we calculate the size
// from the current and next address
if ( is_arm )
next_symbol_file_addr & = 0xfffffffffffffffeull ;
symbol_byte_size = std : : min < lldb : : addr_t > ( next_symbol_file_addr - symbol_file_addr , section_end_file_addr - symbol_file_addr ) ;
}
else
{
symbol_byte_size = section_end_file_addr - symbol_file_addr ;
}
}
}
symbol_value - = section_file_addr ;
}
if ( is_debug = = false )
{
if ( type = = eSymbolTypeCode )
{
// See if we can find a N_FUN entry for any code symbols.
// If we do find a match, and the name matches, then we
// can merge the two into just the function symbol to avoid
// duplicate entries in the symbol table
ValueToSymbolIndexMap : : const_iterator pos = N_FUN_addr_to_sym_idx . find ( nlist . n_value ) ;
if ( pos ! = N_FUN_addr_to_sym_idx . end ( ) )
{
if ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) = = sym [ pos - > second ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) )
{
m_nlist_idx_to_sym_idx [ nlist_idx ] = pos - > second ;
// We just need the flags from the linker symbol, so put these flags
// into the N_FUN flags to avoid duplicate symbols in the symbol table
2013-10-21 18:40:51 +00:00
sym [ pos - > second ] . SetExternal ( sym [ sym_idx ] . IsExternal ( ) ) ;
2013-08-13 01:42:25 +00:00
sym [ pos - > second ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
2014-01-10 22:55:37 +00:00
if ( resolver_addresses . find ( nlist . n_value ) ! = resolver_addresses . end ( ) )
sym [ pos - > second ] . SetType ( eSymbolTypeResolver ) ;
2013-08-13 01:42:25 +00:00
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
2014-01-10 22:55:37 +00:00
else
{
if ( resolver_addresses . find ( nlist . n_value ) ! = resolver_addresses . end ( ) )
sym [ sym_idx ] . SetType ( eSymbolTypeResolver ) ;
}
2013-08-13 01:42:25 +00:00
}
else if ( type = = eSymbolTypeData )
{
// See if we can find a N_STSYM entry for any data symbols.
// If we do find a match, and the name matches, then we
// can merge the two into just the Static symbol to avoid
// duplicate entries in the symbol table
ValueToSymbolIndexMap : : const_iterator pos = N_STSYM_addr_to_sym_idx . find ( nlist . n_value ) ;
if ( pos ! = N_STSYM_addr_to_sym_idx . end ( ) )
{
if ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) = = sym [ pos - > second ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) )
{
m_nlist_idx_to_sym_idx [ nlist_idx ] = pos - > second ;
// We just need the flags from the linker symbol, so put these flags
// into the N_STSYM flags to avoid duplicate symbols in the symbol table
2013-10-21 18:40:51 +00:00
sym [ pos - > second ] . SetExternal ( sym [ sym_idx ] . IsExternal ( ) ) ;
2013-08-13 01:42:25 +00:00
sym [ pos - > second ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
else
{
// Combine N_GSYM stab entries with the non stab symbol
ConstNameToSymbolIndexMap : : const_iterator pos = N_GSYM_name_to_sym_idx . find ( sym [ sym_idx ] . GetMangled ( ) . GetName ( Mangled : : ePreferMangled ) . GetCString ( ) ) ;
if ( pos ! = N_GSYM_name_to_sym_idx . end ( ) )
{
const uint32_t GSYM_sym_idx = pos - > second ;
m_nlist_idx_to_sym_idx [ nlist_idx ] = GSYM_sym_idx ;
// Copy the address, because often the N_GSYM address has an invalid address of zero
// when the global is a common symbol
sym [ GSYM_sym_idx ] . GetAddress ( ) . SetSection ( symbol_section ) ;
sym [ GSYM_sym_idx ] . GetAddress ( ) . SetOffset ( symbol_value ) ;
// We just need the flags from the linker symbol, so put these flags
// into the N_STSYM flags to avoid duplicate symbols in the symbol table
sym [ GSYM_sym_idx ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
sym [ sym_idx ] . Clear ( ) ;
continue ;
}
}
}
}
sym [ sym_idx ] . SetID ( nlist_idx ) ;
sym [ sym_idx ] . SetType ( type ) ;
sym [ sym_idx ] . GetAddress ( ) . SetSection ( symbol_section ) ;
sym [ sym_idx ] . GetAddress ( ) . SetOffset ( symbol_value ) ;
sym [ sym_idx ] . SetFlags ( nlist . n_type < < 16 | nlist . n_desc ) ;
if ( symbol_byte_size > 0 )
sym [ sym_idx ] . SetByteSize ( symbol_byte_size ) ;
if ( demangled_is_synthesized )
sym [ sym_idx ] . SetDemangledNameIsSynthesized ( true ) ;
+ + sym_idx ;
}
else
{
sym [ sym_idx ] . Clear ( ) ;
}
2010-06-08 16:52:24 +00:00
}
}
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
uint32_t synthetic_sym_id = symtab_load_command . nsyms ;
if ( function_starts_count > 0 )
{
char synthetic_function_symbol [ PATH_MAX ] ;
uint32_t num_synthetic_function_symbols = 0 ;
for ( i = 0 ; i < function_starts_count ; + + i )
{
if ( function_starts . GetEntryRef ( i ) . data = = false )
+ + num_synthetic_function_symbols ;
}
2013-03-06 23:19:17 +00:00
2012-03-09 04:26:05 +00:00
if ( num_synthetic_function_symbols > 0 )
{
if ( num_syms < sym_idx + num_synthetic_function_symbols )
{
num_syms = sym_idx + num_synthetic_function_symbols ;
sym = symtab - > Resize ( num_syms ) ;
}
uint32_t synthetic_function_symbol_idx = 0 ;
for ( i = 0 ; i < function_starts_count ; + + i )
{
const FunctionStarts : : Entry * func_start_entry = function_starts . GetEntryAtIndex ( i ) ;
if ( func_start_entry - > data = = false )
{
2012-03-14 01:53:24 +00:00
addr_t symbol_file_addr = func_start_entry - > addr ;
uint32_t symbol_flags = 0 ;
if ( is_arm )
{
if ( symbol_file_addr & 1 )
symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB ;
symbol_file_addr & = 0xfffffffffffffffeull ;
}
2012-03-09 04:26:05 +00:00
Address symbol_addr ;
2012-03-14 01:53:24 +00:00
if ( module_sp - > ResolveFileAddress ( symbol_file_addr , symbol_addr ) )
2012-03-09 04:26:05 +00:00
{
SectionSP symbol_section ( symbol_addr . GetSection ( ) ) ;
uint32_t symbol_byte_size = 0 ;
if ( symbol_section )
{
const addr_t section_file_addr = symbol_section - > GetFileAddress ( ) ;
const FunctionStarts : : Entry * next_func_start_entry = function_starts . FindNextEntry ( func_start_entry ) ;
const addr_t section_end_file_addr = section_file_addr + symbol_section - > GetByteSize ( ) ;
if ( next_func_start_entry )
{
2012-03-14 01:53:24 +00:00
addr_t next_symbol_file_addr = next_func_start_entry - > addr ;
if ( is_arm )
next_symbol_file_addr & = 0xfffffffffffffffeull ;
symbol_byte_size = std : : min < lldb : : addr_t > ( next_symbol_file_addr - symbol_file_addr , section_end_file_addr - symbol_file_addr ) ;
2012-03-09 04:26:05 +00:00
}
else
{
2012-03-14 01:53:24 +00:00
symbol_byte_size = section_end_file_addr - symbol_file_addr ;
2012-03-09 04:26:05 +00:00
}
snprintf ( synthetic_function_symbol ,
sizeof ( synthetic_function_symbol ) ,
" ___lldb_unnamed_function%u$$%s " ,
+ + synthetic_function_symbol_idx ,
module_sp - > GetFileSpec ( ) . GetFilename ( ) . GetCString ( ) ) ;
sym [ sym_idx ] . SetID ( synthetic_sym_id + + ) ;
2012-07-18 23:18:10 +00:00
sym [ sym_idx ] . GetMangled ( ) . SetDemangledName ( ConstString ( synthetic_function_symbol ) ) ;
2012-03-09 04:26:05 +00:00
sym [ sym_idx ] . SetType ( eSymbolTypeCode ) ;
sym [ sym_idx ] . SetIsSynthetic ( true ) ;
sym [ sym_idx ] . GetAddress ( ) = symbol_addr ;
2012-03-14 01:53:24 +00:00
if ( symbol_flags )
sym [ sym_idx ] . SetFlags ( symbol_flags ) ;
2012-03-09 04:26:05 +00:00
if ( symbol_byte_size )
sym [ sym_idx ] . SetByteSize ( symbol_byte_size ) ;
+ + sym_idx ;
}
}
}
}
}
}
// Trim our symbols down to just what we ended up with after
// removing any symbols.
if ( sym_idx < num_syms )
{
num_syms = sym_idx ;
sym = symtab - > Resize ( num_syms ) ;
}
// Now synthesize indirect symbols
if ( m_dysymtab . nindirectsyms ! = 0 )
{
if ( indirect_symbol_index_data . GetByteSize ( ) )
{
NListIndexToSymbolIndexMap : : const_iterator end_index_pos = m_nlist_idx_to_sym_idx . end ( ) ;
for ( uint32_t sect_idx = 1 ; sect_idx < m_mach_sections . size ( ) ; + + sect_idx )
{
2013-08-27 05:04:57 +00:00
if ( ( m_mach_sections [ sect_idx ] . flags & SECTION_TYPE ) = = S_SYMBOL_STUBS )
2012-03-09 04:26:05 +00:00
{
uint32_t symbol_stub_byte_size = m_mach_sections [ sect_idx ] . reserved2 ;
if ( symbol_stub_byte_size = = 0 )
continue ;
const uint32_t num_symbol_stubs = m_mach_sections [ sect_idx ] . size / symbol_stub_byte_size ;
if ( num_symbol_stubs = = 0 )
continue ;
const uint32_t symbol_stub_index_offset = m_mach_sections [ sect_idx ] . reserved1 ;
for ( uint32_t stub_idx = 0 ; stub_idx < num_symbol_stubs ; + + stub_idx )
{
const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx ;
const lldb : : addr_t symbol_stub_addr = m_mach_sections [ sect_idx ] . addr + ( stub_idx * symbol_stub_byte_size ) ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t symbol_stub_offset = symbol_stub_index * 4 ;
2012-03-09 04:26:05 +00:00
if ( indirect_symbol_index_data . ValidOffsetForDataOfSize ( symbol_stub_offset , 4 ) )
{
const uint32_t stub_sym_id = indirect_symbol_index_data . GetU32 ( & symbol_stub_offset ) ;
2013-08-27 05:04:57 +00:00
if ( stub_sym_id & ( INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL ) )
2012-03-09 04:26:05 +00:00
continue ;
NListIndexToSymbolIndexMap : : const_iterator index_pos = m_nlist_idx_to_sym_idx . find ( stub_sym_id ) ;
Symbol * stub_symbol = NULL ;
if ( index_pos ! = end_index_pos )
{
// We have a remapping from the original nlist index to
// a current symbol index, so just look this up by index
stub_symbol = symtab - > SymbolAtIndex ( index_pos - > second ) ;
}
2013-03-06 23:19:17 +00:00
else
2012-03-09 04:26:05 +00:00
{
// We need to lookup a symbol using the original nlist
2013-03-06 23:19:17 +00:00
// symbol index since this index is coming from the
2012-03-09 04:26:05 +00:00
// S_SYMBOL_STUBS
stub_symbol = symtab - > FindSymbolByID ( stub_sym_id ) ;
}
if ( stub_symbol )
{
Address so_addr ( symbol_stub_addr , section_list ) ;
if ( stub_symbol - > GetType ( ) = = eSymbolTypeUndefined )
{
// Change the external symbol into a trampoline that makes sense
// These symbols were N_UNDF N_EXT, and are useless to us, so we
// can re-use them so we don't have to make up a synthetic symbol
// for no good reason.
2013-10-21 18:40:51 +00:00
if ( resolver_addresses . find ( symbol_stub_addr ) = = resolver_addresses . end ( ) )
stub_symbol - > SetType ( eSymbolTypeTrampoline ) ;
else
stub_symbol - > SetType ( eSymbolTypeResolver ) ;
2012-03-09 04:26:05 +00:00
stub_symbol - > SetExternal ( false ) ;
stub_symbol - > GetAddress ( ) = so_addr ;
stub_symbol - > SetByteSize ( symbol_stub_byte_size ) ;
}
else
{
// Make a synthetic symbol to describe the trampoline stub
2012-04-24 02:09:58 +00:00
Mangled stub_symbol_mangled_name ( stub_symbol - > GetMangled ( ) ) ;
2012-03-09 04:26:05 +00:00
if ( sym_idx > = num_syms )
2012-04-24 02:09:58 +00:00
{
2012-03-09 04:26:05 +00:00
sym = symtab - > Resize ( + + num_syms ) ;
2012-04-24 02:09:58 +00:00
stub_symbol = NULL ; // this pointer no longer valid
}
2012-03-09 04:26:05 +00:00
sym [ sym_idx ] . SetID ( synthetic_sym_id + + ) ;
2012-04-24 02:09:58 +00:00
sym [ sym_idx ] . GetMangled ( ) = stub_symbol_mangled_name ;
2013-10-21 18:40:51 +00:00
if ( resolver_addresses . find ( symbol_stub_addr ) = = resolver_addresses . end ( ) )
sym [ sym_idx ] . SetType ( eSymbolTypeTrampoline ) ;
else
sym [ sym_idx ] . SetType ( eSymbolTypeResolver ) ;
2012-03-09 04:26:05 +00:00
sym [ sym_idx ] . SetIsSynthetic ( true ) ;
sym [ sym_idx ] . GetAddress ( ) = so_addr ;
sym [ sym_idx ] . SetByteSize ( symbol_stub_byte_size ) ;
+ + sym_idx ;
}
}
2012-09-05 01:38:55 +00:00
else
{
if ( log )
log - > Warning ( " symbol stub referencing symbol table symbol %u that isn't in our minimal symbol table, fix this!!! " , stub_sym_id ) ;
}
2012-03-09 04:26:05 +00:00
}
}
}
}
}
}
2013-10-21 18:40:51 +00:00
if ( ! trie_entries . empty ( ) )
{
for ( const auto & e : trie_entries )
{
if ( e . entry . import_name )
{
// Make a synthetic symbol to describe re-exported symbol.
if ( sym_idx > = num_syms )
sym = symtab - > Resize ( + + num_syms ) ;
sym [ sym_idx ] . SetID ( synthetic_sym_id + + ) ;
sym [ sym_idx ] . GetMangled ( ) = Mangled ( e . entry . name ) ;
sym [ sym_idx ] . SetType ( eSymbolTypeReExported ) ;
sym [ sym_idx ] . SetIsSynthetic ( true ) ;
sym [ sym_idx ] . SetReExportedSymbolName ( e . entry . import_name ) ;
if ( e . entry . other > 0 & & e . entry . other < = dylib_files . GetSize ( ) )
{
sym [ sym_idx ] . SetReExportedSymbolSharedLibrary ( dylib_files . GetFileSpecAtIndex ( e . entry . other - 1 ) ) ;
}
+ + sym_idx ;
}
}
}
2013-07-10 01:23:25 +00:00
// StreamFile s(stdout, false);
// s.Printf ("Symbol table before CalculateSymbolSizes():\n");
// symtab->Dump(&s, NULL, eSortOrderNone);
// Set symbol byte sizes correctly since mach-o nlist entries don't have sizes
symtab - > CalculateSymbolSizes ( ) ;
// s.Printf ("Symbol table after CalculateSymbolSizes():\n");
// symtab->Dump(&s, NULL, eSortOrderNone);
2012-03-09 04:26:05 +00:00
return symtab - > GetNumSymbols ( ) ;
2010-06-08 16:52:24 +00:00
}
return 0 ;
}
void
ObjectFileMachO : : Dump ( Stream * s )
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
{
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
s - > Printf ( " %p: " , this ) ;
s - > Indent ( ) ;
2013-08-27 05:04:57 +00:00
if ( m_header . magic = = MH_MAGIC_64 | | m_header . magic = = MH_CIGAM_64 )
2012-03-13 23:14:29 +00:00
s - > PutCString ( " ObjectFileMachO64 " ) ;
else
s - > PutCString ( " ObjectFileMachO32 " ) ;
2010-06-08 16:52:24 +00:00
2012-03-13 23:14:29 +00:00
ArchSpec header_arch ( eArchTypeMachO , m_header . cputype , m_header . cpusubtype ) ;
2010-06-08 16:52:24 +00:00
2012-03-13 23:14:29 +00:00
* s < < " , file = ' " < < m_file < < " ', arch = " < < header_arch . GetArchitectureName ( ) < < " \n " ;
2010-06-08 16:52:24 +00:00
2013-07-10 01:23:25 +00:00
SectionList * sections = GetSectionList ( ) ;
if ( sections )
sections - > Dump ( s , NULL , true , UINT32_MAX ) ;
2010-06-08 16:52:24 +00:00
2012-03-13 23:14:29 +00:00
if ( m_symtab_ap . get ( ) )
m_symtab_ap - > Dump ( s , NULL , eSortOrderNone ) ;
}
2010-06-08 16:52:24 +00:00
}
2013-04-24 22:29:28 +00:00
bool
ObjectFileMachO : : GetUUID ( const llvm : : MachO : : mach_header & header ,
const lldb_private : : DataExtractor & data ,
lldb : : offset_t lc_offset ,
lldb_private : : UUID & uuid )
{
uint32_t i ;
struct uuid_command load_cmd ;
lldb : : offset_t offset = lc_offset ;
for ( i = 0 ; i < header . ncmds ; + + i )
{
const lldb : : offset_t cmd_offset = offset ;
if ( data . GetU32 ( & offset , & load_cmd , 2 ) = = NULL )
break ;
2013-08-27 05:04:57 +00:00
if ( load_cmd . cmd = = LC_UUID )
2013-04-24 22:29:28 +00:00
{
const uint8_t * uuid_bytes = data . PeekData ( offset , 16 ) ;
if ( uuid_bytes )
{
// OpenCL on Mac OS X uses the same UUID for each of its object files.
// We pretend these object files have no UUID to prevent crashing.
const uint8_t opencl_uuid [ ] = { 0x8c , 0x8e , 0xb3 , 0x9b ,
0x3b , 0xa8 ,
0x4b , 0x16 ,
0xb6 , 0xa4 ,
0x27 , 0x63 , 0xbb , 0x14 , 0xf0 , 0x0d } ;
if ( ! memcmp ( uuid_bytes , opencl_uuid , 16 ) )
return false ;
uuid . SetBytes ( uuid_bytes ) ;
return true ;
}
return false ;
}
offset = cmd_offset + load_cmd . cmdsize ;
}
return false ;
}
2010-06-08 16:52:24 +00:00
bool
2011-02-04 18:53:10 +00:00
ObjectFileMachO : : GetUUID ( lldb_private : : UUID * uuid )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2013-04-24 22:29:28 +00:00
return GetUUID ( m_header , m_data , offset , * uuid ) ;
2010-06-08 16:52:24 +00:00
}
return false ;
}
uint32_t
ObjectFileMachO : : GetDependentModules ( FileSpecList & files )
{
uint32_t count = 0 ;
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
struct load_command load_cmd ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2012-03-13 23:14:29 +00:00
const bool resolve_path = false ; // Don't resolve the dependend file paths since they may not reside on this system
uint32_t i ;
for ( i = 0 ; i < m_header . ncmds ; + + i )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
const uint32_t cmd_offset = offset ;
if ( m_data . GetU32 ( & offset , & load_cmd , 2 ) = = NULL )
break ;
2010-06-08 16:52:24 +00:00
2012-03-13 23:14:29 +00:00
switch ( load_cmd . cmd )
{
2013-08-27 05:04:57 +00:00
case LC_LOAD_DYLIB :
case LC_LOAD_WEAK_DYLIB :
case LC_REEXPORT_DYLIB :
case LC_LOAD_DYLINKER :
case LC_LOADFVMLIB :
case LC_LOAD_UPWARD_DYLIB :
2012-03-13 23:14:29 +00:00
{
uint32_t name_offset = cmd_offset + m_data . GetU32 ( & offset ) ;
const char * path = m_data . PeekCStr ( name_offset ) ;
// Skip any path that starts with '@' since these are usually:
// @executable_path/.../file
// @rpath/.../file
if ( path & & path [ 0 ] ! = ' @ ' )
{
FileSpec file_spec ( path , resolve_path ) ;
if ( files . AppendIfUnique ( file_spec ) )
count + + ;
}
}
break ;
default :
break ;
}
offset = cmd_offset + load_cmd . cmdsize ;
2010-06-08 16:52:24 +00:00
}
}
return count ;
}
2011-03-07 23:44:08 +00:00
lldb_private : : Address
2013-03-06 23:19:17 +00:00
ObjectFileMachO : : GetEntryPointAddress ( )
2011-03-07 23:44:08 +00:00
{
// If the object file is not an executable it can't hold the entry point. m_entry_point_address
// is initialized to an invalid address, so we can just return that.
// If m_entry_point_address is valid it means we've found it already, so return the cached value.
2013-03-06 23:19:17 +00:00
2011-03-07 23:44:08 +00:00
if ( ! IsExecutable ( ) | | m_entry_point_address . IsValid ( ) )
return m_entry_point_address ;
2013-03-06 23:19:17 +00:00
// Otherwise, look for the UnixThread or Thread command. The data for the Thread command is given in
2011-03-07 23:44:08 +00:00
// /usr/include/mach-o.h, but it is basically:
//
// uint32_t flavor - this is the flavor argument you would pass to thread_get_state
// uint32_t count - this is the count of longs in the thread state data
// struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor.
// <repeat this trio>
2013-03-06 23:19:17 +00:00
//
2011-03-07 23:44:08 +00:00
// So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there.
// FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers
// out of data in this form & attach them to a given thread. That should underlie the MacOS X User process plugin,
// and we'll also need it for the MacOS X Core File process plugin. When we have that we can also use it here.
//
// For now we hard-code the offsets and flavors we need:
//
//
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2011-03-07 23:44:08 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
struct load_command load_cmd ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2012-03-13 23:14:29 +00:00
uint32_t i ;
lldb : : addr_t start_address = LLDB_INVALID_ADDRESS ;
bool done = false ;
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
for ( i = 0 ; i < m_header . ncmds ; + + i )
2011-03-07 23:44:08 +00:00
{
2013-01-25 18:06:21 +00:00
const lldb : : offset_t cmd_offset = offset ;
2012-03-13 23:14:29 +00:00
if ( m_data . GetU32 ( & offset , & load_cmd , 2 ) = = NULL )
break ;
switch ( load_cmd . cmd )
2011-03-07 23:44:08 +00:00
{
2013-08-27 05:04:57 +00:00
case LC_UNIXTHREAD :
case LC_THREAD :
2011-03-07 23:44:08 +00:00
{
2012-03-13 23:14:29 +00:00
while ( offset < cmd_offset + load_cmd . cmdsize )
2011-03-07 23:44:08 +00:00
{
2012-03-13 23:14:29 +00:00
uint32_t flavor = m_data . GetU32 ( & offset ) ;
uint32_t count = m_data . GetU32 ( & offset ) ;
if ( count = = 0 )
{
// We've gotten off somehow, log and exit;
return m_entry_point_address ;
2011-03-07 23:44:08 +00:00
}
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
switch ( m_header . cputype )
{
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_ARM :
2012-03-13 23:14:29 +00:00
if ( flavor = = 1 ) // ARM_THREAD_STATE from mach/arm/thread_status.h
{
offset + = 60 ; // This is the offset of pc in the GPR thread state data structure.
start_address = m_data . GetU32 ( & offset ) ;
done = true ;
}
2011-03-07 23:44:08 +00:00
break ;
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_I386 :
2012-03-13 23:14:29 +00:00
if ( flavor = = 1 ) // x86_THREAD_STATE32 from mach/i386/thread_status.h
{
offset + = 40 ; // This is the offset of eip in the GPR thread state data structure.
start_address = m_data . GetU32 ( & offset ) ;
done = true ;
}
break ;
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_X86_64 :
2012-03-13 23:14:29 +00:00
if ( flavor = = 4 ) // x86_THREAD_STATE64 from mach/i386/thread_status.h
{
offset + = 16 * 8 ; // This is the offset of rip in the GPR thread state data structure.
start_address = m_data . GetU64 ( & offset ) ;
done = true ;
}
break ;
default :
return m_entry_point_address ;
}
// Haven't found the GPR flavor yet, skip over the data for this flavor:
if ( done )
break ;
offset + = count * 4 ;
}
2011-03-07 23:44:08 +00:00
}
2012-03-13 23:14:29 +00:00
break ;
2013-08-27 05:04:57 +00:00
case LC_MAIN :
2012-03-08 02:39:03 +00:00
{
2012-03-13 23:14:29 +00:00
ConstString text_segment_name ( " __TEXT " ) ;
uint64_t entryoffset = m_data . GetU64 ( & offset ) ;
SectionSP text_segment_sp = GetSectionList ( ) - > FindSectionByName ( text_segment_name ) ;
if ( text_segment_sp )
{
done = true ;
start_address = text_segment_sp - > GetFileAddress ( ) + entryoffset ;
}
2012-03-08 02:39:03 +00:00
}
2012-03-13 23:14:29 +00:00
default :
break ;
2012-03-08 02:39:03 +00:00
}
2012-03-13 23:14:29 +00:00
if ( done )
break ;
2011-03-07 23:44:08 +00:00
2012-03-13 23:14:29 +00:00
// Go to the next load command:
offset = cmd_offset + load_cmd . cmdsize ;
2011-03-07 23:44:08 +00:00
}
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
if ( start_address ! = LLDB_INVALID_ADDRESS )
2012-02-24 01:59:29 +00:00
{
2013-03-06 23:19:17 +00:00
// We got the start address from the load commands, so now resolve that address in the sections
2012-03-13 23:14:29 +00:00
// of this ObjectFile:
if ( ! m_entry_point_address . ResolveAddressUsingFileSections ( start_address , GetSectionList ( ) ) )
2012-02-24 01:59:29 +00:00
{
2012-03-13 23:14:29 +00:00
m_entry_point_address . Clear ( ) ;
}
}
else
{
// We couldn't read the UnixThread load command - maybe it wasn't there. As a fallback look for the
// "start" symbol in the main executable.
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
if ( module_sp )
{
SymbolContextList contexts ;
SymbolContext context ;
if ( module_sp - > FindSymbolsWithNameAndType ( ConstString ( " start " ) , eSymbolTypeCode , contexts ) )
{
if ( contexts . GetContextAtIndex ( 0 , context ) )
m_entry_point_address = context . symbol - > GetAddress ( ) ;
}
2012-02-24 01:59:29 +00:00
}
}
2011-03-07 23:44:08 +00:00
}
2013-03-06 23:19:17 +00:00
2011-03-07 23:44:08 +00:00
return m_entry_point_address ;
}
2012-02-05 02:38:54 +00:00
lldb_private : : Address
ObjectFileMachO : : GetHeaderAddress ( )
{
lldb_private : : Address header_addr ;
SectionList * section_list = GetSectionList ( ) ;
if ( section_list )
{
SectionSP text_segment_sp ( section_list - > FindSectionByName ( GetSegmentNameTEXT ( ) ) ) ;
if ( text_segment_sp )
{
2012-02-24 01:59:29 +00:00
header_addr . SetSection ( text_segment_sp ) ;
2012-02-05 02:38:54 +00:00
header_addr . SetOffset ( 0 ) ;
}
}
return header_addr ;
}
2012-02-09 06:16:32 +00:00
uint32_t
ObjectFileMachO : : GetNumThreadContexts ( )
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2012-02-09 06:16:32 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
if ( ! m_thread_context_offsets_valid )
2012-02-09 06:16:32 +00:00
{
2012-03-13 23:14:29 +00:00
m_thread_context_offsets_valid = true ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2012-03-13 23:14:29 +00:00
FileRangeArray : : Entry file_range ;
thread_command thread_cmd ;
for ( uint32_t i = 0 ; i < m_header . ncmds ; + + i )
2012-02-09 06:16:32 +00:00
{
2012-03-13 23:14:29 +00:00
const uint32_t cmd_offset = offset ;
if ( m_data . GetU32 ( & offset , & thread_cmd , 2 ) = = NULL )
break ;
2013-03-06 23:19:17 +00:00
2013-08-27 05:04:57 +00:00
if ( thread_cmd . cmd = = LC_THREAD )
2012-03-13 23:14:29 +00:00
{
file_range . SetRangeBase ( offset ) ;
file_range . SetByteSize ( thread_cmd . cmdsize - 8 ) ;
m_thread_context_offsets . Append ( file_range ) ;
}
offset = cmd_offset + thread_cmd . cmdsize ;
2012-02-09 06:16:32 +00:00
}
}
}
return m_thread_context_offsets . GetSize ( ) ;
}
lldb : : RegisterContextSP
ObjectFileMachO : : GetThreadContextAtIndex ( uint32_t idx , lldb_private : : Thread & thread )
{
lldb : : RegisterContextSP reg_ctx_sp ;
2012-02-13 23:10:39 +00:00
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2012-02-09 06:16:32 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
if ( ! m_thread_context_offsets_valid )
GetNumThreadContexts ( ) ;
const FileRangeArray : : Entry * thread_context_file_range = m_thread_context_offsets . GetEntryAtIndex ( idx ) ;
2012-10-12 17:34:26 +00:00
if ( thread_context_file_range )
2012-03-13 23:14:29 +00:00
{
2013-03-06 23:19:17 +00:00
DataExtractor data ( m_data ,
thread_context_file_range - > GetRangeBase ( ) ,
2012-10-12 17:34:26 +00:00
thread_context_file_range - > GetByteSize ( ) ) ;
switch ( m_header . cputype )
{
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_ARM :
2012-10-12 17:34:26 +00:00
reg_ctx_sp . reset ( new RegisterContextDarwin_arm_Mach ( thread , data ) ) ;
break ;
2013-03-06 23:19:17 +00:00
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_I386 :
2012-10-12 17:34:26 +00:00
reg_ctx_sp . reset ( new RegisterContextDarwin_i386_Mach ( thread , data ) ) ;
break ;
2013-03-06 23:19:17 +00:00
2013-08-27 05:04:57 +00:00
case llvm : : MachO : : CPU_TYPE_X86_64 :
2012-10-12 17:34:26 +00:00
reg_ctx_sp . reset ( new RegisterContextDarwin_x86_64_Mach ( thread , data ) ) ;
break ;
}
2012-03-13 23:14:29 +00:00
}
2012-02-09 06:16:32 +00:00
}
return reg_ctx_sp ;
}
2012-02-05 02:38:54 +00:00
2011-07-09 00:41:34 +00:00
ObjectFile : : Type
ObjectFileMachO : : CalculateType ( )
{
switch ( m_header . filetype )
{
2013-08-27 05:04:57 +00:00
case MH_OBJECT : // 0x1u
2011-07-09 00:41:34 +00:00
if ( GetAddressByteSize ( ) = = 4 )
{
// 32 bit kexts are just object files, but they do have a valid
// UUID load command.
UUID uuid ;
if ( GetUUID ( & uuid ) )
{
// this checking for the UUID load command is not enough
2013-03-06 23:19:17 +00:00
// we could eventually look for the symbol named
2011-07-09 00:41:34 +00:00
// "OSKextGetCurrentIdentifier" as this is required of kexts
if ( m_strata = = eStrataInvalid )
m_strata = eStrataKernel ;
return eTypeSharedLibrary ;
}
}
return eTypeObjectFile ;
2013-08-27 05:04:57 +00:00
case MH_EXECUTE : return eTypeExecutable ; // 0x2u
case MH_FVMLIB : return eTypeSharedLibrary ; // 0x3u
case MH_CORE : return eTypeCoreFile ; // 0x4u
case MH_PRELOAD : return eTypeSharedLibrary ; // 0x5u
case MH_DYLIB : return eTypeSharedLibrary ; // 0x6u
case MH_DYLINKER : return eTypeDynamicLinker ; // 0x7u
case MH_BUNDLE : return eTypeSharedLibrary ; // 0x8u
case MH_DYLIB_STUB : return eTypeStubLibrary ; // 0x9u
case MH_DSYM : return eTypeDebugInfo ; // 0xAu
case MH_KEXT_BUNDLE : return eTypeSharedLibrary ; // 0xBu
2011-07-09 00:41:34 +00:00
default :
break ;
}
return eTypeUnknown ;
}
ObjectFile : : Strata
ObjectFileMachO : : CalculateStrata ( )
{
switch ( m_header . filetype )
{
2013-08-27 05:04:57 +00:00
case MH_OBJECT : // 0x1u
2011-07-09 00:41:34 +00:00
{
// 32 bit kexts are just object files, but they do have a valid
// UUID load command.
UUID uuid ;
if ( GetUUID ( & uuid ) )
{
// this checking for the UUID load command is not enough
2013-03-06 23:19:17 +00:00
// we could eventually look for the symbol named
2011-07-09 00:41:34 +00:00
// "OSKextGetCurrentIdentifier" as this is required of kexts
if ( m_type = = eTypeInvalid )
m_type = eTypeSharedLibrary ;
return eStrataKernel ;
}
}
return eStrataUnknown ;
2013-08-27 05:04:57 +00:00
case MH_EXECUTE : // 0x2u
2011-07-09 00:41:34 +00:00
// Check for the MH_DYLDLINK bit in the flags
2013-08-27 05:04:57 +00:00
if ( m_header . flags & MH_DYLDLINK )
2012-02-10 20:22:35 +00:00
{
2011-07-09 00:41:34 +00:00
return eStrataUser ;
2012-02-10 20:22:35 +00:00
}
2013-03-06 23:19:17 +00:00
else
2012-02-10 20:22:35 +00:00
{
SectionList * section_list = GetSectionList ( ) ;
if ( section_list )
{
static ConstString g_kld_section_name ( " __KLD " ) ;
if ( section_list - > FindSectionByName ( g_kld_section_name ) )
return eStrataKernel ;
}
}
return eStrataRawImage ;
2011-07-09 00:41:34 +00:00
2013-08-27 05:04:57 +00:00
case MH_FVMLIB : return eStrataUser ; // 0x3u
case MH_CORE : return eStrataUnknown ; // 0x4u
case MH_PRELOAD : return eStrataRawImage ; // 0x5u
case MH_DYLIB : return eStrataUser ; // 0x6u
case MH_DYLINKER : return eStrataUser ; // 0x7u
case MH_BUNDLE : return eStrataUser ; // 0x8u
case MH_DYLIB_STUB : return eStrataUser ; // 0x9u
case MH_DSYM : return eStrataUnknown ; // 0xAu
case MH_KEXT_BUNDLE : return eStrataKernel ; // 0xBu
2011-07-09 00:41:34 +00:00
default :
break ;
}
return eStrataUnknown ;
}
2012-02-22 19:41:02 +00:00
uint32_t
ObjectFileMachO : : GetVersion ( uint32_t * versions , uint32_t num_versions )
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2012-02-22 19:41:02 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
struct dylib_command load_cmd ;
2013-01-25 18:06:21 +00:00
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
2012-03-13 23:14:29 +00:00
uint32_t version_cmd = 0 ;
uint64_t version = 0 ;
uint32_t i ;
for ( i = 0 ; i < m_header . ncmds ; + + i )
2012-02-22 19:41:02 +00:00
{
2013-01-25 18:06:21 +00:00
const lldb : : offset_t cmd_offset = offset ;
2012-03-13 23:14:29 +00:00
if ( m_data . GetU32 ( & offset , & load_cmd , 2 ) = = NULL )
break ;
2013-03-06 23:19:17 +00:00
2013-08-27 05:04:57 +00:00
if ( load_cmd . cmd = = LC_ID_DYLIB )
2012-02-22 19:41:02 +00:00
{
2012-03-13 23:14:29 +00:00
if ( version_cmd = = 0 )
{
version_cmd = load_cmd . cmd ;
if ( m_data . GetU32 ( & offset , & load_cmd . dylib , 4 ) = = NULL )
break ;
version = load_cmd . dylib . current_version ;
}
2013-03-06 23:19:17 +00:00
break ; // Break for now unless there is another more complete version
2012-03-13 23:14:29 +00:00
// number load command in the future.
2012-02-22 19:41:02 +00:00
}
2012-03-13 23:14:29 +00:00
offset = cmd_offset + load_cmd . cmdsize ;
2012-02-22 19:41:02 +00:00
}
2013-03-06 23:19:17 +00:00
2013-08-27 05:04:57 +00:00
if ( version_cmd = = LC_ID_DYLIB )
2012-02-22 19:41:02 +00:00
{
2012-03-13 23:14:29 +00:00
if ( versions ! = NULL & & num_versions > 0 )
{
if ( num_versions > 0 )
versions [ 0 ] = ( version & 0xFFFF0000ull ) > > 16 ;
if ( num_versions > 1 )
versions [ 1 ] = ( version & 0x0000FF00ull ) > > 8 ;
if ( num_versions > 2 )
versions [ 2 ] = ( version & 0x000000FFull ) ;
// Fill in an remaining version numbers with invalid values
for ( i = 3 ; i < num_versions ; + + i )
versions [ i ] = UINT32_MAX ;
}
// The LC_ID_DYLIB load command has a version with 3 version numbers
// in it, so always return 3
return 3 ;
2012-02-22 19:41:02 +00:00
}
}
return false ;
}
2010-06-08 16:52:24 +00:00
bool
2011-02-15 21:59:32 +00:00
ObjectFileMachO : : GetArchitecture ( ArchSpec & arch )
2010-06-08 16:52:24 +00:00
{
2012-03-13 23:14:29 +00:00
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
2011-09-21 03:57:31 +00:00
{
2012-03-13 23:14:29 +00:00
lldb_private : : Mutex : : Locker locker ( module_sp - > GetMutex ( ) ) ;
arch . SetArchitecture ( eArchTypeMachO , m_header . cputype , m_header . cpusubtype ) ;
2013-03-06 23:19:17 +00:00
2012-03-13 23:14:29 +00:00
// Files with type MH_PRELOAD are currently used in cases where the image
2013-03-06 23:19:17 +00:00
// debugs at the addresses in the file itself. Below we set the OS to
2012-03-13 23:14:29 +00:00
// unknown to make sure we use the DynamicLoaderStatic()...
2013-08-27 05:04:57 +00:00
if ( m_header . filetype = = MH_PRELOAD )
2012-03-13 23:14:29 +00:00
{
arch . GetTriple ( ) . setOS ( llvm : : Triple : : UnknownOS ) ;
}
return true ;
2011-09-21 03:57:31 +00:00
}
2012-03-13 23:14:29 +00:00
return false ;
2010-06-08 16:52:24 +00:00
}
2013-04-16 06:24:42 +00:00
UUID
ObjectFileMachO : : GetProcessSharedCacheUUID ( Process * process )
{
UUID uuid ;
if ( process )
{
addr_t all_image_infos = process - > GetImageInfoAddress ( ) ;
// The address returned by GetImageInfoAddress may be the address of dyld (don't want)
// or it may be the address of the dyld_all_image_infos structure (want). The first four
// bytes will be either the version field (all_image_infos) or a Mach-O file magic constant.
// Version 13 and higher of dyld_all_image_infos is required to get the sharedCacheUUID field.
Error err ;
uint32_t version_or_magic = process - > ReadUnsignedIntegerFromMemory ( all_image_infos , 4 , - 1 , err ) ;
if ( version_or_magic ! = - 1
2013-08-27 05:04:57 +00:00
& & version_or_magic ! = MH_MAGIC
& & version_or_magic ! = MH_CIGAM
& & version_or_magic ! = MH_MAGIC_64
& & version_or_magic ! = MH_CIGAM_64
2013-04-16 06:24:42 +00:00
& & version_or_magic > = 13 )
{
addr_t sharedCacheUUID_address = LLDB_INVALID_ADDRESS ;
int wordsize = process - > GetAddressByteSize ( ) ;
if ( wordsize = = 8 )
{
sharedCacheUUID_address = all_image_infos + 160 ; // sharedCacheUUID <mach-o/dyld_images.h>
}
if ( wordsize = = 4 )
{
sharedCacheUUID_address = all_image_infos + 84 ; // sharedCacheUUID <mach-o/dyld_images.h>
}
if ( sharedCacheUUID_address ! = LLDB_INVALID_ADDRESS )
{
uuid_t shared_cache_uuid ;
if ( process - > ReadMemory ( sharedCacheUUID_address , shared_cache_uuid , sizeof ( uuid_t ) , err ) = = sizeof ( uuid_t ) )
{
uuid . SetBytes ( shared_cache_uuid ) ;
}
}
}
}
return uuid ;
}
UUID
ObjectFileMachO : : GetLLDBSharedCacheUUID ( )
{
UUID uuid ;
# if defined (__APPLE__) && defined (__arm__)
uint8_t * ( * dyld_get_all_image_infos ) ( void ) ;
dyld_get_all_image_infos = ( uint8_t * ( * ) ( ) ) dlsym ( RTLD_DEFAULT , " _dyld_get_all_image_infos " ) ;
if ( dyld_get_all_image_infos )
{
uint8_t * dyld_all_image_infos_address = dyld_get_all_image_infos ( ) ;
if ( dyld_all_image_infos_address )
{
2013-04-16 21:42:58 +00:00
uint32_t * version = ( uint32_t * ) dyld_all_image_infos_address ; // version <mach-o/dyld_images.h>
if ( * version > = 13 )
2013-04-16 06:24:42 +00:00
{
2013-04-16 22:56:17 +00:00
uuid_t * sharedCacheUUID_address = ( uuid_t * ) ( ( uint8_t * ) dyld_all_image_infos_address + 84 ) ; // sharedCacheUUID <mach-o/dyld_images.h>
2013-04-16 06:24:42 +00:00
uuid . SetBytes ( sharedCacheUUID_address ) ;
}
}
}
# endif
return uuid ;
}
2013-10-24 22:54:08 +00:00
uint32_t
ObjectFileMachO : : GetMinimumOSVersion ( uint32_t * versions , uint32_t num_versions )
{
if ( m_min_os_versions . empty ( ) )
{
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
bool success = false ;
for ( uint32_t i = 0 ; success = = false & & i < m_header . ncmds ; + + i )
{
const lldb : : offset_t load_cmd_offset = offset ;
version_min_command lc ;
if ( m_data . GetU32 ( & offset , & lc . cmd , 2 ) = = NULL )
break ;
if ( lc . cmd = = LC_VERSION_MIN_MACOSX | | lc . cmd = = LC_VERSION_MIN_IPHONEOS )
{
if ( m_data . GetU32 ( & offset , & lc . version , ( sizeof ( lc ) / sizeof ( uint32_t ) ) - 2 ) )
{
const uint32_t xxxx = lc . version > > 16 ;
const uint32_t yy = ( lc . version > > 8 ) & 0xffu ;
const uint32_t zz = lc . version & 0xffu ;
if ( xxxx )
{
m_min_os_versions . push_back ( xxxx ) ;
if ( yy )
{
m_min_os_versions . push_back ( yy ) ;
if ( zz )
m_min_os_versions . push_back ( zz ) ;
}
}
success = true ;
}
}
offset = load_cmd_offset + lc . cmdsize ;
}
if ( success = = false )
{
// Push an invalid value so we don't keep trying to
m_min_os_versions . push_back ( UINT32_MAX ) ;
}
}
if ( m_min_os_versions . size ( ) > 1 | | m_min_os_versions [ 0 ] ! = UINT32_MAX )
{
if ( versions ! = NULL & & num_versions > 0 )
{
for ( size_t i = 0 ; i < num_versions ; + + i )
{
if ( i < m_min_os_versions . size ( ) )
versions [ i ] = m_min_os_versions [ i ] ;
else
versions [ i ] = 0 ;
}
}
return m_min_os_versions . size ( ) ;
}
// Call the superclasses version that will empty out the data
return ObjectFile : : GetMinimumOSVersion ( versions , num_versions ) ;
}
uint32_t
ObjectFileMachO : : GetSDKVersion ( uint32_t * versions , uint32_t num_versions )
{
if ( m_sdk_versions . empty ( ) )
{
lldb : : offset_t offset = MachHeaderSizeFromMagic ( m_header . magic ) ;
bool success = false ;
for ( uint32_t i = 0 ; success = = false & & i < m_header . ncmds ; + + i )
{
const lldb : : offset_t load_cmd_offset = offset ;
version_min_command lc ;
if ( m_data . GetU32 ( & offset , & lc . cmd , 2 ) = = NULL )
break ;
if ( lc . cmd = = LC_VERSION_MIN_MACOSX | | lc . cmd = = LC_VERSION_MIN_IPHONEOS )
{
if ( m_data . GetU32 ( & offset , & lc . version , ( sizeof ( lc ) / sizeof ( uint32_t ) ) - 2 ) )
{
const uint32_t xxxx = lc . reserved > > 16 ;
const uint32_t yy = ( lc . reserved > > 8 ) & 0xffu ;
const uint32_t zz = lc . reserved & 0xffu ;
if ( xxxx )
{
m_sdk_versions . push_back ( xxxx ) ;
if ( yy )
{
m_sdk_versions . push_back ( yy ) ;
if ( zz )
m_sdk_versions . push_back ( zz ) ;
}
}
success = true ;
}
}
offset = load_cmd_offset + lc . cmdsize ;
}
if ( success = = false )
{
// Push an invalid value so we don't keep trying to
m_sdk_versions . push_back ( UINT32_MAX ) ;
}
}
if ( m_sdk_versions . size ( ) > 1 | | m_sdk_versions [ 0 ] ! = UINT32_MAX )
{
if ( versions ! = NULL & & num_versions > 0 )
{
for ( size_t i = 0 ; i < num_versions ; + + i )
{
if ( i < m_sdk_versions . size ( ) )
versions [ i ] = m_sdk_versions [ i ] ;
else
versions [ i ] = 0 ;
}
}
return m_sdk_versions . size ( ) ;
}
// Call the superclasses version that will empty out the data
return ObjectFile : : GetSDKVersion ( versions , num_versions ) ;
}
2013-04-16 06:24:42 +00:00
2010-06-08 16:52:24 +00:00
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
2013-05-10 21:47:16 +00:00
lldb_private : : ConstString
2010-06-08 16:52:24 +00:00
ObjectFileMachO : : GetPluginName ( )
{
return GetPluginNameStatic ( ) ;
}
uint32_t
ObjectFileMachO : : GetPluginVersion ( )
{
return 1 ;
}