forked from OSchip/llvm-project
Remove the deprecated MacOSX native plug-in.
llvm-svn: 136626
This commit is contained in:
parent
0516c503ec
commit
89f138ae63
|
@ -74,7 +74,6 @@
|
|||
2671A0D013482601003A87BB /* ConnectionMachPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2671A0CF13482601003A87BB /* ConnectionMachPort.cpp */; };
|
||||
26744EF11338317700EF765A /* GDBRemoteCommunicationClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EED1338317700EF765A /* GDBRemoteCommunicationClient.cpp */; };
|
||||
26744EF31338317700EF765A /* GDBRemoteCommunicationServer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26744EEF1338317700EF765A /* GDBRemoteCommunicationServer.cpp */; };
|
||||
2676045A13D49D2300AB1B6A /* ProcessControl-mig.defs in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */; settings = {ATTRIBUTES = (Client, Server, ); }; };
|
||||
267C012B136880DF006E963E /* OptionGroupValueObjectDisplay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 267C012A136880DF006E963E /* OptionGroupValueObjectDisplay.cpp */; };
|
||||
267C01371368C49C006E963E /* OptionGroupOutputFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26BCFC531368B3E4006DC050 /* OptionGroupOutputFile.cpp */; };
|
||||
2686536C1370ACB200D186A3 /* OptionGroupBoolean.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2686536B1370ACB200D186A3 /* OptionGroupBoolean.cpp */; };
|
||||
|
@ -220,19 +219,6 @@
|
|||
2689009F13353E4200698AC0 /* ProcessGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2618EE5F1315B29C001D6D71 /* ProcessGDBRemote.cpp */; };
|
||||
268900A013353E4200698AC0 /* ProcessGDBRemoteLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2618EE611315B29C001D6D71 /* ProcessGDBRemoteLog.cpp */; };
|
||||
268900A113353E4200698AC0 /* ThreadGDBRemote.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2618EE631315B29C001D6D71 /* ThreadGDBRemote.cpp */; };
|
||||
268900A213353E5000698AC0 /* MachException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899210F57C5600BB2B04 /* MachException.cpp */; };
|
||||
268900A313353E5000698AC0 /* MachTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899410F57C5600BB2B04 /* MachTask.cpp */; };
|
||||
268900A413353E5000698AC0 /* MachThreadContext_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */; };
|
||||
268900A513353E5000698AC0 /* MachThreadContext_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */; };
|
||||
268900A613353E5000698AC0 /* MachThreadContext_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */; };
|
||||
268900A713353E5000698AC0 /* MachVMMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */; };
|
||||
268900A813353E5000698AC0 /* MachVMRegion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */; };
|
||||
268900A913353E5000698AC0 /* ProcessMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */; };
|
||||
268900AA13353E5000698AC0 /* ProcessMacOSXLog.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */; };
|
||||
268900AB13353E5000698AC0 /* RegisterContextMach_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */; };
|
||||
268900AC13353E5000698AC0 /* RegisterContextMach_i386.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */; };
|
||||
268900AD13353E5000698AC0 /* RegisterContextMach_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */; };
|
||||
268900AE13353E5000698AC0 /* ThreadMacOSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */; };
|
||||
268900AF13353E5000698AC0 /* UnwindLLDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF68D32F1255A110002FF25B /* UnwindLLDB.cpp */; };
|
||||
268900B013353E5000698AC0 /* RegisterContextLLDB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF68D2541255416E002FF25B /* RegisterContextLLDB.cpp */; };
|
||||
268900B413353E5000698AC0 /* RegisterContextMacOSXFrameBackchain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 26E3EEF711A994E800FBADB6 /* RegisterContextMacOSXFrameBackchain.cpp */; };
|
||||
|
@ -539,37 +525,6 @@
|
|||
260C898610F57C5600BB2B04 /* ObjectFileELF.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFileELF.h; sourceTree = "<group>"; };
|
||||
260C898810F57C5600BB2B04 /* ObjectFileMachO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ObjectFileMachO.cpp; sourceTree = "<group>"; };
|
||||
260C898910F57C5600BB2B04 /* ObjectFileMachO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ObjectFileMachO.h; sourceTree = "<group>"; };
|
||||
260C898D10F57C5600BB2B04 /* cc-swig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "cc-swig"; sourceTree = "<group>"; };
|
||||
260C898E10F57C5600BB2B04 /* config.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = config.pl; sourceTree = "<group>"; };
|
||||
260C898F10F57C5600BB2B04 /* test-ProcessDebug.pl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = "test-ProcessDebug.pl"; sourceTree = "<group>"; };
|
||||
260C899210F57C5600BB2B04 /* MachException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachException.cpp; sourceTree = "<group>"; };
|
||||
260C899310F57C5600BB2B04 /* MachException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachException.h; sourceTree = "<group>"; };
|
||||
260C899410F57C5600BB2B04 /* MachTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachTask.cpp; sourceTree = "<group>"; };
|
||||
260C899510F57C5600BB2B04 /* MachTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachTask.h; sourceTree = "<group>"; };
|
||||
260C899610F57C5600BB2B04 /* MachThreadContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext.h; sourceTree = "<group>"; };
|
||||
260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_arm.cpp; sourceTree = "<group>"; };
|
||||
260C899810F57C5600BB2B04 /* MachThreadContext_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_arm.h; sourceTree = "<group>"; };
|
||||
260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_i386.cpp; sourceTree = "<group>"; };
|
||||
260C899A10F57C5600BB2B04 /* MachThreadContext_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_i386.h; sourceTree = "<group>"; };
|
||||
260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachThreadContext_x86_64.cpp; sourceTree = "<group>"; };
|
||||
260C899C10F57C5600BB2B04 /* MachThreadContext_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachThreadContext_x86_64.h; sourceTree = "<group>"; };
|
||||
260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMMemory.cpp; sourceTree = "<group>"; };
|
||||
260C899E10F57C5600BB2B04 /* MachVMMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMMemory.h; sourceTree = "<group>"; };
|
||||
260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MachVMRegion.cpp; sourceTree = "<group>"; };
|
||||
260C89A010F57C5600BB2B04 /* MachVMRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachVMRegion.h; sourceTree = "<group>"; };
|
||||
260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; path = "ProcessControl-mig.defs"; sourceTree = "<group>"; };
|
||||
260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessMacOSX.cpp; sourceTree = "<group>"; };
|
||||
260C89A410F57C5600BB2B04 /* ProcessMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessMacOSX.h; sourceTree = "<group>"; };
|
||||
260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessMacOSXLog.cpp; sourceTree = "<group>"; };
|
||||
260C89A610F57C5600BB2B04 /* ProcessMacOSXLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessMacOSXLog.h; sourceTree = "<group>"; };
|
||||
260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_arm.cpp; sourceTree = "<group>"; };
|
||||
260C89AA10F57C5600BB2B04 /* RegisterContextMach_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_arm.h; sourceTree = "<group>"; };
|
||||
260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_i386.cpp; sourceTree = "<group>"; };
|
||||
260C89AC10F57C5600BB2B04 /* RegisterContextMach_i386.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_i386.h; sourceTree = "<group>"; };
|
||||
260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RegisterContextMach_x86_64.cpp; sourceTree = "<group>"; };
|
||||
260C89AE10F57C5600BB2B04 /* RegisterContextMach_x86_64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegisterContextMach_x86_64.h; sourceTree = "<group>"; };
|
||||
260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadMacOSX.cpp; sourceTree = "<group>"; };
|
||||
260C89B010F57C5600BB2B04 /* ThreadMacOSX.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMacOSX.h; sourceTree = "<group>"; };
|
||||
260C89B310F57C5600BB2B04 /* DWARFAbbreviationDeclaration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DWARFAbbreviationDeclaration.cpp; sourceTree = "<group>"; };
|
||||
260C89B410F57C5600BB2B04 /* DWARFAbbreviationDeclaration.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFAbbreviationDeclaration.h; sourceTree = "<group>"; };
|
||||
260C89B610F57C5600BB2B04 /* DWARFAttribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DWARFAttribute.h; sourceTree = "<group>"; };
|
||||
|
@ -1525,74 +1480,11 @@
|
|||
children = (
|
||||
4CEE62F71145F1C70064CF93 /* GDB Remote */,
|
||||
2642FBA713D003B400ED6808 /* MacOSX-Kernel */,
|
||||
260C898B10F57C5600BB2B04 /* MacOSX-User */,
|
||||
26B4666E11A2080F00CF6220 /* Utility */,
|
||||
);
|
||||
path = Process;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
260C898B10F57C5600BB2B04 /* MacOSX-User */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
260C898C10F57C5600BB2B04 /* scripts */,
|
||||
260C899010F57C5600BB2B04 /* source */,
|
||||
);
|
||||
path = "MacOSX-User";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
260C898C10F57C5600BB2B04 /* scripts */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
260C898D10F57C5600BB2B04 /* cc-swig */,
|
||||
260C898E10F57C5600BB2B04 /* config.pl */,
|
||||
260C898F10F57C5600BB2B04 /* test-ProcessDebug.pl */,
|
||||
);
|
||||
path = scripts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
260C899010F57C5600BB2B04 /* source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
260C899110F57C5600BB2B04 /* MacOSX */,
|
||||
260C89A310F57C5600BB2B04 /* ProcessMacOSX.cpp */,
|
||||
260C89A410F57C5600BB2B04 /* ProcessMacOSX.h */,
|
||||
260C89A510F57C5600BB2B04 /* ProcessMacOSXLog.cpp */,
|
||||
260C89A610F57C5600BB2B04 /* ProcessMacOSXLog.h */,
|
||||
260C89A910F57C5600BB2B04 /* RegisterContextMach_arm.cpp */,
|
||||
260C89AA10F57C5600BB2B04 /* RegisterContextMach_arm.h */,
|
||||
260C89AB10F57C5600BB2B04 /* RegisterContextMach_i386.cpp */,
|
||||
260C89AC10F57C5600BB2B04 /* RegisterContextMach_i386.h */,
|
||||
260C89AD10F57C5600BB2B04 /* RegisterContextMach_x86_64.cpp */,
|
||||
260C89AE10F57C5600BB2B04 /* RegisterContextMach_x86_64.h */,
|
||||
260C89AF10F57C5600BB2B04 /* ThreadMacOSX.cpp */,
|
||||
260C89B010F57C5600BB2B04 /* ThreadMacOSX.h */,
|
||||
);
|
||||
path = source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
260C899110F57C5600BB2B04 /* MacOSX */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
260C899210F57C5600BB2B04 /* MachException.cpp */,
|
||||
260C899310F57C5600BB2B04 /* MachException.h */,
|
||||
260C899410F57C5600BB2B04 /* MachTask.cpp */,
|
||||
260C899510F57C5600BB2B04 /* MachTask.h */,
|
||||
260C899610F57C5600BB2B04 /* MachThreadContext.h */,
|
||||
260C899710F57C5600BB2B04 /* MachThreadContext_arm.cpp */,
|
||||
260C899810F57C5600BB2B04 /* MachThreadContext_arm.h */,
|
||||
260C899910F57C5600BB2B04 /* MachThreadContext_i386.cpp */,
|
||||
260C899A10F57C5600BB2B04 /* MachThreadContext_i386.h */,
|
||||
260C899B10F57C5600BB2B04 /* MachThreadContext_x86_64.cpp */,
|
||||
260C899C10F57C5600BB2B04 /* MachThreadContext_x86_64.h */,
|
||||
260C899D10F57C5600BB2B04 /* MachVMMemory.cpp */,
|
||||
260C899E10F57C5600BB2B04 /* MachVMMemory.h */,
|
||||
260C899F10F57C5600BB2B04 /* MachVMRegion.cpp */,
|
||||
260C89A010F57C5600BB2B04 /* MachVMRegion.h */,
|
||||
260C89A110F57C5600BB2B04 /* ProcessControl-mig.defs */,
|
||||
);
|
||||
path = MacOSX;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
260C89B110F57C5600BB2B04 /* SymbolFile */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3197,19 +3089,6 @@
|
|||
2689009F13353E4200698AC0 /* ProcessGDBRemote.cpp in Sources */,
|
||||
268900A013353E4200698AC0 /* ProcessGDBRemoteLog.cpp in Sources */,
|
||||
268900A113353E4200698AC0 /* ThreadGDBRemote.cpp in Sources */,
|
||||
268900A213353E5000698AC0 /* MachException.cpp in Sources */,
|
||||
268900A313353E5000698AC0 /* MachTask.cpp in Sources */,
|
||||
268900A413353E5000698AC0 /* MachThreadContext_arm.cpp in Sources */,
|
||||
268900A513353E5000698AC0 /* MachThreadContext_i386.cpp in Sources */,
|
||||
268900A613353E5000698AC0 /* MachThreadContext_x86_64.cpp in Sources */,
|
||||
268900A713353E5000698AC0 /* MachVMMemory.cpp in Sources */,
|
||||
268900A813353E5000698AC0 /* MachVMRegion.cpp in Sources */,
|
||||
268900A913353E5000698AC0 /* ProcessMacOSX.cpp in Sources */,
|
||||
268900AA13353E5000698AC0 /* ProcessMacOSXLog.cpp in Sources */,
|
||||
268900AB13353E5000698AC0 /* RegisterContextMach_arm.cpp in Sources */,
|
||||
268900AC13353E5000698AC0 /* RegisterContextMach_i386.cpp in Sources */,
|
||||
268900AD13353E5000698AC0 /* RegisterContextMach_x86_64.cpp in Sources */,
|
||||
268900AE13353E5000698AC0 /* ThreadMacOSX.cpp in Sources */,
|
||||
268900AF13353E5000698AC0 /* UnwindLLDB.cpp in Sources */,
|
||||
268900B013353E5000698AC0 /* RegisterContextLLDB.cpp in Sources */,
|
||||
268900B413353E5000698AC0 /* RegisterContextMacOSXFrameBackchain.cpp in Sources */,
|
||||
|
@ -3365,7 +3244,6 @@
|
|||
265205AA13D3E3F700132FE2 /* RegisterContextKDP_i386.cpp in Sources */,
|
||||
265205AC13D3E3F700132FE2 /* RegisterContextKDP_x86_64.cpp in Sources */,
|
||||
2628A4D513D4977900F5487A /* ThreadKDP.cpp in Sources */,
|
||||
2676045A13D49D2300AB1B6A /* ProcessControl-mig.defs in Sources */,
|
||||
26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */,
|
||||
B271B11413D6139300C3FEDB /* FormatClasses.cpp in Sources */,
|
||||
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */,
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
##===- source/Plugins/Process/MacOSX-User/Makefile ---------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LLDB_LEVEL := ../../../..
|
||||
LIBRARYNAME := lldbPluginProcessMacOSXUser
|
||||
BUILD_ARCHIVE = 1
|
||||
|
||||
Source := $(wildcard $(PROJ_SRC_DIR)/source/*.cpp)
|
||||
Source += $(wildcard $(PROJ_SRC_DIR)/source/MacOSX/*.cpp)
|
||||
|
||||
include $(LLDB_LEVEL)/Makefile
|
|
@ -1,47 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use File::Basename;
|
||||
|
||||
sub execute_command
|
||||
{
|
||||
print join(' ', @_), "\n";
|
||||
if (scalar(@_) > 0) {
|
||||
system(@_);
|
||||
} else {
|
||||
system($_[0]);
|
||||
}
|
||||
}
|
||||
|
||||
my $infile = $ENV{SCRIPT_INPUT_FILE_1};
|
||||
my($in_basename, $in_dirname, $in_extension) = fileparse($infile, qr/\.[^.]*/);
|
||||
my $outdir = "$ENV{DERIVED_FILE_DIR}";
|
||||
my $perl_wrap_c = "$outdir/${in_basename}_perl_wrap.c";
|
||||
mkdir "$ENV{OBJECT_FILE_DIR}";
|
||||
my $perl_wrap_o = "$ENV{OBJECT_FILE_DIR}/${in_basename}_perl_wrap.o";
|
||||
my $perl_module = "$outdir/${in_basename}.pm";
|
||||
my $header_paths = "-I'../../../../../debugcore/source' -I'../../../../../DebugBase'";
|
||||
my $framework_opts = "-F'$ENV{CONFIGURATION_BUILD_DIR}' ";
|
||||
execute_command("/usr/bin/swig -shadow -perl5 -DHAS_BOOL $header_paths -outdir '$outdir' -o '$perl_wrap_c' '$infile'");
|
||||
|
||||
# Get any needed perl options for the next compile
|
||||
my $ccopts = `perl -MExtUtils::Embed -e ccopts`;
|
||||
my $libperl_dir = undef;
|
||||
if ($ccopts =~ /-I(\/System.*CORE)/)
|
||||
{
|
||||
$libperl_dir = $1;
|
||||
print "libperl directory: '$libperl_dir'\n";
|
||||
}
|
||||
|
||||
execute_command("cd '$ENV{OBJECT_FILE_DIR}' && ln -s '$libperl_dir/libperl.dylib'");
|
||||
|
||||
|
||||
# Strip out the default architectures it gave us, we will add them back with
|
||||
# the $arch_opts below
|
||||
$ccopts =~ s/-arch [a-z_0-9]+//g;
|
||||
|
||||
# Get a list of our build architectures
|
||||
my $arch_opts = "-arch " . join(' -arch ', split('\s+', $ENV{ARCHS}));
|
||||
|
||||
execute_command("gcc -c -Dbool=char $arch_opts $ccopts $header_paths $framework_opts -I'$ENV{PROJECT_DIR}/source' '$perl_wrap_c' -o '$perl_wrap_o'");
|
||||
|
||||
execute_command("cp '$perl_module' '$ENV{CONFIGURATION_BUILD_DIR}/$ENV{SHARED_SUPPORT_FOLDER_PATH}'");
|
|
@ -1,71 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
my $config_file = "$ENV{SCRIPT_OUTPUT_FILE_0}";
|
||||
|
||||
# Define the tests we need to run during this configuration
|
||||
my @config_tests = (
|
||||
{
|
||||
NAME => "HAVE_64_BIT_MACH_EXCEPTIONS",
|
||||
TEST => "-e '$ENV{SDKROOT}/usr/include/mach/mach_exc.defs'",
|
||||
COMMENT => "// Defined if we can use 64 bit mach exceptions",
|
||||
FAIL => "#undef HAVE_64_BIT_MACH_EXCEPTIONS\
|
||||
#define mach_exception_data_t exception_data_t\
|
||||
#define mach_exception_data_type_t exception_data_type_t\
|
||||
#define mach_exc_server exc_server\
|
||||
#define MACH_EXCEPTION_CODES 0\n",
|
||||
SUCCESS => "#define HAVE_64_BIT_MACH_EXCEPTIONS 1\n",
|
||||
}
|
||||
);
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Open the config file
|
||||
#----------------------------------------------------------------------
|
||||
open(CONFIG, "> $config_file") || die "Couldn't open '$config_file' for writing: $!\n";
|
||||
print CONFIG "/*" . "-" x 72 . "\n";
|
||||
print CONFIG "// This file is auto generated by a config.pl, do not edit by hand!\n";
|
||||
print CONFIG "//" . "-" x 72 . "\n";
|
||||
print CONFIG "// COMMAND LINE\n";
|
||||
print CONFIG "// " . join(' ', @ARGV) . "\n";
|
||||
print CONFIG "//" . "-" x 72 . "\n";
|
||||
print CONFIG "// ENVIRONMENT\n";
|
||||
my $key;
|
||||
my $val;
|
||||
while (($key, $val) = each %ENV)
|
||||
{
|
||||
printf CONFIG "// %s = %s\n", $key, $val;
|
||||
}
|
||||
print CONFIG "//" . "-" x 72 . "\n";
|
||||
print CONFIG "// SETTINGS\n";
|
||||
print CONFIG "// config_file: '$config_file'\n";
|
||||
print CONFIG "//" . "-" x 72 . "\n";
|
||||
print CONFIG "*/\n\n";
|
||||
print CONFIG "#ifndef liblldb_PDConfig_h_\n";
|
||||
print CONFIG "#define liblldb_PDConfig_h_\n";
|
||||
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Run the tests
|
||||
#----------------------------------------------------------------------
|
||||
foreach my $test_href (@config_tests)
|
||||
{
|
||||
if (exists $test_href->{COMMENT}) {
|
||||
print CONFIG "\n$test_href->{COMMENT}\n";
|
||||
} else {
|
||||
print CONFIG "\n// $test_href->{NAME}\n";
|
||||
}
|
||||
|
||||
my $test_result = eval "$test_href->{TEST}";
|
||||
if ($test_result != 0)
|
||||
{
|
||||
print CONFIG "$test_href->{SUCCESS}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print CONFIG "$test_href->{FAIL}\n";
|
||||
}
|
||||
}
|
||||
|
||||
print CONFIG "#endif // #ifndef liblldb_PDConfig_h_\n";
|
||||
close(CONFIG);
|
||||
|
|
@ -1,409 +0,0 @@
|
|||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use Cwd 'abs_path';
|
||||
our $home = $ENV{HOME} || die "ERROR: Couldn't deduce your home directory...\n";
|
||||
|
||||
our @inc_paths = (
|
||||
'./include',
|
||||
);
|
||||
|
||||
my $inc_paths_added = 0;
|
||||
foreach my $inc_path (@inc_paths)
|
||||
{
|
||||
if (-e $inc_path)
|
||||
{
|
||||
push (@INC, abs_path($inc_path));
|
||||
$inc_paths_added++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($inc_paths_added == 0)
|
||||
{
|
||||
die "Please compile the Release version of lldb\n";
|
||||
}
|
||||
|
||||
require lldb;
|
||||
|
||||
# my $state = lldb::eStateAttaching;
|
||||
|
||||
use constant UINT32_MAX => 4294967295;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Interactive Commands
|
||||
#----------------------------------------------------------------------
|
||||
our %commands = (
|
||||
break => {
|
||||
name => 'break', # in case an alias is used to get to this command
|
||||
description => "Sets a breakpoint.",
|
||||
usage => ["break ADDR"],
|
||||
function => \&command_set_breakpoint,
|
||||
runs_target => 0,
|
||||
},
|
||||
delete => {
|
||||
name => 'delete', # in case an alias is used to get to this command
|
||||
description => "Deletes one or more breakpoints by ID.\
|
||||
If no breakpoint IDs are given all breakpoints will be deleted.\
|
||||
If one or more IDs are given, only those breakpoints will be deleted.",
|
||||
usage => ["delete [ID1 ID2 ...]"],
|
||||
function => \&command_clear_breakpoint,
|
||||
runs_target => 0,
|
||||
},
|
||||
continue => {
|
||||
name => 'continue', # in case an alias is used to get to this command
|
||||
description => "Continues target execution.",
|
||||
usage => ["continue [ADDR]"],
|
||||
function => \&command_continue,
|
||||
runs_target => 1
|
||||
},
|
||||
step => {
|
||||
name => 'step', # in case an alias is used to get to this command
|
||||
description => "Single steps one instruction.",
|
||||
usage => ["step"],
|
||||
function => \&command_step,
|
||||
runs_target => 1
|
||||
},
|
||||
info => {
|
||||
name => 'info', # in case an alias is used to get to this command
|
||||
description => "Gets info on a variety of things.",
|
||||
usage => ["info reg", "info thread", "info threads"],
|
||||
function => \&command_info,
|
||||
runs_target => 0
|
||||
},
|
||||
help => {
|
||||
name => 'help', # in case an alias is used to get to this command
|
||||
description => "Displays a list of all commands, or help for a specific command.",
|
||||
usage => ["help", "help CMD"],
|
||||
function => \&command_help,
|
||||
runs_target => 0
|
||||
}
|
||||
);
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Command aliases
|
||||
#----------------------------------------------------------------------
|
||||
our %aliases = (
|
||||
b => $commands{break},
|
||||
c => $commands{continue},
|
||||
s => $commands{step},
|
||||
d => $commands{delete},
|
||||
h => $commands{help}
|
||||
);
|
||||
|
||||
our $opt_g = 0; # Enable verbose debug logging
|
||||
our $opt_v = 0; # Verbose mode
|
||||
my $prev_command_href = undef;
|
||||
my $stdio = '/dev/stdin';
|
||||
my $launch = 0;
|
||||
my @env = ();
|
||||
my @break_ids;
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Given a command string, return the command hash reference for it, or
|
||||
# undef if it doesn't exist.
|
||||
#----------------------------------------------------------------------
|
||||
sub get_command_hash_ref
|
||||
{
|
||||
my $cmd = shift;
|
||||
my $cmd_href = undef;
|
||||
if (length($cmd) == 0) { $cmd_href = $prev_command_href; }
|
||||
elsif (exists $aliases{$cmd}) { $cmd_href = $aliases{$cmd}; }
|
||||
elsif (exists $commands{$cmd}) { $cmd_href = $commands{$cmd}; }
|
||||
defined $cmd_href and $prev_command_href = $cmd_href;
|
||||
return $cmd_href;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Set a breakpoint
|
||||
#----------------------------------------------------------------------
|
||||
sub command_set_breakpoint
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
$opt_g and print "command_set_breakpoint (pid = $pid, locations = @_)\n";
|
||||
foreach my $location (@_)
|
||||
{
|
||||
my $success = 0;
|
||||
my $address = hex($location);
|
||||
if ($address != 0)
|
||||
{
|
||||
my $break_id = lldb::PDBreakpointSet ($pid, $address, 1, 0);
|
||||
if ($break_id != $lldb::PD_INVALID_BREAK_ID)
|
||||
{
|
||||
printf("Breakpoint %i is set.\n", $break_id);
|
||||
push(@break_ids, $break_id);
|
||||
$success = 1;
|
||||
}
|
||||
}
|
||||
$success or print("error: failed to set breakpoint at $location.\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
# Clear a breakpoint
|
||||
#----------------------------------------------------------------------
|
||||
sub command_clear_breakpoint
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
if (@_)
|
||||
{
|
||||
my $break_id;
|
||||
my @cleared_break_ids;
|
||||
my @new_break_ids;
|
||||
$opt_g and print "command_clear_breakpoint (pid = $pid, break_ids = @_)\n";
|
||||
foreach $break_id (@_)
|
||||
{
|
||||
if (lldb::PDBreakpointClear ($pid, $break_id))
|
||||
{
|
||||
printf("Breakpoint %i has been cleared.\n", $break_id);
|
||||
push (@cleared_break_ids, $break_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("error: failed to clear breakpoint %i.\n", $break_id);
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $old_break_id (@break_ids)
|
||||
{
|
||||
my $found_break_id = 0;
|
||||
foreach $break_id (@cleared_break_ids)
|
||||
{
|
||||
if ($old_break_id == $break_id)
|
||||
{
|
||||
$found_break_id = 1;
|
||||
}
|
||||
}
|
||||
$found_break_id or push (@new_break_ids, $old_break_id);
|
||||
}
|
||||
@break_ids = @new_break_ids;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Nothing specified, clear all breakpoints
|
||||
return command_clear_breakpoint($pid, $tid, @break_ids);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#----------------------------------------------------------------------
|
||||
# Continue program execution
|
||||
#----------------------------------------------------------------------
|
||||
sub command_continue
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
$opt_g and print "command_continue (pid = $pid)\n";
|
||||
if ($pid != $lldb::PD_INVALID_PROCESS_ID)
|
||||
{
|
||||
$opt_v and printf("Resuming pid %d...\n", $pid);
|
||||
return lldb::PDProcessResume ($pid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub command_step
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
$opt_g and print "command_step (pid = $pid, tid = $tid)\n";
|
||||
if ($pid != $lldb::PD_INVALID_PROCESS_ID)
|
||||
{
|
||||
$opt_v and printf("Single stepping pid %d tid = %4.4x...\n", $pid, $tid);
|
||||
return lldb::PDThreadResume ($pid, $tid, 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub command_info
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
$opt_g and print "command_step (pid = $pid, tid = $tid)\n";
|
||||
if ($pid != $lldb::PD_INVALID_PROCESS_ID)
|
||||
{
|
||||
if (@_)
|
||||
{
|
||||
my $info_cmd = shift;
|
||||
if ($info_cmd eq 'reg')
|
||||
{
|
||||
|
||||
}
|
||||
elsif ($info_cmd eq 'thread')
|
||||
{
|
||||
# info on the current thread
|
||||
printf("thread 0x%4.4x %s\n", $tid, lldb::PDThreadGetInfo($pid, $tid));
|
||||
}
|
||||
elsif ($info_cmd eq 'threads')
|
||||
{
|
||||
my $num_threads = lldb::PDProcessGetNumThreads( $pid );
|
||||
for my $thread_num (1..$num_threads)
|
||||
{
|
||||
my $curr_tid = lldb::PDProcessGetThreadAtIndex ( $pid, $thread_num - 1 );
|
||||
printf("%c%u - thread 0x%4.4x %s\n", $curr_tid == $tid ? '*' : ' ', $thread_num, $curr_tid, lldb::PDThreadGetInfo($pid, $curr_tid));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#----------------------------------------------------------------------
|
||||
# Get help on all commands, or a specific list of commands
|
||||
#----------------------------------------------------------------------
|
||||
sub command_help
|
||||
{
|
||||
my $pid = shift;
|
||||
my $tid = shift;
|
||||
if (@_)
|
||||
{
|
||||
$opt_g and print "command_continue (pid = $pid, commands = @_)\n";
|
||||
foreach my $cmd (@_)
|
||||
{
|
||||
my $cmd_href = get_command_hash_ref($cmd);
|
||||
if ($cmd_href)
|
||||
{
|
||||
print '#', '-' x 72, "\n# $cmd_href->{name}\n", '#', '-' x 72, "\n";
|
||||
my $usage_aref = $cmd_href->{usage};
|
||||
if (@{$usage_aref})
|
||||
{
|
||||
print " USAGE\n";
|
||||
foreach my $usage (@{$usage_aref}) {
|
||||
print " $usage\n";
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
print " DESCRIPTION\n $cmd_href->{description}\n\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
print " invalid command: '$cmd'\n\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return command_help($pid, sort keys %commands);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#lldb::PDLogSetLogMask ($lldb::PD_LOG_ALL);
|
||||
#lldb::PDLogSetLogFile ('/dev/stdout');
|
||||
|
||||
print "running: ", join(' ', @ARGV), "\n";
|
||||
|
||||
my $pid = lldb::PDProcessLaunch ($ARGV[0], \@ARGV, \@env, "i386", '/dev/stdin', '/dev/stdout', '/dev/stderr', $launch, '', 0);
|
||||
my $pid_state;
|
||||
while ($pid)
|
||||
{
|
||||
$opt_g and printf("PDProcessWaitForEvents (%d, 0x%4.4x, SET, 1)\n", $pid, $lldb::PD_ALL_EVENTS);
|
||||
my $events = lldb::PDProcessWaitForEvents ($pid, $lldb::PD_ALL_EVENTS, 1, 1);
|
||||
if ($events)
|
||||
{
|
||||
$opt_g and printf ("Got event: 0x%8.8x\n", $events);
|
||||
|
||||
if ($events & $lldb::PD_EVENT_IMAGES_CHANGED)
|
||||
{
|
||||
$opt_g and printf("pid %d images changed...\n", $pid);
|
||||
}
|
||||
|
||||
if ($events & $lldb::PD_EVENT_STDIO)
|
||||
{
|
||||
$opt_g and printf("pid %d has stdio...\n", $pid);
|
||||
}
|
||||
|
||||
if ($events & $lldb::PD_EVENT_ASYNC_INTERRUPT)
|
||||
{
|
||||
$opt_g and printf("pid %d got async interrupt...\n", $pid);
|
||||
}
|
||||
|
||||
if ($events & $lldb::PD_EVENT_RUNNING)
|
||||
{
|
||||
$pid_state = lldb::PDProcessGetState ($pid);
|
||||
$opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
|
||||
}
|
||||
|
||||
if ($events & $lldb::PD_EVENT_STOPPED)
|
||||
{
|
||||
$pid_state = lldb::PDProcessGetState ($pid);
|
||||
$opt_v and printf( "pid %d state: %s.\n", $pid, lldb::PDStateAsString ($pid_state) );
|
||||
|
||||
if ($pid_state == $lldb::eStateUnloaded ||
|
||||
$pid_state == $lldb::eStateAttaching ||
|
||||
$pid_state == $lldb::eStateLaunching )
|
||||
{
|
||||
|
||||
}
|
||||
elsif ( $pid_state == $lldb::eStateStopped )
|
||||
{
|
||||
my $tid = lldb::PDProcessGetSelectedThread ( $pid );
|
||||
my $pc = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "eip", 0);
|
||||
$pc != 0 and printf("pc = 0x%8.8x ", $pc);
|
||||
# my $sp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "esp", 0);
|
||||
# $sp != 0 and printf("sp = 0x%8.8x ", $sp);
|
||||
# my $fp = lldb::PDThreadGetRegisterHexValueByName($pid, $tid, $lldb::PD_REGISTER_SET_ALL, "ebp", 0);
|
||||
# $sp != 0 and printf("fp = 0x%8.8x ", $fp);
|
||||
# print "\n";
|
||||
my $done = 0;
|
||||
my $input;
|
||||
while (!$done)
|
||||
{
|
||||
print '(pdbg) ';
|
||||
|
||||
chomp($input = <STDIN>);
|
||||
my @argv = split(/\s+/, $input);
|
||||
my $cmd = @argv ? shift @argv : undef;
|
||||
my $cmd_href = get_command_hash_ref ($cmd);
|
||||
if ($cmd_href)
|
||||
{
|
||||
# Print the expanded alias if one was used
|
||||
if ($opt_v and $cmd_href->{name} ne $cmd)
|
||||
{
|
||||
print "$cmd_href->{name} @argv\n";
|
||||
}
|
||||
|
||||
# Call the command's callback function to make things happen
|
||||
if ($cmd_href->{function}($pid, $tid, @argv))
|
||||
{
|
||||
$done = $cmd_href->{runs_target};
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print "invalid command: '$cmd'\nType 'help' for a list of all commands.\nType 'help CMD' for help on a specific commmand.\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
elsif ( $pid_state == $lldb::eStateRunning ||
|
||||
$pid_state == $lldb::eStateStepping )
|
||||
{
|
||||
|
||||
}
|
||||
elsif ( $pid_state == $lldb::eStateCrashed ||
|
||||
$pid_state == $lldb::eStateDetached ||
|
||||
$pid_state == $lldb::eStateExited )
|
||||
{
|
||||
$pid = 0;
|
||||
}
|
||||
elsif ( $pid_state == $lldb::eStateSuspended )
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if ($pid)
|
||||
{
|
||||
$opt_g and printf("PDProcessResetEvents(%d, 0x%8.8x)\n", $pid, $events);
|
||||
lldb::PDProcessResetEvents($pid, $events);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($pid != $lldb::PD_INVALID_PROCESS_ID)
|
||||
{
|
||||
lldb::PDProcessDetach ($pid);
|
||||
}
|
|
@ -1,539 +0,0 @@
|
|||
//===-- MachException.cpp ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "StopInfoMachException.h"
|
||||
|
||||
#include "MachException.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
// Routine mach_exception_raise
|
||||
extern "C"
|
||||
kern_return_t catch_mach_exception_raise
|
||||
(
|
||||
mach_port_t exception_port,
|
||||
mach_port_t thread,
|
||||
mach_port_t task,
|
||||
exception_type_t exception,
|
||||
mach_exception_data_t code,
|
||||
mach_msg_type_number_t codeCnt
|
||||
);
|
||||
|
||||
extern "C"
|
||||
kern_return_t catch_mach_exception_raise_state
|
||||
(
|
||||
mach_port_t exception_port,
|
||||
exception_type_t exception,
|
||||
const mach_exception_data_t code,
|
||||
mach_msg_type_number_t codeCnt,
|
||||
int *flavor,
|
||||
const thread_state_t old_state,
|
||||
mach_msg_type_number_t old_stateCnt,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t *new_stateCnt
|
||||
);
|
||||
|
||||
// Routine mach_exception_raise_state_identity
|
||||
extern "C"
|
||||
kern_return_t catch_mach_exception_raise_state_identity
|
||||
(
|
||||
mach_port_t exception_port,
|
||||
mach_port_t thread,
|
||||
mach_port_t task,
|
||||
exception_type_t exception,
|
||||
mach_exception_data_t code,
|
||||
mach_msg_type_number_t codeCnt,
|
||||
int *flavor,
|
||||
thread_state_t old_state,
|
||||
mach_msg_type_number_t old_stateCnt,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t *new_stateCnt
|
||||
);
|
||||
|
||||
extern "C" boolean_t mach_exc_server(
|
||||
mach_msg_header_t *InHeadP,
|
||||
mach_msg_header_t *OutHeadP);
|
||||
|
||||
// Any access to the g_message variable should be done by locking the
|
||||
// g_message_mutex first, using the g_message variable, then unlocking
|
||||
// the g_message_mutex. See MachException::Message::CatchExceptionRaise()
|
||||
// for sample code.
|
||||
|
||||
static MachException::Data *g_message = NULL;
|
||||
//static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
|
||||
extern "C"
|
||||
kern_return_t
|
||||
catch_mach_exception_raise_state
|
||||
(
|
||||
mach_port_t exc_port,
|
||||
exception_type_t exc_type,
|
||||
const mach_exception_data_t exc_data,
|
||||
mach_msg_type_number_t exc_data_count,
|
||||
int * flavor,
|
||||
const thread_state_t old_state,
|
||||
mach_msg_type_number_t old_stateCnt,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t * new_stateCnt
|
||||
)
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
{
|
||||
log->Printf("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data = " MACH_EXCEPTION_DATA_FMT_HEX ", exc_data_count = %d)",
|
||||
__FUNCTION__,
|
||||
exc_port,
|
||||
exc_type, MachException::Name(exc_type),
|
||||
exc_data,
|
||||
exc_data_count);
|
||||
}
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
kern_return_t
|
||||
catch_mach_exception_raise_state_identity
|
||||
(
|
||||
mach_port_t exc_port,
|
||||
mach_port_t thread_port,
|
||||
mach_port_t task_port,
|
||||
exception_type_t exc_type,
|
||||
mach_exception_data_t exc_data,
|
||||
mach_msg_type_number_t exc_data_count,
|
||||
int * flavor,
|
||||
thread_state_t old_state,
|
||||
mach_msg_type_number_t old_stateCnt,
|
||||
thread_state_t new_state,
|
||||
mach_msg_type_number_t *new_stateCnt
|
||||
)
|
||||
{
|
||||
kern_return_t kret;
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
{
|
||||
log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
|
||||
__FUNCTION__,
|
||||
exc_port,
|
||||
thread_port,
|
||||
task_port,
|
||||
exc_type, MachException::Name(exc_type),
|
||||
exc_data_count,
|
||||
exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
|
||||
exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
|
||||
}
|
||||
kret = mach_port_deallocate (mach_task_self (), task_port);
|
||||
kret = mach_port_deallocate (mach_task_self (), thread_port);
|
||||
|
||||
return KERN_FAILURE;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
kern_return_t
|
||||
catch_mach_exception_raise
|
||||
(
|
||||
mach_port_t exc_port,
|
||||
mach_port_t thread_port,
|
||||
mach_port_t task_port,
|
||||
exception_type_t exc_type,
|
||||
mach_exception_data_t exc_data,
|
||||
mach_msg_type_number_t exc_data_count)
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
{
|
||||
log->Printf("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { " MACH_EXCEPTION_DATA_FMT_HEX ", " MACH_EXCEPTION_DATA_FMT_HEX " })",
|
||||
__FUNCTION__,
|
||||
exc_port,
|
||||
thread_port,
|
||||
task_port,
|
||||
exc_type, MachException::Name(exc_type),
|
||||
exc_data_count,
|
||||
exc_data_count > 0 ? exc_data[0] : 0xBADDBADD,
|
||||
exc_data_count > 1 ? exc_data[1] : 0xBADDBADD);
|
||||
}
|
||||
|
||||
g_message->task_port = task_port;
|
||||
g_message->thread_port = thread_port;
|
||||
g_message->exc_type = exc_type;
|
||||
g_message->exc_data.resize(exc_data_count);
|
||||
::memcpy (&g_message->exc_data[0], exc_data, g_message->exc_data.size() * sizeof (mach_exception_data_type_t));
|
||||
return KERN_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MachException::Message::PutToLog(Log *log) const
|
||||
{
|
||||
if (log)
|
||||
{
|
||||
log->Printf(" exc_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx } ",
|
||||
exc_msg.hdr.msgh_bits,
|
||||
exc_msg.hdr.msgh_size,
|
||||
exc_msg.hdr.msgh_remote_port,
|
||||
exc_msg.hdr.msgh_local_port,
|
||||
exc_msg.hdr.msgh_reserved,
|
||||
exc_msg.hdr.msgh_id);
|
||||
|
||||
log->Printf( "reply_msg { bits = 0x%8.8lx size = 0x%8.8lx remote-port = 0x%8.8lx local-port = 0x%8.8lx reserved = 0x%8.8lx id = 0x%8.8lx }",
|
||||
reply_msg.hdr.msgh_bits,
|
||||
reply_msg.hdr.msgh_size,
|
||||
reply_msg.hdr.msgh_remote_port,
|
||||
reply_msg.hdr.msgh_local_port,
|
||||
reply_msg.hdr.msgh_reserved,
|
||||
reply_msg.hdr.msgh_id);
|
||||
state.PutToLog(log);
|
||||
}
|
||||
}
|
||||
|
||||
lldb::StopInfoSP
|
||||
MachException::Data::GetStopInfo (lldb_private::Thread &thread) const
|
||||
{
|
||||
|
||||
const size_t exc_data_count = exc_data.size();
|
||||
return StopInfoMachException::CreateStopReasonWithMachException (thread,
|
||||
exc_type,
|
||||
exc_data_count,
|
||||
exc_data_count >= 1 ? exc_data[0] : 0,
|
||||
exc_data_count >= 2 ? exc_data[1] : 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MachException::Data::DumpStopReason() const
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet());
|
||||
if (log)
|
||||
{
|
||||
int signal = SoftSignal();
|
||||
if (signal > 0)
|
||||
{
|
||||
const char *signal_str = Host::GetSignalAsCString(signal);
|
||||
if (signal_str)
|
||||
log->Printf ("signal(%s)", signal_str);
|
||||
else
|
||||
log->Printf ("signal(%i)", signal);
|
||||
return;
|
||||
}
|
||||
log->Printf ("%s", Name(exc_type));
|
||||
}
|
||||
}
|
||||
|
||||
kern_return_t
|
||||
MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, mach_msg_timeout_t timeout, mach_port_t notify_port)
|
||||
{
|
||||
Error err;
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS));
|
||||
mach_msg_timeout_t mach_msg_timeout = options & MACH_RCV_TIMEOUT ? timeout : 0;
|
||||
if (log && ((options & MACH_RCV_TIMEOUT) == 0))
|
||||
{
|
||||
// Dump this log message if we have no timeout in case it never returns
|
||||
log->Printf ("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
|
||||
exc_msg.hdr.msgh_bits,
|
||||
exc_msg.hdr.msgh_size,
|
||||
exc_msg.hdr.msgh_remote_port,
|
||||
exc_msg.hdr.msgh_local_port,
|
||||
exc_msg.hdr.msgh_reserved,
|
||||
exc_msg.hdr.msgh_id,
|
||||
options,
|
||||
0,
|
||||
sizeof (exc_msg.data),
|
||||
port,
|
||||
mach_msg_timeout,
|
||||
notify_port);
|
||||
}
|
||||
|
||||
err = ::mach_msg (&exc_msg.hdr,
|
||||
options, // options
|
||||
0, // Send size
|
||||
sizeof (exc_msg.data), // Receive size
|
||||
port, // exception port to watch for exception on
|
||||
mach_msg_timeout, // timeout in msec (obeyed only if MACH_RCV_TIMEOUT is ORed into the options parameter)
|
||||
notify_port);
|
||||
|
||||
// Dump any errors we get
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS);
|
||||
if (log && err.GetError() != MACH_RCV_TIMED_OUT)
|
||||
{
|
||||
log->Error("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)",
|
||||
exc_msg.hdr.msgh_bits,
|
||||
exc_msg.hdr.msgh_size,
|
||||
exc_msg.hdr.msgh_remote_port,
|
||||
exc_msg.hdr.msgh_local_port,
|
||||
exc_msg.hdr.msgh_reserved,
|
||||
exc_msg.hdr.msgh_id,
|
||||
options,
|
||||
0,
|
||||
sizeof (exc_msg.data),
|
||||
port,
|
||||
mach_msg_timeout,
|
||||
notify_port);
|
||||
}
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
bool
|
||||
MachException::Message::CatchExceptionRaise()
|
||||
{
|
||||
bool success = false;
|
||||
// locker will keep a mutex locked until it goes out of scope
|
||||
// Mutex::Locker locker(&g_message_mutex);
|
||||
// log->Printf ("calling mach_exc_server");
|
||||
g_message = &state;
|
||||
// The exc_server function is the MIG generated server handling function
|
||||
// to handle messages from the kernel relating to the occurrence of an
|
||||
// exception in a thread. Such messages are delivered to the exception port
|
||||
// set via thread_set_exception_ports or task_set_exception_ports. When an
|
||||
// exception occurs in a thread, the thread sends an exception message to
|
||||
// its exception port, blocking in the kernel waiting for the receipt of a
|
||||
// reply. The exc_server function performs all necessary argument handling
|
||||
// for this kernel message and calls catch_exception_raise,
|
||||
// catch_exception_raise_state or catch_exception_raise_state_identity,
|
||||
// which should handle the exception. If the called routine returns
|
||||
// KERN_SUCCESS, a reply message will be sent, allowing the thread to
|
||||
// continue from the point of the exception; otherwise, no reply message
|
||||
// is sent and the called routine must have dealt with the exception
|
||||
// thread directly.
|
||||
if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr))
|
||||
{
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
log->Printf ("mach_exc_server returned zero...");
|
||||
}
|
||||
g_message = NULL;
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
|
||||
kern_return_t
|
||||
MachException::Message::Reply(task_t task, pid_t pid, int signal)
|
||||
{
|
||||
// Reply to the exception...
|
||||
Error err;
|
||||
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet());
|
||||
if (log)
|
||||
log->Printf("MachException::Message::Reply (task = 0x%4.4x, pid = %i, signal = %i)", task, pid, signal);
|
||||
|
||||
// If we had a soft signal, we need to update the thread first so it can
|
||||
// continue without signaling
|
||||
int soft_signal = state.SoftSignal();
|
||||
int state_pid = LLDB_INVALID_PROCESS_ID;
|
||||
if (task == state.task_port)
|
||||
{
|
||||
// This is our task, so we can update the signal to send to it
|
||||
state_pid = pid;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = ::pid_for_task(state.task_port, &state_pid);
|
||||
}
|
||||
|
||||
if (signal == LLDB_INVALID_SIGNAL_NUMBER)
|
||||
signal = 0;
|
||||
|
||||
if (log)
|
||||
log->Printf("MachException::Message::Reply () updating thread signal to %i (original soft_signal = %i)", signal, soft_signal);
|
||||
|
||||
if (state_pid != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
errno = 0;
|
||||
if (::ptrace (PT_THUPDATE, state_pid, (caddr_t)state.thread_port, signal) != 0)
|
||||
{
|
||||
if (soft_signal != LLDB_INVALID_SIGNAL_NUMBER)
|
||||
// We know we currently can't forward signals for threads that didn't stop in EXC_SOFT_SIGNAL...
|
||||
// So only report it as an error if we should have been able to do it.
|
||||
err.SetErrorToErrno();
|
||||
else
|
||||
err.Clear();
|
||||
}
|
||||
else
|
||||
err.Clear();
|
||||
|
||||
if (log && (log->GetMask().Test(PD_LOG_EXCEPTIONS) || err.Fail()))
|
||||
err.PutToLog(log.get(), "::ptrace (request = PT_THUPDATE, pid = %i, tid = 0x%4.4x, signal = %i)", state_pid, state.thread_port, signal);
|
||||
}
|
||||
|
||||
err = ::mach_msg ( &reply_msg.hdr,
|
||||
MACH_SEND_MSG | MACH_SEND_INTERRUPT,
|
||||
reply_msg.hdr.msgh_size,
|
||||
0,
|
||||
MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE,
|
||||
MACH_PORT_NULL);
|
||||
|
||||
if (log)
|
||||
log->LogIf (PD_LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x) = 0x%8.8x",
|
||||
reply_msg.hdr.msgh_bits,
|
||||
reply_msg.hdr.msgh_size,
|
||||
reply_msg.hdr.msgh_remote_port,
|
||||
reply_msg.hdr.msgh_local_port,
|
||||
reply_msg.hdr.msgh_reserved,
|
||||
reply_msg.hdr.msgh_id,
|
||||
MACH_SEND_MSG | MACH_SEND_INTERRUPT,
|
||||
reply_msg.hdr.msgh_size,
|
||||
0,
|
||||
MACH_PORT_NULL,
|
||||
MACH_MSG_TIMEOUT_NONE,
|
||||
MACH_PORT_NULL,
|
||||
err.GetError());
|
||||
|
||||
|
||||
if (err.Fail())
|
||||
{
|
||||
if (err.GetError() == MACH_SEND_INTERRUPTED)
|
||||
{
|
||||
err.PutToLog(log.get(), "::mach_msg() - send interrupted");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (state.task_port == task)
|
||||
{
|
||||
err.PutToLog(log.get(), "::mach_msg() - failed (task)");
|
||||
abort ();
|
||||
}
|
||||
else
|
||||
{
|
||||
err.PutToLog(log.get(), "::mach_msg() - failed (child of task)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MachException::Data::PutToLog(Log *log) const
|
||||
{
|
||||
if (log == NULL)
|
||||
return;
|
||||
|
||||
const char *exc_type_name = MachException::Name(exc_type);
|
||||
|
||||
log->Printf (" state { task_port = 0x%4.4x, thread_port = 0x%4.4x, exc_type = %i (%s) ...", task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???");
|
||||
|
||||
const size_t exc_data_count = exc_data.size();
|
||||
// Dump any special exception data contents
|
||||
int soft_signal = SoftSignal();
|
||||
if (soft_signal > 0)
|
||||
{
|
||||
const char *sig_str = Host::GetSignalAsCString(soft_signal);
|
||||
log->Printf (" exc_data: EXC_SOFT_SIGNAL (%i (%s))", soft_signal, sig_str ? sig_str : "unknown signal");
|
||||
}
|
||||
else
|
||||
{
|
||||
// No special disassembly for this data, just dump the data
|
||||
size_t idx;
|
||||
for (idx = 0; idx < exc_data_count; ++idx)
|
||||
{
|
||||
log->Printf(" exc_data[%u]: " MACH_EXCEPTION_DATA_FMT_HEX, idx, exc_data[idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MachException::PortInfo::PortInfo() :
|
||||
count(0)
|
||||
{
|
||||
::memset (masks, 0, sizeof(masks));
|
||||
::memset (ports, 0, sizeof(ports));
|
||||
::memset (behaviors, 0, sizeof(behaviors));
|
||||
::memset (flavors, 0, sizeof(flavors));
|
||||
}
|
||||
|
||||
|
||||
kern_return_t
|
||||
MachException::PortInfo::Save (task_t task)
|
||||
{
|
||||
count = EXC_TYPES_COUNT;
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
log->Printf ("MachException::PortInfo::Save (task = 0x%4.4x)", task);
|
||||
Error err;
|
||||
if (log)
|
||||
log->Printf("::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)...", task, EXC_MASK_ALL, count);
|
||||
err = ::task_get_exception_ports (task, EXC_MASK_ALL, masks, &count, ports, behaviors, flavors);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_get_exception_ports (task=0x%4.4x, mask=0x%x, maskCnt<=>%u, ports, behaviors, flavors)", task, EXC_MASK_ALL, count);
|
||||
if (log)
|
||||
{
|
||||
mach_msg_type_number_t i;
|
||||
log->Printf("Index Mask Port Behavior Flavor", masks[i], ports[i], behaviors[i], flavors[i]);
|
||||
log->Printf("===== -------- -------- -------- --------");
|
||||
for (i=0; i<count; ++i)
|
||||
log->Printf("[%3u] %8.8x %8.8x %8.8x %8.8x", i, masks[i], ports[i], behaviors[i], flavors[i]);
|
||||
}
|
||||
if (err.Fail())
|
||||
count = 0;
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
kern_return_t
|
||||
MachException::PortInfo::Restore (task_t task)
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS));
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE))
|
||||
log->Printf("MachException::PortInfo::Restore (task = 0x%4.4x)", task);
|
||||
uint32_t i = 0;
|
||||
Error err;
|
||||
if (count > 0)
|
||||
{
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
err = ::task_set_exception_ports (task, masks[i], ports[i], behaviors[i], flavors[i]);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]);
|
||||
|
||||
if (err.Fail())
|
||||
break;
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
const char *
|
||||
MachException::Name(exception_type_t exc_type)
|
||||
{
|
||||
switch (exc_type)
|
||||
{
|
||||
case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS";
|
||||
case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
|
||||
case EXC_ARITHMETIC: return "EXC_ARITHMETIC";
|
||||
case EXC_EMULATION: return "EXC_EMULATION";
|
||||
case EXC_SOFTWARE: return "EXC_SOFTWARE";
|
||||
case EXC_BREAKPOINT: return "EXC_BREAKPOINT";
|
||||
case EXC_SYSCALL: return "EXC_SYSCALL";
|
||||
case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL";
|
||||
case EXC_RPC_ALERT: return "EXC_RPC_ALERT";
|
||||
#ifdef EXC_CRASH
|
||||
case EXC_CRASH: return "EXC_CRASH";
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
//===-- MachException.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef liblldb_MachException_h_
|
||||
#define liblldb_MachException_h_
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <vector>
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
// TODO: Get the config script to run to this plug-in
|
||||
//#include "PDConfig.h"
|
||||
#define HAVE_64_BIT_MACH_EXCEPTIONS // REMOVE THIS WHEN PDConfig.h is included above
|
||||
#ifdef HAVE_64_BIT_MACH_EXCEPTIONS
|
||||
|
||||
#define MACH_EXCEPTION_DATA_FMT_DEC "%lld"
|
||||
#define MACH_EXCEPTION_DATA_FMT_HEX "0x%16.16llx"
|
||||
#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%llx"
|
||||
|
||||
#else
|
||||
|
||||
#define MACH_EXCEPTION_DATA_FMT_DEC "%d"
|
||||
#define MACH_EXCEPTION_DATA_FMT_HEX "0x%8.8x"
|
||||
#define MACH_EXCEPTION_DATA_FMT_MINHEX "0x%x"
|
||||
|
||||
#endif
|
||||
|
||||
class MachProcess;
|
||||
|
||||
typedef union MachMessageTag
|
||||
{
|
||||
mach_msg_header_t hdr;
|
||||
char data[1024];
|
||||
} MachMessage;
|
||||
|
||||
|
||||
class MachException
|
||||
{
|
||||
public:
|
||||
|
||||
struct PortInfo
|
||||
{
|
||||
exception_mask_t masks[EXC_TYPES_COUNT];
|
||||
mach_port_t ports[EXC_TYPES_COUNT];
|
||||
exception_behavior_t behaviors[EXC_TYPES_COUNT];
|
||||
thread_state_flavor_t flavors[EXC_TYPES_COUNT];
|
||||
mach_msg_type_number_t count;
|
||||
|
||||
PortInfo();
|
||||
kern_return_t Save(task_t task);
|
||||
kern_return_t Restore(task_t task);
|
||||
};
|
||||
|
||||
struct Data
|
||||
{
|
||||
task_t task_port;
|
||||
lldb::tid_t thread_port;
|
||||
exception_type_t exc_type;
|
||||
std::vector<lldb::addr_t> exc_data;
|
||||
Data() :
|
||||
task_port(TASK_NULL),
|
||||
thread_port(THREAD_NULL),
|
||||
exc_type(0),
|
||||
exc_data()
|
||||
{
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
task_port = TASK_NULL;
|
||||
thread_port = THREAD_NULL;
|
||||
exc_type = 0;
|
||||
exc_data.clear();
|
||||
}
|
||||
bool IsValid() const
|
||||
{
|
||||
return task_port != TASK_NULL &&
|
||||
thread_port != THREAD_NULL &&
|
||||
exc_type != 0;
|
||||
}
|
||||
// Return the SoftSignal for this MachException data, or zero if there is none
|
||||
int SoftSignal() const
|
||||
{
|
||||
if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL)
|
||||
return exc_data[1];
|
||||
return LLDB_INVALID_SIGNAL_NUMBER;
|
||||
}
|
||||
bool IsBreakpoint() const
|
||||
{
|
||||
return (exc_type == EXC_BREAKPOINT) || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1);
|
||||
}
|
||||
void PutToLog(lldb_private::Log *log) const;
|
||||
void DumpStopReason() const;
|
||||
lldb::StopInfoSP GetStopInfo (lldb_private::Thread &thread) const;
|
||||
};
|
||||
|
||||
struct Message
|
||||
{
|
||||
MachMessage exc_msg;
|
||||
MachMessage reply_msg;
|
||||
Data state;
|
||||
|
||||
Message() :
|
||||
exc_msg(),
|
||||
reply_msg(),
|
||||
state()
|
||||
{
|
||||
memset(&exc_msg, 0, sizeof(exc_msg));
|
||||
memset(&reply_msg, 0, sizeof(reply_msg));
|
||||
}
|
||||
bool CatchExceptionRaise();
|
||||
void PutToLog(lldb_private::Log *log) const;
|
||||
kern_return_t Reply (task_t task, pid_t pid, int signal);
|
||||
kern_return_t Receive( mach_port_t receive_port,
|
||||
mach_msg_option_t options,
|
||||
mach_msg_timeout_t timeout,
|
||||
mach_port_t notify_port = MACH_PORT_NULL);
|
||||
|
||||
typedef std::vector<Message> collection;
|
||||
typedef collection::iterator iterator;
|
||||
typedef collection::const_iterator const_iterator;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
e_actionForward, // Forward signal to inferior process
|
||||
e_actionStop // Stop when this signal is received
|
||||
};
|
||||
struct Action
|
||||
{
|
||||
task_t task_port; // Set to TASK_NULL for any TASK
|
||||
lldb::tid_t thread_port; // Set to THREAD_NULL for any thread
|
||||
exception_type_t exc_mask; // Mach exception mask to watch for
|
||||
std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to exception data, or empty to ignore exc_data value for exception
|
||||
std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare to exception data after masking, or empty to ignore exc_data value for exception
|
||||
uint8_t flags; // Action flags describing what to do with the exception
|
||||
};
|
||||
static const char *Name(exception_type_t exc_type);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,680 +0,0 @@
|
|||
//===-- MachTask.cpp --------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MachTask.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
|
||||
// Other libraries and framework includes
|
||||
#if defined (__arm__)
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <SpringBoardServices/SpringBoardServer.h>
|
||||
#include <SpringBoardServices/SBSWatchdogAssertion.h>
|
||||
|
||||
#endif
|
||||
|
||||
#include "lldb/Host/Endian.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Core/DataExtractor.h"
|
||||
|
||||
// Project includes
|
||||
#include "ProcessMacOSX.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask constructor
|
||||
//----------------------------------------------------------------------
|
||||
MachTask::MachTask(ProcessMacOSX *process) :
|
||||
m_process (process),
|
||||
m_task (TASK_NULL),
|
||||
m_vm_memory (),
|
||||
m_exc_port_info(),
|
||||
m_exception_thread (0),
|
||||
m_exception_port (MACH_PORT_NULL)
|
||||
{
|
||||
memset(&m_exc_port_info, 0, sizeof(m_exc_port_info));
|
||||
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Destructor
|
||||
//----------------------------------------------------------------------
|
||||
MachTask::~MachTask()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::Suspend
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::Suspend()
|
||||
{
|
||||
Error err;
|
||||
task_t task = GetTaskPort();
|
||||
err = ::task_suspend (task);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK));
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_suspend ( target_task = 0x%4.4x )", task);
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::Resume
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::Resume()
|
||||
{
|
||||
Error err;
|
||||
task_t task = GetTaskPort();
|
||||
err = ::task_resume (task);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK));
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_resume ( target_task = 0x%4.4x )", task);
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
int32_t
|
||||
MachTask::GetSuspendCount () const
|
||||
{
|
||||
struct task_basic_info task_info;
|
||||
if (BasicInfo(&task_info) == KERN_SUCCESS)
|
||||
return task_info.suspend_count;
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::ExceptionPort
|
||||
//----------------------------------------------------------------------
|
||||
mach_port_t
|
||||
MachTask::ExceptionPort() const
|
||||
{
|
||||
return m_exception_port;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::ExceptionPortIsValid
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
MachTask::ExceptionPortIsValid() const
|
||||
{
|
||||
return MACH_PORT_VALID(m_exception_port);
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::Clear
|
||||
//----------------------------------------------------------------------
|
||||
void
|
||||
MachTask::Clear()
|
||||
{
|
||||
// Do any cleanup needed for this task
|
||||
m_task = TASK_NULL;
|
||||
m_exception_thread = 0;
|
||||
m_exception_port = MACH_PORT_NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::SaveExceptionPortInfo
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::SaveExceptionPortInfo()
|
||||
{
|
||||
return m_exc_port_info.Save(GetTaskPort());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::RestoreExceptionPortInfo
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::RestoreExceptionPortInfo()
|
||||
{
|
||||
return m_exc_port_info.Restore(GetTaskPort());
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::ReadMemory
|
||||
//----------------------------------------------------------------------
|
||||
size_t
|
||||
MachTask::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error& error)
|
||||
{
|
||||
size_t n = 0;
|
||||
task_t task = GetTaskPort();
|
||||
if (task != TASK_NULL)
|
||||
{
|
||||
n = m_vm_memory.Read(task, addr, buf, size, error);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY));
|
||||
if (log)
|
||||
{
|
||||
log->Printf ("MachTask::ReadMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes read", (uint64_t)addr, size, buf, n);
|
||||
if (log->GetMask().Test(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().Test(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
|
||||
{
|
||||
DataExtractor data((uint8_t*)buf, n, lldb::endian::InlHostByteOrder(), 4);
|
||||
data.PutToLog(log.get(), 0, n, addr, 16, DataExtractor::TypeUInt8);
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::WriteMemory
|
||||
//----------------------------------------------------------------------
|
||||
size_t
|
||||
MachTask::WriteMemory (lldb::addr_t addr, const void *buf, size_t size, Error& error)
|
||||
{
|
||||
size_t n = 0;
|
||||
task_t task = GetTaskPort();
|
||||
if (task != TASK_NULL)
|
||||
{
|
||||
n = m_vm_memory.Write(task, addr, buf, size, error);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY));
|
||||
if (log)
|
||||
{
|
||||
log->Printf ("MachTask::WriteMemory ( addr = 0x%16.16llx, size = %zu, buf = %8.8p) => %u bytes written", (uint64_t)addr, size, buf, n);
|
||||
if (log->GetMask().Test(PD_LOG_MEMORY_DATA_LONG) || (log->GetMask().Test(PD_LOG_MEMORY_DATA_SHORT) && size <= 8))
|
||||
{
|
||||
DataExtractor data((uint8_t*)buf, n, lldb::endian::InlHostByteOrder(), 4);
|
||||
data.PutToLog(log.get(), 0, n, addr, 16, DataExtractor::TypeUInt8);
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::AllocateMemory
|
||||
//----------------------------------------------------------------------
|
||||
lldb::addr_t
|
||||
MachTask::AllocateMemory (size_t size, uint32_t permissions, Error& error)
|
||||
{
|
||||
// FIXME: vm_allocate allocates a page at a time, so we should use
|
||||
// host_page_size to get the host page size and then parcel out the
|
||||
// page we get back until it is filled.
|
||||
// FIXME: Add log messages.
|
||||
|
||||
kern_return_t kret;
|
||||
mach_vm_address_t addr;
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY));
|
||||
|
||||
kret = ::mach_vm_allocate (GetTaskPort(), &addr, size, TRUE);
|
||||
if (kret == KERN_SUCCESS)
|
||||
{
|
||||
// Set the protections:
|
||||
vm_prot_t mach_prot = 0;
|
||||
if (permissions & lldb::ePermissionsReadable)
|
||||
mach_prot |= VM_PROT_READ;
|
||||
if (permissions & lldb::ePermissionsWritable)
|
||||
mach_prot |= VM_PROT_WRITE;
|
||||
if (permissions & lldb::ePermissionsExecutable)
|
||||
mach_prot |= VM_PROT_EXECUTE;
|
||||
|
||||
kret = ::mach_vm_protect (GetTaskPort(), addr, size, 0, mach_prot);
|
||||
if (kret == KERN_SUCCESS)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Allocated memory at addr = 0x%16.16llx, size = %zu, prot = 0x%x)", (uint64_t) addr, size, mach_prot);
|
||||
m_allocations.insert (std::make_pair(addr, size));
|
||||
return (lldb::addr_t) addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Failed to set protections on memory at addr = 0x%16.16llx, size = %zu), prot = 0x%x", (uint64_t) addr, size, mach_prot);
|
||||
kret = ::mach_vm_deallocate (GetTaskPort(), addr, size);
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf("Failed to set allocate memory: size = %zu)", size);
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::DeallocateMemory
|
||||
//----------------------------------------------------------------------
|
||||
Error
|
||||
MachTask::DeallocateMemory (lldb::addr_t ptr)
|
||||
{
|
||||
Error error;
|
||||
// We have to stash away sizes for the allocations...
|
||||
allocation_collection::iterator pos, end = m_allocations.end();
|
||||
for (pos = m_allocations.begin(); pos != end; pos++)
|
||||
{
|
||||
if ((*pos).first == ptr)
|
||||
{
|
||||
m_allocations.erase (pos);
|
||||
error = ::mach_vm_deallocate (GetTaskPort(), (vm_address_t) ptr, (*pos).second);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
error.SetErrorStringWithFormat("no memory allocated at 0x%llx", (uint64_t)ptr);
|
||||
return error;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::TaskPortForProcessID
|
||||
//----------------------------------------------------------------------
|
||||
task_t
|
||||
MachTask::GetTaskPortForProcessID (Error &err)
|
||||
{
|
||||
err.Clear();
|
||||
if (m_task == TASK_NULL && m_process != NULL)
|
||||
m_task = MachTask::GetTaskPortForProcessID(m_process->GetID(), err);
|
||||
return m_task;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::TaskPortForProcessID
|
||||
//----------------------------------------------------------------------
|
||||
task_t
|
||||
MachTask::GetTaskPortForProcessID (lldb::pid_t pid, Error &err)
|
||||
{
|
||||
task_t task = TASK_NULL;
|
||||
if (pid != LLDB_INVALID_PROCESS_ID)
|
||||
{
|
||||
mach_port_t task_self = mach_task_self ();
|
||||
err = ::task_for_pid ( task_self, pid, &task);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK));
|
||||
if (log || err.Fail())
|
||||
{
|
||||
err.PutToLog(log.get(), "::task_for_pid ( target_tport = 0x%4.4x, pid = %d, task => 0x%4.4x ) %u/%u %u/%u", task_self, pid, task, getuid(), geteuid(), getgid(), getegid());
|
||||
}
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::BasicInfo
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::BasicInfo(struct task_basic_info *info) const
|
||||
{
|
||||
return BasicInfo (GetTaskPort(), info);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::BasicInfo
|
||||
//----------------------------------------------------------------------
|
||||
kern_return_t
|
||||
MachTask::BasicInfo(task_t task, struct task_basic_info *info)
|
||||
{
|
||||
if (info == NULL)
|
||||
return KERN_INVALID_ARGUMENT;
|
||||
|
||||
Error err;
|
||||
mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
|
||||
err = ::task_info (task, TASK_BASIC_INFO, (task_info_t)info, &count);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_TASK));
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_info ( target_task = 0x%4.4x, flavor = TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => %u )", task, info, count);
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE) && err.Success())
|
||||
{
|
||||
float user = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
|
||||
float system = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f;
|
||||
log->Printf ("task_basic_info = { suspend_count = %i, virtual_size = 0x%8.8x, resident_size = 0x%8.8x, user_time = %f, system_time = %f }",
|
||||
info->suspend_count, info->virtual_size, info->resident_size, user, system);
|
||||
}
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::IsValid
|
||||
//
|
||||
// Returns true if a task is a valid task port for a current process.
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
MachTask::IsValid () const
|
||||
{
|
||||
return MachTask::IsValid(GetTaskPort());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// MachTask::IsValid
|
||||
//
|
||||
// Returns true if a task is a valid task port for a current process.
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
MachTask::IsValid (task_t task)
|
||||
{
|
||||
if (task != TASK_NULL)
|
||||
{
|
||||
struct task_basic_info task_info;
|
||||
return BasicInfo(task, &task_info) == KERN_SUCCESS;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
MachTask::StartExceptionThread(Error &err)
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS));
|
||||
|
||||
if (log)
|
||||
log->Printf ("MachTask::%s ( )", __FUNCTION__);
|
||||
task_t task = GetTaskPortForProcessID(err);
|
||||
if (MachTask::IsValid(task))
|
||||
{
|
||||
// Got the mach port for the current process
|
||||
mach_port_t task_self = mach_task_self ();
|
||||
|
||||
// Allocate an exception port that we will use to track our child process
|
||||
err = ::mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &m_exception_port);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::mach_port_allocate (task_self=0x%4.4x, MACH_PORT_RIGHT_RECEIVE, &m_exception_port => 0x%4.4x)",
|
||||
task_self, m_exception_port);
|
||||
if (err.Fail())
|
||||
return false;
|
||||
|
||||
// Add the ability to send messages on the new exception port
|
||||
err = ::mach_port_insert_right (task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::mach_port_insert_right (task_self=0x%4.4x, m_exception_port=0x%4.4x, m_exception_port=0x%4.4x, MACH_MSG_TYPE_MAKE_SEND)",
|
||||
task_self, m_exception_port, m_exception_port);
|
||||
if (err.Fail())
|
||||
return false;
|
||||
|
||||
// Save the original state of the exception ports for our child process
|
||||
err = SaveExceptionPortInfo();
|
||||
|
||||
// Set the ability to get all exceptions on this port
|
||||
err = ::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::task_set_exception_ports (task, EXC_MASK_ALL, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE)");
|
||||
if (err.Fail())
|
||||
return false;
|
||||
|
||||
// Create the exception thread
|
||||
char thread_name[256];
|
||||
::snprintf (thread_name, sizeof(thread_name), "<lldb.process.process-macosx.mach-exception-%d>", m_process->GetID());
|
||||
m_exception_thread = Host::ThreadCreate (thread_name, MachTask::ExceptionThread, this, &err);
|
||||
|
||||
return err.Success();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
kern_return_t
|
||||
MachTask::ShutDownExceptionThread()
|
||||
{
|
||||
Error err;
|
||||
|
||||
if (m_exception_thread == NULL)
|
||||
return KERN_SUCCESS;
|
||||
|
||||
err = RestoreExceptionPortInfo();
|
||||
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS));
|
||||
|
||||
// NULL our our exception port and let our exception thread exit
|
||||
mach_port_t exception_port = m_exception_port;
|
||||
m_exception_port = NULL;
|
||||
|
||||
Host::ThreadCancel (m_exception_thread, &err);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "Host::ThreadCancel ( thread = %p )", m_exception_thread);
|
||||
|
||||
Host::ThreadJoin (m_exception_thread, NULL, &err);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "Host::ThreadJoin ( thread = %p, result_ptr = NULL)", m_exception_thread);
|
||||
|
||||
// Deallocate our exception port that we used to track our child process
|
||||
mach_port_t task_self = mach_task_self ();
|
||||
err = ::mach_port_deallocate (task_self, exception_port);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port);
|
||||
exception_port = NULL;
|
||||
|
||||
Clear();
|
||||
return err.GetError();
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
MachTask::ExceptionThread (void *arg)
|
||||
{
|
||||
if (arg == NULL)
|
||||
return NULL;
|
||||
|
||||
MachTask *mach_task = (MachTask*) arg;
|
||||
ProcessMacOSX *mach_proc = mach_task->Process();
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS));
|
||||
if (log)
|
||||
log->Printf ("MachTask::%s (arg = %p) thread starting...", __FUNCTION__, arg);
|
||||
|
||||
// We keep a count of the number of consecutive exceptions received so
|
||||
// we know to grab all exceptions without a timeout. We do this to get a
|
||||
// bunch of related exceptions on our exception port so we can process
|
||||
// then together. When we have multiple threads, we can get an exception
|
||||
// per thread and they will come in consecutively. The main loop in this
|
||||
// thread can stop periodically if needed to service things related to this
|
||||
// process.
|
||||
// flag set in the options, so we will wait forever for an exception on
|
||||
// our exception port. After we get one exception, we then will use the
|
||||
// MACH_RCV_TIMEOUT option with a zero timeout to grab all other current
|
||||
// exceptions for our process. After we have received the last pending
|
||||
// exception, we will get a timeout which enables us to then notify
|
||||
// our main thread that we have an exception bundle available. We then wait
|
||||
// for the main thread to tell this exception thread to start trying to get
|
||||
// exceptions messages again and we start again with a mach_msg read with
|
||||
// infinite timeout.
|
||||
uint32_t num_exceptions_received = 0;
|
||||
Error err;
|
||||
task_t task = mach_task->GetTaskPort();
|
||||
mach_msg_timeout_t periodic_timeout = 1000;
|
||||
|
||||
#if defined (__arm__)
|
||||
mach_msg_timeout_t watchdog_elapsed = 0;
|
||||
mach_msg_timeout_t watchdog_timeout = 60 * 1000;
|
||||
lldb::pid_t pid = mach_proc->GetID();
|
||||
CFReleaser<SBSWatchdogAssertionRef> watchdog;
|
||||
|
||||
if (mach_proc->ProcessUsingSpringBoard())
|
||||
{
|
||||
// Request a renewal for every 60 seconds if we attached using SpringBoard
|
||||
watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60));
|
||||
if (log)
|
||||
log->Printf ("::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", pid, watchdog.get());
|
||||
|
||||
if (watchdog.get())
|
||||
{
|
||||
::SBSWatchdogAssertionRenew (watchdog.get());
|
||||
|
||||
CFTimeInterval watchdogRenewalInterval = ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get());
|
||||
if (log)
|
||||
log->Printf ("::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", watchdog.get(), watchdogRenewalInterval);
|
||||
if (watchdogRenewalInterval > 0.0)
|
||||
{
|
||||
watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000;
|
||||
if (watchdog_timeout > 3000)
|
||||
watchdog_timeout -= 1000; // Give us a second to renew our timeout
|
||||
else if (watchdog_timeout > 1000)
|
||||
watchdog_timeout -= 250; // Give us a quarter of a second to renew our timeout
|
||||
}
|
||||
}
|
||||
if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout)
|
||||
periodic_timeout = watchdog_timeout;
|
||||
}
|
||||
#endif // #if defined (__arm__)
|
||||
|
||||
while (mach_task->ExceptionPortIsValid())
|
||||
{
|
||||
//::pthread_testcancel ();
|
||||
|
||||
MachException::Message exception_message;
|
||||
|
||||
|
||||
if (num_exceptions_received > 0)
|
||||
{
|
||||
// No timeout, just receive as many exceptions as we can since we already have one and we want
|
||||
// to get all currently available exceptions for this task
|
||||
err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0);
|
||||
}
|
||||
else if (periodic_timeout > 0)
|
||||
{
|
||||
// We need to stop periodically in this loop, so try and get a mach message with a valid timeout (ms)
|
||||
err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, periodic_timeout);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We don't need to parse all current exceptions or stop periodically,
|
||||
// just wait for an exception forever.
|
||||
err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0);
|
||||
}
|
||||
|
||||
if (err.GetError() == MACH_RCV_INTERRUPTED)
|
||||
{
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
|
||||
// If we have no task port we should exit this thread
|
||||
if (!mach_task->ExceptionPortIsValid())
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("thread cancelled...");
|
||||
break;
|
||||
}
|
||||
|
||||
// Make sure our task is still valid
|
||||
if (MachTask::IsValid(task))
|
||||
{
|
||||
// Task is still ok
|
||||
if (log)
|
||||
log->Printf ("interrupted, but task still valid, continuing...");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("task has exited...");
|
||||
mach_proc->SetPrivateState (eStateExited);
|
||||
// Our task has died, exit the thread.
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (err.GetError() == MACH_RCV_TIMED_OUT)
|
||||
{
|
||||
if (num_exceptions_received > 0)
|
||||
{
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
|
||||
|
||||
// We were receiving all current exceptions with a timeout of zero
|
||||
// it is time to go back to our normal looping mode
|
||||
num_exceptions_received = 0;
|
||||
|
||||
// Notify our main thread we have a complete exception message
|
||||
// bundle available.
|
||||
mach_proc->ExceptionMessageBundleComplete();
|
||||
|
||||
// in case we use a timeout value when getting exceptions...
|
||||
// Make sure our task is still valid
|
||||
if (MachTask::IsValid(task))
|
||||
{
|
||||
// Task is still ok
|
||||
if (log)
|
||||
log->Printf ("got a timeout, continuing...");
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("task has exited...");
|
||||
mach_proc->SetPrivateState (eStateExited);
|
||||
// Our task has died, exit the thread.
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined (__arm__)
|
||||
if (watchdog.get())
|
||||
{
|
||||
watchdog_elapsed += periodic_timeout;
|
||||
if (watchdog_elapsed >= watchdog_timeout)
|
||||
{
|
||||
LogIf(PD_LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", watchdog.get());
|
||||
::SBSWatchdogAssertionRenew (watchdog.get());
|
||||
watchdog_elapsed = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if (err.GetError() != KERN_SUCCESS)
|
||||
{
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
|
||||
if (log)
|
||||
log->Printf ("got some other error, do something about it??? nah, continuing for now...");
|
||||
// TODO: notify of error?
|
||||
}
|
||||
else
|
||||
{
|
||||
if (exception_message.CatchExceptionRaise())
|
||||
{
|
||||
++num_exceptions_received;
|
||||
mach_proc->ExceptionMessageReceived(exception_message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (__arm__)
|
||||
if (watchdog.get())
|
||||
{
|
||||
// TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we
|
||||
// all are up and running on systems that support it. The SBS framework has a #define
|
||||
// that will forward SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel for now
|
||||
// so it should still build either way.
|
||||
LogIf(PD_LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get());
|
||||
::SBSWatchdogAssertionRelease (watchdog.get());
|
||||
}
|
||||
#endif // #if defined (__arm__)
|
||||
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_EXCEPTIONS);
|
||||
if (log)
|
||||
log->Printf ("MachTask::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lldb::addr_t
|
||||
MachTask::GetDYLDAllImageInfosAddress ()
|
||||
{
|
||||
#ifdef TASK_DYLD_INFO
|
||||
task_dyld_info_data_t dyld_info;
|
||||
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||
Error err;
|
||||
// The actual task shouldn't matter for the DYLD info, so lets just use ours
|
||||
kern_return_t kret = ::task_info (GetTaskPortForProcessID (err), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
|
||||
if (kret == KERN_SUCCESS)
|
||||
{
|
||||
// We now have the address of the all image infos structure
|
||||
return dyld_info.all_image_info_addr;
|
||||
}
|
||||
#endif
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
//===-- MachTask.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef __MachTask_h__
|
||||
#define __MachTask_h__
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
#include <map>
|
||||
// Other libraries and framework includes
|
||||
#include <mach/mach.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
// Project includes
|
||||
#include "MachException.h"
|
||||
#include "MachVMMemory.h"
|
||||
|
||||
class ProcessMacOSX;
|
||||
|
||||
class MachTask
|
||||
{
|
||||
public:
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
MachTask (ProcessMacOSX *process);
|
||||
|
||||
virtual
|
||||
~MachTask ();
|
||||
|
||||
void
|
||||
Clear ();
|
||||
|
||||
kern_return_t
|
||||
Suspend ();
|
||||
|
||||
kern_return_t
|
||||
Resume ();
|
||||
|
||||
int32_t
|
||||
GetSuspendCount () const;
|
||||
|
||||
size_t
|
||||
ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error& error);
|
||||
|
||||
size_t
|
||||
WriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error& error);
|
||||
|
||||
lldb::addr_t
|
||||
AllocateMemory (size_t size, uint32_t permissions, lldb_private::Error& error);
|
||||
|
||||
lldb_private::Error
|
||||
DeallocateMemory (lldb::addr_t addr);
|
||||
|
||||
mach_port_t
|
||||
ExceptionPort () const;
|
||||
|
||||
bool
|
||||
ExceptionPortIsValid () const;
|
||||
|
||||
kern_return_t
|
||||
SaveExceptionPortInfo ();
|
||||
|
||||
kern_return_t
|
||||
RestoreExceptionPortInfo ();
|
||||
|
||||
kern_return_t
|
||||
ShutDownExceptionThread ();
|
||||
|
||||
bool
|
||||
StartExceptionThread (lldb_private::Error &err);
|
||||
|
||||
lldb::addr_t
|
||||
GetDYLDAllImageInfosAddress ();
|
||||
|
||||
kern_return_t
|
||||
BasicInfo (struct task_basic_info *info) const;
|
||||
|
||||
static kern_return_t
|
||||
BasicInfo (task_t task, struct task_basic_info *info);
|
||||
|
||||
bool
|
||||
IsValid () const;
|
||||
|
||||
static bool
|
||||
IsValid (task_t task);
|
||||
|
||||
static void *
|
||||
ExceptionThread (void *arg);
|
||||
|
||||
task_t
|
||||
GetTaskPort () const
|
||||
{
|
||||
return m_task;
|
||||
}
|
||||
|
||||
task_t
|
||||
GetTaskPortForProcessID (lldb_private::Error &err);
|
||||
|
||||
static task_t
|
||||
GetTaskPortForProcessID (lldb::pid_t pid, lldb_private::Error &err);
|
||||
|
||||
ProcessMacOSX *
|
||||
Process ()
|
||||
{
|
||||
return m_process;
|
||||
}
|
||||
|
||||
const ProcessMacOSX *
|
||||
Process () const
|
||||
{
|
||||
return m_process;
|
||||
}
|
||||
|
||||
protected:
|
||||
ProcessMacOSX * m_process; // The mach process that owns this MachTask
|
||||
task_t m_task;
|
||||
MachVMMemory m_vm_memory; // Special mach memory reading class that will take care of watching for page and region boundaries
|
||||
MachException::PortInfo m_exc_port_info; // Saved settings for all exception ports
|
||||
lldb::thread_t m_exception_thread; // Thread ID for the exception thread in case we need it
|
||||
mach_port_t m_exception_port; // Exception port on which we will receive child exceptions
|
||||
|
||||
// Maybe sort this by address and use find?
|
||||
typedef std::map<vm_address_t,size_t> allocation_collection;
|
||||
allocation_collection m_allocations;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (MachTask);
|
||||
};
|
||||
|
||||
#endif // __MachTask_h__
|
|
@ -1,48 +0,0 @@
|
|||
//===-- MachThreadContext.h -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachThreadContext_h_
|
||||
#define liblldb_MachThreadContext_h_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "MachException.h"
|
||||
|
||||
class ThreadMacOSX;
|
||||
|
||||
class MachThreadContext
|
||||
{
|
||||
public:
|
||||
MachThreadContext (ThreadMacOSX &thread) :
|
||||
m_thread (thread)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MachThreadContext()
|
||||
{
|
||||
}
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContext (lldb_private::StackFrame *frame) const = 0;
|
||||
|
||||
virtual void InitializeInstance() = 0;
|
||||
virtual void ThreadWillResume () = 0;
|
||||
virtual bool ShouldStop () = 0;
|
||||
virtual void RefreshStateAfterStop() = 0;
|
||||
virtual bool NotifyException (MachException::Data& exc) { return false; }
|
||||
virtual bool StepNotComplete () { return false; }
|
||||
virtual size_t GetStackFrameData(lldb_private::StackFrame *frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs) { return 0; }
|
||||
// virtual const uint8_t * SoftwareBreakpointOpcode (size_t byte_size) = 0;
|
||||
|
||||
protected:
|
||||
ThreadMacOSX &m_thread;
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef liblldb_MachThreadContext_h_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,60 +0,0 @@
|
|||
//===-- MachThreadContext_arm.h ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachThreadContext_arm_h_
|
||||
#define liblldb_MachThreadContext_arm_h_
|
||||
|
||||
#include "MachThreadContext.h"
|
||||
#include "RegisterContextMach_arm.h"
|
||||
|
||||
class ThreadMacOSX;
|
||||
|
||||
class MachThreadContext_arm : public MachThreadContext
|
||||
{
|
||||
public:
|
||||
enum { kMaxNumThumbITBreakpoints = 4 };
|
||||
|
||||
static MachThreadContext*
|
||||
Create (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
|
||||
|
||||
static void
|
||||
Initialize();
|
||||
|
||||
MachThreadContext_arm(ThreadMacOSX &thread);
|
||||
|
||||
virtual
|
||||
~MachThreadContext_arm();
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContext (lldb_private::StackFrame *frame) const;
|
||||
|
||||
virtual void
|
||||
InitializeInstance();
|
||||
|
||||
virtual void
|
||||
ThreadWillResume ();
|
||||
|
||||
virtual bool
|
||||
ShouldStop ();
|
||||
|
||||
virtual void
|
||||
RefreshStateAfterStop ();
|
||||
|
||||
protected:
|
||||
kern_return_t
|
||||
EnableHardwareSingleStep (bool enable);
|
||||
|
||||
protected:
|
||||
lldb::addr_t m_hw_single_chained_step_addr;
|
||||
uint32_t m_bvr0_reg;
|
||||
uint32_t m_bcr0_reg;
|
||||
uint32_t m_bvr0_save;
|
||||
uint32_t m_bcr0_save;
|
||||
};
|
||||
#endif // #ifndef liblldb_MachThreadContext_arm_h_
|
|
@ -1,243 +0,0 @@
|
|||
//===-- MachThreadContext_i386.cpp ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
|
||||
|
||||
#include "MachThreadContext_i386.h"
|
||||
|
||||
#include "lldb/Symbol/Function.h"
|
||||
#include "lldb/Symbol/Symbol.h"
|
||||
|
||||
#include "ProcessMacOSX.h"
|
||||
#include "ThreadMacOSX.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
MachThreadContext_i386::MachThreadContext_i386 (ThreadMacOSX &thread) :
|
||||
MachThreadContext (thread),
|
||||
m_flags_reg(LLDB_INVALID_REGNUM)
|
||||
{
|
||||
}
|
||||
|
||||
MachThreadContext_i386::~MachThreadContext_i386()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
MachThreadContext*
|
||||
MachThreadContext_i386::Create (const ArchSpec &arch_spec, ThreadMacOSX &thread)
|
||||
{
|
||||
return new MachThreadContext_i386(thread);
|
||||
}
|
||||
|
||||
// Class init function
|
||||
void
|
||||
MachThreadContext_i386::Initialize()
|
||||
{
|
||||
llvm::Triple triple;
|
||||
triple.setArch (llvm::Triple::x86);
|
||||
triple.setVendor (llvm::Triple::Apple);
|
||||
triple.setOS (llvm::Triple::Darwin);
|
||||
ArchSpec arch_spec (triple);
|
||||
ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_i386::Create);
|
||||
}
|
||||
|
||||
// Instance init function
|
||||
void
|
||||
MachThreadContext_i386::InitializeInstance()
|
||||
{
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx != NULL);
|
||||
m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
|
||||
}
|
||||
|
||||
void
|
||||
MachThreadContext_i386::ThreadWillResume()
|
||||
{
|
||||
m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
|
||||
}
|
||||
|
||||
bool
|
||||
MachThreadContext_i386::ShouldStop()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MachThreadContext_i386::RefreshStateAfterStop()
|
||||
{
|
||||
m_thread.GetRegisterContext()->HardwareSingleStep (false);
|
||||
}
|
||||
|
||||
bool
|
||||
MachThreadContext_i386::NotifyException (MachException::Data& exc)
|
||||
{
|
||||
switch (exc.exc_type)
|
||||
{
|
||||
case EXC_BAD_ACCESS:
|
||||
break;
|
||||
case EXC_BAD_INSTRUCTION:
|
||||
break;
|
||||
case EXC_ARITHMETIC:
|
||||
break;
|
||||
case EXC_EMULATION:
|
||||
break;
|
||||
case EXC_SOFTWARE:
|
||||
break;
|
||||
case EXC_BREAKPOINT:
|
||||
if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
|
||||
{
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx);
|
||||
lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
|
||||
if (pc != LLDB_INVALID_ADDRESS && pc > 0)
|
||||
{
|
||||
pc -= 1;
|
||||
reg_ctx->SetPC(pc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case EXC_SYSCALL:
|
||||
break;
|
||||
case EXC_MACH_SYSCALL:
|
||||
break;
|
||||
case EXC_RPC_ALERT:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Set the single step bit in the processor status register.
|
||||
//kern_return_t
|
||||
//MachThreadContext_i386::EnableHardwareSingleStep (bool enable)
|
||||
//{
|
||||
// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
|
||||
// assert (reg_ctx);
|
||||
// Scalar rflags_scalar;
|
||||
//
|
||||
// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
|
||||
// {
|
||||
// Flags rflags(rflags_scalar.UInt());
|
||||
// const uint32_t trace_bit = 0x100u;
|
||||
// if (enable)
|
||||
// {
|
||||
// // If the trace bit is already cleared, there is nothing to do
|
||||
// if (rflags.IsSet (trace_bit))
|
||||
// return KERN_SUCCESS;
|
||||
// else
|
||||
// rflags.Set (trace_bit);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // If the trace bit is already cleared, there is nothing to do
|
||||
// if (rflags.IsClear (trace_bit))
|
||||
// return KERN_SUCCESS;
|
||||
// else
|
||||
// rflags.Clear(trace_bit);
|
||||
// }
|
||||
//
|
||||
// rflags_scalar = rflags.Get();
|
||||
// // If the code makes it here we have changes to the GPRs which
|
||||
// // we need to write back out, so lets do that.
|
||||
// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
|
||||
// return KERN_SUCCESS;
|
||||
// }
|
||||
// // Return the error code for reading the GPR registers back
|
||||
// return KERN_INVALID_ARGUMENT;
|
||||
//}
|
||||
|
||||
RegisterContextSP
|
||||
MachThreadContext_i386::CreateRegisterContext (StackFrame *frame) const
|
||||
{
|
||||
lldb::RegisterContextSP reg_ctx_sp (new RegisterContextMach_i386(m_thread, frame->GetConcreteFrameIndex()));
|
||||
return reg_ctx_sp;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
MachThreadContext_i386::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
|
||||
{
|
||||
fp_pc_pairs.clear();
|
||||
|
||||
std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
|
||||
|
||||
struct Frame_i386
|
||||
{
|
||||
uint32_t fp;
|
||||
uint32_t pc;
|
||||
};
|
||||
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx);
|
||||
|
||||
Frame_i386 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
|
||||
|
||||
fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
|
||||
|
||||
const size_t k_frame_size = sizeof(frame);
|
||||
Error error;
|
||||
|
||||
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
|
||||
{
|
||||
// Read both the FP and PC (8 bytes)
|
||||
if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
|
||||
break;
|
||||
|
||||
if (frame.pc != 0)
|
||||
fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
|
||||
}
|
||||
if (!fp_pc_pairs.empty())
|
||||
{
|
||||
lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
|
||||
if (first_frame_pc != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
const uint32_t resolve_scope = eSymbolContextModule |
|
||||
eSymbolContextCompUnit |
|
||||
eSymbolContextFunction |
|
||||
eSymbolContextSymbol;
|
||||
|
||||
SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
|
||||
const AddressRange *addr_range_ptr = NULL;
|
||||
if (first_frame_sc.function)
|
||||
addr_range_ptr = &first_frame_sc.function->GetAddressRange();
|
||||
else if (first_frame_sc.symbol)
|
||||
addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
|
||||
|
||||
if (addr_range_ptr)
|
||||
{
|
||||
if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
|
||||
{
|
||||
// We are at the first instruction, so we can recover the
|
||||
// previous PC by dereferencing the SP
|
||||
lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
|
||||
// Read the real second frame return address into frame.pc
|
||||
if (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
|
||||
{
|
||||
// Construct a correct second frame (we already read the pc for it above
|
||||
frame.fp = fp_pc_pairs.front().first;
|
||||
|
||||
// Insert the frame
|
||||
fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
|
||||
|
||||
// Correct the fp in the first frame to use the SP
|
||||
fp_pc_pairs.front().first = first_frame_sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fp_pc_pairs.size();
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined (__i386__)
|
|
@ -1,56 +0,0 @@
|
|||
//===-- MachThreadContext_i386.h --------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachThreadContext_i386_h_
|
||||
#define liblldb_MachThreadContext_i386_h_
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
|
||||
#include "MachThreadContext.h"
|
||||
#include "RegisterContextMach_i386.h"
|
||||
|
||||
class ThreadMacOSX;
|
||||
|
||||
class MachThreadContext_i386 : public MachThreadContext
|
||||
{
|
||||
public:
|
||||
static MachThreadContext* Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
|
||||
|
||||
// Class init function
|
||||
static void Initialize();
|
||||
|
||||
MachThreadContext_i386(ThreadMacOSX &thread);
|
||||
|
||||
virtual
|
||||
~MachThreadContext_i386();
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContext (lldb_private::StackFrame *frame) const;
|
||||
|
||||
virtual void InitializeInstance();
|
||||
virtual void ThreadWillResume();
|
||||
virtual bool ShouldStop ();
|
||||
virtual void RefreshStateAfterStop();
|
||||
|
||||
virtual bool NotifyException(MachException::Data& exc);
|
||||
virtual size_t GetStackFrameData(lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
|
||||
|
||||
protected:
|
||||
// kern_return_t EnableHardwareSingleStep (bool enable);
|
||||
uint32_t m_flags_reg;
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (MachThreadContext_i386);
|
||||
};
|
||||
|
||||
//#if defined (__i386__)
|
||||
//typedef MachThreadContext_i386 DNBArch;
|
||||
//#endif
|
||||
|
||||
#endif // defined (__i386__) || defined (__x86_64__)
|
||||
#endif // #ifndef liblldb_MachThreadContext_i386_h_
|
|
@ -1,256 +0,0 @@
|
|||
//===-- MachThreadContext_x86_64.cpp ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
#include "llvm/ADT/Triple.h"
|
||||
|
||||
#include "lldb/Symbol/Function.h"
|
||||
#include "lldb/Symbol/Symbol.h"
|
||||
|
||||
#include "MachThreadContext_x86_64.h"
|
||||
#include "ProcessMacOSX.h"
|
||||
#include "ThreadMacOSX.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
MachThreadContext_x86_64::MachThreadContext_x86_64(ThreadMacOSX &thread) :
|
||||
MachThreadContext (thread),
|
||||
m_flags_reg(LLDB_INVALID_REGNUM)
|
||||
{
|
||||
}
|
||||
|
||||
MachThreadContext_x86_64::~MachThreadContext_x86_64()
|
||||
{
|
||||
}
|
||||
|
||||
MachThreadContext*
|
||||
MachThreadContext_x86_64::Create(const ArchSpec &arch_spec, ThreadMacOSX &thread)
|
||||
{
|
||||
return new MachThreadContext_x86_64(thread);
|
||||
}
|
||||
|
||||
// Class init function
|
||||
void
|
||||
MachThreadContext_x86_64::Initialize()
|
||||
{
|
||||
llvm::Triple triple;
|
||||
triple.setArch (llvm::Triple::x86_64);
|
||||
triple.setVendor (llvm::Triple::Apple);
|
||||
triple.setOS (llvm::Triple::Darwin);
|
||||
ArchSpec arch_spec (triple);
|
||||
ProcessMacOSX::AddArchCreateCallback(arch_spec, MachThreadContext_x86_64::Create);
|
||||
}
|
||||
|
||||
// Instance init function
|
||||
void
|
||||
MachThreadContext_x86_64::InitializeInstance()
|
||||
{
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx != NULL);
|
||||
m_flags_reg = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
|
||||
}
|
||||
|
||||
void
|
||||
MachThreadContext_x86_64::ThreadWillResume()
|
||||
{
|
||||
m_thread.GetRegisterContext()->HardwareSingleStep (m_thread.GetState() == eStateStepping);
|
||||
}
|
||||
|
||||
bool
|
||||
MachThreadContext_x86_64::ShouldStop()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
MachThreadContext_x86_64::RefreshStateAfterStop()
|
||||
{
|
||||
m_thread.GetRegisterContext()->HardwareSingleStep (false);
|
||||
}
|
||||
|
||||
bool
|
||||
MachThreadContext_x86_64::NotifyException(MachException::Data& exc)
|
||||
{
|
||||
switch (exc.exc_type)
|
||||
{
|
||||
case EXC_BAD_ACCESS:
|
||||
break;
|
||||
case EXC_BAD_INSTRUCTION:
|
||||
break;
|
||||
case EXC_ARITHMETIC:
|
||||
break;
|
||||
case EXC_EMULATION:
|
||||
break;
|
||||
case EXC_SOFTWARE:
|
||||
break;
|
||||
case EXC_BREAKPOINT:
|
||||
if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2)
|
||||
{
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx);
|
||||
lldb::addr_t pc = reg_ctx->GetPC(LLDB_INVALID_ADDRESS);
|
||||
if (pc != LLDB_INVALID_ADDRESS && pc > 0)
|
||||
{
|
||||
pc -= 1;
|
||||
reg_ctx->SetPC(pc);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case EXC_SYSCALL:
|
||||
break;
|
||||
case EXC_MACH_SYSCALL:
|
||||
break;
|
||||
case EXC_RPC_ALERT:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Set the single step bit in the processor status register.
|
||||
//kern_return_t
|
||||
//MachThreadContext_x86_64::EnableHardwareSingleStep (bool enable)
|
||||
//{
|
||||
// RegisterContext *reg_ctx = m_thread.GetRegisterContext();
|
||||
// assert (reg_ctx);
|
||||
// Scalar rflags_scalar;
|
||||
//
|
||||
// if (reg_ctx->ReadRegisterValue (m_flags_reg, rflags_scalar))
|
||||
// {
|
||||
// Flags rflags(rflags_scalar.UInt());
|
||||
// const uint32_t trace_bit = 0x100u;
|
||||
// if (enable)
|
||||
// {
|
||||
// // If the trace bit is already set, there is nothing to do
|
||||
// if (rflags.IsSet (trace_bit))
|
||||
// return KERN_SUCCESS;
|
||||
// else
|
||||
// rflags.Set (trace_bit);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // If the trace bit is already cleared, there is nothing to do
|
||||
// if (rflags.IsClear (trace_bit))
|
||||
// return KERN_SUCCESS;
|
||||
// else
|
||||
// rflags.Clear(trace_bit);
|
||||
// }
|
||||
//
|
||||
// rflags_scalar = rflags.Get();
|
||||
// // If the code makes it here we have changes to the GPRs which
|
||||
// // we need to write back out, so lets do that.
|
||||
// if (reg_ctx->WriteRegisterValue(m_flags_reg, rflags_scalar))
|
||||
// return KERN_SUCCESS;
|
||||
// }
|
||||
// // Return the error code for reading the GPR registers back
|
||||
// return KERN_INVALID_ARGUMENT;
|
||||
//}
|
||||
//
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Register information defintions for 32 bit PowerPC.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
RegisterContextSP
|
||||
MachThreadContext_x86_64::CreateRegisterContext (StackFrame *frame) const
|
||||
{
|
||||
lldb::RegisterContextSP reg_ctx_sp (new RegisterContextMach_x86_64(m_thread, frame->GetConcreteFrameIndex()));
|
||||
return reg_ctx_sp;
|
||||
}
|
||||
|
||||
|
||||
//bool
|
||||
//MachThreadContext_x86_64::RegisterSetStateIsValid (uint32_t set) const
|
||||
//{
|
||||
// return m_state.RegisterSetIsCached(set);
|
||||
//}
|
||||
|
||||
|
||||
size_t
|
||||
MachThreadContext_x86_64::GetStackFrameData(StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
|
||||
{
|
||||
fp_pc_pairs.clear();
|
||||
|
||||
std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
|
||||
|
||||
struct Frame_x86_64
|
||||
{
|
||||
uint64_t fp;
|
||||
uint64_t pc;
|
||||
};
|
||||
|
||||
RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
|
||||
assert (reg_ctx);
|
||||
|
||||
Frame_x86_64 frame = { reg_ctx->GetFP(0), reg_ctx->GetPC(LLDB_INVALID_ADDRESS) };
|
||||
|
||||
fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
|
||||
Error error;
|
||||
const size_t k_frame_size = sizeof(frame);
|
||||
while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
|
||||
{
|
||||
// Read both the FP and PC (16 bytes)
|
||||
if (m_thread.GetProcess().ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
|
||||
break;
|
||||
|
||||
if (frame.pc >= 0x1000)
|
||||
fp_pc_pairs.push_back(std::make_pair(frame.fp, frame.pc));
|
||||
}
|
||||
if (!fp_pc_pairs.empty())
|
||||
{
|
||||
lldb::addr_t first_frame_pc = fp_pc_pairs.front().second;
|
||||
if (first_frame_pc != LLDB_INVALID_ADDRESS)
|
||||
{
|
||||
const uint32_t resolve_scope = eSymbolContextModule |
|
||||
eSymbolContextCompUnit |
|
||||
eSymbolContextFunction |
|
||||
eSymbolContextSymbol;
|
||||
|
||||
SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
|
||||
const AddressRange *addr_range_ptr = NULL;
|
||||
if (first_frame_sc.function)
|
||||
addr_range_ptr = &first_frame_sc.function->GetAddressRange();
|
||||
else if (first_frame_sc.symbol)
|
||||
addr_range_ptr = first_frame_sc.symbol->GetAddressRangePtr();
|
||||
|
||||
if (addr_range_ptr)
|
||||
{
|
||||
if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
|
||||
{
|
||||
// We are at the first instruction, so we can recover the
|
||||
// previous PC by dereferencing the SP
|
||||
lldb::addr_t first_frame_sp = reg_ctx->GetSP(0);
|
||||
// Read the real second frame return address into frame.pc
|
||||
if (m_thread.GetProcess().ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
|
||||
{
|
||||
// Construct a correct second frame (we already read the pc for it above
|
||||
frame.fp = fp_pc_pairs.front().first;
|
||||
|
||||
// Insert the frame
|
||||
fp_pc_pairs.insert(fp_pc_pairs.begin()+1, std::make_pair(frame.fp, frame.pc));
|
||||
|
||||
// Correct the fp in the first frame to use the SP
|
||||
fp_pc_pairs.front().first = first_frame_sp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fp_pc_pairs.size();
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined (__i386__) || defined (__x86_64__)
|
|
@ -1,69 +0,0 @@
|
|||
//===-- MachThreadContext_x86_64.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachThreadContext_x86_64_h_
|
||||
#define liblldb_MachThreadContext_x86_64_h_
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
|
||||
#include "MachThreadContext.h"
|
||||
#include "RegisterContextMach_x86_64.h"
|
||||
|
||||
class ThreadMacOSX;
|
||||
|
||||
class MachThreadContext_x86_64 : public MachThreadContext
|
||||
{
|
||||
public:
|
||||
static MachThreadContext*
|
||||
Create(const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
|
||||
|
||||
// Class init function
|
||||
static void
|
||||
Initialize();
|
||||
|
||||
// Instance init function
|
||||
void
|
||||
InitializeInstance();
|
||||
|
||||
MachThreadContext_x86_64 (ThreadMacOSX &thread);
|
||||
|
||||
virtual
|
||||
~MachThreadContext_x86_64();
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContext (lldb_private::StackFrame *frame) const;
|
||||
|
||||
virtual void
|
||||
ThreadWillResume ();
|
||||
|
||||
virtual bool
|
||||
ShouldStop ();
|
||||
|
||||
virtual void
|
||||
RefreshStateAfterStop ();
|
||||
|
||||
virtual bool
|
||||
NotifyException (MachException::Data& exc);
|
||||
|
||||
virtual size_t
|
||||
GetStackFrameData (lldb_private::StackFrame *first_frame, std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
|
||||
|
||||
protected:
|
||||
// kern_return_t EnableHardwareSingleStep (bool enable);
|
||||
uint32_t m_flags_reg;
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN (MachThreadContext_x86_64);
|
||||
};
|
||||
|
||||
//#if defined (__x86_64__)
|
||||
//typedef MachThreadContext_x86_64 DNBArch;
|
||||
//#endif
|
||||
|
||||
#endif // defined (__i386__) || defined (__x86_64__)
|
||||
#endif // #ifndef liblldb_MachThreadContext_x86_64_h_
|
|
@ -1,196 +0,0 @@
|
|||
//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MachVMMemory.h"
|
||||
|
||||
#include <mach/mach_vm.h>
|
||||
|
||||
#include "MachVMRegion.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
MachVMMemory::MachVMMemory() :
|
||||
m_page_size (kInvalidPageSize)
|
||||
{
|
||||
}
|
||||
|
||||
MachVMMemory::~MachVMMemory()
|
||||
{
|
||||
}
|
||||
|
||||
size_t
|
||||
MachVMMemory::PageSize(lldb_private::Error &error)
|
||||
{
|
||||
if (m_page_size == kInvalidPageSize)
|
||||
{
|
||||
error = ::host_page_size( ::mach_host_self(), &m_page_size);
|
||||
if (error.Fail())
|
||||
m_page_size = 0;
|
||||
}
|
||||
|
||||
if (m_page_size != 0 && m_page_size != kInvalidPageSize)
|
||||
{
|
||||
if (error.Success())
|
||||
error.SetErrorString ("unable to determine page size");
|
||||
}
|
||||
return m_page_size;
|
||||
}
|
||||
|
||||
size_t
|
||||
MachVMMemory::MaxBytesLeftInPage (lldb::addr_t addr, size_t count)
|
||||
{
|
||||
Error error;
|
||||
const size_t page_size = PageSize(error);
|
||||
if (page_size > 0)
|
||||
{
|
||||
size_t page_offset = (addr % page_size);
|
||||
size_t bytes_left_in_page = page_size - page_offset;
|
||||
if (count > bytes_left_in_page)
|
||||
count = bytes_left_in_page;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
MachVMMemory::Read(task_t task, lldb::addr_t address, void *data, size_t data_count, Error &error)
|
||||
{
|
||||
if (data == NULL || data_count == 0)
|
||||
return 0;
|
||||
|
||||
size_t total_bytes_read = 0;
|
||||
lldb::addr_t curr_addr = address;
|
||||
uint8_t *curr_data = (uint8_t*)data;
|
||||
while (total_bytes_read < data_count)
|
||||
{
|
||||
mach_vm_size_t curr_size = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_read);
|
||||
mach_msg_type_number_t curr_bytes_read = 0;
|
||||
vm_offset_t vm_memory = NULL;
|
||||
error = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY|PD_LOG_VERBOSE));
|
||||
|
||||
if (log || error.Fail())
|
||||
error.PutToLog (log.get(), "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i)", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
|
||||
|
||||
if (error.Success())
|
||||
{
|
||||
if (curr_bytes_read != curr_size)
|
||||
{
|
||||
if (log)
|
||||
error.PutToLog (log.get(), "::mach_vm_read (task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
|
||||
}
|
||||
::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
|
||||
::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
|
||||
total_bytes_read += curr_bytes_read;
|
||||
curr_addr += curr_bytes_read;
|
||||
curr_data += curr_bytes_read;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_bytes_read;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
MachVMMemory::Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, Error &error)
|
||||
{
|
||||
MachVMRegion vmRegion(task);
|
||||
|
||||
size_t total_bytes_written = 0;
|
||||
lldb::addr_t curr_addr = address;
|
||||
const uint8_t *curr_data = (const uint8_t*)data;
|
||||
|
||||
|
||||
while (total_bytes_written < data_count)
|
||||
{
|
||||
if (vmRegion.GetRegionForAddress(curr_addr))
|
||||
{
|
||||
mach_vm_size_t curr_data_count = data_count - total_bytes_written;
|
||||
mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
|
||||
if (region_bytes_left == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (curr_data_count > region_bytes_left)
|
||||
curr_data_count = region_bytes_left;
|
||||
|
||||
if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
|
||||
{
|
||||
size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count, error);
|
||||
if (bytes_written <= 0)
|
||||
{
|
||||
// Error should have already be posted by WriteRegion...
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
total_bytes_written += bytes_written;
|
||||
curr_addr += bytes_written;
|
||||
curr_data += bytes_written;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMacOSXLog::LogIf (PD_LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return total_bytes_written;
|
||||
}
|
||||
|
||||
|
||||
size_t
|
||||
MachVMMemory::WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, Error &error)
|
||||
{
|
||||
if (data == NULL || data_count == 0)
|
||||
return 0;
|
||||
|
||||
size_t total_bytes_written = 0;
|
||||
lldb::addr_t curr_addr = address;
|
||||
const uint8_t *curr_data = (const uint8_t*)data;
|
||||
while (total_bytes_written < data_count)
|
||||
{
|
||||
mach_msg_type_number_t curr_data_count = MaxBytesLeftInPage(curr_addr, data_count - total_bytes_written);
|
||||
error = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY));
|
||||
if (log || error.Fail())
|
||||
error.PutToLog (log.get(), "::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
|
||||
|
||||
#if defined (__powerpc__) || defined (__ppc__)
|
||||
vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
|
||||
|
||||
error = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
|
||||
if (log || error.Fail())
|
||||
error.Log(log.get(), "::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
|
||||
#endif
|
||||
|
||||
if (error.Success())
|
||||
{
|
||||
total_bytes_written += curr_data_count;
|
||||
curr_addr += curr_data_count;
|
||||
curr_data += curr_data_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_bytes_written;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
//===-- MachVMMemory.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachVMMemory_h_
|
||||
#define liblldb_MachVMMemory_h_
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
|
||||
class MachVMMemory
|
||||
{
|
||||
public:
|
||||
enum { kInvalidPageSize = ~0 };
|
||||
MachVMMemory();
|
||||
~MachVMMemory();
|
||||
size_t Read(task_t task, lldb::addr_t address, void *data, size_t data_count, lldb_private::Error &error);
|
||||
size_t Write(task_t task, lldb::addr_t address, const void *data, size_t data_count, lldb_private::Error &error);
|
||||
size_t PageSize(lldb_private::Error &error);
|
||||
|
||||
protected:
|
||||
size_t MaxBytesLeftInPage(lldb::addr_t addr, size_t count);
|
||||
|
||||
size_t WriteRegion(task_t task, const lldb::addr_t address, const void *data, const size_t data_count, lldb_private::Error &error);
|
||||
vm_size_t m_page_size;
|
||||
};
|
||||
|
||||
|
||||
#endif // #ifndef liblldb_MachVMMemory_h_
|
|
@ -1,184 +0,0 @@
|
|||
//===-- MachVMRegion.cpp ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <assert.h>
|
||||
#include <mach/mach_vm.h>
|
||||
#include "MachVMRegion.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
MachVMRegion::MachVMRegion(task_t task) :
|
||||
m_task(task),
|
||||
m_addr(LLDB_INVALID_ADDRESS),
|
||||
m_err(),
|
||||
m_start(LLDB_INVALID_ADDRESS),
|
||||
m_size(0),
|
||||
m_depth(-1),
|
||||
m_data(),
|
||||
m_curr_protection(0),
|
||||
m_protection_addr(LLDB_INVALID_ADDRESS),
|
||||
m_protection_size(0)
|
||||
{
|
||||
memset(&m_data, 0, sizeof(m_data));
|
||||
}
|
||||
|
||||
MachVMRegion::~MachVMRegion()
|
||||
{
|
||||
// Restore any original protections and clear our vars
|
||||
Clear();
|
||||
}
|
||||
|
||||
void
|
||||
MachVMRegion::Clear()
|
||||
{
|
||||
RestoreProtections();
|
||||
m_addr = LLDB_INVALID_ADDRESS;
|
||||
m_err.Clear();
|
||||
m_start = LLDB_INVALID_ADDRESS;
|
||||
m_size = 0;
|
||||
m_depth = -1;
|
||||
memset(&m_data, 0, sizeof(m_data));
|
||||
m_curr_protection = 0;
|
||||
m_protection_addr = LLDB_INVALID_ADDRESS;
|
||||
m_protection_size = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot)
|
||||
{
|
||||
if (ContainsAddress(addr))
|
||||
{
|
||||
mach_vm_size_t prot_size = size;
|
||||
mach_vm_address_t end_addr = EndAddress();
|
||||
if (prot_size > (end_addr - addr))
|
||||
prot_size = end_addr - addr;
|
||||
|
||||
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS));
|
||||
if (prot_size > 0)
|
||||
{
|
||||
if (prot == (m_curr_protection & VM_PROT_ALL))
|
||||
{
|
||||
if (log)
|
||||
log->Printf ("MachVMRegion::%s: protections (%u) already sufficient for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, prot, m_task, (uint64_t)addr);
|
||||
// Protections are already set as requested...
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot);
|
||||
if (log || m_err.Fail())
|
||||
m_err.PutToLog(log.get(), "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot);
|
||||
if (m_err.Fail())
|
||||
{
|
||||
// Try again with the ability to create a copy on write region
|
||||
m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot | VM_PROT_COPY);
|
||||
if (log || m_err.Fail())
|
||||
m_err.PutToLog(log.get(), "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot | VM_PROT_COPY);
|
||||
}
|
||||
if (m_err.Success())
|
||||
{
|
||||
m_curr_protection = prot;
|
||||
m_protection_addr = addr;
|
||||
m_protection_size = prot_size;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log->Printf("MachVMRegion::%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, m_task, (uint64_t)addr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MachVMRegion::RestoreProtections()
|
||||
{
|
||||
if (m_curr_protection != m_data.protection && m_protection_size > 0)
|
||||
{
|
||||
m_err = ::mach_vm_protect (m_task, m_protection_addr, m_protection_size, 0, m_data.protection);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS));
|
||||
if (log || m_err.Fail())
|
||||
m_err.PutToLog(log.get(), "::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)m_protection_addr, (uint64_t)m_protection_size, 0, m_data.protection);
|
||||
if (m_err.Success())
|
||||
{
|
||||
m_protection_size = 0;
|
||||
m_protection_addr = LLDB_INVALID_ADDRESS;
|
||||
m_curr_protection = m_data.protection;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_err.Clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
MachVMRegion::GetRegionForAddress(lldb::addr_t addr)
|
||||
{
|
||||
// Restore any original protections and clear our vars
|
||||
Clear();
|
||||
m_addr = addr;
|
||||
m_start = addr;
|
||||
m_depth = 1024;
|
||||
mach_msg_type_number_t info_size = kRegionInfoSize;
|
||||
assert(sizeof(info_size) == 4);
|
||||
m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size);
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet (PD_LOG_MEMORY_PROTECTIONS));
|
||||
if (log || m_err.Fail())
|
||||
m_err.PutToLog(log.get(), "::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr);
|
||||
if (m_err.Fail())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE))
|
||||
{
|
||||
log->Printf("info = { prot = %u, "
|
||||
"max_prot = %u, "
|
||||
"inheritance = 0x%8.8x, "
|
||||
"offset = 0x%8.8llx, "
|
||||
"user_tag = 0x%8.8x, "
|
||||
"ref_count = %u, "
|
||||
"shadow_depth = %u, "
|
||||
"ext_pager = %u, "
|
||||
"share_mode = %u, "
|
||||
"is_submap = %d, "
|
||||
"behavior = %d, "
|
||||
"object_id = 0x%8.8x, "
|
||||
"user_wired_count = 0x%4.4x }",
|
||||
m_data.protection,
|
||||
m_data.max_protection,
|
||||
m_data.inheritance,
|
||||
(uint64_t)m_data.offset,
|
||||
m_data.user_tag,
|
||||
m_data.ref_count,
|
||||
m_data.shadow_depth,
|
||||
m_data.external_pager,
|
||||
m_data.share_mode,
|
||||
m_data.is_submap,
|
||||
m_data.behavior,
|
||||
m_data.object_id,
|
||||
m_data.user_wired_count);
|
||||
}
|
||||
}
|
||||
|
||||
m_curr_protection = m_data.protection;
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
//===-- MachVMRegion.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MachVMRegion_h_
|
||||
#define liblldb_MachVMRegion_h_
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include "lldb/lldb-private.h"
|
||||
#include "lldb/Core/Error.h"
|
||||
|
||||
class MachVMRegion
|
||||
{
|
||||
public:
|
||||
MachVMRegion(task_t task);
|
||||
~MachVMRegion();
|
||||
|
||||
void Clear();
|
||||
mach_vm_address_t StartAddress() const { return m_start; }
|
||||
mach_vm_address_t EndAddress() const { return m_start + m_size; }
|
||||
mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const
|
||||
{
|
||||
if (ContainsAddress(addr))
|
||||
return m_size - (addr - m_start);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
bool ContainsAddress(mach_vm_address_t addr) const
|
||||
{
|
||||
return addr >= StartAddress() && addr < EndAddress();
|
||||
}
|
||||
|
||||
bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot);
|
||||
bool RestoreProtections();
|
||||
bool GetRegionForAddress(lldb::addr_t addr);
|
||||
protected:
|
||||
#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64)
|
||||
typedef vm_region_submap_short_info_data_64_t RegionInfo;
|
||||
enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
|
||||
#else
|
||||
typedef vm_region_submap_info_data_64_t RegionInfo;
|
||||
enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 };
|
||||
#endif
|
||||
|
||||
task_t m_task;
|
||||
mach_vm_address_t m_addr;
|
||||
lldb_private::Error m_err;
|
||||
mach_vm_address_t m_start;
|
||||
mach_vm_size_t m_size;
|
||||
natural_t m_depth;
|
||||
RegionInfo m_data;
|
||||
vm_prot_t m_curr_protection; // The current, possibly modified protections. Original value is saved in m_data.protections.
|
||||
mach_vm_address_t m_protection_addr; // The start address at which protections were changed
|
||||
mach_vm_size_t m_protection_size; // The size of memory that had its protections changed
|
||||
|
||||
};
|
||||
|
||||
#endif // #ifndef liblldb_MachVMRegion_h_
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* nub.defs
|
||||
*/
|
||||
|
||||
/*
|
||||
* DNBConfig.h is autogenerated by a perl script that is run as a build
|
||||
* script in XCode. XCode is responsible for calling the script and setting
|
||||
* the include paths correctly to locate it. The file will exist in the
|
||||
* derived sources directory in the build folder.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "DNBConfig.h"
|
||||
|
||||
|
||||
#include <mach/mach_exc.defs>
|
File diff suppressed because it is too large
Load Diff
|
@ -1,480 +0,0 @@
|
|||
//===-- ProcessMacOSX.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_MacOSXProcess_H_
|
||||
#define liblldb_MacOSXProcess_H_
|
||||
|
||||
// C Includes
|
||||
|
||||
// C++ Includes
|
||||
#include <list>
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/ThreadSafeValue.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
// Project includes
|
||||
#include "MacOSX/MachTask.h"
|
||||
#include "MacOSX/MachException.h"
|
||||
|
||||
typedef enum PDLaunch
|
||||
{
|
||||
eLaunchDefault = 0,
|
||||
eLaunchPosixSpawn,
|
||||
eLaunchForkExec,
|
||||
#if defined (__arm__)
|
||||
eLaunchSpringBoard,
|
||||
#endif
|
||||
kNumPDLaunchTypes
|
||||
} PDLaunchType;
|
||||
|
||||
|
||||
|
||||
class ThreadMacOSX;
|
||||
class MachThreadContext;
|
||||
|
||||
class ProcessMacOSX :
|
||||
public lldb_private::Process
|
||||
{
|
||||
public:
|
||||
friend class ThreadMacOSX;
|
||||
friend class MachTask;
|
||||
|
||||
typedef MachThreadContext* (*CreateArchCalback) (const lldb_private::ArchSpec &arch_spec, ThreadMacOSX &thread);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
static Process*
|
||||
CreateInstance (lldb_private::Target& target, lldb_private::Listener &listener);
|
||||
|
||||
static void
|
||||
Initialize();
|
||||
|
||||
static void
|
||||
Terminate();
|
||||
|
||||
static const char *
|
||||
GetPluginNameStatic();
|
||||
|
||||
static const char *
|
||||
GetPluginDescriptionStatic();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
ProcessMacOSX(lldb_private::Target& target, lldb_private::Listener &listener);
|
||||
|
||||
virtual
|
||||
~ProcessMacOSX();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Check if a given Process
|
||||
//------------------------------------------------------------------
|
||||
virtual bool
|
||||
CanDebug (lldb_private::Target &target,
|
||||
bool plugin_specified_by_name);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Creating a new process, or attaching to an existing one
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb_private::Error
|
||||
WillLaunch (lldb_private::Module* module);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoLaunch (lldb_private::Module* module,
|
||||
char const *argv[], // Can be NULL
|
||||
char const *envp[], // Can be NULL
|
||||
uint32_t launch_flags,
|
||||
const char *stdin_path, // Can be NULL
|
||||
const char *stdout_path, // Can be NULL
|
||||
const char *stderr_path, // Can be NULL
|
||||
const char *working_dir); // Can be NULL
|
||||
|
||||
virtual void
|
||||
DidLaunch ();
|
||||
|
||||
virtual lldb_private::Error
|
||||
WillAttachToProcessWithID (lldb::pid_t pid);
|
||||
|
||||
virtual lldb_private::Error
|
||||
WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoAttachToProcessWithID (lldb::pid_t pid);
|
||||
|
||||
virtual void
|
||||
DidAttach ();
|
||||
|
||||
// virtual uint32_t
|
||||
// ListProcessesMatchingName (const char *name, lldb_private::StringList &matches, std::vector<lldb::pid_t> &pids);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// PluginInterface protocol
|
||||
//------------------------------------------------------------------
|
||||
virtual const char *
|
||||
GetPluginName();
|
||||
|
||||
virtual const char *
|
||||
GetShortPluginName();
|
||||
|
||||
virtual uint32_t
|
||||
GetPluginVersion();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Control
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb_private::Error
|
||||
DoResume ();
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoHalt (bool &caused_stop);
|
||||
|
||||
virtual lldb_private::Error
|
||||
WillDetach ();
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoDetach ();
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoSignal (int signal);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoDestroy ();
|
||||
|
||||
virtual void
|
||||
RefreshStateAfterStop();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Queries
|
||||
//------------------------------------------------------------------
|
||||
virtual bool
|
||||
IsAlive ();
|
||||
|
||||
virtual lldb::addr_t
|
||||
GetImageInfoAddress();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Memory
|
||||
//------------------------------------------------------------------
|
||||
virtual size_t
|
||||
DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
|
||||
|
||||
virtual size_t
|
||||
DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
|
||||
|
||||
virtual lldb::addr_t
|
||||
DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DoDeallocateMemory (lldb::addr_t ptr);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process STDIO
|
||||
//------------------------------------------------------------------
|
||||
virtual size_t
|
||||
GetSTDOUT (char *buf, size_t buf_size, lldb_private::Error &error);
|
||||
|
||||
virtual size_t
|
||||
GetSTDERR (char *buf, size_t buf_size, lldb_private::Error &error);
|
||||
|
||||
virtual size_t
|
||||
PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Process Breakpoints
|
||||
//----------------------------------------------------------------------
|
||||
virtual lldb_private::Error
|
||||
EnableBreakpoint (lldb_private::BreakpointSite *bp_site);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DisableBreakpoint (lldb_private::BreakpointSite *bp_site);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Process Watchpoints
|
||||
//----------------------------------------------------------------------
|
||||
virtual lldb_private::Error
|
||||
EnableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
|
||||
|
||||
virtual lldb_private::Error
|
||||
DisableWatchpoint (lldb_private::WatchpointLocation *wp_loc);
|
||||
|
||||
static void
|
||||
AddArchCreateCallback(const lldb_private::ArchSpec& arch_spec,
|
||||
ProcessMacOSX::CreateArchCalback callback);
|
||||
|
||||
protected:
|
||||
|
||||
bool m_stdio_ours; // True if we created and own the child STDIO file handles, false if they were supplied to us and owned by someone else
|
||||
int m_child_stdin;
|
||||
int m_child_stdout;
|
||||
int m_child_stderr;
|
||||
MachTask m_task; // The mach task for this process
|
||||
lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
|
||||
lldb::thread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio
|
||||
lldb::thread_t m_monitor_thread; // Thread ID for the thread that watches for child process stdio
|
||||
lldb_private::Mutex m_stdio_mutex; // Multithreaded protection for stdio
|
||||
std::string m_stdout_data;
|
||||
MachException::Message::collection m_exception_messages; // A collection of exception messages caught when listening to the exception port
|
||||
lldb_private::Mutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages
|
||||
lldb_private::ArchSpec m_arch_spec;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Child process control
|
||||
//----------------------------------------------------------------------
|
||||
lldb::pid_t
|
||||
LaunchForDebug (const char *path,
|
||||
char const *argv[],
|
||||
char const *envp[],
|
||||
lldb_private::ArchSpec& arch_spec,
|
||||
const char *stdin_path,
|
||||
const char *stdout_path,
|
||||
const char *stderr_path,
|
||||
PDLaunchType launch_type,
|
||||
uint32_t flags,
|
||||
lldb_private::Error &launch_err);
|
||||
|
||||
static lldb::pid_t
|
||||
ForkChildForPTraceDebugging (const char *path,
|
||||
char const *argv[],
|
||||
char const *envp[],
|
||||
lldb_private::ArchSpec& arch_spec,
|
||||
const char *stdin_path,
|
||||
const char *stdout_path,
|
||||
const char *stderr_path,
|
||||
ProcessMacOSX* process,
|
||||
lldb_private::Error &launch_err);
|
||||
|
||||
static lldb::pid_t
|
||||
PosixSpawnChildForPTraceDebugging (const char *path,
|
||||
char const *argv[],
|
||||
char const *envp[],
|
||||
lldb_private::ArchSpec& arch_spec,
|
||||
const char *stdin_path,
|
||||
const char *stdout_path,
|
||||
const char *stderr_path,
|
||||
ProcessMacOSX* process,
|
||||
int disable_aslr,
|
||||
lldb_private::Error &launch_err);
|
||||
|
||||
#if defined (__arm__)
|
||||
lldb::pid_t
|
||||
SBLaunchForDebug (const char *path,
|
||||
char const *argv[],
|
||||
char const *envp[],
|
||||
lldb_private::ArchSpec& arch_spec,
|
||||
const char *stdin_path,
|
||||
const char *stdout_path,
|
||||
const char *stderr_path,
|
||||
lldb_private::Error &launch_err);
|
||||
|
||||
static lldb::pid_t
|
||||
SBLaunchForDebug (const char *path,
|
||||
char const *argv[],
|
||||
char const *envp[],
|
||||
lldb_private::ArchSpec& arch_spec,
|
||||
const char *stdin_path,
|
||||
const char *stdout_path,
|
||||
const char *stderr_path,
|
||||
ProcessMacOSX* process,
|
||||
lldb_private::Error &launch_err);
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Exception thread functions
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
StartSTDIOThread ();
|
||||
|
||||
void
|
||||
StopSTDIOThread (bool close_child_fds);
|
||||
|
||||
static void *
|
||||
STDIOThread (void *arg);
|
||||
|
||||
void
|
||||
ExceptionMessageReceived (const MachException::Message& exceptionMessage);
|
||||
|
||||
void
|
||||
ExceptionMessageBundleComplete ();
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Accessors
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
ProcessIDIsValid ( ) const;
|
||||
|
||||
MachTask&
|
||||
Task() { return m_task; }
|
||||
|
||||
const MachTask&
|
||||
Task() const { return m_task; }
|
||||
|
||||
bool
|
||||
IsRunning ( lldb::StateType state )
|
||||
{
|
||||
return state == lldb::eStateRunning || IsStepping(state);
|
||||
}
|
||||
|
||||
bool
|
||||
IsStepping ( lldb::StateType state)
|
||||
{
|
||||
return state == lldb::eStateStepping;
|
||||
}
|
||||
bool
|
||||
CanResume ( lldb::StateType state)
|
||||
{
|
||||
return state == lldb::eStateStopped;
|
||||
}
|
||||
|
||||
bool
|
||||
HasExited (lldb::StateType state)
|
||||
{
|
||||
return state == lldb::eStateExited;
|
||||
}
|
||||
|
||||
void
|
||||
SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno)
|
||||
{
|
||||
m_child_stdin = stdin_fileno;
|
||||
m_child_stdout = stdout_fileno;
|
||||
m_child_stderr = stderr_fileno;
|
||||
}
|
||||
|
||||
int
|
||||
GetStdinFileDescriptor () const
|
||||
{
|
||||
return m_child_stdin;
|
||||
}
|
||||
|
||||
int
|
||||
GetStdoutFileDescriptor () const
|
||||
{
|
||||
return m_child_stdout;
|
||||
}
|
||||
int
|
||||
GetStderrFileDescriptor () const
|
||||
{
|
||||
return m_child_stderr;
|
||||
}
|
||||
bool
|
||||
ReleaseChildFileDescriptors ( int *stdin_fileno, int *stdout_fileno, int *stderr_fileno );
|
||||
|
||||
void
|
||||
AppendSTDOUT (const char* s, size_t len);
|
||||
|
||||
void
|
||||
CloseChildFileDescriptors ()
|
||||
{
|
||||
if (m_child_stdin >= 0)
|
||||
{
|
||||
::close (m_child_stdin);
|
||||
m_child_stdin = -1;
|
||||
}
|
||||
if (m_child_stdout >= 0)
|
||||
{
|
||||
::close (m_child_stdout);
|
||||
m_child_stdout = -1;
|
||||
}
|
||||
if (m_child_stderr >= 0)
|
||||
{
|
||||
::close (m_child_stderr);
|
||||
m_child_stderr = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ProcessUsingSpringBoard() const
|
||||
{
|
||||
return m_flags.Test (eFlagsUsingSBS);
|
||||
}
|
||||
|
||||
lldb_private::ArchSpec&
|
||||
GetArchSpec()
|
||||
{
|
||||
return m_arch_spec;
|
||||
}
|
||||
const lldb_private::ArchSpec&
|
||||
GetArchSpec() const
|
||||
{
|
||||
return m_arch_spec;
|
||||
}
|
||||
|
||||
CreateArchCalback
|
||||
GetArchCreateCallback();
|
||||
|
||||
enum
|
||||
{
|
||||
eFlagsNone = 0,
|
||||
eFlagsAttached = (1 << 0),
|
||||
eFlagsUsingSBS = (1 << 1)
|
||||
};
|
||||
|
||||
void
|
||||
Clear ( );
|
||||
|
||||
lldb_private::Error
|
||||
ReplyToAllExceptions();
|
||||
|
||||
lldb_private::Error
|
||||
PrivateResume ( lldb::tid_t tid);
|
||||
|
||||
lldb_private::Flags &
|
||||
GetFlags ()
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
const lldb_private::Flags &
|
||||
GetFlags () const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
bool
|
||||
STDIOIsOurs() const
|
||||
{
|
||||
return m_stdio_ours;
|
||||
}
|
||||
|
||||
void
|
||||
SetSTDIOIsOurs(bool b)
|
||||
{
|
||||
m_stdio_ours = b;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
UpdateThreadListIfNeeded ();
|
||||
|
||||
private:
|
||||
|
||||
void
|
||||
DidLaunchOrAttach ();
|
||||
|
||||
lldb_private::Error
|
||||
DoSIGSTOP (bool clear_all_breakpoints);
|
||||
|
||||
lldb_private::Error
|
||||
WillLaunchOrAttach ();
|
||||
|
||||
// static void *
|
||||
// WaitForChildProcessToExit (void *pid_ptr);
|
||||
//
|
||||
//
|
||||
//------------------------------------------------------------------
|
||||
// For ProcessMacOSX only
|
||||
//------------------------------------------------------------------
|
||||
DISALLOW_COPY_AND_ASSIGN (ProcessMacOSX);
|
||||
|
||||
};
|
||||
|
||||
#endif // liblldb_MacOSXProcess_H_
|
|
@ -1,175 +0,0 @@
|
|||
//===-- ProcessMacOSXLog.cpp ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
|
||||
#include "ProcessMacOSX.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
// We want to avoid global constructors where code needs to be run so here we
|
||||
// control access to our static g_log_sp by hiding it in a singleton function
|
||||
// that will construct the static g_lob_sp the first time this function is
|
||||
// called.
|
||||
static LogSP &
|
||||
GetLog ()
|
||||
{
|
||||
static LogSP g_log_sp;
|
||||
return g_log_sp;
|
||||
}
|
||||
|
||||
LogSP
|
||||
ProcessMacOSXLog::GetLogIfAllCategoriesSet (uint32_t mask)
|
||||
{
|
||||
LogSP log(GetLog ());
|
||||
if (log && mask)
|
||||
{
|
||||
uint32_t log_mask = log->GetMask().Get();
|
||||
if ((log_mask & mask) != mask)
|
||||
return LogSP();
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessMacOSXLog::DisableLog (Args &args, Stream *feedback_strm)
|
||||
{
|
||||
LogSP log (GetLog ());
|
||||
if (log)
|
||||
{
|
||||
uint32_t flag_bits = 0;
|
||||
const size_t argc = args.GetArgumentCount ();
|
||||
if (argc > 0)
|
||||
{
|
||||
flag_bits = log->GetMask().Get();
|
||||
for (size_t i = 0; i < argc; ++i)
|
||||
{
|
||||
const char *arg = args.GetArgumentAtIndex (i);
|
||||
|
||||
if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~PD_LOG_ALL;
|
||||
else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~PD_LOG_BREAKPOINTS;
|
||||
else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~PD_LOG_DEFAULT;
|
||||
else if (::strncasecmp (arg, "exc", 3) == 0 ) flag_bits &= ~PD_LOG_EXCEPTIONS;
|
||||
else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~PD_LOG_MEMORY;
|
||||
else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~PD_LOG_MEMORY_DATA_SHORT;
|
||||
else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~PD_LOG_MEMORY_DATA_LONG;
|
||||
else if (::strcasecmp (arg, "protections")== 0 ) flag_bits &= ~PD_LOG_PROCESS;
|
||||
else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~PD_LOG_STEP;
|
||||
else if (::strcasecmp (arg, "task") == 0 ) flag_bits &= ~PD_LOG_TASK;
|
||||
else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~PD_LOG_THREAD;
|
||||
else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~PD_LOG_VERBOSE;
|
||||
else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~PD_LOG_WATCHPOINTS;
|
||||
else
|
||||
{
|
||||
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
|
||||
ListLogCategories (feedback_strm);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag_bits == 0)
|
||||
GetLog().reset();
|
||||
else
|
||||
log->GetMask().Reset (flag_bits);
|
||||
}
|
||||
}
|
||||
|
||||
LogSP
|
||||
ProcessMacOSXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, Args &args, Stream *feedback_strm)
|
||||
{
|
||||
// Try see if there already is a log - that way we can reuse its settings.
|
||||
// We could reuse the log in toto, but we don't know that the stream is the same.
|
||||
uint32_t flag_bits = 0;
|
||||
LogSP log(GetLog ());
|
||||
if (log)
|
||||
flag_bits = log->GetMask().Get();
|
||||
|
||||
// Now make a new log with this stream if one was provided
|
||||
if (log_stream_sp)
|
||||
{
|
||||
log = make_shared<Log>(log_stream_sp);
|
||||
GetLog () = log;
|
||||
}
|
||||
|
||||
if (log)
|
||||
{
|
||||
bool got_unknown_category = false;
|
||||
const size_t argc = args.GetArgumentCount();
|
||||
for (size_t i=0; i<argc; ++i)
|
||||
{
|
||||
const char *arg = args.GetArgumentAtIndex(i);
|
||||
|
||||
if (::strcasecmp (arg, "all") == 0 ) flag_bits |= PD_LOG_ALL;
|
||||
else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= PD_LOG_BREAKPOINTS;
|
||||
else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= PD_LOG_DEFAULT;
|
||||
else if (::strncasecmp (arg, "exc", 3) == 0 ) flag_bits |= PD_LOG_EXCEPTIONS;
|
||||
else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= PD_LOG_MEMORY;
|
||||
else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_SHORT;
|
||||
else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= PD_LOG_MEMORY_DATA_LONG;
|
||||
else if (::strcasecmp (arg, "protections")== 0 ) flag_bits |= PD_LOG_MEMORY_PROTECTIONS;
|
||||
else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= PD_LOG_PROCESS;
|
||||
else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= PD_LOG_STEP;
|
||||
else if (::strcasecmp (arg, "task") == 0 ) flag_bits |= PD_LOG_TASK;
|
||||
else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= PD_LOG_THREAD;
|
||||
else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= PD_LOG_VERBOSE;
|
||||
else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= PD_LOG_WATCHPOINTS;
|
||||
else
|
||||
{
|
||||
feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
|
||||
if (got_unknown_category == false)
|
||||
{
|
||||
got_unknown_category = true;
|
||||
ListLogCategories (feedback_strm);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (flag_bits == 0)
|
||||
flag_bits = PD_LOG_DEFAULT;
|
||||
log->GetMask().Reset(flag_bits);
|
||||
log->GetOptions().Reset(log_options);
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
void
|
||||
ProcessMacOSXLog::ListLogCategories (Stream *strm)
|
||||
{
|
||||
strm->Printf("Logging categories for '%s':\n"
|
||||
"\tall - turn on all available logging categories\n"
|
||||
"\tbreak - log breakpoints\n"
|
||||
"\tdefault - enable the default set of logging categories for liblldb\n"
|
||||
"\tmemory - log memory reads and writes\n"
|
||||
"\tdata-short - log memory bytes for memory reads and writes for short transactions only\n"
|
||||
"\tdata-long - log memory bytes for memory reads and writes for all transactions\n"
|
||||
"\tprocess - log process events and activities\n"
|
||||
"\tprotections - log memory protections\n"
|
||||
"\ttask - log mach task calls\n"
|
||||
"\tthread - log thread events and activities\n"
|
||||
"\tstep - log step related activities\n"
|
||||
"\tverbose - enable verbose logging\n"
|
||||
"\twatch - log watchpoint related activities\n", ProcessMacOSX::GetPluginNameStatic());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ProcessMacOSXLog::LogIf (uint32_t mask, const char *format, ...)
|
||||
{
|
||||
LogSP log(ProcessMacOSXLog::GetLogIfAllCategoriesSet (mask));
|
||||
if (log)
|
||||
{
|
||||
va_list args;
|
||||
va_start (args, format);
|
||||
log->VAPrintf (format, args);
|
||||
va_end (args);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
//===-- ProcessMacOSXLog.h --------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_ProcessMacOSXLog_h_
|
||||
#define liblldb_ProcessMacOSXLog_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
|
||||
// Project includes
|
||||
#include "lldb/Core/Log.h"
|
||||
|
||||
#define PD_LOG_VERBOSE (1u << 0)
|
||||
#define PD_LOG_PROCESS (1u << 1)
|
||||
#define PD_LOG_THREAD (1u << 2)
|
||||
#define PD_LOG_EXCEPTIONS (1u << 3)
|
||||
#define PD_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
|
||||
#define PD_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
|
||||
#define PD_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
|
||||
#define PD_LOG_MEMORY_PROTECTIONS (1u << 7) // Log memory protection changes
|
||||
#define PD_LOG_BREAKPOINTS (1u << 8)
|
||||
#define PD_LOG_WATCHPOINTS (1u << 9)
|
||||
#define PD_LOG_STEP (1u << 10)
|
||||
#define PD_LOG_TASK (1u << 11)
|
||||
#define PD_LOG_ALL (UINT32_MAX)
|
||||
#define PD_LOG_DEFAULT (PD_LOG_PROCESS |\
|
||||
PD_LOG_TASK |\
|
||||
PD_LOG_THREAD |\
|
||||
PD_LOG_EXCEPTIONS |\
|
||||
PD_LOG_MEMORY |\
|
||||
PD_LOG_MEMORY_DATA_SHORT |\
|
||||
PD_LOG_BREAKPOINTS |\
|
||||
PD_LOG_WATCHPOINTS |\
|
||||
PD_LOG_STEP )
|
||||
|
||||
class ProcessMacOSXLog
|
||||
{
|
||||
public:
|
||||
static lldb::LogSP
|
||||
GetLogIfAllCategoriesSet(uint32_t mask = 0);
|
||||
|
||||
static void
|
||||
DisableLog (lldb_private::Args &args, lldb_private::Stream *feedback_strm);
|
||||
|
||||
static void
|
||||
DeleteLog ();
|
||||
|
||||
static lldb::LogSP
|
||||
EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, lldb_private::Args &args, lldb_private::Stream *feedback_strm);
|
||||
|
||||
static void
|
||||
ListLogCategories (lldb_private::Stream *strm);
|
||||
|
||||
static void
|
||||
LogIf (uint32_t mask, const char *format, ...);
|
||||
};
|
||||
|
||||
#endif // liblldb_ProcessMacOSXLog_h_
|
File diff suppressed because it is too large
Load Diff
|
@ -1,206 +0,0 @@
|
|||
//===-- ProcessMacOSXRemote.h -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//----------------------------------------------------------------------
|
||||
//
|
||||
// ProcessMacOSXRemote.h
|
||||
// liblldb
|
||||
//
|
||||
// Created by Greg Clayton on 4/21/09.
|
||||
//
|
||||
//
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
#ifndef liblldb_ProcessMacOSXRemote_H_
|
||||
#define liblldb_ProcessMacOSXRemote_H_
|
||||
|
||||
// C Includes
|
||||
|
||||
// C++ Includes
|
||||
#include <list>
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
class ThreadMacOSXRemote;
|
||||
|
||||
class ProcessMacOSXRemote :
|
||||
public Process
|
||||
{
|
||||
public:
|
||||
friend class ThreadMacOSX;
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Constructors and Destructors
|
||||
//------------------------------------------------------------------
|
||||
ProcessMacOSXRemote(Target& target);
|
||||
virtual ~DCProcessMacOSXRemote();
|
||||
|
||||
static Process* CreateInstance (Target& target);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Check if a given Process
|
||||
//------------------------------------------------------------------
|
||||
virtual bool CanDebug(Target &target);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Creating a new process, or attaching to an existing one
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb::pid_t DoLaunch (Module* module,
|
||||
char const *argv[], // Can be NULL
|
||||
char const *envp[], // Can be NULL
|
||||
const char *stdin_path, // Can be NULL
|
||||
const char *stdout_path, // Can be NULL
|
||||
const char *stderr_path); // Can be NULL
|
||||
virtual void DidLaunch ();
|
||||
virtual lldb::pid_t DoAttach (lldb::pid_t pid);
|
||||
virtual void DidAttach ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Control
|
||||
//------------------------------------------------------------------
|
||||
// virtual bool WillResume ();
|
||||
virtual bool DoResume ();
|
||||
// virtual void DidResume ();
|
||||
|
||||
virtual bool DoHalt ();
|
||||
virtual bool WillDetach ();
|
||||
virtual bool DoDetach ();
|
||||
virtual bool DoKill (int signal);
|
||||
|
||||
virtual bool ShouldStop ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Queries
|
||||
//------------------------------------------------------------------
|
||||
virtual bool IsAlive ();
|
||||
virtual bool IsRunning ();
|
||||
virtual lldb::addr_t GetImageInfoAddress();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process Memory
|
||||
//------------------------------------------------------------------
|
||||
virtual size_t DoReadMemory (lldb::addr_t addr, void *buf, size_t size);
|
||||
virtual size_t DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Process STDIO
|
||||
//------------------------------------------------------------------
|
||||
virtual size_t GetSTDOUT (char *buf, size_t buf_size);
|
||||
virtual size_t GetSTDERR (char *buf, size_t buf_size);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Process Breakpoints
|
||||
//----------------------------------------------------------------------
|
||||
virtual size_t
|
||||
GetSoftwareBreakpointTrapOpcode (lldb::BreakpointSite *bp_site);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Process Breakpoints
|
||||
//----------------------------------------------------------------------
|
||||
virtual bool
|
||||
EnableBreakpoint (lldb::BreakpointSite *bp_site);
|
||||
|
||||
virtual bool
|
||||
DisableBreakpoint (lldb::BreakpointSite *bp_site);
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Process Watchpoints
|
||||
//----------------------------------------------------------------------
|
||||
virtual bool EnableWatchpoint (WatchpointLocation *wp_loc);
|
||||
virtual bool DisableWatchpoint (WatchpointLocation *wp_loc);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Thread Queries
|
||||
//------------------------------------------------------------------
|
||||
virtual Thread * GetCurrentThread ();
|
||||
virtual bool SetCurrentThread (lldb::tid_t tid);
|
||||
virtual Thread * GetThreadAtIndex (uint32_t idx);
|
||||
virtual Thread * GetThreadByID (lldb::tid_t tid);
|
||||
virtual size_t GetNumThreads ();
|
||||
|
||||
virtual ByteOrder GetByteOrder () const;
|
||||
|
||||
virtual DynamicLoader *
|
||||
GetDynamicLoader ();
|
||||
|
||||
protected:
|
||||
Flags m_flags; // Process specific flags (see eFlags enums)
|
||||
ArchSpec m_arch_spec;
|
||||
std::auto_ptr<DynamicLoader> m_dynamic_loader_ap;
|
||||
ByteOrder m_byte_order;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Accessors
|
||||
//----------------------------------------------------------------------
|
||||
bool
|
||||
ProcessIDIsValid ( ) const;
|
||||
|
||||
bool
|
||||
IsRunning ( State state )
|
||||
{
|
||||
return state == eStateRunning || IsStepping(state);
|
||||
}
|
||||
|
||||
bool
|
||||
IsStepping ( State state)
|
||||
{
|
||||
return state == eStateStepping;
|
||||
}
|
||||
bool
|
||||
CanResume ( State state)
|
||||
{
|
||||
return state == eStateStopped;
|
||||
}
|
||||
|
||||
ArchSpec&
|
||||
GetArchSpec()
|
||||
{
|
||||
return m_arch_spec;
|
||||
}
|
||||
const ArchSpec&
|
||||
GetArchSpec() const
|
||||
{
|
||||
return m_arch_spec;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
eFlagsNone = 0,
|
||||
eFlagsAttached = (1 << 0),
|
||||
eFlagsUsingSBS = (1 << 1)
|
||||
};
|
||||
|
||||
void
|
||||
Clear ( );
|
||||
|
||||
Flags &
|
||||
GetFlags ()
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
const Flags &
|
||||
GetFlags () const
|
||||
{
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
UpdateThreadListIfNeeded ();
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
// For ProcessMacOSXRemote only
|
||||
//------------------------------------------------------------------
|
||||
DISALLOW_COPY_AND_ASSIGN (ProcessMacOSXRemote);
|
||||
|
||||
};
|
||||
|
||||
#endif // liblldb_ProcessMacOSXRemote_H_
|
|
@ -1,86 +0,0 @@
|
|||
//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "RegisterContextMach_arm.h"
|
||||
|
||||
// C Includes
|
||||
#include <mach/mach_types.h>
|
||||
#include <mach/thread_act.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
//#include "ProcessMacOSXLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
|
||||
RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
|
||||
RegisterContextDarwin_arm (thread, concrete_frame_idx)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterContextMach_arm::~RegisterContextMach_arm()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
|
||||
{
|
||||
mach_msg_type_number_t count = GPRWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
|
||||
{
|
||||
mach_msg_type_number_t count = FPUWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
|
||||
{
|
||||
mach_msg_type_number_t count = EXCWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
|
||||
{
|
||||
mach_msg_type_number_t count = DBGWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
|
||||
}
|
||||
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
//===-- RegisterContextMach_arm.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_RegisterContextMach_arm_h_
|
||||
#define liblldb_RegisterContextMach_arm_h_
|
||||
|
||||
// C Includes
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
|
||||
|
||||
class RegisterContextMach_arm : public RegisterContextDarwin_arm
|
||||
{
|
||||
public:
|
||||
|
||||
RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
|
||||
|
||||
virtual
|
||||
~RegisterContextMach_arm();
|
||||
|
||||
protected:
|
||||
|
||||
virtual int
|
||||
DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
|
||||
|
||||
int
|
||||
DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
|
||||
|
||||
int
|
||||
DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
|
||||
|
||||
int
|
||||
DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
|
||||
|
||||
int
|
||||
DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
|
||||
|
||||
int
|
||||
DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
|
||||
|
||||
int
|
||||
DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
|
||||
|
||||
int
|
||||
DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
|
||||
};
|
||||
|
||||
#endif // liblldb_RegisterContextMach_arm_h_
|
|
@ -1,71 +0,0 @@
|
|||
//===-- RegisterContextMach_i386.cpp ----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// C Includes
|
||||
#include <mach/thread_act.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "RegisterContextMach_i386.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
|
||||
RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
|
||||
RegisterContextDarwin_i386 (thread, concrete_frame_idx)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterContextMach_i386::~RegisterContextMach_i386()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
|
||||
{
|
||||
mach_msg_type_number_t count = GPRWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
|
||||
{
|
||||
mach_msg_type_number_t count = FPUWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
|
||||
{
|
||||
mach_msg_type_number_t count = EXCWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
|
||||
}
|
||||
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
//===-- RegisterContextMach_i386.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_RegisterContextMach_i386_h_
|
||||
#define liblldb_RegisterContextMach_i386_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
|
||||
|
||||
class RegisterContextMach_i386 : public RegisterContextDarwin_i386
|
||||
{
|
||||
public:
|
||||
|
||||
RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
|
||||
|
||||
virtual
|
||||
~RegisterContextMach_i386();
|
||||
|
||||
protected:
|
||||
|
||||
virtual int
|
||||
DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
|
||||
|
||||
int
|
||||
DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
|
||||
|
||||
int
|
||||
DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
|
||||
|
||||
int
|
||||
DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
|
||||
|
||||
int
|
||||
DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
|
||||
|
||||
int
|
||||
DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
|
||||
};
|
||||
|
||||
#endif // liblldb_RegisterContextMach_i386_h_
|
|
@ -1,70 +0,0 @@
|
|||
//===-- RegisterContextMach_x86_64.cpp --------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// C Includes
|
||||
#include <mach/thread_act.h>
|
||||
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "RegisterContextMach_x86_64.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
|
||||
RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
|
||||
RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
|
||||
{
|
||||
mach_msg_type_number_t count = GPRWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
|
||||
{
|
||||
mach_msg_type_number_t count = FPUWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
|
||||
{
|
||||
mach_msg_type_number_t count = EXCWordCount;
|
||||
return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
|
||||
}
|
||||
|
||||
int
|
||||
RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
|
||||
{
|
||||
return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
|
||||
}
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
//===-- RegisterContextMach_x86_64.h ------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_RegisterContextMach_x86_64_h_
|
||||
#define liblldb_RegisterContextMach_x86_64_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
|
||||
|
||||
class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
|
||||
{
|
||||
public:
|
||||
|
||||
RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
|
||||
|
||||
virtual
|
||||
~RegisterContextMach_x86_64();
|
||||
|
||||
protected:
|
||||
|
||||
virtual int
|
||||
DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
|
||||
|
||||
int
|
||||
DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
|
||||
|
||||
int
|
||||
DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
|
||||
|
||||
int
|
||||
DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
|
||||
|
||||
int
|
||||
DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
|
||||
|
||||
int
|
||||
DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
|
||||
};
|
||||
|
||||
#endif // liblldb_RegisterContextMach_x86_64_h_
|
|
@ -1,683 +0,0 @@
|
|||
//===-- ThreadMacOSX.cpp ----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "ThreadMacOSX.h"
|
||||
|
||||
#include "lldb/Core/ArchSpec.h"
|
||||
#include "lldb/Core/DataExtractor.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StopInfo.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
||||
#include "ProcessMacOSX.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
#include "MachThreadContext.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Breakpoint/WatchpointLocation.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Target/Unwind.h"
|
||||
#include "UnwindMacOSXFrameBackchain.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Thread Registers
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
ThreadMacOSX::ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid) :
|
||||
Thread(process, tid),
|
||||
m_fp_pc_pairs(),
|
||||
m_basic_info(),
|
||||
m_suspend_count(0),
|
||||
m_stop_exception(),
|
||||
m_context()
|
||||
{
|
||||
ProcessMacOSX::CreateArchCalback create_arch_callback = process.GetArchCreateCallback();
|
||||
assert(create_arch_callback != NULL);
|
||||
m_context.reset(create_arch_callback(process.GetArchSpec(), *this));
|
||||
assert(m_context.get() != NULL);
|
||||
m_context->InitializeInstance();
|
||||
::memset (&m_basic_info, 0, sizeof (m_basic_info));
|
||||
::memset (&m_ident_info, 0, sizeof (m_ident_info));
|
||||
::memset (&m_proc_threadinfo, 0, sizeof (m_proc_threadinfo));
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_THREAD | PD_LOG_VERBOSE, "ThreadMacOSX::ThreadMacOSX ( pid = %i, tid = 0x%4.4x, )", m_process.GetID(), GetID());
|
||||
}
|
||||
|
||||
ThreadMacOSX::~ThreadMacOSX ()
|
||||
{
|
||||
DestroyThread();
|
||||
}
|
||||
|
||||
#if defined (__i386__) || defined (__x86_64__)
|
||||
#define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_I386_BPT
|
||||
#define MACH_TRAP_DATA_0 EXC_I386_SGL
|
||||
#elif defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__)
|
||||
#define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_PPC_BREAKPOINT
|
||||
|
||||
#elif defined (__arm__)
|
||||
#define MACH_SOFTWARE_BREAKPOINT_DATA_0 EXC_ARM_BREAKPOINT
|
||||
#endif
|
||||
|
||||
|
||||
StopInfoSP
|
||||
ThreadMacOSX::GetPrivateStopReason ()
|
||||
{
|
||||
if (m_actual_stop_info_sp.get() == NULL || m_actual_stop_info_sp->IsValid() == false)
|
||||
m_actual_stop_info_sp = GetStopException().GetStopInfo(*this);
|
||||
return m_actual_stop_info_sp;
|
||||
}
|
||||
|
||||
const char *
|
||||
ThreadMacOSX::GetInfo ()
|
||||
{
|
||||
return GetBasicInfoAsString();
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::GetIdentifierInfo ()
|
||||
{
|
||||
#ifdef THREAD_IDENTIFIER_INFO_COUNT
|
||||
if (m_ident_info.thread_id == 0)
|
||||
{
|
||||
mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
|
||||
return ::thread_info (GetID(), THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count) == KERN_SUCCESS;
|
||||
}
|
||||
#else
|
||||
//m_error.SetErrorString("Thread_info doesn't support THREAD_IDENTIFIER_INFO.");
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
ThreadMacOSX::GetDispatchQueueName()
|
||||
{
|
||||
if (GetIdentifierInfo ())
|
||||
{
|
||||
if (m_ident_info.dispatch_qaddr == 0)
|
||||
return NULL;
|
||||
|
||||
uint8_t memory_buffer[8];
|
||||
addr_t dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
|
||||
DataExtractor data (memory_buffer, sizeof(memory_buffer),
|
||||
m_process.GetTarget().GetArchitecture().GetByteOrder(),
|
||||
m_process.GetTarget().GetArchitecture().GetAddressByteSize());
|
||||
static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
|
||||
const Symbol *dispatch_queue_offsets_symbol = NULL;
|
||||
ModuleSP module_sp(m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libSystem.B.dylib", false), NULL, NULL));
|
||||
if (module_sp)
|
||||
dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
|
||||
|
||||
if (dispatch_queue_offsets_symbol == NULL)
|
||||
{
|
||||
module_sp = m_process.GetTarget().GetImages().FindFirstModuleForFileSpec (FileSpec("libdispatch.dylib", false), NULL, NULL);
|
||||
if (module_sp)
|
||||
dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
|
||||
}
|
||||
if (dispatch_queue_offsets_symbol)
|
||||
dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetValue().GetLoadAddress(&m_process.GetTarget());
|
||||
|
||||
if (dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
|
||||
return NULL;
|
||||
|
||||
// Excerpt from src/queue_private.h
|
||||
struct dispatch_queue_offsets_s
|
||||
{
|
||||
uint16_t dqo_version;
|
||||
uint16_t dqo_label;
|
||||
uint16_t dqo_label_size;
|
||||
} dispatch_queue_offsets;
|
||||
|
||||
Error error;
|
||||
if (m_process.ReadMemory (dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
|
||||
{
|
||||
uint32_t data_offset = 0;
|
||||
if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
|
||||
{
|
||||
if (m_process.ReadMemory (m_ident_info.dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
|
||||
{
|
||||
data_offset = 0;
|
||||
lldb::addr_t queue_addr = data.GetAddress(&data_offset);
|
||||
lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
|
||||
const size_t chunk_size = 32;
|
||||
uint32_t label_pos = 0;
|
||||
m_dispatch_queue_name.resize(chunk_size, '\0');
|
||||
while (1)
|
||||
{
|
||||
size_t bytes_read = m_process.ReadMemory (label_addr + label_pos, &m_dispatch_queue_name[label_pos], chunk_size, error);
|
||||
|
||||
if (bytes_read <= 0)
|
||||
break;
|
||||
|
||||
if (m_dispatch_queue_name.find('\0', label_pos) != std::string::npos)
|
||||
break;
|
||||
label_pos += bytes_read;
|
||||
}
|
||||
m_dispatch_queue_name.erase(m_dispatch_queue_name.find('\0'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_dispatch_queue_name.empty())
|
||||
return NULL;
|
||||
return m_dispatch_queue_name.c_str();
|
||||
}
|
||||
|
||||
const char *
|
||||
ThreadMacOSX::GetName ()
|
||||
{
|
||||
if (GetIdentifierInfo ())
|
||||
::proc_pidinfo (m_process.GetID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo));
|
||||
|
||||
// No thread name, lets return the queue name instead
|
||||
if (m_proc_threadinfo.pth_name[0] == '\0')
|
||||
return GetDispatchQueueName();
|
||||
|
||||
// Return the thread name if there was one
|
||||
if (m_proc_threadinfo.pth_name[0])
|
||||
return m_proc_threadinfo.pth_name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::WillResume (StateType resume_state)
|
||||
{
|
||||
ThreadWillResume(resume_state);
|
||||
Thread::WillResume(resume_state);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ThreadMacOSX::RefreshStateAfterStop()
|
||||
{
|
||||
// Invalidate all registers in our register context
|
||||
GetRegisterContext()->InvalidateIfNeeded (false);
|
||||
|
||||
m_context->RefreshStateAfterStop();
|
||||
|
||||
// We may have suspended this thread so the primary thread could step
|
||||
// without worrying about race conditions, so lets restore our suspend
|
||||
// count.
|
||||
RestoreSuspendCount();
|
||||
|
||||
// Update the basic information for a thread for suspend count reasons.
|
||||
ThreadMacOSX::GetBasicInfo(GetID(), &m_basic_info);
|
||||
m_suspend_count = m_basic_info.suspend_count;
|
||||
m_basic_info_string.clear();
|
||||
}
|
||||
|
||||
Unwind *
|
||||
ThreadMacOSX::GetUnwinder ()
|
||||
{
|
||||
if (m_unwinder_ap.get() == NULL)
|
||||
{
|
||||
const ArchSpec target_arch (GetProcess().GetTarget().GetArchitecture ());
|
||||
#if 0 // Not sure this is the right thing to do for native, but this will all go away with Jason's new
|
||||
// unwinder anyway...
|
||||
if (target_arch == ArchSpec("x86_64") || target_arch == ArchSpec("i386"))
|
||||
{
|
||||
m_unwinder_ap.reset (new UnwindLibUnwind (*this, GetGDBProcess().GetLibUnwindAddressSpace()));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this));
|
||||
}
|
||||
}
|
||||
return m_unwinder_ap.get();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ThreadMacOSX::ClearStackFrames ()
|
||||
{
|
||||
m_fp_pc_pairs.clear();
|
||||
Thread::ClearStackFrames();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t
|
||||
ThreadMacOSX::Suspend()
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE))
|
||||
log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
|
||||
lldb::tid_t tid = GetID ();
|
||||
if (ThreadIDIsValid(tid))
|
||||
{
|
||||
Error err(::thread_suspend (tid), eErrorTypeMachKernel);
|
||||
if (err.Success())
|
||||
m_suspend_count++;
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::thread_suspend (%4.4x)", tid);
|
||||
}
|
||||
return GetSuspendCount();
|
||||
}
|
||||
|
||||
int32_t
|
||||
ThreadMacOSX::Resume()
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE))
|
||||
log->Printf ("ThreadMacOSX::%s ()", __FUNCTION__);
|
||||
lldb::tid_t tid = GetID ();
|
||||
if (ThreadIDIsValid(tid))
|
||||
{
|
||||
while (m_suspend_count > 0)
|
||||
{
|
||||
Error err(::thread_resume (tid), eErrorTypeMachKernel);
|
||||
if (err.Success())
|
||||
m_suspend_count--;
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::thread_resume (%4.4x)", tid);
|
||||
}
|
||||
}
|
||||
return GetSuspendCount();
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::RestoreSuspendCount()
|
||||
{
|
||||
LogSP log (ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD));
|
||||
if (log && log->GetMask().Test(PD_LOG_VERBOSE))
|
||||
log->Printf ("ThreadMacOSX::%s ( )", __FUNCTION__);
|
||||
Error err;
|
||||
lldb::tid_t tid = GetID ();
|
||||
if (ThreadIDIsValid(tid) == false)
|
||||
return false;
|
||||
else if (m_suspend_count > m_basic_info.suspend_count)
|
||||
{
|
||||
while (m_suspend_count > m_basic_info.suspend_count)
|
||||
{
|
||||
err = ::thread_resume (tid);
|
||||
if (err.Success())
|
||||
--m_suspend_count;
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::thread_resume (%4.4x)", tid);
|
||||
}
|
||||
}
|
||||
else if (m_suspend_count < m_basic_info.suspend_count)
|
||||
{
|
||||
while (m_suspend_count < m_basic_info.suspend_count)
|
||||
{
|
||||
err = ::thread_suspend (tid);
|
||||
if (err.Success())
|
||||
--m_suspend_count;
|
||||
log = ProcessMacOSXLog::GetLogIfAllCategoriesSet(PD_LOG_THREAD);
|
||||
if (log || err.Fail())
|
||||
err.PutToLog(log.get(), "::thread_suspend (%4.4x)", tid);
|
||||
}
|
||||
}
|
||||
return m_suspend_count == m_basic_info.suspend_count;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
ThreadMacOSX::GetBasicInfoAsString ()
|
||||
{
|
||||
if (m_basic_info_string.empty())
|
||||
{
|
||||
StreamString sstr;
|
||||
struct thread_basic_info basicInfo;
|
||||
|
||||
lldb::tid_t tid = GetID ();
|
||||
if (GetBasicInfo(tid, &basicInfo))
|
||||
{
|
||||
// char run_state_str[32];
|
||||
// size_t run_state_str_size = sizeof(run_state_str);
|
||||
// switch (basicInfo.run_state)
|
||||
// {
|
||||
// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break;
|
||||
// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break;
|
||||
// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break;
|
||||
// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break;
|
||||
// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break;
|
||||
// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ???
|
||||
// }
|
||||
float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
|
||||
float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f;
|
||||
sstr.Printf("Thread 0x%4.4x: user=%f system=%f cpu=%d sleep_time=%d",
|
||||
InferiorThreadID(),
|
||||
user,
|
||||
system,
|
||||
basicInfo.cpu_usage,
|
||||
basicInfo.sleep_time);
|
||||
m_basic_info_string.assign (sstr.GetData(), sstr.GetSize());
|
||||
}
|
||||
}
|
||||
if (m_basic_info_string.empty())
|
||||
return NULL;
|
||||
return m_basic_info_string.c_str();
|
||||
}
|
||||
|
||||
|
||||
//const uint8_t *
|
||||
//ThreadMacOSX::SoftwareBreakpointOpcode (size_t break_op_size) const
|
||||
//{
|
||||
// return m_context->SoftwareBreakpointOpcode(break_op_size);
|
||||
//}
|
||||
|
||||
|
||||
lldb::tid_t
|
||||
ThreadMacOSX::InferiorThreadID() const
|
||||
{
|
||||
mach_msg_type_number_t i;
|
||||
mach_port_name_array_t names;
|
||||
mach_port_type_array_t types;
|
||||
mach_msg_type_number_t ncount, tcount;
|
||||
lldb::tid_t inferior_tid = LLDB_INVALID_THREAD_ID;
|
||||
task_t my_task = ::mach_task_self();
|
||||
task_t task = GetMacOSXProcess().Task().GetTaskPort();
|
||||
|
||||
kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount);
|
||||
if (kret == KERN_SUCCESS)
|
||||
{
|
||||
lldb::tid_t tid = GetID ();
|
||||
|
||||
for (i = 0; i < ncount; i++)
|
||||
{
|
||||
mach_port_t my_name;
|
||||
mach_msg_type_name_t my_type;
|
||||
|
||||
kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type);
|
||||
if (kret == KERN_SUCCESS)
|
||||
{
|
||||
::mach_port_deallocate (my_task, my_name);
|
||||
if (my_name == tid)
|
||||
{
|
||||
inferior_tid = names[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Free up the names and types
|
||||
::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t));
|
||||
::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t));
|
||||
}
|
||||
return inferior_tid;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::GetBasicInfo(lldb::tid_t thread, struct thread_basic_info *basicInfoPtr)
|
||||
{
|
||||
if (ThreadIDIsValid(thread))
|
||||
{
|
||||
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
|
||||
kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count);
|
||||
if (err == KERN_SUCCESS)
|
||||
return true;
|
||||
}
|
||||
::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ThreadMacOSX::ThreadIDIsValid (lldb::tid_t thread)
|
||||
{
|
||||
return thread != 0;
|
||||
}
|
||||
|
||||
void
|
||||
ThreadMacOSX::Dump(Log *log, uint32_t index)
|
||||
{
|
||||
const char * thread_run_state = NULL;
|
||||
|
||||
switch (m_basic_info.run_state)
|
||||
{
|
||||
case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally
|
||||
case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped
|
||||
case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally
|
||||
case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait
|
||||
case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a
|
||||
default: thread_run_state = "???"; break;
|
||||
}
|
||||
|
||||
RegisterContext *reg_context = GetRegisterContext().get();
|
||||
log->Printf ("thread[%u] %4.4x (%u): pc: 0x%8.8llx sp: 0x%8.8llx breakID: %d user: %d.%06.6d system: %d.%06.6d cpu: %d policy: %d run_state: %d (%s) flags: %d suspend_count: %d (current %d) sleep_time: %d",
|
||||
index,
|
||||
GetID (),
|
||||
reg_context->GetPC (LLDB_INVALID_ADDRESS),
|
||||
reg_context->GetSP (LLDB_INVALID_ADDRESS),
|
||||
m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds,
|
||||
m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds,
|
||||
m_basic_info.cpu_usage,
|
||||
m_basic_info.policy,
|
||||
m_basic_info.run_state,
|
||||
thread_run_state,
|
||||
m_basic_info.flags,
|
||||
m_basic_info.suspend_count, m_suspend_count,
|
||||
m_basic_info.sleep_time);
|
||||
//DumpRegisterState(0);
|
||||
}
|
||||
|
||||
void
|
||||
ThreadMacOSX::ThreadWillResume (StateType resume_state)
|
||||
{
|
||||
// Update the thread state to be the state we wanted when the task resumes
|
||||
SetState (resume_state);
|
||||
switch (resume_state)
|
||||
{
|
||||
case eStateSuspended:
|
||||
Suspend();
|
||||
break;
|
||||
|
||||
case eStateRunning:
|
||||
case eStateStepping:
|
||||
Resume();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
m_context->ThreadWillResume();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadMacOSX::DidResume ()
|
||||
{
|
||||
// TODO: cache current stack frames for next time in case we can match things up??
|
||||
ClearStackFrames();
|
||||
m_stop_exception.Clear();
|
||||
Thread::DidResume();
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::ShouldStop(bool &step_more)
|
||||
{
|
||||
// TODO: REmove this after all is working, Process should be managing this
|
||||
// for us.
|
||||
//
|
||||
// // See if this thread is at a breakpoint?
|
||||
// lldb::user_id_t breakID = CurrentBreakpoint();
|
||||
//
|
||||
// if (LLDB_BREAK_ID_IS_VALID(breakID))
|
||||
// {
|
||||
// // This thread is sitting at a breakpoint, ask the breakpoint
|
||||
// // if we should be stopping here.
|
||||
// if (Process()->Breakpoints().ShouldStop(ProcessID(), ThreadID(), breakID))
|
||||
// return true;
|
||||
// else
|
||||
// {
|
||||
// // The breakpoint said we shouldn't stop, but we may have gotten
|
||||
// // a signal or the user may have requested to stop in some other
|
||||
// // way. Stop if we have a valid exception (this thread won't if
|
||||
// // another thread was the reason this process stopped) and that
|
||||
// // exception, is NOT a breakpoint exception (a common case would
|
||||
// // be a SIGINT signal).
|
||||
// if (GetStopException().IsValid() && !GetStopException().IsBreakpoint())
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
if (m_context->StepNotComplete())
|
||||
{
|
||||
step_more = true;
|
||||
return false;
|
||||
}
|
||||
// // The thread state is used to let us know what the thread was
|
||||
// // trying to do. ThreadMacOSX::ThreadWillResume() will set the
|
||||
// // thread state to various values depending if the thread was
|
||||
// // the current thread and if it was to be single stepped, or
|
||||
// // resumed.
|
||||
// if (GetState() == eStateRunning)
|
||||
// {
|
||||
// // If our state is running, then we should continue as we are in
|
||||
// // the process of stepping over a breakpoint.
|
||||
// return false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Stop if we have any kind of valid exception for this
|
||||
// // thread.
|
||||
// if (GetStopException().IsValid())
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::NotifyException(MachException::Data& exc)
|
||||
{
|
||||
if (m_stop_exception.IsValid())
|
||||
{
|
||||
// We may have more than one exception for a thread, but we need to
|
||||
// only remember the one that we will say is the reason we stopped.
|
||||
// We may have been single stepping and also gotten a signal exception,
|
||||
// so just remember the most pertinent one.
|
||||
if (m_stop_exception.IsBreakpoint())
|
||||
m_stop_exception = exc;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_stop_exception = exc;
|
||||
}
|
||||
// bool handled =
|
||||
m_context->NotifyException(exc);
|
||||
// if (!handled)
|
||||
// {
|
||||
// handled = true;
|
||||
// lldb::addr_t pc = GetPC();
|
||||
// lldb::user_id_t breakID = m_process.Breakpoints().FindIDCyAddress(pc);
|
||||
// SetCurrentBreakpoint(breakID);
|
||||
// switch (exc.exc_type)
|
||||
// {
|
||||
// case EXC_BAD_ACCESS:
|
||||
// break;
|
||||
// case EXC_BAD_INSTRUCTION:
|
||||
// break;
|
||||
// case EXC_ARITHMETIC:
|
||||
// break;
|
||||
// case EXC_EMULATION:
|
||||
// break;
|
||||
// case EXC_SOFTWARE:
|
||||
// break;
|
||||
// case EXC_BREAKPOINT:
|
||||
// break;
|
||||
// case EXC_SYSCALL:
|
||||
// break;
|
||||
// case EXC_MACH_SYSCALL:
|
||||
// break;
|
||||
// case EXC_RPC_ALERT:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// return handled;
|
||||
return true;
|
||||
}
|
||||
|
||||
RegisterContextSP
|
||||
ThreadMacOSX::GetRegisterContext ()
|
||||
{
|
||||
if (m_reg_context_sp.get() == NULL)
|
||||
m_reg_context_sp = CreateRegisterContextForFrame (NULL);
|
||||
return m_reg_context_sp;
|
||||
}
|
||||
|
||||
RegisterContextSP
|
||||
ThreadMacOSX::CreateRegisterContextForFrame (StackFrame *frame)
|
||||
{
|
||||
return m_context->CreateRegisterContext (frame);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ThreadMacOSX::SetHardwareBreakpoint (const BreakpointSite *bp)
|
||||
{
|
||||
if (bp != NULL)
|
||||
return GetRegisterContext()->SetHardwareBreakpoint(bp->GetLoadAddress(), bp->GetByteSize());
|
||||
return LLDB_INVALID_INDEX32;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ThreadMacOSX::SetHardwareWatchpoint (const WatchpointLocation *wp)
|
||||
{
|
||||
if (wp != NULL)
|
||||
return GetRegisterContext()->SetHardwareWatchpoint(wp->GetLoadAddress(), wp->GetByteSize(), wp->WatchpointRead(), wp->WatchpointWrite());
|
||||
return LLDB_INVALID_INDEX32;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ThreadMacOSX::ClearHardwareBreakpoint (const BreakpointSite *bp)
|
||||
{
|
||||
if (bp != NULL && bp->IsHardware())
|
||||
return GetRegisterContext()->ClearHardwareBreakpoint(bp->GetHardwareIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ThreadMacOSX::ClearHardwareWatchpoint (const WatchpointLocation *wp)
|
||||
{
|
||||
if (wp != NULL && wp->IsHardware())
|
||||
return GetRegisterContext()->ClearHardwareWatchpoint(wp->GetHardwareIndex());
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t
|
||||
ThreadMacOSX::GetStackFrameData(std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs)
|
||||
{
|
||||
lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0));
|
||||
return m_context->GetStackFrameData(frame_sp.get(), fp_pc_pairs);
|
||||
}
|
||||
|
||||
|
||||
//void
|
||||
//ThreadMacOSX::NotifyBreakpointChanged (const BreakpointSite *bp)
|
||||
//{
|
||||
// if (bp)
|
||||
// {
|
||||
// lldb::user_id_t breakID = bp->GetID();
|
||||
// if (bp->IsEnabled())
|
||||
// {
|
||||
// if (bp->Address() == GetPC())
|
||||
// {
|
||||
// SetCurrentBreakpoint(breakID);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (CurrentBreakpoint() == breakID)
|
||||
// {
|
||||
// SetCurrentBreakpoint(LLDB_INVALID_BREAK_ID);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
//===-- ThreadMacOSX.h ------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_ThreadMacOSX_h_
|
||||
#define liblldb_ThreadMacOSX_h_
|
||||
|
||||
#include <libproc.h>
|
||||
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
#include "MachException.h"
|
||||
|
||||
class ProcessMacOSX;
|
||||
class MachThreadContext;
|
||||
|
||||
class ThreadMacOSX : public lldb_private::Thread
|
||||
{
|
||||
public:
|
||||
ThreadMacOSX (ProcessMacOSX &process, lldb::tid_t tid);
|
||||
|
||||
virtual
|
||||
~ThreadMacOSX ();
|
||||
|
||||
virtual bool
|
||||
WillResume (lldb::StateType resume_state);
|
||||
|
||||
virtual void
|
||||
RefreshStateAfterStop();
|
||||
|
||||
virtual const char *
|
||||
GetInfo ();
|
||||
|
||||
virtual const char *
|
||||
GetName ();
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
GetRegisterContext ();
|
||||
|
||||
virtual lldb::RegisterContextSP
|
||||
CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
|
||||
|
||||
virtual void
|
||||
ClearStackFrames ();
|
||||
|
||||
ProcessMacOSX &
|
||||
GetMacOSXProcess ()
|
||||
{
|
||||
return (ProcessMacOSX &)m_process;
|
||||
}
|
||||
|
||||
const ProcessMacOSX &
|
||||
GetMacOSXProcess () const
|
||||
{
|
||||
return (ProcessMacOSX &)m_process;
|
||||
}
|
||||
|
||||
void
|
||||
Dump (lldb_private::Log *log, uint32_t index);
|
||||
|
||||
lldb::tid_t
|
||||
InferiorThreadID () const;
|
||||
|
||||
static bool
|
||||
ThreadIDIsValid (lldb::tid_t thread);
|
||||
|
||||
int32_t
|
||||
Resume ();
|
||||
|
||||
int32_t
|
||||
Suspend ();
|
||||
|
||||
int32_t
|
||||
GetSuspendCount () const { return m_suspend_count; }
|
||||
|
||||
bool
|
||||
RestoreSuspendCount ();
|
||||
|
||||
uint32_t
|
||||
SetHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
|
||||
|
||||
uint32_t
|
||||
SetHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
|
||||
|
||||
bool
|
||||
ClearHardwareBreakpoint (const lldb_private::BreakpointSite *bp);
|
||||
|
||||
bool
|
||||
ClearHardwareWatchpoint (const lldb_private::WatchpointLocation *wp);
|
||||
|
||||
void
|
||||
ThreadWillResume (lldb::StateType resume_state);
|
||||
|
||||
virtual void
|
||||
DidResume ();
|
||||
|
||||
bool
|
||||
ShouldStop (bool &step_more);
|
||||
|
||||
bool
|
||||
NotifyException (MachException::Data& exc);
|
||||
|
||||
const MachException::Data&
|
||||
GetStopException () { return m_stop_exception; }
|
||||
|
||||
const char *
|
||||
GetBasicInfoAsString ();
|
||||
|
||||
size_t
|
||||
GetStackFrameData (std::vector<std::pair<lldb::addr_t, lldb::addr_t> >& fp_pc_pairs);
|
||||
|
||||
virtual lldb::StopInfoSP
|
||||
GetPrivateStopReason ();
|
||||
|
||||
protected:
|
||||
bool
|
||||
GetIdentifierInfo ();
|
||||
|
||||
const char *
|
||||
GetDispatchQueueName();
|
||||
|
||||
static bool
|
||||
GetBasicInfo (lldb::tid_t threadID, struct thread_basic_info *basic_info);
|
||||
|
||||
virtual lldb_private::Unwind *
|
||||
GetUnwinder ();
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Member variables.
|
||||
//------------------------------------------------------------------
|
||||
std::vector<std::pair<lldb::addr_t, lldb::addr_t> > m_fp_pc_pairs;
|
||||
struct thread_basic_info m_basic_info; // Basic information for a thread used to see if a thread is valid
|
||||
std::string m_basic_info_string;// Basic thread info as a C string.
|
||||
#ifdef THREAD_IDENTIFIER_INFO_COUNT
|
||||
thread_identifier_info_data_t m_ident_info;
|
||||
struct proc_threadinfo m_proc_threadinfo;
|
||||
std::string m_dispatch_queue_name;
|
||||
#endif
|
||||
int32_t m_suspend_count; // The current suspend count
|
||||
MachException::Data m_stop_exception; // The best exception that describes why this thread is stopped
|
||||
std::auto_ptr<MachThreadContext> m_context; // The arch specific thread context for this thread (register state and more)
|
||||
|
||||
};
|
||||
|
||||
#endif // liblldb_ThreadMacOSX_h_
|
|
@ -27,7 +27,6 @@
|
|||
// Project includes
|
||||
#include "ARM_GCC_Registers.h"
|
||||
#include "ARM_DWARF_Registers.h"
|
||||
#include "ProcessMacOSXLog.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
@ -980,7 +979,7 @@ RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints ()
|
|||
// Zero is reserved for the BRP count, so don't increment it if it is zero
|
||||
if (g_num_supported_hw_breakpoints > 0)
|
||||
g_num_supported_hw_breakpoints++;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
|
||||
// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
|
||||
|
||||
}
|
||||
return g_num_supported_hw_breakpoints;
|
||||
|
@ -1025,13 +1024,13 @@ RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size
|
|||
byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
|
||||
S_USER | // Which modes should this breakpoint stop in?
|
||||
BCR_ENABLE; // Enable this hardware breakpoint
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
|
||||
addr,
|
||||
size,
|
||||
i,
|
||||
i,
|
||||
dbg.bvr[i],
|
||||
dbg.bcr[i]);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
|
||||
// addr,
|
||||
// size,
|
||||
// i,
|
||||
// i,
|
||||
// dbg.bvr[i],
|
||||
// dbg.bcr[i]);
|
||||
}
|
||||
else if (size == 4)
|
||||
{
|
||||
|
@ -1040,25 +1039,25 @@ RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size
|
|||
BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
|
||||
S_USER | // Which modes should this breakpoint stop in?
|
||||
BCR_ENABLE; // Enable this hardware breakpoint
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
|
||||
addr,
|
||||
size,
|
||||
i,
|
||||
i,
|
||||
dbg.bvr[i],
|
||||
dbg.bcr[i]);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
|
||||
// addr,
|
||||
// size,
|
||||
// i,
|
||||
// i,
|
||||
// dbg.bvr[i],
|
||||
// dbg.bcr[i]);
|
||||
}
|
||||
|
||||
kret = WriteDBG();
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
|
||||
|
||||
if (kret == KERN_SUCCESS)
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
|
||||
// }
|
||||
}
|
||||
|
||||
return LLDB_INVALID_INDEX32;
|
||||
|
@ -1075,12 +1074,12 @@ RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
|
|||
if (hw_index < num_hw_points)
|
||||
{
|
||||
dbg.bcr[hw_index] = 0;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_BREAKPOINTS, "RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
|
||||
hw_index,
|
||||
hw_index,
|
||||
dbg.bvr[hw_index],
|
||||
hw_index,
|
||||
dbg.bcr[hw_index]);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
|
||||
// hw_index,
|
||||
// hw_index,
|
||||
// dbg.bvr[hw_index],
|
||||
// hw_index,
|
||||
// dbg.bcr[hw_index]);
|
||||
|
||||
kret = WriteDBG();
|
||||
|
||||
|
@ -1106,7 +1105,7 @@ RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
|
|||
uint32_t register_DBGDIDR;
|
||||
asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
|
||||
g_num_supported_hw_watchpoints = bits(register_DBGDIDR, 31, 28) + 1;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
|
||||
// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
|
||||
}
|
||||
return g_num_supported_hw_watchpoints;
|
||||
#else
|
||||
|
@ -1119,7 +1118,7 @@ RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
|
|||
uint32_t
|
||||
RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
|
||||
{
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
|
||||
|
||||
const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
|
||||
|
||||
|
@ -1140,10 +1139,10 @@ RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size
|
|||
// until the next 4 byte boundary and we need to make sure we can properly
|
||||
// encode this.
|
||||
uint32_t addr_word_offset = addr % 4;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
|
||||
|
||||
uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
|
||||
if (byte_mask > 0xfu)
|
||||
return LLDB_INVALID_INDEX32;
|
||||
|
||||
|
@ -1175,14 +1174,14 @@ RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size
|
|||
WCR_ENABLE; // Enable this watchpoint;
|
||||
|
||||
kret = WriteDBG();
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
|
||||
|
||||
if (kret == KERN_SUCCESS)
|
||||
return i;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
|
||||
}
|
||||
}
|
||||
return LLDB_INVALID_INDEX32;
|
||||
|
@ -1199,12 +1198,12 @@ RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index)
|
|||
if (hw_index < num_hw_points)
|
||||
{
|
||||
dbg.wcr[hw_index] = 0;
|
||||
ProcessMacOSXLog::LogIf(PD_LOG_WATCHPOINTS, "RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
|
||||
hw_index,
|
||||
hw_index,
|
||||
dbg.wvr[hw_index],
|
||||
hw_index,
|
||||
dbg.wcr[hw_index]);
|
||||
// if (log) log->Printf ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
|
||||
// hw_index,
|
||||
// hw_index,
|
||||
// dbg.wvr[hw_index],
|
||||
// hw_index,
|
||||
// dbg.wcr[hw_index]);
|
||||
|
||||
kret = WriteDBG();
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h"
|
||||
#include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h"
|
||||
#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h"
|
||||
#include "Plugins/Process/MacOSX-User/source/ProcessMacOSX.h"
|
||||
#include "Plugins/Process/MacOSX-Kernel/ProcessKDP.h"
|
||||
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
|
||||
#include "Plugins/Platform/MacOSX/PlatformMacOSX.h"
|
||||
|
@ -105,7 +104,6 @@ lldb_private::Initialize ()
|
|||
ObjectFileMachO::Initialize();
|
||||
ProcessKDP::Initialize();
|
||||
ProcessGDBRemote::Initialize();
|
||||
//ProcessMacOSX::Initialize();
|
||||
SymbolVendorMacOSX::Initialize();
|
||||
PlatformMacOSX::Initialize();
|
||||
PlatformRemoteiOS::Initialize();
|
||||
|
@ -171,7 +169,6 @@ lldb_private::Terminate ()
|
|||
ObjectFileMachO::Terminate();
|
||||
ProcessKDP::Terminate();
|
||||
ProcessGDBRemote::Terminate();
|
||||
//ProcessMacOSX::Terminate();
|
||||
SymbolVendorMacOSX::Terminate();
|
||||
PlatformMacOSX::Terminate();
|
||||
PlatformRemoteiOS::Terminate();
|
||||
|
|
Loading…
Reference in New Issue