Vendor import of lldb trunk r306325:

https://llvm.org/svn/llvm-project/lldb/trunk@306325
This commit is contained in:
Dimitry Andric 2017-06-26 20:33:56 +00:00
parent 4befb1f96d
commit fdea456ad8
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/lldb/dist/; revision=320384
svn path=/vendor/lldb/lldb-trunk-r306325/; revision=320385; tag=vendor/lldb/lldb-trunk-r306325
62 changed files with 2270 additions and 1172 deletions

View File

@ -28,6 +28,27 @@ namespace lldb_private {
class FileAction;
class ProcessLaunchInfo;
//----------------------------------------------------------------------
// Exit Type for inferior processes
//----------------------------------------------------------------------
struct WaitStatus {
enum Type : uint8_t {
Exit, // The status represents the return code from normal
// program exit (i.e. WIFEXITED() was true)
Signal, // The status represents the signal number that caused
// the program to exit (i.e. WIFSIGNALED() was true)
Stop, // The status represents the signal number that caused the
// program to stop (i.e. WIFSTOPPED() was true)
};
Type type;
uint8_t status;
WaitStatus(Type type, uint8_t status) : type(type), status(status) {}
static WaitStatus Decode(int wstatus);
};
//----------------------------------------------------------------------
/// @class Host Host.h "lldb/Host/Host.h"
/// @brief A class that provides host computer information.
@ -111,15 +132,6 @@ class Host {
static const char *GetSignalAsCString(int signo);
typedef void (*ThreadLocalStorageCleanupCallback)(void *p);
static lldb::thread_key_t
ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback);
static void *ThreadLocalStorageGet(lldb::thread_key_t key);
static void ThreadLocalStorageSet(lldb::thread_key_t key, void *value);
//------------------------------------------------------------------
/// Given an address in the current process (the process that
/// is running the LLDB code), return the name of the module that
@ -184,22 +196,6 @@ class Host {
static bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info);
#if (defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
defined(__GLIBC__) || defined(__NetBSD__) || defined(__OpenBSD__)) && \
!defined(__ANDROID__)
static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info);
static Status LaunchProcessPosixSpawn(const char *exe_path,
const ProcessLaunchInfo &launch_info,
lldb::pid_t &pid);
static bool AddPosixSpawnFileAction(void *file_actions,
const FileAction *info, Log *log,
Status &error);
#endif
static const lldb::UnixSignalsSP &GetUnixSignals();
static Status LaunchProcess(ProcessLaunchInfo &launch_info);
@ -246,5 +242,14 @@ class Host {
} // namespace lldb_private
namespace llvm {
template <> struct format_provider<lldb_private::WaitStatus> {
/// Options = "" gives a human readable description of the status
/// Options = "g" gives a gdb-remote protocol status (e.g., X09)
static void format(const lldb_private::WaitStatus &WS, raw_ostream &OS,
llvm::StringRef Options);
};
} // namespace llvm
#endif // #if defined(__cplusplus)
#endif // liblldb_Host_h_

View File

@ -11,6 +11,7 @@
#define liblldb_NativeProcessProtocol_h_
#include "lldb/Core/TraceOptions.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
@ -158,12 +159,9 @@ class NativeProcessProtocol
//----------------------------------------------------------------------
// Exit Status
//----------------------------------------------------------------------
virtual bool GetExitStatus(lldb_private::ExitType *exit_type, int *status,
std::string &exit_description);
virtual llvm::Optional<WaitStatus> GetExitStatus();
virtual bool SetExitStatus(lldb_private::ExitType exit_type, int status,
const char *exit_description,
bool bNotifyStateChange);
virtual bool SetExitStatus(WaitStatus status, bool bNotifyStateChange);
//----------------------------------------------------------------------
// Access to threads
@ -421,9 +419,8 @@ class NativeProcessProtocol
lldb::StateType m_state;
mutable std::recursive_mutex m_state_mutex;
lldb_private::ExitType m_exit_type;
int m_exit_status;
std::string m_exit_description;
llvm::Optional<WaitStatus> m_exit_status;
std::recursive_mutex m_delegates_mutex;
std::vector<NativeDelegate *> m_delegates;
NativeBreakpointList m_breakpoint_list;

View File

@ -1,24 +0,0 @@
//===-- ProcessLauncherPosix.h ----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef lldb_Host_posix_ProcessLauncherPosix_h_
#define lldb_Host_posix_ProcessLauncherPosix_h_
#include "lldb/Host/ProcessLauncher.h"
namespace lldb_private {
class ProcessLauncherPosix : public ProcessLauncher {
public:
HostProcess LaunchProcess(const ProcessLaunchInfo &launch_info,
Status &error) override;
};
}
#endif

View File

@ -454,6 +454,8 @@ enum LanguageType {
enum InstrumentationRuntimeType {
eInstrumentationRuntimeTypeAddressSanitizer = 0x0000,
eInstrumentationRuntimeTypeThreadSanitizer = 0x0001,
eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer = 0x0002,
eInstrumentationRuntimeTypeMainThreadChecker = 0x0003,
eNumInstrumentationRuntimeTypes
};

View File

@ -211,19 +211,6 @@ enum class LineStatus {
Done // Lines are complete
};
//----------------------------------------------------------------------
// Exit Type for inferior processes
//----------------------------------------------------------------------
typedef enum ExitType {
eExitTypeInvalid,
eExitTypeExit, // The exit status represents the return code from normal
// program exit (i.e. WIFEXITED() was true)
eExitTypeSignal, // The exit status represents the signal number that caused
// the program to exit (i.e. WIFSIGNALED() was true)
eExitTypeStop, // The exit status represents the stop signal that caused the
// program to exit (i.e. WIFSTOPPED() was true)
} ExitType;
//----------------------------------------------------------------------
// Boolean result of running a Type Validator
//----------------------------------------------------------------------

View File

@ -744,6 +744,7 @@
4CF3D80C15AF4DC800845BF3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; };
4CF52AF51428291E0051E832 /* SBFileSpecList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF52AF41428291E0051E832 /* SBFileSpecList.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; };
54067BF11DF2041B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */; };
6D0F61431C80AAAE00A4ECEE /* JavaASTContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61411C80AAAA00A4ECEE /* JavaASTContext.cpp */; };
6D0F61481C80AAD600A4ECEE /* DWARFASTParserJava.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F61441C80AACF00A4ECEE /* DWARFASTParserJava.cpp */; };
6D0F614E1C80AB0700A4ECEE /* JavaLanguageRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6D0F614A1C80AB0400A4ECEE /* JavaLanguageRuntime.cpp */; };
@ -766,6 +767,7 @@
8C26C4261C3EA5F90031DF7C /* ThreadSanitizerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C26C4241C3EA4340031DF7C /* ThreadSanitizerRuntime.cpp */; };
8C2D6A53197A1EAF006989C9 /* MemoryHistory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A52197A1EAF006989C9 /* MemoryHistory.cpp */; };
8C2D6A5E197A250F006989C9 /* MemoryHistoryASan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */; };
8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */; };
8CCB017E19BA28A80009FD44 /* ThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */; };
8CCB018219BA4E270009FD44 /* SBThreadCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CCB018119BA4E210009FD44 /* SBThreadCollection.h */; settings = {ATTRIBUTES = (Public, ); }; };
8CCB018319BA51BF0009FD44 /* SBThreadCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */; };
@ -2576,6 +2578,8 @@
4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
4CF52AF41428291E0051E832 /* SBFileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpecList.h; path = include/lldb/API/SBFileSpecList.h; sourceTree = "<group>"; };
4CF52AF7142829390051E832 /* SBFileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpecList.cpp; path = source/API/SBFileSpecList.cpp; sourceTree = "<group>"; };
54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.cpp.cpp; name = UndefinedBehaviorSanitizerRuntime.cpp; path = UndefinedBehaviorSanitizer/UndefinedBehaviorSanitizerRuntime.cpp; sourceTree = "<group>"; };
54067BED1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UndefinedBehaviorSanitizerRuntime.h; path = UndefinedBehaviorSanitizer/UndefinedBehaviorSanitizerRuntime.h; sourceTree = "<group>"; };
69A01E1C1236C5D400C660B5 /* Host.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Host.cpp; sourceTree = "<group>"; };
69A01E1F1236C5D400C660B5 /* Symbols.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Symbols.cpp; sourceTree = "<group>"; };
6D0F613C1C80AA8900A4ECEE /* DebugMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebugMacros.h; path = include/lldb/Symbol/DebugMacros.h; sourceTree = "<group>"; };
@ -2624,6 +2628,8 @@
8C2D6A54197A1EBE006989C9 /* MemoryHistory.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MemoryHistory.h; path = include/lldb/Target/MemoryHistory.h; sourceTree = "<group>"; };
8C2D6A5A197A1FDC006989C9 /* MemoryHistoryASan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MemoryHistoryASan.cpp; sourceTree = "<group>"; };
8C2D6A5B197A1FDC006989C9 /* MemoryHistoryASan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MemoryHistoryASan.h; sourceTree = "<group>"; };
8C3BD9931EF45D9B0016C343 /* MainThreadCheckerRuntime.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MainThreadCheckerRuntime.h; sourceTree = "<group>"; };
8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MainThreadCheckerRuntime.cpp; sourceTree = "<group>"; };
8CCB017A19BA283D0009FD44 /* ThreadCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadCollection.cpp; path = source/Target/ThreadCollection.cpp; sourceTree = "<group>"; };
8CCB017C19BA289B0009FD44 /* ThreadCollection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ThreadCollection.h; path = include/lldb/Target/ThreadCollection.h; sourceTree = "<group>"; };
8CCB017F19BA4DD00009FD44 /* SBThreadCollection.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = SBThreadCollection.cpp; path = source/API/SBThreadCollection.cpp; sourceTree = "<group>"; };
@ -5912,6 +5918,15 @@
path = "gdb-remote";
sourceTree = "<group>";
};
54067BEA1DF2033700749AA5 /* UndefinedBehaviorSanitizer */ = {
isa = PBXGroup;
children = (
54067BEC1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp */,
54067BED1DF2034B00749AA5 /* UndefinedBehaviorSanitizerRuntime.h */,
);
name = UndefinedBehaviorSanitizer;
sourceTree = "<group>";
};
69A01E1A1236C5D400C660B5 /* common */ = {
isa = PBXGroup;
children = (
@ -6011,11 +6026,22 @@
path = asan;
sourceTree = "<group>";
};
8C3BD9911EF45D9B0016C343 /* MainThreadChecker */ = {
isa = PBXGroup;
children = (
8C3BD9931EF45D9B0016C343 /* MainThreadCheckerRuntime.h */,
8C3BD9951EF45D9B0016C343 /* MainThreadCheckerRuntime.cpp */,
);
path = MainThreadChecker;
sourceTree = "<group>";
};
8CF02ADD19DCBEC200B14BE0 /* InstrumentationRuntime */ = {
isa = PBXGroup;
children = (
54067BEA1DF2033700749AA5 /* UndefinedBehaviorSanitizer */,
8C26C4221C3EA4050031DF7C /* ThreadSanitizer */,
8CF02ADE19DCBEE600B14BE0 /* AddressSanitizer */,
8C3BD9911EF45D9B0016C343 /* MainThreadChecker */,
);
path = InstrumentationRuntime;
sourceTree = "<group>";
@ -7133,6 +7159,7 @@
2689001213353DDE00698AC0 /* CommandObjectApropos.cpp in Sources */,
4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */,
AE44FB4C1BB4BB540033EB62 /* GoFormatterFunctions.cpp in Sources */,
8C3BD9961EF45DA50016C343 /* MainThreadCheckerRuntime.cpp in Sources */,
23042D121976CA1D00621B2C /* PlatformKalimba.cpp in Sources */,
2689001313353DDE00698AC0 /* CommandObjectArgs.cpp in Sources */,
2689001413353DDE00698AC0 /* CommandObjectBreakpoint.cpp in Sources */,
@ -7623,6 +7650,7 @@
26954EBE1401EE8B00294D09 /* DynamicRegisterInfo.cpp in Sources */,
6D9AB3DD1BB2B74E003F2289 /* TypeMap.cpp in Sources */,
255EFF761AFABA950069F277 /* LockFilePosix.cpp in Sources */,
54067BF11DF2041B00749AA5 /* UndefinedBehaviorSanitizerRuntime.cpp in Sources */,
3FBA69EC1B6067430008F44A /* PythonDataObjects.cpp in Sources */,
26274FA714030F79006BA130 /* DynamicLoaderDarwinKernel.cpp in Sources */,
94FA3DE01405D50400833217 /* ValueObjectConstResultChild.cpp in Sources */,

View File

@ -681,6 +681,53 @@ def is_compiler_clang_with_thread_sanitizer(self):
return None
return skipTestIfFn(is_compiler_clang_with_thread_sanitizer)(func)
def skipUnlessUndefinedBehaviorSanitizer(func):
"""Decorate the item to skip test unless -fsanitize=undefined is supported."""
def is_compiler_clang_with_ubsan(self):
# Write out a temp file which exhibits UB.
inputf = tempfile.NamedTemporaryFile(suffix='.c')
inputf.write('int main() { int x = 0; return x / x; }\n')
inputf.flush()
# We need to write out the object into a named temp file for inspection.
outputf = tempfile.NamedTemporaryFile()
# Try to compile with ubsan turned on.
cmd = '%s -fsanitize=undefined %s -o %s' % (self.getCompiler(), inputf.name, outputf.name)
if os.popen(cmd).close() is not None:
return "Compiler cannot compile with -fsanitize=undefined"
# Check that we actually see ubsan instrumentation in the binary.
cmd = 'nm %s' % outputf.name
with os.popen(cmd) as nm_output:
if '___ubsan_handle_divrem_overflow' not in nm_output.read():
return "Division by zero instrumentation is missing"
# Find the ubsan dylib.
# FIXME: This check should go away once compiler-rt gains support for __ubsan_on_report.
cmd = '%s -fsanitize=undefined -x c - -o - -### 2>&1' % self.getCompiler()
with os.popen(cmd) as cc_output:
driver_jobs = cc_output.read()
m = re.search(r'"([^"]+libclang_rt.ubsan_osx_dynamic.dylib)"', driver_jobs)
if not m:
return "Could not find the ubsan dylib used by the driver"
ubsan_dylib = m.group(1)
# Check that the ubsan dylib has special monitor hooks.
cmd = 'nm -gU %s' % ubsan_dylib
with os.popen(cmd) as nm_output:
syms = nm_output.read()
if '___ubsan_on_report' not in syms:
return "Missing ___ubsan_on_report"
if '___ubsan_get_current_report_data' not in syms:
return "Missing ___ubsan_get_current_report_data"
# OK, this dylib + compiler works for us.
return None
return skipTestIfFn(is_compiler_clang_with_ubsan)(func)
def skipUnlessAddressSanitizer(func):
"""Decorate the item to skip test unless Clang -fsanitize=thread is supported."""

View File

@ -186,16 +186,27 @@ def cleanup():
def nsnumber_data_formatter_commands(self):
# Now enable AppKit and check we are displaying Cocoa classes correctly
self.expect('frame variable num1 num2 num3 num4 num5 num6 num7 num9',
self.expect('frame variable num1 num2 num3 num5 num6 num7 num9',
substrs=['(NSNumber *) num1 = ', ' (int)5',
'(NSNumber *) num2 = ', ' (float)3.1',
'(NSNumber *) num3 = ', ' (double)3.14',
'(NSNumber *) num4 = ', ' (long)-2',
'(NSNumber *) num5 = ', ' (char)65',
'(NSNumber *) num6 = ', ' (long)255',
'(NSNumber *) num7 = ', '2000000',
'(NSNumber *) num9 = ', ' (short)-31616'])
self.runCmd('frame variable num4', check=True)
output = self.res.GetOutput()
i128_handled_correctly = False
if output.find('long') >= 0:
i128_handled_correctly = (output.find('(long)-2') >= 0)
if output.find('int128_t') >= 0:
i128_handled_correctly = (output.find('(int128_t)18446744073709551614') >= 0) # deliberately broken, should be ..14
self.assertTrue(i128_handled_correctly, "Expected valid output for int128_t; got " + output)
self.expect('frame variable num_at1 num_at2 num_at3 num_at4',
substrs=['(NSNumber *) num_at1 = ', ' (int)12',
'(NSNumber *) num_at2 = ', ' (int)-12',

View File

@ -0,0 +1,6 @@
LEVEL = ../../../make
C_SOURCES := main.c
CFLAGS_EXTRAS := -fsanitize=undefined -g
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,90 @@
"""
Tests basic UndefinedBehaviorSanitizer support (detecting an alignment error).
"""
import os
import time
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
import lldbsuite.test.lldbutil as lldbutil
import json
class UbsanBasicTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
@skipUnlessUndefinedBehaviorSanitizer
def test(self):
self.build()
self.ubsan_tests()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
self.line_align = line_number('main.c', '// align line')
def ubsan_tests(self):
# Load the test
exe = os.path.join(os.getcwd(), "a.out")
self.expect(
"file " + exe,
patterns=["Current executable set to .*a.out"])
self.runCmd("run")
process = self.dbg.GetSelectedTarget().process
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
# the stop reason of the thread should be breakpoint.
self.expect("thread list", "A ubsan issue should be detected",
substrs=['stopped', 'stop reason ='])
stop_reason = thread.GetStopReason()
self.assertEqual(stop_reason, lldb.eStopReasonInstrumentation)
# test that the UBSan dylib is present
self.expect(
"image lookup -n __ubsan_on_report",
"__ubsan_on_report should be present",
substrs=['1 match found'])
# We should be stopped in __ubsan_on_report
self.assertTrue("__ubsan_on_report" in frame.GetFunctionName())
# The stopped thread backtrace should contain either 'align line'
found = False
for i in range(thread.GetNumFrames()):
frame = thread.GetFrameAtIndex(i)
if frame.GetLineEntry().GetFileSpec().GetFilename() == "main.c":
if frame.GetLineEntry().GetLine() == self.line_align:
found = True
self.assertTrue(found)
backtraces = thread.GetStopReasonExtendedBacktraces(
lldb.eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer)
self.assertTrue(backtraces.GetSize() == 1)
self.expect(
"thread info -s",
"The extended stop info should contain the UBSan provided fields",
substrs=[
"instrumentation_class",
"memory_address",
"description",
"filename",
"line",
"col"])
output_lines = self.res.GetOutput().split('\n')
json_line = '\n'.join(output_lines[2:])
data = json.loads(json_line)
self.assertEqual(data["instrumentation_class"], "UndefinedBehaviorSanitizer")
self.assertEqual(data["description"], "misaligned-pointer-use")
self.assertEqual(data["filename"], "main.c")
self.assertEqual(data["line"], self.line_align)
self.runCmd("continue")

View File

@ -0,0 +1,4 @@
int main() {
int data[4];
return *(int *)(((char *)&data[0]) + 2); // align line
}

View File

@ -121,8 +121,6 @@ def test_read_dictionary(self):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
@expectedFailureAll(
bugnumber="rdar://32777981")
def test_update_dictionary(self):
self.runToBreakpoint()
@ -165,8 +163,6 @@ def test_array_literal(self):
'7.0.0'])
@skipIf(macos_version=["<", "10.12"])
@expectedFailureAll(archs=["i[3-6]86"])
@expectedFailureAll(
bugnumber="rdar://32777981")
def test_dictionary_literal(self):
self.runToBreakpoint()

View File

@ -929,7 +929,8 @@ void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton);
void LLDBSwigPythonCallPythonLogOutputCallback(const char *str, void *baton) {
if (baton != Py_None) {
SWIG_PYTHON_THREAD_BEGIN_BLOCK;
PyObject_CallFunction(reinterpret_cast<PyObject*>(baton), const_cast<char*>("s"), str);
PyObject *result = PyObject_CallFunction(reinterpret_cast<PyObject*>(baton), const_cast<char*>("s"), str);
Py_XDECREF(result);
SWIG_PYTHON_THREAD_END_BLOCK;
}
}

View File

@ -293,10 +293,6 @@ SBThread::GetStopReasonExtendedBacktraces(InstrumentationRuntimeType type) {
ThreadCollectionSP threads;
threads.reset(new ThreadCollection());
// We currently only support ThreadSanitizer.
if (type != eInstrumentationRuntimeTypeThreadSanitizer)
return threads;
std::unique_lock<std::recursive_mutex> lock;
ExecutionContext exe_ctx(m_opaque_sp.get(), lock);

View File

@ -49,8 +49,10 @@
#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h"
#include "Plugins/DynamicLoader/Windows-DYLD/DynamicLoaderWindowsDYLD.h"
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
#include "Plugins/InstrumentationRuntime/AddressSanitizer/AddressSanitizerRuntime.h"
#include "Plugins/InstrumentationRuntime/ThreadSanitizer/ThreadSanitizerRuntime.h"
#include "Plugins/InstrumentationRuntime/ASan/ASanRuntime.h"
#include "Plugins/InstrumentationRuntime/TSan/TSanRuntime.h"
#include "Plugins/InstrumentationRuntime/UBSan/UBSanRuntime.h"
#include "Plugins/InstrumentationRuntime/MainThreadChecker/MainThreadCheckerRuntime.h"
#include "Plugins/JITLoader/GDB/JITLoaderGDB.h"
#include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
#include "Plugins/Language/Go/GoLanguage.h"
@ -310,6 +312,8 @@ void SystemInitializerFull::Initialize() {
MemoryHistoryASan::Initialize();
AddressSanitizerRuntime::Initialize();
ThreadSanitizerRuntime::Initialize();
UndefinedBehaviorSanitizerRuntime::Initialize();
MainThreadCheckerRuntime::Initialize();
SymbolVendorELF::Initialize();
SymbolFileDWARF::Initialize();
@ -434,6 +438,8 @@ void SystemInitializerFull::Terminate() {
MemoryHistoryASan::Terminate();
AddressSanitizerRuntime::Terminate();
ThreadSanitizerRuntime::Terminate();
UndefinedBehaviorSanitizerRuntime::Terminate();
MainThreadCheckerRuntime::Terminate();
SymbolVendorELF::Terminate();
SymbolFileDWARF::Terminate();
SymbolFilePDB::Terminate();

View File

@ -655,32 +655,30 @@ class CommandObjectFrameVariable : public CommandObjectParsed {
if (num_variables > 0) {
for (size_t i = 0; i < num_variables; i++) {
var_sp = variable_list->GetVariableAtIndex(i);
switch (var_sp->GetScope())
{
case eValueTypeVariableGlobal:
if (!m_option_variable.show_globals)
continue;
break;
case eValueTypeVariableStatic:
if (!m_option_variable.show_globals)
continue;
break;
case eValueTypeVariableArgument:
if (!m_option_variable.show_args)
continue;
break;
case eValueTypeVariableLocal:
if (!m_option_variable.show_locals)
continue;
break;
default:
switch (var_sp->GetScope()) {
case eValueTypeVariableGlobal:
if (!m_option_variable.show_globals)
continue;
break;
break;
case eValueTypeVariableStatic:
if (!m_option_variable.show_globals)
continue;
break;
case eValueTypeVariableArgument:
if (!m_option_variable.show_args)
continue;
break;
case eValueTypeVariableLocal:
if (!m_option_variable.show_locals)
continue;
break;
default:
continue;
break;
}
std::string scope_string;
if (m_option_variable.show_scope)
scope_string = GetScopeString(var_sp).str();
std::string scope_string;
if (m_option_variable.show_scope)
scope_string = GetScopeString(var_sp).str();
// Use the variable object code to make sure we are
// using the same APIs as the public API will be

View File

@ -58,7 +58,7 @@
#include "llvm/ADT/StringRef.h" // for StringRef
#ifdef _MSC_VER
#include <windows.h>
#include "lldb/Host/windows/windows.h"
#endif
#include <memory> // for shared_ptr

View File

@ -10,7 +10,7 @@
#include "lldb/Core/Mangled.h"
#if defined(_WIN32)
#include <windows.h>
#include "lldb/Host/windows/windows.h"
#include <dbghelp.h>
#pragma comment(lib, "dbghelp.lib")

View File

@ -38,20 +38,9 @@ static std::mutex &GetFileMutex() {
return *g_file_mutex_ptr;
}
static void ThreadSpecificCleanup(void *p) {
delete static_cast<TimerStack *>(p);
}
static TimerStack *GetTimerStackForCurrentThread() {
static lldb::thread_key_t g_key =
Host::ThreadLocalStorageCreate(ThreadSpecificCleanup);
void *timer_stack = Host::ThreadLocalStorageGet(g_key);
if (timer_stack == NULL) {
Host::ThreadLocalStorageSet(g_key, new TimerStack);
timer_stack = Host::ThreadLocalStorageGet(g_key);
}
return (TimerStack *)timer_stack;
static TimerStack &GetTimerStackForCurrentThread() {
static thread_local TimerStack g_stack;
return g_stack;
}
Timer::Category::Category(const char *cat) : m_name(cat) {
@ -66,16 +55,14 @@ void Timer::SetQuiet(bool value) { g_quiet = value; }
Timer::Timer(Timer::Category &category, const char *format, ...)
: m_category(category), m_total_start(std::chrono::steady_clock::now()) {
TimerStack *stack = GetTimerStackForCurrentThread();
if (!stack)
return;
TimerStack &stack = GetTimerStackForCurrentThread();
stack->push_back(this);
if (g_quiet && stack->size() <= g_display_depth) {
stack.push_back(this);
if (g_quiet && stack.size() <= g_display_depth) {
std::lock_guard<std::mutex> lock(GetFileMutex());
// Indent
::fprintf(stdout, "%*s", int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "");
::fprintf(stdout, "%*s", int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "");
// Print formatted string
va_list args;
va_start(args, format);
@ -90,26 +77,23 @@ Timer::Timer(Timer::Category &category, const char *format, ...)
Timer::~Timer() {
using namespace std::chrono;
TimerStack *stack = GetTimerStackForCurrentThread();
if (!stack)
return;
auto stop_time = steady_clock::now();
auto total_dur = stop_time - m_total_start;
auto timer_dur = total_dur - m_child_duration;
if (g_quiet && stack->size() <= g_display_depth) {
TimerStack &stack = GetTimerStackForCurrentThread();
if (g_quiet && stack.size() <= g_display_depth) {
std::lock_guard<std::mutex> lock(GetFileMutex());
::fprintf(stdout, "%*s%.9f sec (%.9f sec)\n",
int(stack->size() - 1) * TIMER_INDENT_AMOUNT, "",
int(stack.size() - 1) * TIMER_INDENT_AMOUNT, "",
duration<double>(total_dur).count(),
duration<double>(timer_dur).count());
}
assert(stack->back() == this);
stack->pop_back();
if (!stack->empty())
stack->back()->ChildDuration(total_dur);
assert(stack.back() == this);
stack.pop_back();
if (!stack.empty())
stack.back()->ChildDuration(total_dur);
// Keep total results for each category so we can dump results.
m_category.m_nanos += std::chrono::nanoseconds(timer_dur).count();

View File

@ -90,12 +90,6 @@ else()
posix/ProcessLauncherPosixFork.cpp
)
if (NOT (CMAKE_SYSTEM_NAME MATCHES "Android"))
add_host_subdirectory(posix
posix/ProcessLauncherPosix.cpp
)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
add_host_subdirectory(macosx

View File

@ -68,15 +68,14 @@
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-forward.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#if defined(_WIN32)
#include "lldb/Host/windows/ProcessLauncherWindows.h"
#elif defined(__linux__) || defined(__NetBSD__)
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
#else
#include "lldb/Host/posix/ProcessLauncherPosix.h"
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
#endif
#if defined(__APPLE__)
@ -407,25 +406,6 @@ const char *Host::GetSignalAsCString(int signo) {
#endif
#ifndef _WIN32
lldb::thread_key_t
Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
pthread_key_t key;
::pthread_key_create(&key, callback);
return key;
}
void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
return ::pthread_getspecific(key);
}
void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
::pthread_setspecific(key, value);
}
#endif
#if !defined(__APPLE__) // see Host.mm
bool Host::GetBundleDirectory(const FileSpec &file, FileSpec &bundle) {
@ -602,359 +582,14 @@ Status Host::RunShellCommand(const Args &args, const FileSpec &working_dir,
return error;
}
// LaunchProcessPosixSpawn for Apple, Linux, FreeBSD, NetBSD and other GLIBC
// systems
#if defined(__APPLE__) || defined(__linux__) || defined(__FreeBSD__) || \
defined(__GLIBC__) || defined(__NetBSD__)
#if !defined(__ANDROID__)
// this method needs to be visible to macosx/Host.cpp and
// common/Host.cpp.
short Host::GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
#if defined(__APPLE__)
if (launch_info.GetFlags().Test(eLaunchFlagExec))
flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
if (launch_info.GetFlags().Test(eLaunchFlagDebug))
flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
if (launch_info.GetLaunchInSeparateProcessGroup())
flags |= POSIX_SPAWN_SETPGROUP;
#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
#if defined(__APPLE__) && (defined(__x86_64__) || defined(__i386__))
static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
g_use_close_on_exec_flag = eLazyBoolNo;
uint32_t major, minor, update;
if (HostInfo::GetOSVersion(major, minor, update)) {
// Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
// earlier
if (major > 10 || (major == 10 && minor > 7)) {
// Only enable for 10.8 and later OS versions
g_use_close_on_exec_flag = eLazyBoolYes;
}
}
}
#else
static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
#endif
// Close all files exception those with file actions if this is supported.
if (g_use_close_on_exec_flag == eLazyBoolYes)
flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
#endif
#endif // #if defined (__APPLE__)
return flags;
}
Status Host::LaunchProcessPosixSpawn(const char *exe_path,
const ProcessLaunchInfo &launch_info,
lldb::pid_t &pid) {
Status error;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
LIBLLDB_LOG_PROCESS));
posix_spawnattr_t attr;
error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
return error;
}
// Make a quick class that will cleanup the posix spawn attributes in case
// we return in the middle of this function.
lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup(
&attr, posix_spawnattr_destroy);
sigset_t no_signals;
sigset_t all_signals;
sigemptyset(&no_signals);
sigfillset(&all_signals);
::posix_spawnattr_setsigmask(&attr, &no_signals);
#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
::posix_spawnattr_setsigdefault(&attr, &no_signals);
#else
::posix_spawnattr_setsigdefault(&attr, &all_signals);
#endif
short flags = GetPosixspawnFlags(launch_info);
error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
error, flags);
return error;
}
// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
#if defined(__APPLE__) && !defined(__arm__)
// Don't set the binpref if a shell was provided. After all, that's only
// going to affect what version of the shell
// is launched, not what fork of the binary is launched. We insert "arch
// --arch <ARCH> as part of the shell invocation
// to do that job on OSX.
if (launch_info.GetShell() == nullptr) {
// We don't need to do this for ARM, and we really shouldn't now that we
// have multiple CPU subtypes and no posix_spawnattr call that allows us
// to set which CPU subtype to launch...
const ArchSpec &arch_spec = launch_info.GetArchitecture();
cpu_type_t cpu = arch_spec.GetMachOCPUType();
cpu_type_t sub = arch_spec.GetMachOCPUSubType();
if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
!(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
// to set the CPU type or we will fail
{
size_t ocount = 0;
error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log, "error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
"cpu_type = {1:x}, count => {2} )",
error, cpu, ocount);
if (error.Fail() || ocount != 1)
return error;
}
}
#endif
const char *tmp_argv[2];
char *const *argv = const_cast<char *const *>(
launch_info.GetArguments().GetConstArgumentVector());
char *const *envp = const_cast<char *const *>(
launch_info.GetEnvironmentEntries().GetConstArgumentVector());
if (argv == NULL) {
// posix_spawn gets very unhappy if it doesn't have at least the program
// name in argv[0]. One of the side affects I have noticed is the
// environment
// variables don't make it into the child process if "argv == NULL"!!!
tmp_argv[0] = exe_path;
tmp_argv[1] = NULL;
argv = const_cast<char *const *>(tmp_argv);
}
// The functions below implement process launching for non-Apple-based platforms
#if !defined(__APPLE__)
// manage the working directory
char current_dir[PATH_MAX];
current_dir[0] = '\0';
#endif
FileSpec working_dir{launch_info.GetWorkingDirectory()};
if (working_dir) {
#if defined(__APPLE__)
// Set the working directory on this thread only
if (__pthread_chdir(working_dir.GetCString()) < 0) {
if (errno == ENOENT) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
} else if (errno == ENOTDIR) {
error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
working_dir.GetCString());
} else {
error.SetErrorStringWithFormat("An unknown error occurred when "
"changing directory for process "
"execution.");
}
return error;
}
#else
if (::getcwd(current_dir, sizeof(current_dir)) == NULL) {
error.SetError(errno, eErrorTypePOSIX);
LLDB_LOG(log, "error: {0}, unable to save the current directory", error);
return error;
}
if (::chdir(working_dir.GetCString()) == -1) {
error.SetError(errno, eErrorTypePOSIX);
LLDB_LOG(log, "error: {0}, unable to change working directory to {1}",
error, working_dir);
return error;
}
#endif
}
::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
const size_t num_file_actions = launch_info.GetNumFileActions();
if (num_file_actions > 0) {
posix_spawn_file_actions_t file_actions;
error.SetError(::posix_spawn_file_actions_init(&file_actions),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
error);
return error;
}
// Make a quick class that will cleanup the posix spawn attributes in case
// we return in the middle of this function.
lldb_utility::CleanUp<posix_spawn_file_actions_t *, int>
posix_spawn_file_actions_cleanup(&file_actions,
posix_spawn_file_actions_destroy);
for (size_t i = 0; i < num_file_actions; ++i) {
const FileAction *launch_file_action =
launch_info.GetFileActionAtIndex(i);
if (launch_file_action) {
if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
error))
return error;
}
}
error.SetError(
::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log, "error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
"file_actions = {3}, "
"attr = {4}, argv = {5}, envp = {6} )",
error, result_pid, exe_path, &file_actions, &attr, argv, envp);
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
}
}
} else {
error.SetError(
::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log, "error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
"file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
error, result_pid, exe_path, &attr, argv, envp);
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
}
}
}
pid = result_pid;
if (working_dir) {
#if defined(__APPLE__)
// No more thread specific current working directory
__pthread_fchdir(-1);
#else
if (::chdir(current_dir) == -1 && error.Success()) {
error.SetError(errno, eErrorTypePOSIX);
LLDB_LOG(log,
"error: {0}, unable to change current directory back to {1}",
error, current_dir);
}
#endif
}
return error;
}
bool Host::AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
Log *log, Status &error) {
if (info == NULL)
return false;
posix_spawn_file_actions_t *file_actions =
reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
switch (info->GetAction()) {
case FileAction::eFileActionNone:
error.Clear();
break;
case FileAction::eFileActionClose:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd for posix_spawn_file_actions_addclose(...)");
else {
error.SetError(
::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_addclose "
"(action={1}, fd={2})",
error, file_actions, info->GetFD());
}
break;
case FileAction::eFileActionDuplicate:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd for posix_spawn_file_actions_adddup2(...)");
else if (info->GetActionArgument() == -1)
error.SetErrorString(
"invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
else {
error.SetError(
::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
info->GetActionArgument()),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log, "error: {0}, posix_spawn_file_actions_adddup2 "
"(action={1}, fd={2}, dup_fd={3})",
error, file_actions, info->GetFD(), info->GetActionArgument());
}
break;
case FileAction::eFileActionOpen:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd in posix_spawn_file_actions_addopen(...)");
else {
int oflag = info->GetActionArgument();
mode_t mode = 0;
if (oflag & O_CREAT)
mode = 0640;
error.SetError(::posix_spawn_file_actions_addopen(
file_actions, info->GetFD(),
info->GetPath().str().c_str(), oflag, mode),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(
log, "error: {0}, posix_spawn_file_actions_addopen (action={1}, "
"fd={2}, path='{3}', oflag={4}, mode={5})",
error, file_actions, info->GetFD(), info->GetPath(), oflag, mode);
}
break;
}
return error.Success();
}
#endif // !defined(__ANDROID__)
#endif // defined (__APPLE__) || defined (__linux__) || defined (__FreeBSD__) ||
// defined (__GLIBC__) || defined(__NetBSD__)
#if defined(__linux__) || defined(__FreeBSD__) || defined(__GLIBC__) || \
defined(__NetBSD__) || defined(_WIN32)
// The functions below implement process launching via posix_spawn() for Linux,
// FreeBSD and NetBSD.
Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
std::unique_ptr<ProcessLauncher> delegate_launcher;
#if defined(_WIN32)
delegate_launcher.reset(new ProcessLauncherWindows());
#elif defined(__linux__) || defined(__NetBSD__)
delegate_launcher.reset(new ProcessLauncherPosixFork());
#else
delegate_launcher.reset(new ProcessLauncherPosix());
delegate_launcher.reset(new ProcessLauncherPosixFork());
#endif
MonitoringProcessLauncher launcher(std::move(delegate_launcher));
@ -968,7 +603,7 @@ Status Host::LaunchProcess(ProcessLaunchInfo &launch_info) {
return error;
}
#endif // defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#endif // !defined(__APPLE__)
#ifndef _WIN32
void Host::Kill(lldb::pid_t pid, int signo) { ::kill(pid, signo); }
@ -988,3 +623,51 @@ const UnixSignalsSP &Host::GetUnixSignals() {
UnixSignals::Create(HostInfo::GetArchitecture());
return s_unix_signals_sp;
}
#if defined(LLVM_ON_UNIX)
WaitStatus WaitStatus::Decode(int wstatus) {
if (WIFEXITED(wstatus))
return {Exit, uint8_t(WEXITSTATUS(wstatus))};
else if (WIFSIGNALED(wstatus))
return {Signal, uint8_t(WTERMSIG(wstatus))};
else if (WIFSTOPPED(wstatus))
return {Stop, uint8_t(WSTOPSIG(wstatus))};
llvm_unreachable("Unknown wait status");
}
#endif
void llvm::format_provider<WaitStatus>::format(const WaitStatus &WS,
raw_ostream &OS,
StringRef Options) {
if (Options == "g") {
char type;
switch (WS.type) {
case WaitStatus::Exit:
type = 'W';
break;
case WaitStatus::Signal:
type = 'X';
break;
case WaitStatus::Stop:
type = 'S';
break;
}
OS << formatv("{0}{1:x-2}", type, WS.status);
return;
}
assert(Options.empty());
const char *desc;
switch(WS.type) {
case WaitStatus::Exit:
desc = "Exited with status";
break;
case WaitStatus::Signal:
desc = "Killed by signal";
break;
case WaitStatus::Stop:
desc = "Stopped by signal";
break;
}
OS << desc << " " << int(WS.status);
}

View File

@ -32,7 +32,6 @@ using namespace lldb_private;
NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid)
: m_pid(pid), m_threads(), m_current_thread_id(LLDB_INVALID_THREAD_ID),
m_threads_mutex(), m_state(lldb::eStateInvalid), m_state_mutex(),
m_exit_type(eExitTypeInvalid), m_exit_status(0), m_exit_description(),
m_delegates_mutex(), m_delegates(), m_breakpoint_list(),
m_watchpoint_list(), m_terminal_fd(-1), m_stop_id(0) {}
@ -59,46 +58,29 @@ NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr,
return Status("not implemented");
}
bool NativeProcessProtocol::GetExitStatus(ExitType *exit_type, int *status,
std::string &exit_description) {
if (m_state == lldb::eStateExited) {
*exit_type = m_exit_type;
*status = m_exit_status;
exit_description = m_exit_description;
return true;
}
llvm::Optional<WaitStatus> NativeProcessProtocol::GetExitStatus() {
if (m_state == lldb::eStateExited)
return m_exit_status;
*status = 0;
return false;
return llvm::None;
}
bool NativeProcessProtocol::SetExitStatus(ExitType exit_type, int status,
const char *exit_description,
bool NativeProcessProtocol::SetExitStatus(WaitStatus status,
bool bNotifyStateChange) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("NativeProcessProtocol::%s(%d, %d, %s, %s) called",
__FUNCTION__, exit_type, status,
exit_description ? exit_description : "nullptr",
bNotifyStateChange ? "true" : "false");
LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange);
// Exit status already set
if (m_state == lldb::eStateExited) {
if (log)
log->Printf("NativeProcessProtocol::%s exit status already set to %d, "
"ignoring new set to %d",
__FUNCTION__, m_exit_status, status);
if (m_exit_status)
LLDB_LOG(log, "exit status already set to {0}", *m_exit_status);
else
LLDB_LOG(log, "state is exited, but status not set");
return false;
}
m_state = lldb::eStateExited;
m_exit_type = exit_type;
m_exit_status = status;
if (exit_description && exit_description[0])
m_exit_description = exit_description;
else
m_exit_description.clear();
if (bNotifyStateChange)
SynchronouslyNotifyProcessStateChanged(lldb::eStateExited);

View File

@ -1024,6 +1024,47 @@ static Status getXPCAuthorization(ProcessLaunchInfo &launch_info) {
}
#endif
static short GetPosixspawnFlags(const ProcessLaunchInfo &launch_info) {
short flags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
if (launch_info.GetFlags().Test(eLaunchFlagExec))
flags |= POSIX_SPAWN_SETEXEC; // Darwin specific posix_spawn flag
if (launch_info.GetFlags().Test(eLaunchFlagDebug))
flags |= POSIX_SPAWN_START_SUSPENDED; // Darwin specific posix_spawn flag
if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
flags |= _POSIX_SPAWN_DISABLE_ASLR; // Darwin specific posix_spawn flag
if (launch_info.GetLaunchInSeparateProcessGroup())
flags |= POSIX_SPAWN_SETPGROUP;
#ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
#if defined(__x86_64__) || defined(__i386__)
static LazyBool g_use_close_on_exec_flag = eLazyBoolCalculate;
if (g_use_close_on_exec_flag == eLazyBoolCalculate) {
g_use_close_on_exec_flag = eLazyBoolNo;
uint32_t major, minor, update;
if (HostInfo::GetOSVersion(major, minor, update)) {
// Kernel panic if we use the POSIX_SPAWN_CLOEXEC_DEFAULT on 10.7 or
// earlier
if (major > 10 || (major == 10 && minor > 7)) {
// Only enable for 10.8 and later OS versions
g_use_close_on_exec_flag = eLazyBoolYes;
}
}
}
#else
static LazyBool g_use_close_on_exec_flag = eLazyBoolYes;
#endif // defined(__x86_64__) || defined(__i386__)
// Close all files exception those with file actions if this is supported.
if (g_use_close_on_exec_flag == eLazyBoolYes)
flags |= POSIX_SPAWN_CLOEXEC_DEFAULT;
#endif // ifdef POSIX_SPAWN_CLOEXEC_DEFAULT
return flags;
}
static Status LaunchProcessXPC(const char *exe_path,
ProcessLaunchInfo &launch_info,
lldb::pid_t &pid) {
@ -1107,7 +1148,7 @@ static Status LaunchProcessXPC(const char *exe_path,
xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
launch_info.GetArchitecture().GetMachOCPUType());
xpc_dictionary_set_int64(message, LauncherXPCServicePosixspawnFlagsKey,
Host::GetPosixspawnFlags(launch_info));
GetPosixspawnFlags(launch_info));
const FileAction *file_action = launch_info.GetFileActionForFD(STDIN_FILENO);
if (file_action && !file_action->GetPath().empty()) {
xpc_dictionary_set_string(message, LauncherXPCServiceStdInPathKeyKey,
@ -1161,6 +1202,262 @@ static Status LaunchProcessXPC(const char *exe_path,
#endif
}
static bool AddPosixSpawnFileAction(void *_file_actions, const FileAction *info,
Log *log, Status &error) {
if (info == NULL)
return false;
posix_spawn_file_actions_t *file_actions =
reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
switch (info->GetAction()) {
case FileAction::eFileActionNone:
error.Clear();
break;
case FileAction::eFileActionClose:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd for posix_spawn_file_actions_addclose(...)");
else {
error.SetError(
::posix_spawn_file_actions_addclose(file_actions, info->GetFD()),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, posix_spawn_file_actions_addclose "
"(action={1}, fd={2})",
error, file_actions, info->GetFD());
}
break;
case FileAction::eFileActionDuplicate:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd for posix_spawn_file_actions_adddup2(...)");
else if (info->GetActionArgument() == -1)
error.SetErrorString(
"invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
else {
error.SetError(
::posix_spawn_file_actions_adddup2(file_actions, info->GetFD(),
info->GetActionArgument()),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, posix_spawn_file_actions_adddup2 "
"(action={1}, fd={2}, dup_fd={3})",
error, file_actions, info->GetFD(), info->GetActionArgument());
}
break;
case FileAction::eFileActionOpen:
if (info->GetFD() == -1)
error.SetErrorString(
"invalid fd in posix_spawn_file_actions_addopen(...)");
else {
int oflag = info->GetActionArgument();
mode_t mode = 0;
if (oflag & O_CREAT)
mode = 0640;
error.SetError(::posix_spawn_file_actions_addopen(
file_actions, info->GetFD(),
info->GetPath().str().c_str(), oflag, mode),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, posix_spawn_file_actions_addopen (action={1}, "
"fd={2}, path='{3}', oflag={4}, mode={5})",
error, file_actions, info->GetFD(), info->GetPath(), oflag,
mode);
}
break;
}
return error.Success();
}
static Status LaunchProcessPosixSpawn(const char *exe_path,
const ProcessLaunchInfo &launch_info,
lldb::pid_t &pid) {
Status error;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST |
LIBLLDB_LOG_PROCESS));
posix_spawnattr_t attr;
error.SetError(::posix_spawnattr_init(&attr), eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log, "error: {0}, ::posix_spawnattr_init ( &attr )", error);
return error;
}
// Make a quick class that will cleanup the posix spawn attributes in case
// we return in the middle of this function.
lldb_utility::CleanUp<posix_spawnattr_t *, int> posix_spawnattr_cleanup(
&attr, posix_spawnattr_destroy);
sigset_t no_signals;
sigset_t all_signals;
sigemptyset(&no_signals);
sigfillset(&all_signals);
::posix_spawnattr_setsigmask(&attr, &no_signals);
::posix_spawnattr_setsigdefault(&attr, &all_signals);
short flags = GetPosixspawnFlags(launch_info);
error.SetError(::posix_spawnattr_setflags(&attr, flags), eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_setflags ( &attr, flags={1:x} )",
error, flags);
return error;
}
// posix_spawnattr_setbinpref_np appears to be an Apple extension per:
// http://www.unix.com/man-page/OSX/3/posix_spawnattr_setbinpref_np/
#if !defined(__arm__)
// Don't set the binpref if a shell was provided. After all, that's only
// going to affect what version of the shell
// is launched, not what fork of the binary is launched. We insert "arch
// --arch <ARCH> as part of the shell invocation
// to do that job on OSX.
if (launch_info.GetShell() == nullptr) {
// We don't need to do this for ARM, and we really shouldn't now that we
// have multiple CPU subtypes and no posix_spawnattr call that allows us
// to set which CPU subtype to launch...
const ArchSpec &arch_spec = launch_info.GetArchitecture();
cpu_type_t cpu = arch_spec.GetMachOCPUType();
cpu_type_t sub = arch_spec.GetMachOCPUSubType();
if (cpu != 0 && cpu != static_cast<cpu_type_t>(UINT32_MAX) &&
cpu != static_cast<cpu_type_t>(LLDB_INVALID_CPUTYPE) &&
!(cpu == 0x01000007 && sub == 8)) // If haswell is specified, don't try
// to set the CPU type or we will fail
{
size_t ocount = 0;
error.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu, &ocount),
eErrorTypePOSIX);
if (error.Fail())
LLDB_LOG(log,
"error: {0}, ::posix_spawnattr_setbinpref_np ( &attr, 1, "
"cpu_type = {1:x}, count => {2} )",
error, cpu, ocount);
if (error.Fail() || ocount != 1)
return error;
}
}
#endif // !defined(__arm__)
const char *tmp_argv[2];
char *const *argv = const_cast<char *const *>(
launch_info.GetArguments().GetConstArgumentVector());
char *const *envp = const_cast<char *const *>(
launch_info.GetEnvironmentEntries().GetConstArgumentVector());
if (argv == NULL) {
// posix_spawn gets very unhappy if it doesn't have at least the program
// name in argv[0]. One of the side affects I have noticed is the
// environment
// variables don't make it into the child process if "argv == NULL"!!!
tmp_argv[0] = exe_path;
tmp_argv[1] = NULL;
argv = const_cast<char *const *>(tmp_argv);
}
FileSpec working_dir{launch_info.GetWorkingDirectory()};
if (working_dir) {
// Set the working directory on this thread only
if (__pthread_chdir(working_dir.GetCString()) < 0) {
if (errno == ENOENT) {
error.SetErrorStringWithFormat("No such file or directory: %s",
working_dir.GetCString());
} else if (errno == ENOTDIR) {
error.SetErrorStringWithFormat("Path doesn't name a directory: %s",
working_dir.GetCString());
} else {
error.SetErrorStringWithFormat("An unknown error occurred when "
"changing directory for process "
"execution.");
}
return error;
}
}
::pid_t result_pid = LLDB_INVALID_PROCESS_ID;
const size_t num_file_actions = launch_info.GetNumFileActions();
if (num_file_actions > 0) {
posix_spawn_file_actions_t file_actions;
error.SetError(::posix_spawn_file_actions_init(&file_actions),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawn_file_actions_init ( &file_actions )",
error);
return error;
}
// Make a quick class that will cleanup the posix spawn attributes in case
// we return in the middle of this function.
lldb_utility::CleanUp<posix_spawn_file_actions_t *, int>
posix_spawn_file_actions_cleanup(&file_actions,
posix_spawn_file_actions_destroy);
for (size_t i = 0; i < num_file_actions; ++i) {
const FileAction *launch_file_action =
launch_info.GetFileActionAtIndex(i);
if (launch_file_action) {
if (!AddPosixSpawnFileAction(&file_actions, launch_file_action, log,
error))
return error;
}
}
error.SetError(
::posix_spawnp(&result_pid, exe_path, &file_actions, &attr, argv, envp),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
"file_actions = {3}, "
"attr = {4}, argv = {5}, envp = {6} )",
error, result_pid, exe_path, &file_actions, &attr, argv, envp);
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
}
}
} else {
error.SetError(
::posix_spawnp(&result_pid, exe_path, NULL, &attr, argv, envp),
eErrorTypePOSIX);
if (error.Fail()) {
LLDB_LOG(log,
"error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
"file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
error, result_pid, exe_path, &attr, argv, envp);
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
}
}
}
pid = result_pid;
if (working_dir) {
// No more thread specific current working directory
__pthread_fchdir(-1);
}
return error;
}
static bool ShouldLaunchUsingXPC(ProcessLaunchInfo &launch_info) {
bool result = false;

View File

@ -1,34 +0,0 @@
//===-- ProcessLauncherPosix.cpp --------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/posix/ProcessLauncherPosix.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include <limits.h>
using namespace lldb;
using namespace lldb_private;
HostProcess
ProcessLauncherPosix::LaunchProcess(const ProcessLaunchInfo &launch_info,
Status &error) {
lldb::pid_t pid;
char exe_path[PATH_MAX];
launch_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
// TODO(zturner): Move the code from LaunchProcessPosixSpawn to here, and make
// MacOSX re-use this
// ProcessLauncher when it wants a posix_spawn launch.
error = Host::LaunchProcessPosixSpawn(exe_path, launch_info, pid);
return HostProcess(pid);
}

View File

@ -52,10 +52,10 @@ static void FixupEnvironment(Args &env) {
static void LLVM_ATTRIBUTE_NORETURN ExitWithError(int error_fd,
const char *operation) {
std::ostringstream os;
os << operation << " failed: " << strerror(errno);
write(error_fd, os.str().data(), os.str().size());
close(error_fd);
int err = errno;
llvm::raw_fd_ostream os(error_fd, true);
os << operation << " failed: " << llvm::sys::StrError(err);
os.flush();
_exit(1);
}

View File

@ -101,19 +101,6 @@ lldb::thread_t Host::GetCurrentThread() {
return lldb::thread_t(::GetCurrentThread());
}
lldb::thread_key_t
Host::ThreadLocalStorageCreate(ThreadLocalStorageCleanupCallback callback) {
return TlsAlloc();
}
void *Host::ThreadLocalStorageGet(lldb::thread_key_t key) {
return ::TlsGetValue(key);
}
void Host::ThreadLocalStorageSet(lldb::thread_key_t key, void *value) {
::TlsSetValue(key, value);
}
void Host::Kill(lldb::pid_t pid, int signo) {
TerminateProcess((HANDLE)pid, 1);
}

View File

@ -1951,22 +1951,20 @@ bool ABISysV_arm64::CreateFunctionEntryUnwindPlan(UnwindPlan &unwind_plan) {
uint32_t lr_reg_num = arm64_dwarf::lr;
uint32_t sp_reg_num = arm64_dwarf::sp;
uint32_t pc_reg_num = arm64_dwarf::pc;
UnwindPlan::RowSP row(new UnwindPlan::Row);
// Our previous Call Frame Address is the stack pointer
row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 0);
// Our previous PC is in the LR
row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
unwind_plan.AppendRow(row);
unwind_plan.SetReturnAddressRegister(lr_reg_num);
// All other registers are the same.
unwind_plan.SetSourceName("arm64 at-func-entry default");
unwind_plan.SetSourcedFromCompiler(eLazyBoolNo);
unwind_plan.SetUnwindPlanValidAtAllInstructions(eLazyBoolNo);
return true;
}

View File

@ -21,6 +21,7 @@
#include "lldb/Core/Section.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@ -484,6 +485,27 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
return thread_plan_sp;
}
void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
if (m_vdso_base == LLDB_INVALID_ADDRESS)
return;
FileSpec file("[vdso]", false);
MemoryRegionInfo info;
Status status = m_process->GetMemoryRegionInfo(m_vdso_base, info);
if (status.Fail()) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
LLDB_LOG(log, "Failed to get vdso region info: {0}", status);
return;
}
if (ModuleSP module_sp = m_process->ReadModuleFromMemory(
file, m_vdso_base, info.GetRange().GetByteSize())) {
UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_vdso_base, false);
m_process->GetTarget().GetImages().AppendIfNeeded(module_sp);
}
}
void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
DYLDRendezvous::iterator I;
DYLDRendezvous::iterator E;
@ -502,14 +524,7 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() {
// that ourselves here.
ModuleSP executable = GetTargetExecutable();
m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
if (m_vdso_base != LLDB_INVALID_ADDRESS) {
FileSpec file_spec("[vdso]", false);
ModuleSP module_sp = LoadModuleAtAddress(file_spec, LLDB_INVALID_ADDRESS,
m_vdso_base, false);
if (module_sp.get()) {
module_list.Append(module_sp);
}
}
LoadVDSO(module_list);
std::vector<FileSpec> module_names;
for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)

View File

@ -17,10 +17,10 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Target/DynamicLoader.h"
#include "DYLDRendezvous.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/ModuleList.h"
#include "lldb/Target/DynamicLoader.h"
class AuxVector;
@ -138,6 +138,8 @@ class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader {
/// of all dependent modules.
virtual void LoadAllCurrentModules();
void LoadVDSO(lldb_private::ModuleList &modules);
/// Computes a value for m_load_offset returning the computed address on
/// success and LLDB_INVALID_ADDRESS on failure.
lldb::addr_t ComputeLoadOffset();

View File

@ -1,4 +1,4 @@
//===-- AddressSanitizerRuntime.cpp -----------------------------*- C++ -*-===//
//===-- ASanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "AddressSanitizerRuntime.h"
#include "ASanRuntime.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
@ -308,13 +308,6 @@ void AddressSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("address-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
if (stream_sp) {
stream_sp->Printf("AddressSanitizer debugger support is active. Memory "
"error breakpoint has been installed and you can now use "
"the 'memory history' command.\n");
}
SetActive(true);
}

View File

@ -1,5 +1,5 @@
add_lldb_library(lldbPluginInstrumentationRuntimeAddressSanitizer PLUGIN
AddressSanitizerRuntime.cpp
add_lldb_library(lldbPluginInstrumentationRuntimeASan PLUGIN
ASanRuntime.cpp
LINK_LIBS
lldbBreakpoint

View File

@ -1,2 +1,4 @@
add_subdirectory(AddressSanitizer)
add_subdirectory(ThreadSanitizer)
add_subdirectory(ASan)
add_subdirectory(MainThreadChecker)
add_subdirectory(TSan)
add_subdirectory(UBSan)

View File

@ -0,0 +1,13 @@
add_lldb_library(lldbPluginInstrumentationRuntimeMainThreadChecker PLUGIN
MainThreadCheckerRuntime.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbExpression
lldbInterpreter
lldbSymbol
lldbTarget
LINK_COMPONENTS
Support
)

View File

@ -0,0 +1,273 @@
//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "MainThreadCheckerRuntime.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/RegularExpression.h"
#include "Plugins/Process/Utility/HistoryThread.h"
using namespace lldb;
using namespace lldb_private;
MainThreadCheckerRuntime::~MainThreadCheckerRuntime() {
Deactivate();
}
lldb::InstrumentationRuntimeSP
MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) {
return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp));
}
void MainThreadCheckerRuntime::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.",
CreateInstance, GetTypeStatic);
}
void MainThreadCheckerRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() {
return ConstString("MainThreadChecker");
}
lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() {
return eInstrumentationRuntimeTypeMainThreadChecker;
}
const RegularExpression &
MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() {
static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib"));
return regex;
}
bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid(
const lldb::ModuleSP module_sp) {
static ConstString test_sym("__main_thread_checker_on_report");
const Symbol *symbol =
module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny);
return symbol != nullptr;
}
StructuredData::ObjectSP
MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
ProcessSP process_sp = GetProcessSP();
if (!process_sp)
return StructuredData::ObjectSP();
ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
ModuleSP runtime_module_sp = GetRuntimeModuleSP();
Target &target = process_sp->GetTarget();
if (!frame_sp)
return StructuredData::ObjectSP();
RegisterContextSP regctx_sp = frame_sp->GetRegisterContext();
if (!regctx_sp)
return StructuredData::ObjectSP();
const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1");
if (!reginfo)
return StructuredData::ObjectSP();
uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0);
if (!apiname_ptr)
return StructuredData::ObjectSP();
std::string apiName = "";
Status read_error;
target.ReadCStringFromMemory(apiname_ptr, apiName, read_error);
if (read_error.Fail())
return StructuredData::ObjectSP();
std::string className = "";
std::string selector = "";
if (apiName.substr(0, 2) == "-[") {
size_t spacePos = apiName.find(" ");
if (spacePos != std::string::npos) {
className = apiName.substr(2, spacePos - 2);
selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2);
}
}
// Gather the PCs of the user frames in the backtrace.
StructuredData::Array *trace = new StructuredData::Array();
auto trace_sp = StructuredData::ObjectSP(trace);
StackFrameSP responsible_frame;
for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I);
Address addr = frame->GetFrameCodeAddress();
if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
continue;
// The first non-runtime frame is responsible for the bug.
if (!responsible_frame)
responsible_frame = frame;
// First frame in stacktrace should point to a real PC, not return address.
if (I != 0 && trace->GetSize() == 0) {
addr.Slide(-1);
}
lldb::addr_t PC = addr.GetLoadAddress(&target);
trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
}
auto *d = new StructuredData::Dictionary();
auto dict_sp = StructuredData::ObjectSP(d);
d->AddStringItem("instrumentation_class", "MainThreadChecker");
d->AddStringItem("api_name", apiName);
d->AddStringItem("class_name", className);
d->AddStringItem("selector", selector);
d->AddStringItem("description",
apiName + " must be called from main thread only");
d->AddIntegerItem("tid", thread_sp->GetIndexID());
d->AddItem("trace", trace_sp);
return dict_sp;
}
bool MainThreadCheckerRuntime::NotifyBreakpointHit(
void *baton, StoppointCallbackContext *context, user_id_t break_id,
user_id_t break_loc_id) {
assert(baton && "null baton");
if (!baton)
return false; //< false => resume execution.
MainThreadCheckerRuntime *const instance =
static_cast<MainThreadCheckerRuntime *>(baton);
ProcessSP process_sp = instance->GetProcessSP();
ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
if (!process_sp || !thread_sp ||
process_sp != context->exe_ctx_ref.GetProcessSP())
return false;
StructuredData::ObjectSP report =
instance->RetrieveReportData(context->exe_ctx_ref);
if (report) {
std::string description = report->GetAsDictionary()
->GetValueForKey("description")
->GetAsString()
->GetValue();
thread_sp->SetStopInfo(
InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
*thread_sp, description, report));
return true;
}
return false;
}
void MainThreadCheckerRuntime::Activate() {
if (IsActive())
return;
ProcessSP process_sp = GetProcessSP();
if (!process_sp)
return;
ModuleSP runtime_module_sp = GetRuntimeModuleSP();
ConstString symbol_name("__main_thread_checker_on_report");
const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
symbol_name, eSymbolTypeCode);
if (symbol == nullptr)
return;
if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
return;
Target &target = process_sp->GetTarget();
addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
if (symbol_address == LLDB_INVALID_ADDRESS)
return;
Breakpoint *breakpoint =
process_sp->GetTarget()
.CreateBreakpoint(symbol_address, /*internal=*/true,
/*hardware=*/false)
.get();
breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this,
true);
breakpoint->SetBreakpointKind("main-thread-checker-report");
SetBreakpointID(breakpoint->GetID());
SetActive(true);
}
void MainThreadCheckerRuntime::Deactivate() {
SetActive(false);
auto BID = GetBreakpointID();
if (BID == LLDB_INVALID_BREAK_ID)
return;
if (ProcessSP process_sp = GetProcessSP()) {
process_sp->GetTarget().RemoveBreakpointByID(BID);
SetBreakpointID(LLDB_INVALID_BREAK_ID);
}
}
lldb::ThreadCollectionSP
MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo(
StructuredData::ObjectSP info) {
ThreadCollectionSP threads;
threads.reset(new ThreadCollection());
ProcessSP process_sp = GetProcessSP();
if (info->GetObjectForDotSeparatedPath("instrumentation_class")
->GetStringValue() != "MainThreadChecker")
return threads;
std::vector<lldb::addr_t> PCs;
auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
PCs.push_back(PC->GetAsInteger()->GetValue());
return true;
});
if (PCs.empty())
return threads;
StructuredData::ObjectSP thread_id_obj =
info->GetObjectForDotSeparatedPath("tid");
tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
uint32_t stop_id = 0;
bool stop_id_is_valid = false;
HistoryThread *history_thread =
new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
ThreadSP new_thread_sp(history_thread);
// Save this in the Process' ExtendedThreadList so a strong pointer
// retains the object
process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
threads->AddThread(new_thread_sp);
return threads;
}

View File

@ -0,0 +1,68 @@
//===-- MainThreadCheckerRuntime.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_MainThreadCheckerRuntime_h_
#define liblldb_MainThreadCheckerRuntime_h_
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class MainThreadCheckerRuntime : public lldb_private::InstrumentationRuntime {
public:
~MainThreadCheckerRuntime() override;
static lldb::InstrumentationRuntimeSP
CreateInstance(const lldb::ProcessSP &process_sp);
static void Initialize();
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static lldb::InstrumentationRuntimeType GetTypeStatic();
lldb_private::ConstString GetPluginName() override {
return GetPluginNameStatic();
}
virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
uint32_t GetPluginVersion() override { return 1; }
lldb::ThreadCollectionSP
GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
private:
MainThreadCheckerRuntime(const lldb::ProcessSP &process_sp)
: lldb_private::InstrumentationRuntime(process_sp) {}
const RegularExpression &GetPatternForRuntimeLibrary() override;
bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
void Activate() override;
void Deactivate();
static bool NotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
};
} // namespace lldb_private
#endif // liblldb_MainThreadCheckerRuntime_h_

View File

@ -1,5 +1,5 @@
add_lldb_library(lldbPluginInstrumentationRuntimeThreadSanitizer PLUGIN
ThreadSanitizerRuntime.cpp
add_lldb_library(lldbPluginInstrumentationRuntimeTSan PLUGIN
TSanRuntime.cpp
LINK_LIBS
lldbBreakpoint

View File

@ -1,4 +1,4 @@
//===-- ThreadSanitizerRuntime.cpp ------------------------------*- C++ -*-===//
//===-- TSanRuntime.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "ThreadSanitizerRuntime.h"
#include "TSanRuntime.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
@ -921,11 +921,6 @@ void ThreadSanitizerRuntime::Activate() {
breakpoint->SetBreakpointKind("thread-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
StreamFileSP stream_sp(process_sp->GetTarget().GetDebugger().GetOutputFile());
if (stream_sp) {
stream_sp->Printf("ThreadSanitizer debugger support is active.\n");
}
SetActive(true);
}

View File

@ -0,0 +1,13 @@
add_lldb_library(lldbPluginInstrumentationRuntimeUBSan PLUGIN
UBSanRuntime.cpp
LINK_LIBS
lldbBreakpoint
lldbCore
lldbExpression
lldbInterpreter
lldbSymbol
lldbTarget
LINK_COMPONENTS
Support
)

View File

@ -0,0 +1,340 @@
//===-- UBSanRuntime.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "UBSanRuntime.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include <ctype.h>
using namespace lldb;
using namespace lldb_private;
UndefinedBehaviorSanitizerRuntime::~UndefinedBehaviorSanitizerRuntime() {
Deactivate();
}
lldb::InstrumentationRuntimeSP
UndefinedBehaviorSanitizerRuntime::CreateInstance(
const lldb::ProcessSP &process_sp) {
return InstrumentationRuntimeSP(
new UndefinedBehaviorSanitizerRuntime(process_sp));
}
void UndefinedBehaviorSanitizerRuntime::Initialize() {
PluginManager::RegisterPlugin(
GetPluginNameStatic(),
"UndefinedBehaviorSanitizer instrumentation runtime plugin.",
CreateInstance, GetTypeStatic);
}
void UndefinedBehaviorSanitizerRuntime::Terminate() {
PluginManager::UnregisterPlugin(CreateInstance);
}
lldb_private::ConstString
UndefinedBehaviorSanitizerRuntime::GetPluginNameStatic() {
return ConstString("UndefinedBehaviorSanitizer");
}
lldb::InstrumentationRuntimeType
UndefinedBehaviorSanitizerRuntime::GetTypeStatic() {
return eInstrumentationRuntimeTypeUndefinedBehaviorSanitizer;
}
static const char *ub_sanitizer_retrieve_report_data_prefix = R"(
extern "C" {
void
__ubsan_get_current_report_data(const char **OutIssueKind,
const char **OutMessage, const char **OutFilename, unsigned *OutLine,
unsigned *OutCol, char **OutMemoryAddr);
}
struct data {
const char *issue_kind;
const char *message;
const char *filename;
unsigned line;
unsigned col;
char *memory_addr;
};
)";
static const char *ub_sanitizer_retrieve_report_data_command = R"(
data t;
__ubsan_get_current_report_data(&t.issue_kind, &t.message, &t.filename, &t.line,
&t.col, &t.memory_addr);
t;
)";
static addr_t RetrieveUnsigned(ValueObjectSP return_value_sp,
ProcessSP process_sp,
const std::string &expression_path) {
return return_value_sp->GetValueForExpressionPath(expression_path.c_str())
->GetValueAsUnsigned(0);
}
static std::string RetrieveString(ValueObjectSP return_value_sp,
ProcessSP process_sp,
const std::string &expression_path) {
addr_t ptr = RetrieveUnsigned(return_value_sp, process_sp, expression_path);
std::string str;
Status error;
process_sp->ReadCStringFromMemory(ptr, str, error);
return str;
}
StructuredData::ObjectSP UndefinedBehaviorSanitizerRuntime::RetrieveReportData(
ExecutionContextRef exe_ctx_ref) {
ProcessSP process_sp = GetProcessSP();
if (!process_sp)
return StructuredData::ObjectSP();
ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
ModuleSP runtime_module_sp = GetRuntimeModuleSP();
Target &target = process_sp->GetTarget();
if (!frame_sp)
return StructuredData::ObjectSP();
StreamFileSP Stream(target.GetDebugger().GetOutputFile());
EvaluateExpressionOptions options;
options.SetUnwindOnError(true);
options.SetTryAllThreads(true);
options.SetStopOthers(true);
options.SetIgnoreBreakpoints(true);
options.SetTimeout(std::chrono::seconds(2));
options.SetPrefix(ub_sanitizer_retrieve_report_data_prefix);
options.SetAutoApplyFixIts(false);
options.SetLanguage(eLanguageTypeObjC_plus_plus);
ValueObjectSP main_value;
ExecutionContext exe_ctx;
Status eval_error;
frame_sp->CalculateExecutionContext(exe_ctx);
ExpressionResults result = UserExpression::Evaluate(
exe_ctx, options, ub_sanitizer_retrieve_report_data_command, "",
main_value, eval_error);
if (result != eExpressionCompleted) {
target.GetDebugger().GetAsyncOutputStream()->Printf(
"Warning: Cannot evaluate UndefinedBehaviorSanitizer expression:\n%s\n",
eval_error.AsCString());
return StructuredData::ObjectSP();
}
// Gather the PCs of the user frames in the backtrace.
StructuredData::Array *trace = new StructuredData::Array();
auto trace_sp = StructuredData::ObjectSP(trace);
for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
const Address FCA =
thread_sp->GetStackFrameAtIndex(I)->GetFrameCodeAddress();
if (FCA.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
continue;
lldb::addr_t PC = FCA.GetLoadAddress(&target);
trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
}
std::string IssueKind = RetrieveString(main_value, process_sp, ".issue_kind");
std::string ErrMessage = RetrieveString(main_value, process_sp, ".message");
std::string Filename = RetrieveString(main_value, process_sp, ".filename");
unsigned Line = RetrieveUnsigned(main_value, process_sp, ".line");
unsigned Col = RetrieveUnsigned(main_value, process_sp, ".col");
uintptr_t MemoryAddr =
RetrieveUnsigned(main_value, process_sp, ".memory_addr");
auto *d = new StructuredData::Dictionary();
auto dict_sp = StructuredData::ObjectSP(d);
d->AddStringItem("instrumentation_class", "UndefinedBehaviorSanitizer");
d->AddStringItem("description", IssueKind);
d->AddStringItem("summary", ErrMessage);
d->AddStringItem("filename", Filename);
d->AddIntegerItem("line", Line);
d->AddIntegerItem("col", Col);
d->AddIntegerItem("memory_address", MemoryAddr);
d->AddIntegerItem("tid", thread_sp->GetID());
d->AddItem("trace", trace_sp);
return dict_sp;
}
static std::string GetStopReasonDescription(StructuredData::ObjectSP report) {
llvm::StringRef stop_reason_description_ref;
report->GetAsDictionary()->GetValueForKeyAsString("description",
stop_reason_description_ref);
std::string stop_reason_description = stop_reason_description_ref;
if (!stop_reason_description.size()) {
stop_reason_description = "Undefined behavior detected";
} else {
stop_reason_description[0] = toupper(stop_reason_description[0]);
for (unsigned I = 1; I < stop_reason_description.size(); ++I)
if (stop_reason_description[I] == '-')
stop_reason_description[I] = ' ';
}
return stop_reason_description;
}
bool UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit(
void *baton, StoppointCallbackContext *context, user_id_t break_id,
user_id_t break_loc_id) {
assert(baton && "null baton");
if (!baton)
return false; //< false => resume execution.
UndefinedBehaviorSanitizerRuntime *const instance =
static_cast<UndefinedBehaviorSanitizerRuntime *>(baton);
ProcessSP process_sp = instance->GetProcessSP();
ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
if (!process_sp || !thread_sp ||
process_sp != context->exe_ctx_ref.GetProcessSP())
return false;
StructuredData::ObjectSP report =
instance->RetrieveReportData(context->exe_ctx_ref);
if (report) {
thread_sp->SetStopInfo(
InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
*thread_sp, GetStopReasonDescription(report), report));
return true;
}
return false;
}
const RegularExpression &
UndefinedBehaviorSanitizerRuntime::GetPatternForRuntimeLibrary() {
static RegularExpression regex(llvm::StringRef("libclang_rt\\.(a|t|ub)san_"));
return regex;
}
bool UndefinedBehaviorSanitizerRuntime::CheckIfRuntimeIsValid(
const lldb::ModuleSP module_sp) {
static ConstString ubsan_test_sym("__ubsan_on_report");
const Symbol *symbol = module_sp->FindFirstSymbolWithNameAndType(
ubsan_test_sym, lldb::eSymbolTypeAny);
return symbol != nullptr;
}
// FIXME: Factor out all the logic we have in common with the {a,t}san plugins.
void UndefinedBehaviorSanitizerRuntime::Activate() {
if (IsActive())
return;
ProcessSP process_sp = GetProcessSP();
if (!process_sp)
return;
ModuleSP runtime_module_sp = GetRuntimeModuleSP();
ConstString symbol_name("__ubsan_on_report");
const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
symbol_name, eSymbolTypeCode);
if (symbol == nullptr)
return;
if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
return;
Target &target = process_sp->GetTarget();
addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);
if (symbol_address == LLDB_INVALID_ADDRESS)
return;
Breakpoint *breakpoint =
process_sp->GetTarget()
.CreateBreakpoint(symbol_address, /*internal=*/true,
/*hardware=*/false)
.get();
breakpoint->SetCallback(
UndefinedBehaviorSanitizerRuntime::NotifyBreakpointHit, this, true);
breakpoint->SetBreakpointKind("undefined-behavior-sanitizer-report");
SetBreakpointID(breakpoint->GetID());
SetActive(true);
}
void UndefinedBehaviorSanitizerRuntime::Deactivate() {
SetActive(false);
auto BID = GetBreakpointID();
if (BID == LLDB_INVALID_BREAK_ID)
return;
if (ProcessSP process_sp = GetProcessSP()) {
process_sp->GetTarget().RemoveBreakpointByID(BID);
SetBreakpointID(LLDB_INVALID_BREAK_ID);
}
}
lldb::ThreadCollectionSP
UndefinedBehaviorSanitizerRuntime::GetBacktracesFromExtendedStopInfo(
StructuredData::ObjectSP info) {
ThreadCollectionSP threads;
threads.reset(new ThreadCollection());
ProcessSP process_sp = GetProcessSP();
if (info->GetObjectForDotSeparatedPath("instrumentation_class")
->GetStringValue() != "UndefinedBehaviorSanitizer")
return threads;
std::vector<lldb::addr_t> PCs;
auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
PCs.push_back(PC->GetAsInteger()->GetValue());
return true;
});
if (PCs.empty())
return threads;
StructuredData::ObjectSP thread_id_obj =
info->GetObjectForDotSeparatedPath("tid");
tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;
uint32_t stop_id = 0;
bool stop_id_is_valid = false;
HistoryThread *history_thread =
new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
ThreadSP new_thread_sp(history_thread);
std::string stop_reason_description = GetStopReasonDescription(info);
new_thread_sp->SetName(stop_reason_description.c_str());
// Save this in the Process' ExtendedThreadList so a strong pointer
// retains the object
process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
threads->AddThread(new_thread_sp);
return threads;
}

View File

@ -0,0 +1,69 @@
//===-- UndefinedBehaviorSanitizerRuntime.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_UndefinedBehaviorSanitizerRuntime_h_
#define liblldb_UndefinedBehaviorSanitizerRuntime_h_
#include "lldb/Core/StructuredData.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class UndefinedBehaviorSanitizerRuntime
: public lldb_private::InstrumentationRuntime {
public:
~UndefinedBehaviorSanitizerRuntime() override;
static lldb::InstrumentationRuntimeSP
CreateInstance(const lldb::ProcessSP &process_sp);
static void Initialize();
static void Terminate();
static lldb_private::ConstString GetPluginNameStatic();
static lldb::InstrumentationRuntimeType GetTypeStatic();
lldb_private::ConstString GetPluginName() override {
return GetPluginNameStatic();
}
virtual lldb::InstrumentationRuntimeType GetType() { return GetTypeStatic(); }
uint32_t GetPluginVersion() override { return 1; }
lldb::ThreadCollectionSP
GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) override;
private:
UndefinedBehaviorSanitizerRuntime(const lldb::ProcessSP &process_sp)
: lldb_private::InstrumentationRuntime(process_sp) {}
const RegularExpression &GetPatternForRuntimeLibrary() override;
bool CheckIfRuntimeIsValid(const lldb::ModuleSP module_sp) override;
void Activate() override;
void Deactivate();
static bool NotifyBreakpointHit(void *baton,
StoppointCallbackContext *context,
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id);
StructuredData::ObjectSP RetrieveReportData(ExecutionContextRef exe_ctx_ref);
};
} // namespace lldb_private
#endif // liblldb_UndefinedBehaviorSanitizerRuntime_h_

View File

@ -31,6 +31,8 @@
#include "lldb/Utility/Status.h"
#include "lldb/Utility/Stream.h"
#include "llvm/ADT/APInt.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "NSString.h"
@ -369,6 +371,28 @@ static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
}
static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
const llvm::APInt &value,
lldb::LanguageType lang) {
static ConstString g_TypeHint("NSNumber:int128_t");
std::string prefix, suffix;
if (Language *language = Language::FindPlugin(lang)) {
if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
suffix)) {
prefix.clear();
suffix.clear();
}
}
stream.PutCString(prefix.c_str());
const int radix = 10;
const bool isSigned = true;
std::string str = value.toString(radix, isSigned);
stream.PutCString(str.c_str());
stream.PutCString(suffix.c_str());
}
static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
float value, lldb::LanguageType lang) {
static ConstString g_TypeHint("NSNumber:float");
@ -462,22 +486,72 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
return true;
} else {
Status error;
uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(
valobj_addr + ptr_size, 1, 0, error) &
0x1F);
AppleObjCRuntime *runtime =
llvm::dyn_cast_or_null<AppleObjCRuntime>(
process_sp->GetObjCLanguageRuntime());
const bool new_format =
(runtime && runtime->GetFoundationVersion() >= 1400);
enum class TypeCodes : int {
sint8 = 0x0,
sint16 = 0x1,
sint32 = 0x2,
sint64 = 0x3,
f32 = 0x4,
f64 = 0x5,
sint128 = 0x6
};
uint64_t data_location = valobj_addr + 2 * ptr_size;
TypeCodes type_code;
if (new_format) {
uint64_t cfinfoa =
process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
bool is_preserved_number = cfinfoa & 0x8;
if (is_preserved_number) {
lldbassert(!"We should handle preserved numbers!");
return false;
}
type_code = (TypeCodes)(cfinfoa & 0x7);
} else {
uint8_t data_type =
process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
0, error) & 0x1F;
if (error.Fail())
return false;
switch (data_type) {
case 1: type_code = TypeCodes::sint8; break;
case 2: type_code = TypeCodes::sint16; break;
case 3: type_code = TypeCodes::sint32; break;
case 17: data_location += 8; LLVM_FALLTHROUGH;
case 4: type_code = TypeCodes::sint64; break;
case 5: type_code = TypeCodes::f32; break;
case 6: type_code = TypeCodes::f64; break;
default: return false;
}
}
uint64_t value = 0;
if (error.Fail())
return false;
switch (data_type) {
case 1: // 0B00001
switch (type_code) {
case TypeCodes::sint8:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
break;
case 2: // 0B0010
case TypeCodes::sint16:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
error);
if (error.Fail())
@ -485,24 +559,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatShort(valobj, stream, (short)value,
options.GetLanguage());
break;
case 3: // 0B0011
case TypeCodes::sint32:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
break;
case 17: // 0B10001
data_location += 8;
LLVM_FALLTHROUGH;
case 4: // 0B0100
case TypeCodes::sint64:
value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
error);
if (error.Fail())
return false;
NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
break;
case 5: // 0B0101
case TypeCodes::f32:
{
uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 4, 0, error);
@ -513,7 +584,7 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
break;
}
case 6: // 0B0110
case TypeCodes::f64:
{
uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 8, 0, error);
@ -524,6 +595,21 @@ bool lldb_private::formatters::NSNumberSummaryProvider(
NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
break;
}
case TypeCodes::sint128: // internally, this is the same
{
uint64_t words[2];
words[1] = process_sp->ReadUnsignedIntegerFromMemory(
data_location, 8, 0, error);
if (error.Fail())
return false;
words[0] = process_sp->ReadUnsignedIntegerFromMemory(
data_location + 8, 8, 0, error);
if (error.Fail())
return false;
llvm::APInt i128_value(128, words);
NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
break;
}
default:
return false;
}

View File

@ -160,11 +160,47 @@ class NSArrayMSyntheticFrontEnd_1010 : public NSArrayMSyntheticFrontEnd {
DataDescriptor_64 *m_data_64;
};
class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
class NSArrayMSyntheticFrontEnd_1400 : public NSArrayMSyntheticFrontEnd {
public:
NSArrayISyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
~NSArrayISyntheticFrontEnd() override = default;
~NSArrayMSyntheticFrontEnd_1400() override;
bool Update() override;
protected:
lldb::addr_t GetDataAddress() override;
uint64_t GetUsedCount() override;
uint64_t GetOffset() override;
uint64_t GetSize() override;
private:
struct DataDescriptor_32 {
uint32_t used;
uint32_t offset;
uint32_t size;
uint32_t list;
};
struct DataDescriptor_64 {
uint64_t used;
uint64_t offset;
uint64_t size;
uint64_t list;
};
DataDescriptor_32 *m_data_32;
DataDescriptor_64 *m_data_64;
};
class NSArrayISyntheticFrontEnd_1300 : public SyntheticChildrenFrontEnd {
public:
NSArrayISyntheticFrontEnd_1300(lldb::ValueObjectSP valobj_sp);
~NSArrayISyntheticFrontEnd_1300() override = default;
size_t CalculateNumChildren() override;
@ -184,6 +220,45 @@ class NSArrayISyntheticFrontEnd : public SyntheticChildrenFrontEnd {
CompilerType m_id_type;
};
class NSArrayISyntheticFrontEnd_1400 : public SyntheticChildrenFrontEnd {
public:
NSArrayISyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp);
~NSArrayISyntheticFrontEnd_1400() override;
size_t CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
bool Update() override;
bool MightHaveChildren() override;
size_t GetIndexOfChildWithName(const ConstString &name) override;
private:
ExecutionContextRef m_exe_ctx_ref;
uint8_t m_ptr_size;
struct DataDescriptor_32 {
uint32_t used;
uint32_t offset;
uint32_t size;
uint32_t list;
};
struct DataDescriptor_64 {
uint64_t used;
uint64_t offset;
uint64_t size;
uint64_t list;
};
DataDescriptor_32 *m_data_32;
DataDescriptor_64 *m_data_64;
CompilerType m_id_type;
};
class NSArray0SyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSArray0SyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
@ -257,6 +332,8 @@ bool lldb_private::formatters::NSArraySummaryProvider(
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
static const ConstString g_NSArrayCF("__NSCFArray");
static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return false;
@ -273,6 +350,18 @@ bool lldb_private::formatters::NSArraySummaryProvider(
ptr_size, 0, error);
if (error.Fail())
return false;
} else if (class_name == g_NSArrayMLegacy) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
} else if (class_name == g_NSArrayMImmutable) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
} else if (class_name == g_NSArray0) {
value = 0;
} else if (class_name == g_NSArray1) {
@ -332,6 +421,11 @@ lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::
: NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
m_data_64(nullptr) {}
lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
NSArrayMSyntheticFrontEnd_1400(lldb::ValueObjectSP valobj_sp)
: NSArrayMSyntheticFrontEnd(valobj_sp), m_data_32(nullptr),
m_data_64(nullptr) {}
size_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren() {
return GetUsedCount();
@ -416,6 +510,37 @@ bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::Update() {
return false;
}
bool lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::Update() {
ValueObjectSP valobj_sp = m_backend.GetSP();
m_ptr_size = 0;
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return false;
m_ptr_size = process_sp->GetAddressByteSize();
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
if (m_ptr_size == 4) {
m_data_32 = new DataDescriptor_32();
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
error);
} else {
m_data_64 = new DataDescriptor_64();
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
error);
}
if (error.Fail())
return false;
return false;
}
bool lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren() {
return true;
}
@ -498,7 +623,42 @@ uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1010::GetSize() {
return m_data_32 ? m_data_32->_size : m_data_64->_size;
}
lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::
~NSArrayMSyntheticFrontEnd_1400() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
}
lldb::addr_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetDataAddress() {
if (!m_data_32 && !m_data_64)
return LLDB_INVALID_ADDRESS;
return m_data_32 ? m_data_32->list : m_data_64->list;
}
uint64_t
lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetUsedCount() {
if (!m_data_32 && !m_data_64)
return 0;
return m_data_32 ? m_data_32->used : m_data_64->used;
}
uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetOffset() {
if (!m_data_32 && !m_data_64)
return 0;
return m_data_32 ? m_data_32->offset : m_data_64->offset;
}
uint64_t lldb_private::formatters::NSArrayMSyntheticFrontEnd_1400::GetSize() {
if (!m_data_32 && !m_data_64)
return 0;
return m_data_32 ? m_data_32->size : m_data_64->size;
}
lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::NSArrayISyntheticFrontEnd_1300(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_items(0), m_data_ptr(0) {
@ -516,7 +676,7 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd(
}
size_t
lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetIndexOfChildWithName(
const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
@ -526,11 +686,11 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName(
}
size_t
lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren() {
lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::CalculateNumChildren() {
return m_items;
}
bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::Update() {
m_ptr_size = 0;
m_items = 0;
m_data_ptr = 0;
@ -552,12 +712,12 @@ bool lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() {
return false;
}
bool lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren() {
bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::MightHaveChildren() {
return true;
}
lldb::ValueObjectSP
lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
lldb_private::formatters::NSArrayISyntheticFrontEnd_1300::GetChildAtIndex(
size_t idx) {
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
@ -575,6 +735,99 @@ lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex(
m_exe_ctx_ref, m_id_type);
}
lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::NSArrayISyntheticFrontEnd_1400(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_data_32(nullptr), m_data_64(nullptr) {
if (valobj_sp) {
CompilerType type = valobj_sp->GetCompilerType();
if (type) {
ClangASTContext *ast = valobj_sp->GetExecutionContextRef()
.GetTargetSP()
->GetScratchClangASTContext();
if (ast)
m_id_type = CompilerType(ast->getASTContext(),
ast->getASTContext()->ObjCBuiltinIdTy);
}
}
}
lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::~NSArrayISyntheticFrontEnd_1400() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
}
size_t
lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetIndexOfChildWithName(
const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
size_t
lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::CalculateNumChildren() {
return m_data_32 ? m_data_32->used : m_data_64->used;
}
bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::Update() {
ValueObjectSP valobj_sp = m_backend.GetSP();
m_ptr_size = 0;
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return false;
m_ptr_size = process_sp->GetAddressByteSize();
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
if (m_ptr_size == 4) {
m_data_32 = new DataDescriptor_32();
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
error);
} else {
m_data_64 = new DataDescriptor_64();
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
error);
}
if (error.Fail())
return false;
return false;
}
bool lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::MightHaveChildren() {
return true;
}
lldb::ValueObjectSP
lldb_private::formatters::NSArrayISyntheticFrontEnd_1400::GetChildAtIndex(
size_t idx) {
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
lldb::addr_t object_at_idx = m_data_32 ? m_data_32->list : m_data_64->list;
object_at_idx += (idx * m_ptr_size);
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
if (!process_sp)
return lldb::ValueObjectSP();
Status error;
if (error.Fail())
return lldb::ValueObjectSP();
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
return CreateValueObjectFromAddress(idx_name.GetString(), object_at_idx,
m_exe_ctx_ref, m_id_type);
}
lldb_private::formatters::NSArray0SyntheticFrontEnd::NSArray0SyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {}
@ -683,17 +936,24 @@ lldb_private::formatters::NSArraySyntheticFrontEndCreator(
static const ConstString g_NSArrayM("__NSArrayM");
static const ConstString g_NSArray0("__NSArray0");
static const ConstString g_NSArray1("__NSSingleObjectArrayI");
static const ConstString g_NSArrayMLegacy("__NSArrayM_Legacy");
static const ConstString g_NSArrayMImmutable("__NSArrayM_Immutable");
if (class_name.IsEmpty())
return nullptr;
if (class_name == g_NSArrayI) {
return (new NSArrayISyntheticFrontEnd(valobj_sp));
if (runtime->GetFoundationVersion() >= 1400)
return (new NSArrayISyntheticFrontEnd_1400(valobj_sp));
else
return (new NSArrayISyntheticFrontEnd_1300(valobj_sp));
} else if (class_name == g_NSArray0) {
return (new NSArray0SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArray1) {
return (new NSArray1SyntheticFrontEnd(valobj_sp));
} else if (class_name == g_NSArrayM) {
if (runtime->GetFoundationVersion() >= 1400)
return (new NSArrayMSyntheticFrontEnd_1400(valobj_sp));
if (runtime->GetFoundationVersion() >= 1100)
return (new NSArrayMSyntheticFrontEnd_1010(valobj_sp));
else

View File

@ -17,6 +17,8 @@
// Project includes
#include "NSDictionary.h"
#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
@ -179,6 +181,52 @@ class NSDictionaryMSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
size_t GetIndexOfChildWithName(const ConstString &name) override;
private:
struct DataDescriptor_32 {
uint32_t used : 26;
uint32_t kvo : 1;
uint32_t size;
uint32_t buffer;
};
struct DataDescriptor_64 {
uint64_t used : 58;
uint32_t kvo : 1;
uint64_t size;
uint64_t buffer;
};
struct DictionaryItemDescriptor {
lldb::addr_t key_ptr;
lldb::addr_t val_ptr;
lldb::ValueObjectSP valobj_sp;
};
ExecutionContextRef m_exe_ctx_ref;
uint8_t m_ptr_size;
lldb::ByteOrder m_order;
DataDescriptor_32 *m_data_32;
DataDescriptor_64 *m_data_64;
CompilerType m_pair_type;
std::vector<DictionaryItemDescriptor> m_children;
};
class NSDictionaryMLegacySyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
~NSDictionaryMLegacySyntheticFrontEnd() override;
size_t CalculateNumChildren() override;
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
bool Update() override;
bool MightHaveChildren() override;
size_t GetIndexOfChildWithName(const ConstString &name) override;
private:
struct DataDescriptor_32 {
uint32_t _used : 26;
@ -250,19 +298,21 @@ bool lldb_private::formatters::NSDictionarySummaryProvider(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
static const ConstString g_DictionaryMImmutable("__NSDictionaryM_Immutable");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
if (class_name.IsEmpty())
return false;
if (class_name == g_DictionaryI) {
if (class_name == g_DictionaryI || class_name == g_DictionaryMImmutable) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
if (error.Fail())
return false;
value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U);
} else if (class_name == g_DictionaryM) {
} else if (class_name == g_DictionaryM || class_name == g_DictionaryMLegacy) {
Status error;
value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
ptr_size, 0, error);
@ -311,9 +361,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return nullptr;
ObjCLanguageRuntime *runtime =
(ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
lldb::eLanguageTypeObjC);
AppleObjCRuntime *runtime =
llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
if (!runtime)
return nullptr;
@ -338,6 +387,8 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
static const ConstString g_DictionaryI("__NSDictionaryI");
static const ConstString g_DictionaryM("__NSDictionaryM");
static const ConstString g_Dictionary1("__NSSingleEntryDictionaryI");
static const ConstString g_DictionaryImmutable("__NSDictionaryM_Immutable");
static const ConstString g_DictionaryMLegacy("__NSDictionaryM_Legacy");
if (class_name.IsEmpty())
return nullptr;
@ -345,7 +396,13 @@ lldb_private::formatters::NSDictionarySyntheticFrontEndCreator(
if (class_name == g_DictionaryI) {
return (new NSDictionaryISyntheticFrontEnd(valobj_sp));
} else if (class_name == g_DictionaryM) {
return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
if (runtime->GetFoundationVersion() > 1400) {
return (new NSDictionaryMSyntheticFrontEnd(valobj_sp));
} else {
return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
}
} else if (class_name == g_DictionaryMLegacy) {
return (new NSDictionaryMLegacySyntheticFrontEnd(valobj_sp));
} else if (class_name == g_Dictionary1) {
return (new NSDictionary1SyntheticFrontEnd(valobj_sp));
} else {
@ -611,7 +668,7 @@ size_t lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
CalculateNumChildren() {
if (!m_data_32 && !m_data_64)
return 0;
return (m_data_32 ? m_data_32->_used : m_data_64->_used);
return (m_data_32 ? m_data_32->used : m_data_64->used);
}
bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() {
@ -655,6 +712,165 @@ bool lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::
lldb::ValueObjectSP
lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
lldb::addr_t m_keys_ptr;
lldb::addr_t m_values_ptr;
if (m_data_32) {
uint32_t size = m_data_32->size;
m_keys_ptr = m_data_32->buffer;
m_values_ptr = m_data_32->buffer + (m_ptr_size * size);
} else {
uint32_t size = m_data_64->size;
m_keys_ptr = m_data_64->buffer;
m_values_ptr = m_data_64->buffer + (m_ptr_size * size);
}
uint32_t num_children = CalculateNumChildren();
if (idx >= num_children)
return lldb::ValueObjectSP();
if (m_children.empty()) {
// do the scan phase
lldb::addr_t key_at_idx = 0, val_at_idx = 0;
uint32_t tries = 0;
uint32_t test_idx = 0;
while (tries < num_children) {
key_at_idx = m_keys_ptr + (test_idx * m_ptr_size);
val_at_idx = m_values_ptr + (test_idx * m_ptr_size);
;
ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP();
if (!process_sp)
return lldb::ValueObjectSP();
Status error;
key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error);
if (error.Fail())
return lldb::ValueObjectSP();
test_idx++;
if (!key_at_idx || !val_at_idx)
continue;
tries++;
DictionaryItemDescriptor descriptor = {key_at_idx, val_at_idx,
lldb::ValueObjectSP()};
m_children.push_back(descriptor);
}
}
if (idx >= m_children.size()) // should never happen
return lldb::ValueObjectSP();
DictionaryItemDescriptor &dict_item = m_children[idx];
if (!dict_item.valobj_sp) {
if (!m_pair_type.IsValid()) {
TargetSP target_sp(m_backend.GetTargetSP());
if (!target_sp)
return ValueObjectSP();
m_pair_type = GetLLDBNSPairType(target_sp);
}
if (!m_pair_type.IsValid())
return ValueObjectSP();
DataBufferSP buffer_sp(new DataBufferHeap(2 * m_ptr_size, 0));
if (m_ptr_size == 8) {
uint64_t *data_ptr = (uint64_t *)buffer_sp->GetBytes();
*data_ptr = dict_item.key_ptr;
*(data_ptr + 1) = dict_item.val_ptr;
} else {
uint32_t *data_ptr = (uint32_t *)buffer_sp->GetBytes();
*data_ptr = dict_item.key_ptr;
*(data_ptr + 1) = dict_item.val_ptr;
}
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
DataExtractor data(buffer_sp, m_order, m_ptr_size);
dict_item.valobj_sp = CreateValueObjectFromData(idx_name.GetString(), data,
m_exe_ctx_ref, m_pair_type);
}
return dict_item.valobj_sp;
}
lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
NSDictionaryMLegacySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp), m_exe_ctx_ref(), m_ptr_size(8),
m_order(lldb::eByteOrderInvalid), m_data_32(nullptr), m_data_64(nullptr),
m_pair_type() {}
lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
~NSDictionaryMLegacySyntheticFrontEnd() {
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
}
size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
GetIndexOfChildWithName(const ConstString &name) {
const char *item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
size_t lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
CalculateNumChildren() {
if (!m_data_32 && !m_data_64)
return 0;
return (m_data_32 ? m_data_32->_used : m_data_64->_used);
}
bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::Update() {
m_children.clear();
ValueObjectSP valobj_sp = m_backend.GetSP();
m_ptr_size = 0;
delete m_data_32;
m_data_32 = nullptr;
delete m_data_64;
m_data_64 = nullptr;
if (!valobj_sp)
return false;
m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
Status error;
error.Clear();
lldb::ProcessSP process_sp(valobj_sp->GetProcessSP());
if (!process_sp)
return false;
m_ptr_size = process_sp->GetAddressByteSize();
m_order = process_sp->GetByteOrder();
uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size;
if (m_ptr_size == 4) {
m_data_32 = new DataDescriptor_32();
process_sp->ReadMemory(data_location, m_data_32, sizeof(DataDescriptor_32),
error);
} else {
m_data_64 = new DataDescriptor_64();
process_sp->ReadMemory(data_location, m_data_64, sizeof(DataDescriptor_64),
error);
}
if (error.Fail())
return false;
return false;
}
bool lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::
MightHaveChildren() {
return true;
}
lldb::ValueObjectSP
lldb_private::formatters::NSDictionaryMLegacySyntheticFrontEnd::GetChildAtIndex(
size_t idx) {
lldb::addr_t m_keys_ptr =
(m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr);
lldb::addr_t m_values_ptr =

View File

@ -1026,6 +1026,7 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
static ConstString g_NSNumberShort("NSNumber:short");
static ConstString g_NSNumberInt("NSNumber:int");
static ConstString g_NSNumberLong("NSNumber:long");
static ConstString g_NSNumberInt128("NSNumber:int128_t");
static ConstString g_NSNumberFloat("NSNumber:float");
static ConstString g_NSNumberDouble("NSNumber:double");
@ -1061,6 +1062,10 @@ bool ObjCLanguage::GetFormatterPrefixSuffix(ValueObject &valobj,
prefix = "(long)";
return true;
}
if (type_hint == g_NSNumberInt128) {
prefix = "(int128_t)";
return true;
}
if (type_hint == g_NSNumberFloat) {
prefix = "(float)";
return true;

View File

@ -707,10 +707,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
SectionHeaderColl section_headers;
lldb_private::UUID &uuid = spec.GetUUID();
using namespace std::placeholders;
const SetDataFunction set_data =
std::bind(&ObjectFileELF::SetData, std::cref(data), _1, _2, _3);
GetSectionHeaderInfo(section_headers, set_data, header, uuid,
GetSectionHeaderInfo(section_headers, data, header, uuid,
gnu_debuglink_file, gnu_debuglink_crc,
spec.GetArchitecture());
@ -748,7 +745,7 @@ size_t ObjectFileELF::GetModuleSpecifications(
data.SetData(data_sp);
}
ProgramHeaderColl program_headers;
GetProgramHeaderInfo(program_headers, set_data, header);
GetProgramHeaderInfo(program_headers, data, header);
size_t segment_data_end = 0;
for (ProgramHeaderCollConstIter I = program_headers.begin();
@ -950,29 +947,7 @@ size_t ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const {
bool ObjectFileELF::ParseHeader() {
lldb::offset_t offset = 0;
if (!m_header.Parse(m_data, &offset))
return false;
if (!IsInMemory())
return true;
// For in memory object files m_data might not contain the full object file.
// Try to load it
// until the end of the "Section header table" what is at the end of the ELF
// file.
addr_t file_size = m_header.e_shoff + m_header.e_shnum * m_header.e_shentsize;
if (m_data.GetByteSize() < file_size) {
ProcessSP process_sp(m_process_wp.lock());
if (!process_sp)
return false;
DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
if (!data_sp)
return false;
m_data.SetData(data_sp, 0, file_size);
}
return true;
return m_header.Parse(m_data, &offset);
}
bool ObjectFileELF::GetUUID(lldb_private::UUID *uuid) {
@ -1188,7 +1163,7 @@ size_t ObjectFileELF::ParseDependentModules() {
// GetProgramHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
const SetDataFunction &set_data,
DataExtractor &object_data,
const ELFHeader &header) {
// We have already parsed the program headers
if (!program_headers.empty())
@ -1205,7 +1180,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
const size_t ph_size = header.e_phnum * header.e_phentsize;
const elf_off ph_offset = header.e_phoff;
DataExtractor data;
if (set_data(data, ph_offset, ph_size) != ph_size)
if (data.SetData(object_data, ph_offset, ph_size) != ph_size)
return 0;
uint32_t idx;
@ -1225,12 +1200,7 @@ size_t ObjectFileELF::GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
// ParseProgramHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseProgramHeaders() {
using namespace std::placeholders;
return GetProgramHeaderInfo(
m_program_headers,
std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
_3),
m_header);
return GetProgramHeaderInfo(m_program_headers, m_data, m_header);
}
lldb_private::Status
@ -1562,7 +1532,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
// GetSectionHeaderInfo
//----------------------------------------------------------------------
size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const SetDataFunction &set_data,
DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@ -1634,7 +1604,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const size_t sh_size = header.e_shnum * header.e_shentsize;
const elf_off sh_offset = header.e_shoff;
DataExtractor sh_data;
if (set_data(sh_data, sh_offset, sh_size) != sh_size)
if (sh_data.SetData(object_data, sh_offset, sh_size) != sh_size)
return 0;
uint32_t idx;
@ -1653,7 +1623,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const Elf64_Off offset = sheader.sh_offset;
lldb_private::DataExtractor shstr_data;
if (set_data(shstr_data, offset, byte_size) == byte_size) {
if (shstr_data.SetData(object_data, offset, byte_size) == byte_size) {
for (SectionHeaderCollIter I = section_headers.begin();
I != section_headers.end(); ++I) {
static ConstString g_sect_name_gnu_debuglink(".gnu_debuglink");
@ -1669,8 +1639,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_MIPS_ABIFLAGS) {
if (section_size && (set_data(data, sheader.sh_offset,
section_size) == section_size)) {
if (section_size && (data.SetData(object_data, sheader.sh_offset,
section_size) == section_size)) {
// MIPS ASE Mask is at offset 12 in MIPS.abiflags section
lldb::offset_t offset = 12; // MIPS ABI Flags Version: 0
arch_flags |= data.GetU32(&offset);
@ -1723,7 +1693,7 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
// ABI Mask doesn't cover N32 and N64 ABI.
if (header.e_ident[EI_CLASS] == llvm::ELF::ELFCLASS64)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N64;
else if (header.e_flags && llvm::ELF::EF_MIPS_ABI2)
else if (header.e_flags & llvm::ELF::EF_MIPS_ABI2)
arch_flags |= lldb_private::ArchSpec::eMIPSABI_N32;
break;
}
@ -1735,14 +1705,14 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
DataExtractor data;
if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 &&
set_data(data, sheader.sh_offset, section_size) == section_size)
data.SetData(object_data, sheader.sh_offset, section_size) == section_size)
ParseARMAttributes(data, section_size, arch_spec);
}
if (name == g_sect_name_gnu_debuglink) {
DataExtractor data;
if (section_size && (set_data(data, sheader.sh_offset,
section_size) == section_size)) {
if (section_size && (data.SetData(object_data, sheader.sh_offset,
section_size) == section_size)) {
lldb::offset_t gnu_debuglink_offset = 0;
gnu_debuglink_file = data.GetCStr(&gnu_debuglink_offset);
gnu_debuglink_offset = llvm::alignTo(gnu_debuglink_offset, 4);
@ -1762,8 +1732,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
if (is_note_header) {
// Allow notes to refine module info.
DataExtractor data;
if (section_size && (set_data(data, sheader.sh_offset,
section_size) == section_size)) {
if (section_size && (data.SetData(object_data, sheader.sh_offset,
section_size) == section_size)) {
Status error = RefineModuleDetailsFromNote(data, arch_spec, uuid);
if (error.Fail()) {
if (log)
@ -1819,40 +1789,9 @@ ObjectFileELF::StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const {
// ParseSectionHeaders
//----------------------------------------------------------------------
size_t ObjectFileELF::ParseSectionHeaders() {
using namespace std::placeholders;
return GetSectionHeaderInfo(
m_section_headers,
std::bind(&ObjectFileELF::SetDataWithReadMemoryFallback, this, _1, _2,
_3),
m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc, m_arch_spec);
}
lldb::offset_t ObjectFileELF::SetData(const lldb_private::DataExtractor &src,
lldb_private::DataExtractor &dst,
lldb::offset_t offset,
lldb::offset_t length) {
return dst.SetData(src, offset, length);
}
lldb::offset_t
ObjectFileELF::SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
lldb::offset_t offset,
lldb::offset_t length) {
if (offset + length <= m_data.GetByteSize())
return dst.SetData(m_data, offset, length);
const auto process_sp = m_process_wp.lock();
if (process_sp != nullptr) {
addr_t file_size = offset + length;
DataBufferSP data_sp = ReadMemory(process_sp, m_memory_addr, file_size);
if (!data_sp)
return false;
m_data.SetData(data_sp, 0, file_size);
}
return dst.SetData(m_data, offset, length);
return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid,
m_gnu_debuglink_file, m_gnu_debuglink_crc,
m_arch_spec);
}
const ObjectFileELF::ELFSectionHeaderInfo *

View File

@ -14,7 +14,6 @@
#include <stdint.h>
// C++ Includes
#include <functional>
#include <vector>
// Other libraries and framework includes
@ -182,9 +181,6 @@ class ObjectFileELF : public lldb_private::ObjectFile {
typedef std::map<lldb::addr_t, lldb::AddressClass>
FileAddressToAddressClassMap;
typedef std::function<lldb::offset_t(lldb_private::DataExtractor &,
lldb::offset_t, lldb::offset_t)>
SetDataFunction;
/// Version of this reader common to all plugins based on this class.
static const uint32_t m_plugin_version = 1;
@ -230,7 +226,7 @@ class ObjectFileELF : public lldb_private::ObjectFile {
// Parses the ELF program headers.
static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers,
const SetDataFunction &set_data,
lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header);
// Finds PT_NOTE segments and calculates their crc sum.
@ -255,7 +251,7 @@ class ObjectFileELF : public lldb_private::ObjectFile {
/// Parses the elf section headers and returns the uuid, debug link name, crc,
/// archspec.
static size_t GetSectionHeaderInfo(SectionHeaderColl &section_headers,
const SetDataFunction &set_data,
lldb_private::DataExtractor &object_data,
const elf::ELFHeader &header,
lldb_private::UUID &uuid,
std::string &gnu_debuglink_file,
@ -379,14 +375,6 @@ class ObjectFileELF : public lldb_private::ObjectFile {
RefineModuleDetailsFromNote(lldb_private::DataExtractor &data,
lldb_private::ArchSpec &arch_spec,
lldb_private::UUID &uuid);
static lldb::offset_t SetData(const lldb_private::DataExtractor &src,
lldb_private::DataExtractor &dst,
lldb::offset_t offset, lldb::offset_t length);
lldb::offset_t SetDataWithReadMemoryFallback(lldb_private::DataExtractor &dst,
lldb::offset_t offset,
lldb::offset_t length);
};
#endif // liblldb_ObjectFileELF_h_

View File

@ -1085,8 +1085,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exiting pid from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
notify_status);
SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@ -1099,8 +1098,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
"waitpid exit status from the pipe. Will notify "
"as if parent process died with exit status -1.",
__FUNCTION__);
SetExitStatus(eExitTypeInvalid, -1, "failed to receive waitpid result",
notify_status);
SetExitStatus(WaitStatus(WaitStatus::Exit, -1), notify_status);
return error;
}
@ -1111,18 +1109,7 @@ Status NativeProcessDarwin::HandleWaitpidResult() {
__FUNCTION__, pid,
(pid == m_pid) ? "the inferior" : "not the inferior", status);
ExitType exit_type = eExitTypeInvalid;
int exit_status = -1;
if (WIFEXITED(status)) {
exit_type = eExitTypeExit;
exit_status = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
exit_type = eExitTypeSignal;
exit_status = WTERMSIG(status);
}
SetExitStatus(exit_type, exit_status, nullptr, notify_status);
SetExitStatus(WaitStatus::Decode(status), notify_status);
return error;
}

View File

@ -503,35 +503,9 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) {
return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts);
}
static ExitType convert_pid_status_to_exit_type(int status) {
if (WIFEXITED(status))
return ExitType::eExitTypeExit;
else if (WIFSIGNALED(status))
return ExitType::eExitTypeSignal;
else if (WIFSTOPPED(status))
return ExitType::eExitTypeStop;
else {
// We don't know what this is.
return ExitType::eExitTypeInvalid;
}
}
static int convert_pid_status_to_return_code(int status) {
if (WIFEXITED(status))
return WEXITSTATUS(status);
else if (WIFSIGNALED(status))
return WTERMSIG(status);
else if (WIFSTOPPED(status))
return WSTOPSIG(status);
else {
// We don't know what this is.
return ExitType::eExitTypeInvalid;
}
}
// Handles all waitpid events from the inferior process.
void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
int signal, int status) {
WaitStatus status) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// Certain activities differ based on whether the pid is the tid of the main
@ -564,8 +538,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
: "thread metadata not found",
GetState());
// The main thread exited. We're done monitoring. Report to delegate.
SetExitStatus(convert_pid_status_to_exit_type(status),
convert_pid_status_to_return_code(status), nullptr, true);
SetExitStatus(status, true);
// Notify delegate that our process has exited.
SetState(StateType::eStateExited, true);
@ -658,8 +631,7 @@ void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited,
// Notify the delegate - our process is not available but appears to
// have been killed outside
// our control. Is eStateExited the right exit state in this case?
SetExitStatus(convert_pid_status_to_exit_type(status),
convert_pid_status_to_return_code(status), nullptr, true);
SetExitStatus(status, true);
SetState(StateType::eStateExited, true);
} else {
// This thread was pulled out from underneath us. Anything to do here?
@ -830,10 +802,8 @@ void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info,
data, WIFEXITED(data), WIFSIGNALED(data), thread.GetID(),
is_main_thread);
if (is_main_thread) {
SetExitStatus(convert_pid_status_to_exit_type(data),
convert_pid_status_to_return_code(data), nullptr, true);
}
if (is_main_thread)
SetExitStatus(WaitStatus::Decode(data), true);
StateType state = thread.GetState();
if (!StateIsRunningState(state)) {
@ -2384,33 +2354,17 @@ void NativeProcessLinux::SigchldHandler() {
break;
}
bool exited = false;
int signal = 0;
int exit_status = 0;
const char *status_cstr = nullptr;
if (WIFSTOPPED(status)) {
signal = WSTOPSIG(status);
status_cstr = "STOPPED";
} else if (WIFEXITED(status)) {
exit_status = WEXITSTATUS(status);
status_cstr = "EXITED";
exited = true;
} else if (WIFSIGNALED(status)) {
signal = WTERMSIG(status);
status_cstr = "SIGNALED";
if (wait_pid == static_cast<::pid_t>(GetID())) {
exited = true;
exit_status = -1;
}
} else
status_cstr = "(\?\?\?)";
WaitStatus wait_status = WaitStatus::Decode(status);
bool exited = wait_status.type == WaitStatus::Exit ||
(wait_status.type == WaitStatus::Signal &&
wait_pid == static_cast<::pid_t>(GetID()));
LLDB_LOG(log,
"waitpid (-1, &status, _) => pid = {0}, status = {1:x} "
"({2}), signal = {3}, exit_state = {4}",
wait_pid, status, status_cstr, signal, exit_status);
LLDB_LOG(
log,
"waitpid (-1, &status, _) => pid = {0}, status = {1}, exited = {2}",
wait_pid, wait_status, exited);
MonitorCallback(wait_pid, exited, signal, exit_status);
MonitorCallback(wait_pid, exited, wait_status);
}
}

View File

@ -153,7 +153,7 @@ class NativeProcessLinux : public NativeProcessProtocol {
static void *MonitorThread(void *baton);
void MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status);
void MonitorCallback(lldb::pid_t pid, bool exited, WaitStatus status);
void WaitForNewThread(::pid_t tid);

View File

@ -40,32 +40,6 @@ using namespace lldb_private;
using namespace lldb_private::process_netbsd;
using namespace llvm;
static ExitType convert_pid_status_to_exit_type(int status) {
if (WIFEXITED(status))
return ExitType::eExitTypeExit;
else if (WIFSIGNALED(status))
return ExitType::eExitTypeSignal;
else if (WIFSTOPPED(status))
return ExitType::eExitTypeStop;
else {
// We don't know what this is.
return ExitType::eExitTypeInvalid;
}
}
static int convert_pid_status_to_return_code(int status) {
if (WIFEXITED(status))
return WEXITSTATUS(status);
else if (WIFSIGNALED(status))
return WTERMSIG(status);
else if (WIFSTOPPED(status))
return WSTOPSIG(status);
else {
// We don't know what this is.
return ExitType::eExitTypeInvalid;
}
}
// Simple helper function to ensure flags are enabled on the given file
// descriptor.
static Status EnsureFDFlags(int fd, int flags) {
@ -177,17 +151,15 @@ void NativeProcessNetBSD::MonitorCallback(lldb::pid_t pid, int signal) {
}
}
void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, int signal,
int status) {
void NativeProcessNetBSD::MonitorExited(lldb::pid_t pid, WaitStatus status) {
Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS));
LLDB_LOG(log, "got exit signal({0}) , pid = {1}", signal, pid);
LLDB_LOG(log, "got exit signal({0}) , pid = {1}", status, pid);
/* Stop Tracking All Threads attached to Process */
m_threads.clear();
SetExitStatus(convert_pid_status_to_exit_type(status),
convert_pid_status_to_return_code(status), nullptr, true);
SetExitStatus(status, true);
// Notify delegate that our process has exited.
SetState(StateType::eStateExited, true);
@ -861,36 +833,21 @@ void NativeProcessNetBSD::SigchldHandler() {
LLDB_LOG(log, "waitpid ({0}, &status, _) failed: {1}", GetID(), error);
}
bool exited = false;
int signal = 0;
int exit_status = 0;
const char *status_cstr = nullptr;
if (WIFSTOPPED(status)) {
signal = WSTOPSIG(status);
status_cstr = "STOPPED";
} else if (WIFEXITED(status)) {
exit_status = WEXITSTATUS(status);
status_cstr = "EXITED";
exited = true;
} else if (WIFSIGNALED(status)) {
signal = WTERMSIG(status);
status_cstr = "SIGNALED";
if (wait_pid == static_cast<::pid_t>(GetID())) {
exited = true;
exit_status = -1;
}
} else
status_cstr = "(\?\?\?)";
WaitStatus wait_status = WaitStatus::Decode(status);
bool exited = wait_status.type == WaitStatus::Exit ||
(wait_status.type == WaitStatus::Signal &&
wait_pid == static_cast<::pid_t>(GetID()));
LLDB_LOG(log,
"waitpid ({0}, &status, _) => pid = {1}, status = {2:x} "
"({3}), signal = {4}, exit_state = {5}",
GetID(), wait_pid, status, status_cstr, signal, exit_status);
"waitpid ({0}, &status, _) => pid = {1}, status = {2}, exited = {3}",
GetID(), wait_pid, status, exited);
if (exited)
MonitorExited(wait_pid, signal, exit_status);
else
MonitorCallback(wait_pid, signal);
MonitorExited(wait_pid, wait_status);
else {
assert(wait_status.type == WaitStatus::Stop);
MonitorCallback(wait_pid, wait_status.status);
}
}
bool NativeProcessNetBSD::HasThreadNoLock(lldb::tid_t thread_id) {

View File

@ -123,7 +123,7 @@ class NativeProcessNetBSD : public NativeProcessProtocol {
void AttachToInferior(MainLoop &mainloop, lldb::pid_t pid, Status &error);
void MonitorCallback(lldb::pid_t pid, int signal);
void MonitorExited(lldb::pid_t pid, int signal, int status);
void MonitorExited(lldb::pid_t pid, WaitStatus status);
void MonitorSIGSTOP(lldb::pid_t pid);
void MonitorSIGTRAP(lldb::pid_t pid);
void MonitorSignal(lldb::pid_t pid, int signal);

View File

@ -370,53 +370,23 @@ GDBRemoteCommunicationServerLLGS::SendWResponse(
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
// send W notification
ExitType exit_type = ExitType::eExitTypeInvalid;
int return_code = 0;
std::string exit_description;
const bool got_exit_info =
process->GetExitStatus(&exit_type, &return_code, exit_description);
if (!got_exit_info) {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
", failed to retrieve process exit status",
__FUNCTION__, process->GetID());
auto wait_status = process->GetExitStatus();
if (!wait_status) {
LLDB_LOG(log, "pid = {0}, failed to retrieve process exit status",
process->GetID());
StreamGDBRemote response;
response.PutChar('E');
response.PutHex8(GDBRemoteServerError::eErrorExitStatus);
return SendPacketNoLock(response.GetString());
} else {
if (log)
log->Printf("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64
", returning exit type %d, return code %d [%s]",
__FUNCTION__, process->GetID(), exit_type, return_code,
exit_description.c_str());
StreamGDBRemote response;
char return_type_code;
switch (exit_type) {
case ExitType::eExitTypeExit:
return_type_code = 'W';
break;
case ExitType::eExitTypeSignal:
return_type_code = 'X';
break;
case ExitType::eExitTypeStop:
return_type_code = 'S';
break;
case ExitType::eExitTypeInvalid:
return_type_code = 'E';
break;
}
response.PutChar(return_type_code);
// POSIX exit status limited to unsigned 8 bits.
response.PutHex8(return_code);
return SendPacketNoLock(response.GetString());
}
LLDB_LOG(log, "pid = {0}, returning exit type {1}", process->GetID(),
*wait_status);
StreamGDBRemote response;
response.Format("{0:g}", *wait_status);
return SendPacketNoLock(response.GetString());
}
static void AppendHexValue(StreamString &response, const uint8_t *buf,

View File

@ -1,6 +1,7 @@
set (FILES
FileSpecTest.cpp
FileSystemTest.cpp
HostTest.cpp
MainLoopTest.cpp
SocketAddressTest.cpp
SocketTest.cpp

View File

@ -0,0 +1,22 @@
//===-- HostTest.cpp --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Host/Host.h"
#include "gtest/gtest.h"
using namespace lldb_private;
using namespace llvm;
TEST(Host, WaitStatusFormat) {
EXPECT_EQ("W01", formatv("{0:g}", WaitStatus{WaitStatus::Exit, 1}).str());
EXPECT_EQ("X02", formatv("{0:g}", WaitStatus{WaitStatus::Signal, 2}).str());
EXPECT_EQ("S03", formatv("{0:g}", WaitStatus{WaitStatus::Stop, 3}).str());
EXPECT_EQ("Exited with status 4",
formatv("{0}", WaitStatus{WaitStatus::Exit, 4}).str());
}

View File

@ -9,6 +9,9 @@ add_lldb_unittest(ProcessGdbRemoteTests
lldbPluginPlatformMacOSX
lldbPluginProcessUtility
lldbPluginProcessGDBRemote
LLVMTestingSupport
LINK_COMPONENTS
Support
)

View File

@ -14,8 +14,8 @@
#include "Plugins/Process/gdb-remote/GDBRemoteClientBase.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h"
#include "lldb/Utility/StreamGDBRemote.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Testing/Support/Error.h"
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@ -45,13 +45,20 @@ struct TestClient : public GDBRemoteClientBase {
}
};
struct ContinueFixture {
MockDelegate delegate;
class GDBRemoteClientBaseTest : public GDBRemoteTest {
public:
void SetUp() override {
ASSERT_THAT_ERROR(Connect(client, server), llvm::Succeeded());
ASSERT_EQ(TestClient::eBroadcastBitRunPacketSent,
listener_sp->StartListeningForEvents(
&client, TestClient::eBroadcastBitRunPacketSent));
}
protected:
TestClient client;
MockServer server;
ListenerSP listener_sp;
ContinueFixture();
MockDelegate delegate;
ListenerSP listener_sp = Listener::MakeListener("listener");
StateType SendCPacket(StringExtractorGDBRemote &response) {
return client.SendContinuePacketAndWaitForResponse(delegate, LinuxSignals(),
@ -65,76 +72,61 @@ struct ContinueFixture {
}
};
ContinueFixture::ContinueFixture()
: listener_sp(Listener::MakeListener("listener")) {
Connect(client, server);
listener_sp->StartListeningForEvents(&client,
TestClient::eBroadcastBitRunPacketSent);
}
} // end anonymous namespace
class GDBRemoteClientBaseTest : public GDBRemoteTest {};
TEST_F(GDBRemoteClientBaseTest, SendContinueAndWait) {
StringExtractorGDBRemote response;
ContinueFixture fix;
if (HasFailure())
return;
// Continue. The inferior will stop with a signal.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
// Continue. The inferior will exit.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("W01"));
ASSERT_EQ(eStateExited, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket("W01"));
ASSERT_EQ(eStateExited, SendCPacket(response));
ASSERT_EQ("W01", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
// Continue. The inferior will get killed.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("X01"));
ASSERT_EQ(eStateExited, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket("X01"));
ASSERT_EQ(eStateExited, SendCPacket(response));
ASSERT_EQ("X01", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
StringExtractorGDBRemote continue_response, response;
ContinueFixture fix;
if (HasFailure())
return;
// SendAsyncSignal should do nothing when we are not running.
ASSERT_FALSE(fix.client.SendAsyncSignal(0x47));
ASSERT_FALSE(client.SendAsyncSignal(0x47));
// Continue. After the run packet is sent, send an async signal.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
std::future<bool> async_result = std::async(
std::launch::async, [&] { return fix.client.SendAsyncSignal(0x47); });
std::launch::async, [&] { return client.SendAsyncSignal(0x47); });
// First we'll get interrupted.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// Then we get the signal packet.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("C47", response.GetStringRef());
ASSERT_TRUE(async_result.get());
// And we report back a signal stop.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T47"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T47"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T47", continue_response.GetStringRef());
}
@ -142,72 +134,66 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncSignal) {
TEST_F(GDBRemoteClientBaseTest, SendContinueAndAsyncPacket) {
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
ContinueFixture fix;
if (HasFailure())
return;
// Continue. After the run packet is sent, send an async packet.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
// Sending without async enabled should fail.
ASSERT_EQ(
PacketResult::ErrorSendFailed,
fix.client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
client.SendPacketAndWaitForResponse("qTest1", response, !send_async));
std::future<PacketResult> async_result = std::async(std::launch::async, [&] {
return fix.client.SendPacketAndWaitForResponse("qTest2", async_response,
send_async);
return client.SendPacketAndWaitForResponse("qTest2", async_response,
send_async);
});
// First we'll get interrupted.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// Then we get the async packet.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("qTest2", response.GetStringRef());
// Send the response and receive it.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest2"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest2"));
ASSERT_EQ(PacketResult::Success, async_result.get());
ASSERT_EQ("QTest2", async_response.GetStringRef());
// And we get resumed again.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T01", continue_response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
StringExtractorGDBRemote continue_response, response;
ContinueFixture fix;
if (HasFailure())
return;
// Interrupt should do nothing when we're not running.
ASSERT_FALSE(fix.client.Interrupt());
ASSERT_FALSE(client.Interrupt());
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
std::future<bool> async_result =
std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// And that's it.
ASSERT_EQ(eStateStopped, continue_state.get());
@ -217,62 +203,56 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt) {
TEST_F(GDBRemoteClientBaseTest, SendContinueAndLateInterrupt) {
StringExtractorGDBRemote continue_response, response;
ContinueFixture fix;
if (HasFailure())
return;
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
std::future<bool> async_result =
std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
std::async(std::launch::async, [&] { return client.Interrupt(); });
// However, the target stops due to a different reason than the original
// interrupt.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, continue_state.get());
ASSERT_EQ("T01", continue_response.GetStringRef());
ASSERT_TRUE(async_result.get());
// The subsequent continue packet should work normally.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
StringExtractorGDBRemote continue_response, async_response, response;
const bool send_async = true;
ContinueFixture fix;
if (HasFailure())
return;
// Interrupt should do nothing when we're not running.
ASSERT_FALSE(fix.client.Interrupt());
ASSERT_FALSE(client.Interrupt());
// Continue. After the run packet is sent, send an async signal.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
std::future<bool> interrupt_result =
std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted. We'll send two packets to simulate a buggy stub.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T13"));
// We should stop.
ASSERT_EQ(eStateStopped, continue_state.get());
@ -281,37 +261,34 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueAndInterrupt2PacketBug) {
// Packet stream should remain synchronized.
std::future<PacketResult> send_result = std::async(std::launch::async, [&] {
return fix.client.SendPacketAndWaitForResponse("qTest", async_response,
!send_async);
return client.SendPacketAndWaitForResponse("qTest", async_response,
!send_async);
});
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("qTest", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("QTest"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("QTest"));
ASSERT_EQ(PacketResult::Success, send_result.get());
ASSERT_EQ("QTest", async_response.GetStringRef());
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateInterface) {
StringExtractorGDBRemote response;
ContinueFixture fix;
if (HasFailure())
return;
// Continue. We'll have the server send a bunch of async packets before it
// stops.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4142"));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Apro"));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("O4344"));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("Afile"));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket("O4142"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("Apro"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("O4344"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("Afile"));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
EXPECT_EQ("ABCD", fix.delegate.output);
EXPECT_EQ("profile", fix.delegate.misc_data);
EXPECT_EQ(1u, fix.delegate.stop_reply_called);
EXPECT_EQ("ABCD", delegate.output);
EXPECT_EQ("profile", delegate.misc_data);
EXPECT_EQ(1u, delegate.stop_reply_called);
}
TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
@ -327,42 +304,35 @@ TEST_F(GDBRemoteClientBaseTest, SendContinueDelegateStructuredDataReceipt) {
stream.PutEscapedBytes(json_packet.c_str(), json_packet.length());
stream.Flush();
// Set up the
StringExtractorGDBRemote response;
ContinueFixture fix;
if (HasFailure())
return;
// Send async structured data packet, then stop.
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket(stream.GetData()));
ASSERT_EQ(PacketResult::Success, fix.server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, fix.SendCPacket(response));
ASSERT_EQ(PacketResult::Success, server.SendPacket(stream.GetData()));
ASSERT_EQ(PacketResult::Success, server.SendPacket("T01"));
ASSERT_EQ(eStateStopped, SendCPacket(response));
ASSERT_EQ("T01", response.GetStringRef());
ASSERT_EQ(1ul, fix.delegate.structured_data_packets.size());
ASSERT_EQ(1ul, delegate.structured_data_packets.size());
// Verify the packet contents. It should have been unescaped upon packet
// reception.
ASSERT_EQ(json_packet, fix.delegate.structured_data_packets[0]);
ASSERT_EQ(json_packet, delegate.structured_data_packets[0]);
}
TEST_F(GDBRemoteClientBaseTest, InterruptNoResponse) {
StringExtractorGDBRemote continue_response, response;
ContinueFixture fix;
if (HasFailure())
return;
// Continue. After the run packet is sent, send an interrupt.
std::future<StateType> continue_state = std::async(
std::launch::async, [&] { return fix.SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
std::launch::async, [&] { return SendCPacket(continue_response); });
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("c", response.GetStringRef());
fix.WaitForRunEvent();
WaitForRunEvent();
std::future<bool> async_result =
std::async(std::launch::async, [&] { return fix.client.Interrupt(); });
std::async(std::launch::async, [&] { return client.Interrupt(); });
// We get interrupted, but we don't send a stop packet.
ASSERT_EQ(PacketResult::Success, fix.server.GetPacket(response));
ASSERT_EQ(PacketResult::Success, server.GetPacket(response));
ASSERT_EQ("\x03", response.GetStringRef());
// The functions should still terminate (after a timeout).

View File

@ -11,14 +11,14 @@
#include "GDBRemoteTestUtils.h"
#include "Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/StructuredData.h"
#include "lldb/Core/TraceOptions.h"
#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Utility/DataBuffer.h"
#include "lldb/lldb-enumerations.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Testing/Support/Error.h"
using namespace lldb_private::process_gdb_remote;
using namespace lldb_private;
@ -58,15 +58,18 @@ std::string one_register_hex = "41424344";
} // end anonymous namespace
class GDBRemoteCommunicationClientTest : public GDBRemoteTest {};
class GDBRemoteCommunicationClientTest : public GDBRemoteTest {
public:
void SetUp() override {
ASSERT_THAT_ERROR(Connect(client, server), llvm::Succeeded());
}
TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
protected:
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
};
TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result = std::async(std::launch::async, [&] {
@ -87,12 +90,6 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegister) {
}
TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> write_result = std::async(std::launch::async, [&] {
@ -113,12 +110,6 @@ TEST_F(GDBRemoteCommunicationClientTest, WriteRegisterNoSuffix) {
}
TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::tid_t tid = 0x47;
const uint32_t reg_num = 4;
std::future<bool> async_result = std::async(
@ -145,12 +136,6 @@ TEST_F(GDBRemoteCommunicationClientTest, ReadRegister) {
}
TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::tid_t tid = 0x47;
uint32_t save_id;
std::future<bool> async_result = std::async(std::launch::async, [&] {
@ -170,12 +155,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SaveRestoreRegistersNoSuffix) {
}
TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::tid_t tid = 0x47;
std::future<bool> async_result = std::async(
std::launch::async, [&] { return client.SyncThreadState(tid); });
@ -185,12 +164,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SyncThreadState) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
llvm::Triple triple("i386-pc-linux");
FileSpec file_specs[] = {
@ -225,12 +198,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfo) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
llvm::Triple triple("i386-pc-linux");
FileSpec file_spec("/foo/bar.so", false, FileSpec::ePathSyntaxPosix);
@ -267,13 +234,7 @@ TEST_F(GDBRemoteCommunicationClientTest, GetModulesInfoInvalidResponse) {
}
TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
std::thread server_thread([&server] {
std::thread server_thread([this] {
for (;;) {
StringExtractorGDBRemote request;
PacketResult result = server.GetPacket(request);
@ -312,12 +273,6 @@ TEST_F(GDBRemoteCommunicationClientTest, TestPacketSpeedJSON) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
std::future<Status> result = std::async(std::launch::async, [&] {
return client.SendSignalsToIgnore({2, 3, 5, 7, 0xB, 0xD, 0x11});
});
@ -334,12 +289,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendSignalsToIgnore) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::addr_t addr = 0xa000;
MemoryRegionInfo region_info;
std::future<Status> result = std::async(std::launch::async, [&] {
@ -355,12 +304,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfo) {
}
TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
const lldb::addr_t addr = 0x4000;
MemoryRegionInfo region_info;
std::future<Status> result = std::async(std::launch::async, [&] {
@ -372,12 +315,6 @@ TEST_F(GDBRemoteCommunicationClientTest, GetMemoryRegionInfoInvalidResponse) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
TraceOptions options;
Status error;
@ -417,12 +354,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendStartTracePacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@ -444,12 +375,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendStopTracePacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@ -482,12 +407,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetDataPacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
@ -520,12 +439,6 @@ TEST_F(GDBRemoteCommunicationClientTest, SendGetMetaDataPacket) {
}
TEST_F(GDBRemoteCommunicationClientTest, SendGetTraceConfigPacket) {
TestClient client;
MockServer server;
Connect(client, server);
if (HasFailure())
return;
lldb::tid_t thread_id = 0x23;
lldb::user_id_t trace_id = 3;
TraceOptions options;

View File

@ -30,30 +30,33 @@ void GDBRemoteTest::TearDownTestCase() {
#endif
}
void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server) {
llvm::Error GDBRemoteTest::Connect(GDBRemoteCommunication &client,
GDBRemoteCommunication &server) {
bool child_processes_inherit = false;
Status error;
TCPSocket listen_socket(true, child_processes_inherit);
ASSERT_FALSE(error.Fail());
error = listen_socket.Listen("127.0.0.1:0", 5);
ASSERT_FALSE(error.Fail());
if (llvm::Error error = listen_socket.Listen("127.0.0.1:0", 5).ToError())
return error;
Socket *accept_socket;
std::future<Status> accept_error = std::async(
std::future<Status> accept_status = std::async(
std::launch::async, [&] { return listen_socket.Accept(accept_socket); });
char connect_remote_address[64];
snprintf(connect_remote_address, sizeof(connect_remote_address),
"connect://localhost:%u", listen_socket.GetLocalPortNumber());
llvm::SmallString<32> remote_addr;
llvm::raw_svector_ostream(remote_addr)
<< "connect://localhost:" << listen_socket.GetLocalPortNumber();
std::unique_ptr<ConnectionFileDescriptor> conn_ap(
std::unique_ptr<ConnectionFileDescriptor> conn_up(
new ConnectionFileDescriptor());
ASSERT_EQ(conn_ap->Connect(connect_remote_address, nullptr),
lldb::eConnectionStatusSuccess);
if (conn_up->Connect(remote_addr, nullptr) != lldb::eConnectionStatusSuccess)
return llvm::make_error<llvm::StringError>("Unable to connect",
llvm::inconvertibleErrorCode());
client.SetConnection(conn_up.release());
if (llvm::Error error = accept_status.get().ToError())
return error;
client.SetConnection(conn_ap.release());
ASSERT_TRUE(accept_error.get().Success());
server.SetConnection(new ConnectionFileDescriptor(accept_socket));
return llvm::Error::success();
}
} // namespace process_gdb_remote

View File

@ -19,11 +19,12 @@ namespace process_gdb_remote {
class GDBRemoteTest : public testing::Test {
public:
static void SetUpTestCase();
static void TearDownTestCase();
};
void Connect(GDBRemoteCommunication &client, GDBRemoteCommunication &server);
protected:
llvm::Error Connect(GDBRemoteCommunication &client,
GDBRemoteCommunication &server);
};
struct MockServer : public GDBRemoteCommunicationServer {
MockServer()

View File

@ -12,7 +12,6 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/common/TCPSocket.h"
#include "lldb/Host/posix/ConnectionFileDescriptorPosix.h"
#include "lldb/Host/posix/ProcessLauncherPosix.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "llvm/ADT/StringExtras.h"