Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,192 @@
macro(add_host_subdirectory group)
list(APPEND HOST_SOURCES ${ARGN})
source_group(${group} FILES ${ARGN})
endmacro()
add_host_subdirectory(common
common/File.cpp
common/FileCache.cpp
common/FileSystem.cpp
common/GetOptInc.cpp
common/Host.cpp
common/HostInfoBase.cpp
common/HostNativeThreadBase.cpp
common/HostProcess.cpp
common/HostThread.cpp
common/LockFileBase.cpp
common/MainLoop.cpp
common/MonitoringProcessLauncher.cpp
common/NativeBreakpoint.cpp
common/NativeBreakpointList.cpp
common/NativeWatchpointList.cpp
common/NativeProcessProtocol.cpp
common/NativeRegisterContext.cpp
common/NativeThreadProtocol.cpp
common/OptionParser.cpp
common/PipeBase.cpp
common/ProcessRunLock.cpp
common/PseudoTerminal.cpp
common/Socket.cpp
common/SocketAddress.cpp
common/SoftwareBreakpoint.cpp
common/StringConvert.cpp
common/Symbols.cpp
common/TaskPool.cpp
common/TCPSocket.cpp
common/Terminal.cpp
common/ThreadLauncher.cpp
common/XML.cpp
common/UDPSocket.cpp
)
# Keep track of whether we want to provide a define for the
# Python's architecture-specific lib path (i.e. where a
# Python lldb module would go).
set (get_python_libdir 0)
if (NOT LLDB_DISABLE_LIBEDIT)
add_host_subdirectory(common
common/Editline.cpp
)
endif()
add_host_subdirectory(posix
posix/ConnectionFileDescriptorPosix.cpp
)
if(NOT LLDB_DISABLE_PYTHON)
list(APPEND LLDB_PLUGINS lldbPluginScriptInterpreterPython)
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Windows")
add_host_subdirectory(windows
windows/ConnectionGenericFileWindows.cpp
windows/EditLineWin.cpp
windows/FileSystem.cpp
windows/Host.cpp
windows/HostInfoWindows.cpp
windows/HostProcessWindows.cpp
windows/HostThreadWindows.cpp
windows/LockFileWindows.cpp
windows/PipeWindows.cpp
windows/ProcessLauncherWindows.cpp
windows/ProcessRunLock.cpp
windows/Windows.cpp
)
else()
if (NOT LLDB_DISABLE_PYTHON)
# We'll grab the arch-specific python libdir on POSIX systems.
set (get_python_libdir 1)
endif()
add_host_subdirectory(posix
posix/DomainSocket.cpp
posix/FileSystem.cpp
posix/HostInfoPosix.cpp
posix/HostProcessPosix.cpp
posix/HostThreadPosix.cpp
posix/LockFilePosix.cpp
posix/PipePosix.cpp
posix/ProcessLauncherPosixFork.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
include_directories(SYSTEM ${LIBXML2_INCLUDE_DIR})
add_host_subdirectory(macosx
macosx/Host.mm
macosx/HostInfoMacOSX.mm
macosx/HostThreadMacOSX.mm
macosx/Symbols.cpp
macosx/cfcpp/CFCBundle.cpp
macosx/cfcpp/CFCData.cpp
macosx/cfcpp/CFCMutableArray.cpp
macosx/cfcpp/CFCMutableDictionary.cpp
macosx/cfcpp/CFCMutableSet.cpp
macosx/cfcpp/CFCString.cpp
)
if(IOS)
set_property(SOURCE macosx/Host.mm APPEND PROPERTY
COMPILE_DEFINITIONS "NO_XPC_SERVICES=1")
endif()
elseif (CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
add_host_subdirectory(linux
linux/AbstractSocket.cpp
linux/Host.cpp
linux/HostInfoLinux.cpp
linux/LibcGlue.cpp
linux/Support.cpp
)
if (CMAKE_SYSTEM_NAME MATCHES "Android")
add_host_subdirectory(android
android/HostInfoAndroid.cpp
android/LibcGlue.cpp
)
endif()
elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
add_host_subdirectory(freebsd
freebsd/Host.cpp
freebsd/HostInfoFreeBSD.cpp
)
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
add_host_subdirectory(netbsd
netbsd/Host.cpp
netbsd/HostInfoNetBSD.cpp
)
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
add_host_subdirectory(openbsd
openbsd/Host.cpp
openbsd/HostInfoOpenBSD.cpp
)
endif()
endif()
if (${get_python_libdir})
# Call a python script to gather the arch-specific libdir for
# modules like the lldb module.
execute_process(
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/../../scripts/get_relative_lib_dir.py
RESULT_VARIABLE get_libdir_status
OUTPUT_VARIABLE relative_libdir
)
if (get_libdir_status EQUAL 0)
add_definitions(-DLLDB_PYTHON_RELATIVE_LIBDIR="${relative_libdir}")
endif()
endif()
set(EXTRA_LIBS)
if (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
list(APPEND EXTRA_LIBS kvm)
endif ()
if (APPLE)
list(APPEND EXTRA_LIBS xml2)
else ()
if (LIBXML2_FOUND)
list(APPEND EXTRA_LIBS ${LIBXML2_LIBRARIES})
endif()
endif ()
if (HAVE_LIBDL)
list(APPEND EXTRA_LIBS ${CMAKE_DL_LIBS})
endif()
if (NOT LLDB_DISABLE_LIBEDIT)
list(APPEND EXTRA_LIBS edit)
endif()
add_lldb_library(lldbHost
${HOST_SOURCES}
LINK_LIBS
lldbCore
lldbInterpreter
lldbSymbol
lldbTarget
lldbUtility
${LLDB_PLUGINS}
${EXTRA_LIBS}
LINK_COMPONENTS
Support
)

View File

@@ -0,0 +1,93 @@
//===-- HostInfoAndroid.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/android/HostInfoAndroid.h"
#include "lldb/Host/linux/HostInfoLinux.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
using namespace lldb_private;
using namespace llvm;
void HostInfoAndroid::ComputeHostArchitectureSupport(ArchSpec &arch_32,
ArchSpec &arch_64) {
HostInfoLinux::ComputeHostArchitectureSupport(arch_32, arch_64);
if (arch_32.IsValid()) {
arch_32.GetTriple().setEnvironment(llvm::Triple::Android);
}
if (arch_64.IsValid()) {
arch_64.GetTriple().setEnvironment(llvm::Triple::Android);
}
}
FileSpec HostInfoAndroid::GetDefaultShell() {
return FileSpec("/system/bin/sh", false);
}
FileSpec HostInfoAndroid::ResolveLibraryPath(const std::string &module_path,
const ArchSpec &arch) {
static const char *const ld_library_path_separator = ":";
static const char *const default_lib32_path[] = {"/vendor/lib", "/system/lib",
nullptr};
static const char *const default_lib64_path[] = {"/vendor/lib64",
"/system/lib64", nullptr};
if (module_path.empty() || module_path[0] == '/')
return FileSpec(module_path.c_str(), true);
SmallVector<StringRef, 4> ld_paths;
if (const char *ld_library_path = ::getenv("LD_LIBRARY_PATH"))
StringRef(ld_library_path)
.split(ld_paths, StringRef(ld_library_path_separator), -1, false);
const char *const *default_lib_path = nullptr;
switch (arch.GetAddressByteSize()) {
case 4:
default_lib_path = default_lib32_path;
break;
case 8:
default_lib_path = default_lib64_path;
break;
default:
assert(false && "Unknown address byte size");
return FileSpec();
}
for (const char *const *it = default_lib_path; *it; ++it)
ld_paths.push_back(StringRef(*it));
for (const StringRef &path : ld_paths) {
FileSpec file_candidate(path.str().c_str(), true);
file_candidate.AppendPathComponent(module_path.c_str());
if (file_candidate.Exists())
return file_candidate;
}
return FileSpec();
}
bool HostInfoAndroid::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
bool success = HostInfoLinux::ComputeTempFileBaseDirectory(file_spec);
// On Android, there is no path which is guaranteed to be writable. If the
// user has not
// provided a path via an environment variable, the generic algorithm will
// deduce /tmp, which
// is plain wrong. In that case we have an invalid directory, we substitute
// the path with
// /data/local/tmp, which is correct at least in some cases (i.e., when
// running as shell user).
if (!success || !file_spec.Exists())
file_spec = FileSpec("/data/local/tmp", false);
return file_spec.Exists();
}

View File

@@ -0,0 +1,29 @@
//===-- LibcGlue.cpp --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This files adds functions missing from libc on earlier versions of Android
#include <android/api-level.h>
#include <sys/syscall.h>
#if __ANDROID_API__ < 21
#include <fcntl.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "lldb/Host/Time.h"
time_t timegm(struct tm *t) { return (time_t)timegm64(t); }
int posix_openpt(int flags) { return open("/dev/ptmx", flags); }
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,113 @@
//===-- FileCache.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/FileCache.h"
#include "lldb/Host/File.h"
using namespace lldb;
using namespace lldb_private;
FileCache *FileCache::m_instance = nullptr;
FileCache &FileCache::GetInstance() {
if (m_instance == nullptr)
m_instance = new FileCache();
return *m_instance;
}
lldb::user_id_t FileCache::OpenFile(const FileSpec &file_spec, uint32_t flags,
uint32_t mode, Status &error) {
std::string path(file_spec.GetPath());
if (path.empty()) {
error.SetErrorString("empty path");
return UINT64_MAX;
}
FileSP file_sp(new File());
error = file_sp->Open(path.c_str(), flags, mode);
if (file_sp->IsValid() == false)
return UINT64_MAX;
lldb::user_id_t fd = file_sp->GetDescriptor();
m_cache[fd] = file_sp;
return fd;
}
bool FileCache::CloseFile(lldb::user_id_t fd, Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return false;
}
FDToFileMap::iterator pos = m_cache.find(fd);
if (pos == m_cache.end()) {
error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
return false;
}
FileSP file_sp = pos->second;
if (!file_sp) {
error.SetErrorString("invalid host backing file");
return false;
}
error = file_sp->Close();
m_cache.erase(pos);
return error.Success();
}
uint64_t FileCache::WriteFile(lldb::user_id_t fd, uint64_t offset,
const void *src, uint64_t src_len,
Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return UINT64_MAX;
}
FDToFileMap::iterator pos = m_cache.find(fd);
if (pos == m_cache.end()) {
error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
return false;
}
FileSP file_sp = pos->second;
if (!file_sp) {
error.SetErrorString("invalid host backing file");
return UINT64_MAX;
}
if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset ||
error.Fail())
return UINT64_MAX;
size_t bytes_written = src_len;
error = file_sp->Write(src, bytes_written);
if (error.Fail())
return UINT64_MAX;
return bytes_written;
}
uint64_t FileCache::ReadFile(lldb::user_id_t fd, uint64_t offset, void *dst,
uint64_t dst_len, Status &error) {
if (fd == UINT64_MAX) {
error.SetErrorString("invalid file descriptor");
return UINT64_MAX;
}
FDToFileMap::iterator pos = m_cache.find(fd);
if (pos == m_cache.end()) {
error.SetErrorStringWithFormat("invalid host file descriptor %" PRIu64, fd);
return false;
}
FileSP file_sp = pos->second;
if (!file_sp) {
error.SetErrorString("invalid host backing file");
return UINT64_MAX;
}
if (static_cast<uint64_t>(file_sp->SeekFromStart(offset, &error)) != offset ||
error.Fail())
return UINT64_MAX;
size_t bytes_read = dst_len;
error = file_sp->Read(dst, bytes_read);
if (error.Fail())
return UINT64_MAX;
return bytes_read;
}

View File

@@ -0,0 +1,28 @@
//===-- FileSystem.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/FileSystem.h"
#include "llvm/Support/FileSystem.h"
#include <algorithm>
#include <fstream>
#include <vector>
using namespace lldb;
using namespace lldb_private;
llvm::sys::TimePoint<>
FileSystem::GetModificationTime(const FileSpec &file_spec) {
llvm::sys::fs::file_status status;
std::error_code ec = llvm::sys::fs::status(file_spec.GetPath(), status);
if (ec)
return llvm::sys::TimePoint<>();
return status.getLastModificationTime();
}

View File

@@ -0,0 +1,452 @@
//===-- GetOptInc.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/common/GetOptInc.h"
#if defined(REPLACE_GETOPT) || defined(REPLACE_GETOPT_LONG) || \
defined(REPLACE_GETOPT_LONG_ONLY)
// getopt.cpp
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#if defined(REPLACE_GETOPT)
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
#define EMSG ""
static int getopt_internal(int, char *const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char *const *, const char *,
const struct option *, int *, int);
static int gcd(int, int);
static void permute_args(int, int, int, char *const *);
static const char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/*
* Compute the greatest common divisor of a and b.
*/
static int gcd(int a, int b) {
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
static void pass() {}
#define warnx(a, ...) pass();
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void permute_args(int panonopt_start, int panonopt_end, int opt_end,
char *const *nargv) {
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end + i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **)nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int parse_long_options(char *const *nargv, const char *options,
const struct option *long_options, int *idx,
int short_too) {
char *current_argv, *has_equal;
size_t current_argv_len;
int i, match;
current_argv = const_cast<char *>(place);
match = -1;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name, current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* partial match */
match = i;
else {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig, (int)current_argv_len, current_argv);
optopt = 0;
return (BADCH);
}
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument && has_equal) {
if (PRINT_ERROR)
warnx(noarg, (int)current_argv_len, current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
return (BADARG);
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg == required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument) &&
(optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring, current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring, current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int getopt_internal(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx,
int flags) {
const char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end, optind, nargv);
optind -= nonopt_end - nonopt_start;
} else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
(place[1] == '\0' && strchr(options, '-') == NULL)) {
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind, nargv);
nonopt_start = optind - (nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end, optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
if (*place == '-')
place++; /* --foo long option */
else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options, idx, short_too);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
if (PRINT_ERROR)
warnx(illoptchar, optchar);
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
optchar = parse_long_options(nargv, options, long_options, idx, 0);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = const_cast<char *>(place);
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
#if defined(REPLACE_GETOPT)
int getopt(int nargc, char *const *nargv, const char *options) {
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
#if defined(REPLACE_GETOPT_LONG)
int getopt_long(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx) {
return (
getopt_internal(nargc, nargv, options, long_options, idx, FLAG_PERMUTE));
}
#endif
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
#if defined(REPLACE_GETOPT_LONG_ONLY)
int getopt_long_only(int nargc, char *const *nargv, const char *options,
const struct option *long_options, int *idx) {
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE | FLAG_LONGONLY));
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,390 @@
//===-- HostInfoBase.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/Config.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/HostInfoBase.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/StreamString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Support/Host.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
#include <mutex>
#include <thread>
using namespace lldb;
using namespace lldb_private;
namespace {
//----------------------------------------------------------------------
// The HostInfoBaseFields is a work around for windows not supporting
// static variables correctly in a thread safe way. Really each of the
// variables in HostInfoBaseFields should live in the functions in which
// they are used and each one should be static, but the work around is
// in place to avoid this restriction. Ick.
//----------------------------------------------------------------------
struct HostInfoBaseFields {
~HostInfoBaseFields() {
if (m_lldb_process_tmp_dir.Exists()) {
// Remove the LLDB temporary directory if we have one. Set "recurse" to
// true to all files that were created for the LLDB process can be cleaned
// up.
llvm::sys::fs::remove_directories(m_lldb_process_tmp_dir.GetPath());
}
}
std::string m_host_triple;
ArchSpec m_host_arch_32;
ArchSpec m_host_arch_64;
FileSpec m_lldb_so_dir;
FileSpec m_lldb_support_exe_dir;
FileSpec m_lldb_headers_dir;
FileSpec m_lldb_python_dir;
FileSpec m_lldb_clang_resource_dir;
FileSpec m_lldb_system_plugin_dir;
FileSpec m_lldb_user_plugin_dir;
FileSpec m_lldb_process_tmp_dir;
FileSpec m_lldb_global_tmp_dir;
};
HostInfoBaseFields *g_fields = nullptr;
}
void HostInfoBase::Initialize() { g_fields = new HostInfoBaseFields(); }
void HostInfoBase::Terminate() {
delete g_fields;
g_fields = nullptr;
}
llvm::StringRef HostInfoBase::GetTargetTriple() {
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() {
g_fields->m_host_triple =
HostInfo::GetArchitecture().GetTriple().getTriple();
});
return g_fields->m_host_triple;
}
const ArchSpec &HostInfoBase::GetArchitecture(ArchitectureKind arch_kind) {
static llvm::once_flag g_once_flag;
llvm::call_once(g_once_flag, []() {
HostInfo::ComputeHostArchitectureSupport(g_fields->m_host_arch_32,
g_fields->m_host_arch_64);
});
// If an explicit 32 or 64-bit architecture was requested, return that.
if (arch_kind == eArchKind32)
return g_fields->m_host_arch_32;
if (arch_kind == eArchKind64)
return g_fields->m_host_arch_64;
// Otherwise prefer the 64-bit architecture if it is valid.
return (g_fields->m_host_arch_64.IsValid()) ? g_fields->m_host_arch_64
: g_fields->m_host_arch_32;
}
llvm::Optional<HostInfoBase::ArchitectureKind> HostInfoBase::ParseArchitectureKind(llvm::StringRef kind) {
return llvm::StringSwitch<llvm::Optional<ArchitectureKind>>(kind)
.Case(LLDB_ARCH_DEFAULT, eArchKindDefault)
.Case(LLDB_ARCH_DEFAULT_32BIT, eArchKind32)
.Case(LLDB_ARCH_DEFAULT_64BIT, eArchKind64)
.Default(llvm::None);
}
bool HostInfoBase::GetLLDBPath(lldb::PathType type, FileSpec &file_spec) {
file_spec.Clear();
#if defined(LLDB_DISABLE_PYTHON)
if (type == lldb::ePathTypePythonDir)
return false;
#endif
FileSpec *result = nullptr;
switch (type) {
case lldb::ePathTypeLLDBShlibDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success =
HostInfo::ComputeSharedLibraryDirectory(g_fields->m_lldb_so_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeLLDBShlibDir) => '%s'",
g_fields->m_lldb_so_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_so_dir;
} break;
case lldb::ePathTypeSupportExecutableDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeSupportExeDirectory(
g_fields->m_lldb_support_exe_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf(
"HostInfoBase::GetLLDBPath(ePathTypeSupportExecutableDir) => '%s'",
g_fields->m_lldb_support_exe_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_support_exe_dir;
} break;
case lldb::ePathTypeHeaderDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeHeaderDirectory(g_fields->m_lldb_headers_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf("HostInfoBase::GetLLDBPath(ePathTypeHeaderDir) => '%s'",
g_fields->m_lldb_headers_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_headers_dir;
} break;
case lldb::ePathTypePythonDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputePythonDirectory(g_fields->m_lldb_python_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf("HostInfoBase::GetLLDBPath(ePathTypePythonDir) => '%s'",
g_fields->m_lldb_python_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_python_dir;
} break;
case lldb::ePathTypeClangDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success =
HostInfo::ComputeClangDirectory(g_fields->m_lldb_clang_resource_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf(
"HostInfoBase::GetLLDBPath(ePathTypeClangResourceDir) => '%s'",
g_fields->m_lldb_clang_resource_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_clang_resource_dir;
} break;
case lldb::ePathTypeLLDBSystemPlugins: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeSystemPluginsDirectory(
g_fields->m_lldb_system_plugin_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf(
"HostInfoBase::GetLLDBPath(ePathTypeLLDBSystemPlugins) => '%s'",
g_fields->m_lldb_system_plugin_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_system_plugin_dir;
} break;
case lldb::ePathTypeLLDBUserPlugins: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeUserPluginsDirectory(
g_fields->m_lldb_user_plugin_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf(
"HostInfoBase::GetLLDBPath(ePathTypeLLDBUserPlugins) => '%s'",
g_fields->m_lldb_user_plugin_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_user_plugin_dir;
} break;
case lldb::ePathTypeLLDBTempSystemDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeProcessTempFileDirectory(
g_fields->m_lldb_process_tmp_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf(
"HostInfoBase::GetLLDBPath(ePathTypeLLDBTempSystemDir) => '%s'",
g_fields->m_lldb_process_tmp_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_process_tmp_dir;
} break;
case lldb::ePathTypeGlobalLLDBTempSystemDir: {
static llvm::once_flag g_once_flag;
static bool success = false;
llvm::call_once(g_once_flag, []() {
success = HostInfo::ComputeGlobalTempFileDirectory(
g_fields->m_lldb_global_tmp_dir);
Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
if (log)
log->Printf("HostInfoBase::GetLLDBPath("
"ePathTypeGlobalLLDBTempSystemDir) => '%s'",
g_fields->m_lldb_global_tmp_dir.GetPath().c_str());
});
if (success)
result = &g_fields->m_lldb_global_tmp_dir;
} break;
}
if (!result)
return false;
file_spec = *result;
return true;
}
ArchSpec HostInfoBase::GetAugmentedArchSpec(llvm::StringRef triple) {
if (triple.empty())
return ArchSpec();
llvm::Triple normalized_triple(llvm::Triple::normalize(triple));
if (!ArchSpec::ContainsOnlyArch(normalized_triple))
return ArchSpec(triple);
if (auto kind = HostInfo::ParseArchitectureKind(triple))
return HostInfo::GetArchitecture(*kind);
llvm::Triple host_triple(llvm::sys::getDefaultTargetTriple());
if (normalized_triple.getVendorName().empty())
normalized_triple.setVendor(host_triple.getVendor());
if (normalized_triple.getOSName().empty())
normalized_triple.setOS(host_triple.getOS());
if (normalized_triple.getEnvironmentName().empty())
normalized_triple.setEnvironment(host_triple.getEnvironment());
return ArchSpec(normalized_triple);
}
bool HostInfoBase::ComputeSharedLibraryDirectory(FileSpec &file_spec) {
// To get paths related to LLDB we get the path to the executable that
// contains this function. On MacOSX this will be "LLDB.framework/.../LLDB",
// on linux this is assumed to be the "lldb" main executable. If LLDB on
// linux is actually in a shared library (liblldb.so) then this function will
// need to be modified to "do the right thing".
FileSpec lldb_file_spec(
Host::GetModuleFileSpecForHostAddress(reinterpret_cast<void *>(
reinterpret_cast<intptr_t>(HostInfoBase::GetLLDBPath))));
// This is necessary because when running the testsuite the shlib might be a
// symbolic link inside the Python resource dir.
FileSystem::ResolveSymbolicLink(lldb_file_spec, lldb_file_spec);
// Remove the filename so that this FileSpec only represents the directory.
file_spec.GetDirectory() = lldb_file_spec.GetDirectory();
return (bool)file_spec.GetDirectory();
}
bool HostInfoBase::ComputeSupportExeDirectory(FileSpec &file_spec) {
return GetLLDBPath(lldb::ePathTypeLLDBShlibDir, file_spec);
}
bool HostInfoBase::ComputeProcessTempFileDirectory(FileSpec &file_spec) {
FileSpec temp_file_spec;
if (!HostInfo::ComputeGlobalTempFileDirectory(temp_file_spec))
return false;
std::string pid_str{llvm::to_string(Host::GetCurrentProcessID())};
temp_file_spec.AppendPathComponent(pid_str);
if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
return false;
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
return true;
}
bool HostInfoBase::ComputeTempFileBaseDirectory(FileSpec &file_spec) {
llvm::SmallVector<char, 16> tmpdir;
llvm::sys::path::system_temp_directory(/*ErasedOnReboot*/ true, tmpdir);
file_spec = FileSpec(std::string(tmpdir.data(), tmpdir.size()), true);
return true;
}
bool HostInfoBase::ComputeGlobalTempFileDirectory(FileSpec &file_spec) {
file_spec.Clear();
FileSpec temp_file_spec;
if (!HostInfo::ComputeTempFileBaseDirectory(temp_file_spec))
return false;
temp_file_spec.AppendPathComponent("lldb");
if (llvm::sys::fs::create_directory(temp_file_spec.GetPath()))
return false;
file_spec.GetDirectory().SetCString(temp_file_spec.GetCString());
return true;
}
bool HostInfoBase::ComputeHeaderDirectory(FileSpec &file_spec) {
// TODO(zturner): Figure out how to compute the header directory for all
// platforms.
return false;
}
bool HostInfoBase::ComputeSystemPluginsDirectory(FileSpec &file_spec) {
// TODO(zturner): Figure out how to compute the system plugins directory for
// all platforms.
return false;
}
bool HostInfoBase::ComputeClangDirectory(FileSpec &file_spec) { return false; }
bool HostInfoBase::ComputeUserPluginsDirectory(FileSpec &file_spec) {
// TODO(zturner): Figure out how to compute the user plugins directory for all
// platforms.
return false;
}
void HostInfoBase::ComputeHostArchitectureSupport(ArchSpec &arch_32,
ArchSpec &arch_64) {
llvm::Triple triple(llvm::sys::getProcessTriple());
arch_32.Clear();
arch_64.Clear();
switch (triple.getArch()) {
default:
arch_32.SetTriple(triple);
break;
case llvm::Triple::aarch64:
case llvm::Triple::ppc64:
case llvm::Triple::x86_64:
arch_64.SetTriple(triple);
arch_32.SetTriple(triple.get32BitArchVariant());
break;
case llvm::Triple::mips64:
case llvm::Triple::mips64el:
case llvm::Triple::sparcv9:
case llvm::Triple::systemz:
arch_64.SetTriple(triple);
break;
}
}

View File

@@ -0,0 +1,67 @@
//===-- HostNativeThreadBase.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/HostNativeThreadBase.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Utility/Log.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Threading.h"
using namespace lldb;
using namespace lldb_private;
HostNativeThreadBase::HostNativeThreadBase()
: m_thread(LLDB_INVALID_HOST_THREAD), m_result(0) {}
HostNativeThreadBase::HostNativeThreadBase(thread_t thread)
: m_thread(thread), m_result(0) {}
lldb::thread_t HostNativeThreadBase::GetSystemHandle() const {
return m_thread;
}
lldb::thread_result_t HostNativeThreadBase::GetResult() const {
return m_result;
}
bool HostNativeThreadBase::IsJoinable() const {
return m_thread != LLDB_INVALID_HOST_THREAD;
}
void HostNativeThreadBase::Reset() {
m_thread = LLDB_INVALID_HOST_THREAD;
m_result = 0;
}
lldb::thread_t HostNativeThreadBase::Release() {
lldb::thread_t result = m_thread;
m_thread = LLDB_INVALID_HOST_THREAD;
m_result = 0;
return result;
}
lldb::thread_result_t
HostNativeThreadBase::ThreadCreateTrampoline(lldb::thread_arg_t arg) {
ThreadLauncher::HostThreadCreateInfo *info =
(ThreadLauncher::HostThreadCreateInfo *)arg;
llvm::set_thread_name(info->thread_name);
thread_func_t thread_fptr = info->thread_fptr;
thread_arg_t thread_arg = info->thread_arg;
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (log)
log->Printf("thread created");
delete info;
return thread_fptr(thread_arg);
}

View File

@@ -0,0 +1,48 @@
//===-- HostProcess.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/HostProcess.h"
#include "lldb/Host/HostNativeProcess.h"
#include "lldb/Host/HostThread.h"
using namespace lldb;
using namespace lldb_private;
HostProcess::HostProcess() : m_native_process(new HostNativeProcess) {}
HostProcess::HostProcess(lldb::process_t process)
: m_native_process(new HostNativeProcess(process)) {}
HostProcess::~HostProcess() {}
Status HostProcess::Terminate() { return m_native_process->Terminate(); }
Status HostProcess::GetMainModule(FileSpec &file_spec) const {
return m_native_process->GetMainModule(file_spec);
}
lldb::pid_t HostProcess::GetProcessId() const {
return m_native_process->GetProcessId();
}
bool HostProcess::IsRunning() const { return m_native_process->IsRunning(); }
HostThread
HostProcess::StartMonitoring(const Host::MonitorChildProcessCallback &callback,
bool monitor_signals) {
return m_native_process->StartMonitoring(callback, monitor_signals);
}
HostNativeProcessBase &HostProcess::GetNativeProcess() {
return *m_native_process;
}
const HostNativeProcessBase &HostProcess::GetNativeProcess() const {
return *m_native_process;
}

View File

@@ -0,0 +1,47 @@
//===-- HostThread.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/HostThread.h"
#include "lldb/Host/HostNativeThread.h"
using namespace lldb;
using namespace lldb_private;
HostThread::HostThread() : m_native_thread(new HostNativeThread) {}
HostThread::HostThread(lldb::thread_t thread)
: m_native_thread(new HostNativeThread(thread)) {}
Status HostThread::Join(lldb::thread_result_t *result) {
return m_native_thread->Join(result);
}
Status HostThread::Cancel() { return m_native_thread->Cancel(); }
void HostThread::Reset() { return m_native_thread->Reset(); }
lldb::thread_t HostThread::Release() { return m_native_thread->Release(); }
bool HostThread::IsJoinable() const { return m_native_thread->IsJoinable(); }
HostNativeThread &HostThread::GetNativeThread() {
return static_cast<HostNativeThread &>(*m_native_thread);
}
const HostNativeThread &HostThread::GetNativeThread() const {
return static_cast<const HostNativeThread &>(*m_native_thread);
}
lldb::thread_result_t HostThread::GetResult() const {
return m_native_thread->GetResult();
}
bool HostThread::EqualsThread(lldb::thread_t thread) const {
return m_native_thread->GetSystemHandle() == thread;
}

View File

@@ -0,0 +1,82 @@
//===-- LockFileBase.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/LockFileBase.h"
using namespace lldb;
using namespace lldb_private;
namespace {
Status AlreadyLocked() { return Status("Already locked"); }
Status NotLocked() { return Status("Not locked"); }
}
LockFileBase::LockFileBase(int fd)
: m_fd(fd), m_locked(false), m_start(0), m_len(0) {}
bool LockFileBase::IsLocked() const { return m_locked; }
Status LockFileBase::WriteLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoWriteLock(start, len); },
start, len);
}
Status LockFileBase::TryWriteLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoTryWriteLock(start, len); },
start, len);
}
Status LockFileBase::ReadLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoReadLock(start, len); },
start, len);
}
Status LockFileBase::TryReadLock(const uint64_t start, const uint64_t len) {
return DoLock([&](const uint64_t start,
const uint64_t len) { return DoTryReadLock(start, len); },
start, len);
}
Status LockFileBase::Unlock() {
if (!IsLocked())
return NotLocked();
const auto error = DoUnlock();
if (error.Success()) {
m_locked = false;
m_start = 0;
m_len = 0;
}
return error;
}
bool LockFileBase::IsValidFile() const { return m_fd != -1; }
Status LockFileBase::DoLock(const Locker &locker, const uint64_t start,
const uint64_t len) {
if (!IsValidFile())
return Status("File is invalid");
if (IsLocked())
return AlreadyLocked();
const auto error = locker(start, len);
if (error.Success()) {
m_locked = true;
m_start = start;
m_len = len;
}
return error;
}

View File

@@ -0,0 +1,402 @@
//===-- MainLoop.cpp --------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Config/llvm-config.h"
#include "lldb/Host/MainLoop.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Utility/Status.h"
#include <algorithm>
#include <cassert>
#include <cerrno>
#include <csignal>
#include <time.h>
#include <vector>
// Multiplexing is implemented using kqueue on systems that support it (BSD
// variants including OSX). On linux we use ppoll, while android uses pselect
// (ppoll is present but not implemented properly). On windows we use WSApoll
// (which does not support signals).
#if HAVE_SYS_EVENT_H
#include <sys/event.h>
#elif defined(LLVM_ON_WIN32)
#include <winsock2.h>
#elif defined(__ANDROID__)
#include <sys/syscall.h>
#else
#include <poll.h>
#endif
#ifdef LLVM_ON_WIN32
#define POLL WSAPoll
#else
#define POLL poll
#endif
#if SIGNAL_POLLING_UNSUPPORTED
#ifdef LLVM_ON_WIN32
typedef int sigset_t;
typedef int siginfo_t;
#endif
int ppoll(struct pollfd *fds, size_t nfds, const struct timespec *timeout_ts,
const sigset_t *) {
int timeout =
(timeout_ts == nullptr)
? -1
: (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
return POLL(fds, nfds, timeout);
}
#endif
using namespace lldb;
using namespace lldb_private;
static sig_atomic_t g_signal_flags[NSIG];
static void SignalHandler(int signo, siginfo_t *info, void *) {
assert(signo < NSIG);
g_signal_flags[signo] = 1;
}
class MainLoop::RunImpl {
public:
RunImpl(MainLoop &loop);
~RunImpl() = default;
Status Poll();
void ProcessEvents();
private:
MainLoop &loop;
#if HAVE_SYS_EVENT_H
std::vector<struct kevent> in_events;
struct kevent out_events[4];
int num_events = -1;
#else
#ifdef __ANDROID__
fd_set read_fd_set;
#else
std::vector<struct pollfd> read_fds;
#endif
sigset_t get_sigmask();
#endif
};
#if HAVE_SYS_EVENT_H
MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
in_events.reserve(loop.m_read_fds.size());
}
Status MainLoop::RunImpl::Poll() {
in_events.resize(loop.m_read_fds.size());
unsigned i = 0;
for (auto &fd : loop.m_read_fds)
EV_SET(&in_events[i++], fd.first, EVFILT_READ, EV_ADD, 0, 0, 0);
num_events = kevent(loop.m_kqueue, in_events.data(), in_events.size(),
out_events, llvm::array_lengthof(out_events), nullptr);
if (num_events < 0)
return Status("kevent() failed with error %d\n", num_events);
return Status();
}
void MainLoop::RunImpl::ProcessEvents() {
assert(num_events >= 0);
for (int i = 0; i < num_events; ++i) {
if (loop.m_terminate_request)
return;
switch (out_events[i].filter) {
case EVFILT_READ:
loop.ProcessReadObject(out_events[i].ident);
break;
case EVFILT_SIGNAL:
loop.ProcessSignal(out_events[i].ident);
break;
default:
llvm_unreachable("Unknown event");
}
}
}
#else
MainLoop::RunImpl::RunImpl(MainLoop &loop) : loop(loop) {
#ifndef __ANDROID__
read_fds.reserve(loop.m_read_fds.size());
#endif
}
sigset_t MainLoop::RunImpl::get_sigmask() {
#if SIGNAL_POLLING_UNSUPPORTED
return 0;
#else
sigset_t sigmask;
int ret = pthread_sigmask(SIG_SETMASK, nullptr, &sigmask);
assert(ret == 0);
(void) ret;
for (const auto &sig : loop.m_signals)
sigdelset(&sigmask, sig.first);
return sigmask;
#endif
}
#ifdef __ANDROID__
Status MainLoop::RunImpl::Poll() {
// ppoll(2) is not supported on older all android versions. Also, older
// versions android (API <= 19) implemented pselect in a non-atomic way, as a
// combination of pthread_sigmask and select. This is not sufficient for us,
// as we rely on the atomicity to correctly implement signal polling, so we
// call the underlying syscall ourselves.
FD_ZERO(&read_fd_set);
int nfds = 0;
for (const auto &fd : loop.m_read_fds) {
FD_SET(fd.first, &read_fd_set);
nfds = std::max(nfds, fd.first + 1);
}
union {
sigset_t set;
uint64_t pad;
} kernel_sigset;
memset(&kernel_sigset, 0, sizeof(kernel_sigset));
kernel_sigset.set = get_sigmask();
struct {
void *sigset_ptr;
size_t sigset_len;
} extra_data = {&kernel_sigset, sizeof(kernel_sigset)};
if (syscall(__NR_pselect6, nfds, &read_fd_set, nullptr, nullptr, nullptr,
&extra_data) == -1 &&
errno != EINTR)
return Status(errno, eErrorTypePOSIX);
return Status();
}
#else
Status MainLoop::RunImpl::Poll() {
read_fds.clear();
sigset_t sigmask = get_sigmask();
for (const auto &fd : loop.m_read_fds) {
struct pollfd pfd;
pfd.fd = fd.first;
pfd.events = POLLIN;
pfd.revents = 0;
read_fds.push_back(pfd);
}
if (ppoll(read_fds.data(), read_fds.size(), nullptr, &sigmask) == -1 &&
errno != EINTR)
return Status(errno, eErrorTypePOSIX);
return Status();
}
#endif
void MainLoop::RunImpl::ProcessEvents() {
#ifdef __ANDROID__
// Collect first all readable file descriptors into a separate vector and then
// iterate over it to invoke callbacks. Iterating directly over
// loop.m_read_fds is not possible because the callbacks can modify the
// container which could invalidate the iterator.
std::vector<IOObject::WaitableHandle> fds;
for (const auto &fd : loop.m_read_fds)
if (FD_ISSET(fd.first, &read_fd_set))
fds.push_back(fd.first);
for (const auto &handle : fds) {
#else
for (const auto &fd : read_fds) {
if ((fd.revents & (POLLIN | POLLHUP)) == 0)
continue;
IOObject::WaitableHandle handle = fd.fd;
#endif
if (loop.m_terminate_request)
return;
loop.ProcessReadObject(handle);
}
std::vector<int> signals;
for (const auto &entry : loop.m_signals)
if (g_signal_flags[entry.first] != 0)
signals.push_back(entry.first);
for (const auto &signal : signals) {
if (loop.m_terminate_request)
return;
g_signal_flags[signal] = 0;
loop.ProcessSignal(signal);
}
}
#endif
MainLoop::MainLoop() {
#if HAVE_SYS_EVENT_H
m_kqueue = kqueue();
assert(m_kqueue >= 0);
#endif
}
MainLoop::~MainLoop() {
#if HAVE_SYS_EVENT_H
close(m_kqueue);
#endif
assert(m_read_fds.size() == 0);
assert(m_signals.size() == 0);
}
MainLoop::ReadHandleUP MainLoop::RegisterReadObject(const IOObjectSP &object_sp,
const Callback &callback,
Status &error) {
#ifdef LLVM_ON_WIN32
if (object_sp->GetFdType() != IOObject:: eFDTypeSocket) {
error.SetErrorString("MainLoop: non-socket types unsupported on Windows");
return nullptr;
}
#endif
if (!object_sp || !object_sp->IsValid()) {
error.SetErrorString("IO object is not valid.");
return nullptr;
}
const bool inserted =
m_read_fds.insert({object_sp->GetWaitableHandle(), callback}).second;
if (!inserted) {
error.SetErrorStringWithFormat("File descriptor %d already monitored.",
object_sp->GetWaitableHandle());
return nullptr;
}
return CreateReadHandle(object_sp);
}
// We shall block the signal, then install the signal handler. The signal will
// be unblocked in
// the Run() function to check for signal delivery.
MainLoop::SignalHandleUP
MainLoop::RegisterSignal(int signo, const Callback &callback, Status &error) {
#ifdef SIGNAL_POLLING_UNSUPPORTED
error.SetErrorString("Signal polling is not supported on this platform.");
return nullptr;
#else
if (m_signals.find(signo) != m_signals.end()) {
error.SetErrorStringWithFormat("Signal %d already monitored.", signo);
return nullptr;
}
SignalInfo info;
info.callback = callback;
struct sigaction new_action;
new_action.sa_sigaction = &SignalHandler;
new_action.sa_flags = SA_SIGINFO;
sigemptyset(&new_action.sa_mask);
sigaddset(&new_action.sa_mask, signo);
sigset_t old_set;
g_signal_flags[signo] = 0;
// Even if using kqueue, the signal handler will still be invoked, so it's
// important to replace it with our "bening" handler.
int ret = sigaction(signo, &new_action, &info.old_action);
assert(ret == 0 && "sigaction failed");
#if HAVE_SYS_EVENT_H
struct kevent ev;
EV_SET(&ev, signo, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
assert(ret == 0);
#endif
// If we're using kqueue, the signal needs to be unblocked in order to recieve
// it. If using pselect/ppoll, we need to block it, and later unblock it as a
// part of the system call.
ret = pthread_sigmask(HAVE_SYS_EVENT_H ? SIG_UNBLOCK : SIG_BLOCK,
&new_action.sa_mask, &old_set);
assert(ret == 0 && "pthread_sigmask failed");
info.was_blocked = sigismember(&old_set, signo);
m_signals.insert({signo, info});
return SignalHandleUP(new SignalHandle(*this, signo));
#endif
}
void MainLoop::UnregisterReadObject(IOObject::WaitableHandle handle) {
bool erased = m_read_fds.erase(handle);
UNUSED_IF_ASSERT_DISABLED(erased);
assert(erased);
}
void MainLoop::UnregisterSignal(int signo) {
#if SIGNAL_POLLING_UNSUPPORTED
Status("Signal polling is not supported on this platform.");
#else
auto it = m_signals.find(signo);
assert(it != m_signals.end());
sigaction(signo, &it->second.old_action, nullptr);
sigset_t set;
sigemptyset(&set);
sigaddset(&set, signo);
int ret = pthread_sigmask(it->second.was_blocked ? SIG_BLOCK : SIG_UNBLOCK,
&set, nullptr);
assert(ret == 0);
(void)ret;
#if HAVE_SYS_EVENT_H
struct kevent ev;
EV_SET(&ev, signo, EVFILT_SIGNAL, EV_DELETE, 0, 0, 0);
ret = kevent(m_kqueue, &ev, 1, nullptr, 0, nullptr);
assert(ret == 0);
#endif
m_signals.erase(it);
#endif
}
Status MainLoop::Run() {
m_terminate_request = false;
Status error;
RunImpl impl(*this);
// run until termination or until we run out of things to listen to
while (!m_terminate_request && (!m_read_fds.empty() || !m_signals.empty())) {
error = impl.Poll();
if (error.Fail())
return error;
impl.ProcessEvents();
if (m_terminate_request)
return Status();
}
return Status();
}
void MainLoop::ProcessSignal(int signo) {
auto it = m_signals.find(signo);
if (it != m_signals.end())
it->second.callback(*this); // Do the work
}
void MainLoop::ProcessReadObject(IOObject::WaitableHandle handle) {
auto it = m_read_fds.find(handle);
if (it != m_read_fds.end())
it->second(*this); // Do the work
}

View File

@@ -0,0 +1,97 @@
//===-- MonitoringProcessLauncher.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/MonitoringProcessLauncher.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/HostProcess.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "llvm/Support/FileSystem.h"
using namespace lldb;
using namespace lldb_private;
MonitoringProcessLauncher::MonitoringProcessLauncher(
std::unique_ptr<ProcessLauncher> delegate_launcher)
: m_delegate_launcher(std::move(delegate_launcher)) {}
HostProcess
MonitoringProcessLauncher::LaunchProcess(const ProcessLaunchInfo &launch_info,
Status &error) {
ProcessLaunchInfo resolved_info(launch_info);
error.Clear();
char exe_path[PATH_MAX];
PlatformSP host_platform_sp(Platform::GetHostPlatform());
const ArchSpec &arch_spec = resolved_info.GetArchitecture();
FileSpec exe_spec(resolved_info.GetExecutableFile());
llvm::sys::fs::file_status stats;
status(exe_spec.GetPath(), stats);
if (!is_regular_file(stats)) {
ModuleSpec module_spec(exe_spec, arch_spec);
lldb::ModuleSP exe_module_sp;
error =
host_platform_sp->ResolveExecutable(module_spec, exe_module_sp, NULL);
if (error.Fail())
return HostProcess();
if (exe_module_sp) {
exe_spec = exe_module_sp->GetFileSpec();
status(exe_spec.GetPath(), stats);
}
}
if (exists(stats)) {
exe_spec.GetPath(exe_path, sizeof(exe_path));
} else {
resolved_info.GetExecutableFile().GetPath(exe_path, sizeof(exe_path));
error.SetErrorStringWithFormat("executable doesn't exist: '%s'", exe_path);
return HostProcess();
}
resolved_info.SetExecutableFile(exe_spec, false);
assert(!resolved_info.GetFlags().Test(eLaunchFlagLaunchInTTY));
HostProcess process =
m_delegate_launcher->LaunchProcess(resolved_info, error);
if (process.GetProcessId() != LLDB_INVALID_PROCESS_ID) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Host::MonitorChildProcessCallback callback =
launch_info.GetMonitorProcessCallback();
bool monitor_signals = false;
if (callback) {
// If the ProcessLaunchInfo specified a callback, use that.
monitor_signals = launch_info.GetMonitorSignals();
} else {
callback = Process::SetProcessExitStatus;
}
process.StartMonitoring(callback, monitor_signals);
if (log)
log->PutCString("started monitoring child process.");
} else {
// Invalid process ID, something didn't go well
if (error.Success())
error.SetErrorString("process launch failed for unknown reasons");
}
return process;
}

View File

@@ -0,0 +1,109 @@
//===-- NativeBreakpoint.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/common/NativeBreakpoint.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-defines.h"
using namespace lldb_private;
NativeBreakpoint::NativeBreakpoint(lldb::addr_t addr)
: m_addr(addr), m_ref_count(1), m_enabled(true) {
assert(addr != LLDB_INVALID_ADDRESS && "breakpoint set for invalid address");
}
NativeBreakpoint::~NativeBreakpoint() {}
void NativeBreakpoint::AddRef() {
++m_ref_count;
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" bumped up, new ref count %" PRIu32,
__FUNCTION__, m_addr, m_ref_count);
}
int32_t NativeBreakpoint::DecRef() {
--m_ref_count;
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" ref count decremented, new ref count %" PRIu32,
__FUNCTION__, m_addr, m_ref_count);
return m_ref_count;
}
Status NativeBreakpoint::Enable() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (m_enabled) {
// We're already enabled. Just log and exit.
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" already enabled, ignoring.",
__FUNCTION__, m_addr);
return Status();
}
// Log and enable.
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " enabling...",
__FUNCTION__, m_addr);
Status error = DoEnable();
if (error.Success()) {
m_enabled = true;
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable SUCCESS.",
__FUNCTION__, m_addr);
} else {
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " enable FAIL: %s",
__FUNCTION__, m_addr, error.AsCString());
}
return error;
}
Status NativeBreakpoint::Disable() {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (!m_enabled) {
// We're already disabled. Just log and exit.
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64
" already disabled, ignoring.",
__FUNCTION__, m_addr);
return Status();
}
// Log and disable.
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " disabling...",
__FUNCTION__, m_addr);
Status error = DoDisable();
if (error.Success()) {
m_enabled = false;
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable SUCCESS.",
__FUNCTION__, m_addr);
} else {
if (log)
log->Printf("NativeBreakpoint::%s addr = 0x%" PRIx64 " disable FAIL: %s",
__FUNCTION__, m_addr, error.AsCString());
}
return error;
}

View File

@@ -0,0 +1,229 @@
//===-- NativeBreakpointList.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/common/NativeBreakpointList.h"
#include "lldb/Utility/Log.h"
#include "lldb/Host/common/NativeBreakpoint.h"
#include "lldb/Host/common/SoftwareBreakpoint.h"
using namespace lldb;
using namespace lldb_private;
NativeBreakpointList::NativeBreakpointList() : m_mutex() {}
Status NativeBreakpointList::AddRef(lldb::addr_t addr, size_t size_hint,
bool hardware,
CreateBreakpointFunc create_func) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
", size_hint = %zu, hardware = %s",
__FUNCTION__, addr, size_hint, hardware ? "true" : "false");
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Check if the breakpoint is already set.
auto iter = m_breakpoints.find(addr);
if (iter != m_breakpoints.end()) {
// Yes - bump up ref count.
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- already enabled, upping ref count",
__FUNCTION__, addr);
iter->second->AddRef();
return Status();
}
// Create a new breakpoint using the given create func.
if (log)
log->Printf(
"NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64
", size_hint = %zu, hardware = %s",
__FUNCTION__, addr, size_hint, hardware ? "true" : "false");
NativeBreakpointSP breakpoint_sp;
Status error = create_func(addr, size_hint, hardware, breakpoint_sp);
if (error.Fail()) {
if (log)
log->Printf(
"NativeBreakpointList::%s creating breakpoint for addr = 0x%" PRIx64
", size_hint = %zu, hardware = %s -- FAILED: %s",
__FUNCTION__, addr, size_hint, hardware ? "true" : "false",
error.AsCString());
return error;
}
// Remember the breakpoint.
assert(breakpoint_sp && "NativeBreakpoint create function succeeded but "
"returned NULL breakpoint");
m_breakpoints.insert(BreakpointMap::value_type(addr, breakpoint_sp));
return error;
}
Status NativeBreakpointList::DecRef(lldb::addr_t addr) {
Status error;
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
addr);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Check if the breakpoint is already set.
auto iter = m_breakpoints.find(addr);
if (iter == m_breakpoints.end()) {
// Not found!
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
__FUNCTION__, addr);
error.SetErrorString("breakpoint not found");
return error;
}
// Decrement ref count.
const int32_t new_ref_count = iter->second->DecRef();
assert(new_ref_count >= 0 && "NativeBreakpoint ref count went negative");
if (new_ref_count > 0) {
// Still references to this breakpoint. Leave it alone.
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- new breakpoint ref count %" PRIu32,
__FUNCTION__, addr, new_ref_count);
return error;
}
// Breakpoint has no more references. Disable it if it's not
// already disabled.
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- removing due to no remaining references",
__FUNCTION__, addr);
// If it's enabled, we need to disable it.
if (iter->second->IsEnabled()) {
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- currently enabled, now disabling",
__FUNCTION__, addr);
error = iter->second->Disable();
if (error.Fail()) {
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- removal FAILED: %s",
__FUNCTION__, addr, error.AsCString());
// Continue since we still want to take it out of the breakpoint list.
}
} else {
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- already disabled, nothing to do",
__FUNCTION__, addr);
}
// Take the breakpoint out of the list.
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64
" -- removed from breakpoint map",
__FUNCTION__, addr);
m_breakpoints.erase(iter);
return error;
}
Status NativeBreakpointList::EnableBreakpoint(lldb::addr_t addr) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
addr);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Ensure we have said breakpoint.
auto iter = m_breakpoints.find(addr);
if (iter == m_breakpoints.end()) {
// Not found!
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
__FUNCTION__, addr);
return Status("breakpoint not found");
}
// Enable it.
return iter->second->Enable();
}
Status NativeBreakpointList::DisableBreakpoint(lldb::addr_t addr) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
addr);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Ensure we have said breakpoint.
auto iter = m_breakpoints.find(addr);
if (iter == m_breakpoints.end()) {
// Not found!
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64 " -- NOT FOUND",
__FUNCTION__, addr);
return Status("breakpoint not found");
}
// Disable it.
return iter->second->Disable();
}
Status NativeBreakpointList::GetBreakpoint(lldb::addr_t addr,
NativeBreakpointSP &breakpoint_sp) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeBreakpointList::%s addr = 0x%" PRIx64, __FUNCTION__,
addr);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
// Ensure we have said breakpoint.
auto iter = m_breakpoints.find(addr);
if (iter == m_breakpoints.end()) {
// Not found!
breakpoint_sp.reset();
return Status("breakpoint not found");
}
// Disable it.
breakpoint_sp = iter->second;
return Status();
}
Status NativeBreakpointList::RemoveTrapsFromBuffer(lldb::addr_t addr, void *buf,
size_t size) const {
for (const auto &map : m_breakpoints) {
lldb::addr_t bp_addr = map.first;
// Breapoint not in range, ignore
if (bp_addr < addr || addr + size <= bp_addr)
continue;
const auto &bp_sp = map.second;
// Not software breakpoint, ignore
if (!bp_sp->IsSoftwareBreakpoint())
continue;
auto software_bp_sp = std::static_pointer_cast<SoftwareBreakpoint>(bp_sp);
auto opcode_addr = static_cast<char *>(buf) + bp_addr - addr;
auto saved_opcodes = software_bp_sp->m_saved_opcodes;
auto opcode_size = software_bp_sp->m_opcode_size;
::memcpy(opcode_addr, saved_opcodes, opcode_size);
}
return Status();
}

View File

@@ -0,0 +1,456 @@
//===-- NativeProcessProtocol.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/common/NativeProcessProtocol.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/State.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/common/NativeRegisterContext.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Host/common/SoftwareBreakpoint.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/lldb-enumerations.h"
using namespace lldb;
using namespace lldb_private;
// -----------------------------------------------------------------------------
// NativeProcessProtocol Members
// -----------------------------------------------------------------------------
NativeProcessProtocol::NativeProcessProtocol(lldb::pid_t pid, int terminal_fd,
NativeDelegate &delegate)
: m_pid(pid), m_terminal_fd(terminal_fd) {
bool registered = RegisterNativeDelegate(delegate);
assert(registered);
(void)registered;
}
lldb_private::Status NativeProcessProtocol::Interrupt() {
Status error;
#if !defined(SIGSTOP)
error.SetErrorString("local host does not support signaling");
return error;
#else
return Signal(SIGSTOP);
#endif
}
Status NativeProcessProtocol::IgnoreSignals(llvm::ArrayRef<int> signals) {
m_signals_to_ignore.clear();
m_signals_to_ignore.insert(signals.begin(), signals.end());
return Status();
}
lldb_private::Status
NativeProcessProtocol::GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) {
// Default: not implemented.
return Status("not implemented");
}
llvm::Optional<WaitStatus> NativeProcessProtocol::GetExitStatus() {
if (m_state == lldb::eStateExited)
return m_exit_status;
return llvm::None;
}
bool NativeProcessProtocol::SetExitStatus(WaitStatus status,
bool bNotifyStateChange) {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
LLDB_LOG(log, "status = {0}, notify = {1}", status, bNotifyStateChange);
// Exit status already set
if (m_state == lldb::eStateExited) {
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_status = status;
if (bNotifyStateChange)
SynchronouslyNotifyProcessStateChanged(lldb::eStateExited);
return true;
}
NativeThreadProtocol *NativeProcessProtocol::GetThreadAtIndex(uint32_t idx) {
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
if (idx < m_threads.size())
return m_threads[idx].get();
return nullptr;
}
NativeThreadProtocol *
NativeProcessProtocol::GetThreadByIDUnlocked(lldb::tid_t tid) {
for (const auto &thread : m_threads) {
if (thread->GetID() == tid)
return thread.get();
}
return nullptr;
}
NativeThreadProtocol *NativeProcessProtocol::GetThreadByID(lldb::tid_t tid) {
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
return GetThreadByIDUnlocked(tid);
}
bool NativeProcessProtocol::IsAlive() const {
return m_state != eStateDetached && m_state != eStateExited &&
m_state != eStateInvalid && m_state != eStateUnloaded;
}
const NativeWatchpointList::WatchpointMap &
NativeProcessProtocol::GetWatchpointMap() const {
return m_watchpoint_list.GetWatchpointMap();
}
llvm::Optional<std::pair<uint32_t, uint32_t>>
NativeProcessProtocol::GetHardwareDebugSupportInfo() const {
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// get any thread
NativeThreadProtocol *thread(
const_cast<NativeProcessProtocol *>(this)->GetThreadAtIndex(0));
if (!thread) {
LLDB_LOG(log, "failed to find a thread to grab a NativeRegisterContext!");
return llvm::None;
}
NativeRegisterContext &reg_ctx = thread->GetRegisterContext();
return std::make_pair(reg_ctx.NumSupportedHardwareBreakpoints(),
reg_ctx.NumSupportedHardwareWatchpoints());
}
Status NativeProcessProtocol::SetWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags,
bool hardware) {
// This default implementation assumes setting the watchpoint for
// the process will require setting the watchpoint for each of the
// threads. Furthermore, it will track watchpoints set for the
// process and will add them to each thread that is attached to
// via the (FIXME implement) OnThreadAttached () method.
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// Update the thread list
UpdateThreads();
// Keep track of the threads we successfully set the watchpoint
// for. If one of the thread watchpoint setting operations fails,
// back off and remove the watchpoint for all the threads that
// were successfully set so we get back to a consistent state.
std::vector<NativeThreadProtocol *> watchpoint_established_threads;
// Tell each thread to set a watchpoint. In the event that
// hardware watchpoints are requested but the SetWatchpoint fails,
// try to set a software watchpoint as a fallback. It's
// conceivable that if there are more threads than hardware
// watchpoints available, some of the threads will fail to set
// hardware watchpoints while software ones may be available.
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
for (const auto &thread : m_threads) {
assert(thread && "thread list should not have a NULL thread!");
Status thread_error =
thread->SetWatchpoint(addr, size, watch_flags, hardware);
if (thread_error.Fail() && hardware) {
// Try software watchpoints since we failed on hardware watchpoint setting
// and we may have just run out of hardware watchpoints.
thread_error = thread->SetWatchpoint(addr, size, watch_flags, false);
if (thread_error.Success())
LLDB_LOG(log,
"hardware watchpoint requested but software watchpoint set");
}
if (thread_error.Success()) {
// Remember that we set this watchpoint successfully in
// case we need to clear it later.
watchpoint_established_threads.push_back(thread.get());
} else {
// Unset the watchpoint for each thread we successfully
// set so that we get back to a consistent state of "not
// set" for the watchpoint.
for (auto unwatch_thread_sp : watchpoint_established_threads) {
Status remove_error = unwatch_thread_sp->RemoveWatchpoint(addr);
if (remove_error.Fail())
LLDB_LOG(log, "RemoveWatchpoint failed for pid={0}, tid={1}: {2}",
GetID(), unwatch_thread_sp->GetID(), remove_error);
}
return thread_error;
}
}
return m_watchpoint_list.Add(addr, size, watch_flags, hardware);
}
Status NativeProcessProtocol::RemoveWatchpoint(lldb::addr_t addr) {
// Update the thread list
UpdateThreads();
Status overall_error;
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
for (const auto &thread : m_threads) {
assert(thread && "thread list should not have a NULL thread!");
const Status thread_error = thread->RemoveWatchpoint(addr);
if (thread_error.Fail()) {
// Keep track of the first thread error if any threads
// fail. We want to try to remove the watchpoint from
// every thread, though, even if one or more have errors.
if (!overall_error.Fail())
overall_error = thread_error;
}
}
const Status error = m_watchpoint_list.Remove(addr);
return overall_error.Fail() ? overall_error : error;
}
const HardwareBreakpointMap &
NativeProcessProtocol::GetHardwareBreakpointMap() const {
return m_hw_breakpoints_map;
}
Status NativeProcessProtocol::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
// This default implementation assumes setting a hardware breakpoint for
// this process will require setting same hardware breakpoint for each
// of its existing threads. New thread will do the same once created.
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
// Update the thread list
UpdateThreads();
// Exit here if target does not have required hardware breakpoint capability.
auto hw_debug_cap = GetHardwareDebugSupportInfo();
if (hw_debug_cap == llvm::None || hw_debug_cap->first == 0 ||
hw_debug_cap->first <= m_hw_breakpoints_map.size())
return Status("Target does not have required no of hardware breakpoints");
// Vector below stores all thread pointer for which we have we successfully
// set this hardware breakpoint. If any of the current process threads fails
// to set this hardware breakpoint then roll back and remove this breakpoint
// for all the threads that had already set it successfully.
std::vector<NativeThreadProtocol *> breakpoint_established_threads;
// Request to set a hardware breakpoint for each of current process threads.
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
for (const auto &thread : m_threads) {
assert(thread && "thread list should not have a NULL thread!");
Status thread_error = thread->SetHardwareBreakpoint(addr, size);
if (thread_error.Success()) {
// Remember that we set this breakpoint successfully in
// case we need to clear it later.
breakpoint_established_threads.push_back(thread.get());
} else {
// Unset the breakpoint for each thread we successfully
// set so that we get back to a consistent state of "not
// set" for this hardware breakpoint.
for (auto rollback_thread_sp : breakpoint_established_threads) {
Status remove_error =
rollback_thread_sp->RemoveHardwareBreakpoint(addr);
if (remove_error.Fail())
LLDB_LOG(log,
"RemoveHardwareBreakpoint failed for pid={0}, tid={1}: {2}",
GetID(), rollback_thread_sp->GetID(), remove_error);
}
return thread_error;
}
}
// Register new hardware breakpoint into hardware breakpoints map of current
// process.
m_hw_breakpoints_map[addr] = {addr, size};
return Status();
}
Status NativeProcessProtocol::RemoveHardwareBreakpoint(lldb::addr_t addr) {
// Update the thread list
UpdateThreads();
Status error;
std::lock_guard<std::recursive_mutex> guard(m_threads_mutex);
for (const auto &thread : m_threads) {
assert(thread && "thread list should not have a NULL thread!");
error = thread->RemoveHardwareBreakpoint(addr);
}
// Also remove from hardware breakpoint map of current process.
m_hw_breakpoints_map.erase(addr);
return error;
}
bool NativeProcessProtocol::RegisterNativeDelegate(
NativeDelegate &native_delegate) {
std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
if (std::find(m_delegates.begin(), m_delegates.end(), &native_delegate) !=
m_delegates.end())
return false;
m_delegates.push_back(&native_delegate);
native_delegate.InitializeDelegate(this);
return true;
}
bool NativeProcessProtocol::UnregisterNativeDelegate(
NativeDelegate &native_delegate) {
std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
const auto initial_size = m_delegates.size();
m_delegates.erase(
remove(m_delegates.begin(), m_delegates.end(), &native_delegate),
m_delegates.end());
// We removed the delegate if the count of delegates shrank after
// removing all copies of the given native_delegate from the vector.
return m_delegates.size() < initial_size;
}
void NativeProcessProtocol::SynchronouslyNotifyProcessStateChanged(
lldb::StateType state) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
for (auto native_delegate : m_delegates)
native_delegate->ProcessStateChanged(this, state);
if (log) {
if (!m_delegates.empty()) {
log->Printf("NativeProcessProtocol::%s: sent state notification [%s] "
"from process %" PRIu64,
__FUNCTION__, lldb_private::StateAsCString(state), GetID());
} else {
log->Printf("NativeProcessProtocol::%s: would send state notification "
"[%s] from process %" PRIu64 ", but no delegates",
__FUNCTION__, lldb_private::StateAsCString(state), GetID());
}
}
}
void NativeProcessProtocol::NotifyDidExec() {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
log->Printf("NativeProcessProtocol::%s - preparing to call delegates",
__FUNCTION__);
{
std::lock_guard<std::recursive_mutex> guard(m_delegates_mutex);
for (auto native_delegate : m_delegates)
native_delegate->DidExec(this);
}
}
Status NativeProcessProtocol::SetSoftwareBreakpoint(lldb::addr_t addr,
uint32_t size_hint) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
if (log)
log->Printf("NativeProcessProtocol::%s addr = 0x%" PRIx64, __FUNCTION__,
addr);
return m_breakpoint_list.AddRef(
addr, size_hint, false,
[this](lldb::addr_t addr, size_t size_hint, bool /* hardware */,
NativeBreakpointSP &breakpoint_sp) -> Status {
return SoftwareBreakpoint::CreateSoftwareBreakpoint(
*this, addr, size_hint, breakpoint_sp);
});
}
Status NativeProcessProtocol::RemoveBreakpoint(lldb::addr_t addr,
bool hardware) {
if (hardware)
return RemoveHardwareBreakpoint(addr);
else
return m_breakpoint_list.DecRef(addr);
}
Status NativeProcessProtocol::EnableBreakpoint(lldb::addr_t addr) {
return m_breakpoint_list.EnableBreakpoint(addr);
}
Status NativeProcessProtocol::DisableBreakpoint(lldb::addr_t addr) {
return m_breakpoint_list.DisableBreakpoint(addr);
}
lldb::StateType NativeProcessProtocol::GetState() const {
std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
return m_state;
}
void NativeProcessProtocol::SetState(lldb::StateType state,
bool notify_delegates) {
std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
if (state == m_state)
return;
m_state = state;
if (StateIsStoppedState(state, false)) {
++m_stop_id;
// Give process a chance to do any stop id bump processing, such as
// clearing cached data that is invalidated each time the process runs.
// Note if/when we support some threads running, we'll end up needing
// to manage this per thread and per process.
DoStopIDBumped(m_stop_id);
}
// Optionally notify delegates of the state change.
if (notify_delegates)
SynchronouslyNotifyProcessStateChanged(state);
}
uint32_t NativeProcessProtocol::GetStopID() const {
std::lock_guard<std::recursive_mutex> guard(m_state_mutex);
return m_stop_id;
}
void NativeProcessProtocol::DoStopIDBumped(uint32_t /* newBumpId */) {
// Default implementation does nothing.
}
Status NativeProcessProtocol::ResolveProcessArchitecture(lldb::pid_t pid,
ArchSpec &arch) {
// Grab process info for the running process.
ProcessInstanceInfo process_info;
if (!Host::GetProcessInfo(pid, process_info))
return Status("failed to get process info");
// Resolve the executable module.
ModuleSpecList module_specs;
if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(), 0,
0, module_specs))
return Status("failed to get module specifications");
lldbassert(module_specs.GetSize() == 1);
arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture();
if (arch.IsValid())
return Status();
else
return Status(
"failed to retrieve a valid architecture from the exe module");
}
NativeProcessProtocol::Factory::~Factory() = default;

View File

@@ -0,0 +1,429 @@
//===-- NativeRegisterContext.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/common/NativeRegisterContext.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Utility/Log.h"
#include "lldb/Host/PosixApi.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
using namespace lldb;
using namespace lldb_private;
NativeRegisterContext::NativeRegisterContext(NativeThreadProtocol &thread)
: m_thread(thread) {}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
NativeRegisterContext::~NativeRegisterContext() {}
// FIXME revisit invalidation, process stop ids, etc. Right now we don't
// support caching in NativeRegisterContext. We can do this later by
// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
// NativeRegisterContext.
// void
// NativeRegisterContext::InvalidateIfNeeded (bool force)
// {
// ProcessSP process_sp (m_thread.GetProcess());
// bool invalidate = force;
// uint32_t process_stop_id = UINT32_MAX;
// if (process_sp)
// process_stop_id = process_sp->GetStopID();
// else
// invalidate = true;
// if (!invalidate)
// invalidate = process_stop_id != GetStopID();
// if (invalidate)
// {
// InvalidateAllRegisters ();
// SetStopID (process_stop_id);
// }
// }
const RegisterInfo *
NativeRegisterContext::GetRegisterInfoByName(llvm::StringRef reg_name,
uint32_t start_idx) {
if (reg_name.empty())
return nullptr;
const uint32_t num_registers = GetRegisterCount();
for (uint32_t reg = start_idx; reg < num_registers; ++reg) {
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_name.equals_lower(reg_info->name) ||
reg_name.equals_lower(reg_info->alt_name))
return reg_info;
}
return nullptr;
}
const RegisterInfo *NativeRegisterContext::GetRegisterInfo(uint32_t kind,
uint32_t num) {
const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
if (reg_num == LLDB_INVALID_REGNUM)
return nullptr;
return GetRegisterInfoAtIndex(reg_num);
}
const char *NativeRegisterContext::GetRegisterName(uint32_t reg) {
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
if (reg_info)
return reg_info->name;
return nullptr;
}
const char *NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex(
uint32_t reg_index) const {
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
if (!reg_info)
return nullptr;
for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) {
const RegisterSet *const reg_set = GetRegisterSet(set_index);
if (!reg_set)
continue;
for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers;
++reg_num_index) {
const uint32_t reg_num = reg_set->registers[reg_num_index];
// FIXME double check we're checking the right register kind here.
if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num) {
// The given register is a member of this register set. Return the
// register set name.
return reg_set->name;
}
}
}
// Didn't find it.
return nullptr;
}
lldb::addr_t NativeRegisterContext::GetPC(lldb::addr_t fail_value) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC);
if (log)
log->Printf("NativeRegisterContext::%s using reg index %" PRIu32
" (default %" PRIu64 ")",
__FUNCTION__, reg, fail_value);
const uint64_t retval = ReadRegisterAsUnsigned(reg, fail_value);
if (log)
log->Printf("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64,
__FUNCTION__, retval);
return retval;
}
lldb::addr_t
NativeRegisterContext::GetPCfromBreakpointLocation(lldb::addr_t fail_value) {
return GetPC(fail_value);
}
Status NativeRegisterContext::SetPC(lldb::addr_t pc) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_PC);
return WriteRegisterFromUnsigned(reg, pc);
}
lldb::addr_t NativeRegisterContext::GetSP(lldb::addr_t fail_value) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP);
return ReadRegisterAsUnsigned(reg, fail_value);
}
Status NativeRegisterContext::SetSP(lldb::addr_t sp) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_SP);
return WriteRegisterFromUnsigned(reg, sp);
}
lldb::addr_t NativeRegisterContext::GetFP(lldb::addr_t fail_value) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FP);
return ReadRegisterAsUnsigned(reg, fail_value);
}
Status NativeRegisterContext::SetFP(lldb::addr_t fp) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FP);
return WriteRegisterFromUnsigned(reg, fp);
}
lldb::addr_t NativeRegisterContext::GetReturnAddress(lldb::addr_t fail_value) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_RA);
return ReadRegisterAsUnsigned(reg, fail_value);
}
lldb::addr_t NativeRegisterContext::GetFlags(lldb::addr_t fail_value) {
uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
LLDB_REGNUM_GENERIC_FLAGS);
return ReadRegisterAsUnsigned(reg, fail_value);
}
lldb::addr_t
NativeRegisterContext::ReadRegisterAsUnsigned(uint32_t reg,
lldb::addr_t fail_value) {
if (reg != LLDB_INVALID_REGNUM)
return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value);
return fail_value;
}
uint64_t
NativeRegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
lldb::addr_t fail_value) {
Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
if (reg_info) {
RegisterValue value;
Status error = ReadRegister(reg_info, value);
if (error.Success()) {
if (log)
log->Printf("NativeRegisterContext::%s ReadRegister() succeeded, value "
"%" PRIu64,
__FUNCTION__, value.GetAsUInt64());
return value.GetAsUInt64();
} else {
if (log)
log->Printf("NativeRegisterContext::%s ReadRegister() failed, error %s",
__FUNCTION__, error.AsCString());
}
} else {
if (log)
log->Printf("NativeRegisterContext::%s ReadRegister() null reg_info",
__FUNCTION__);
}
return fail_value;
}
Status NativeRegisterContext::WriteRegisterFromUnsigned(uint32_t reg,
uint64_t uval) {
if (reg == LLDB_INVALID_REGNUM)
return Status("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval);
}
Status
NativeRegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info,
uint64_t uval) {
assert(reg_info);
if (!reg_info)
return Status("reg_info is nullptr");
RegisterValue value;
if (!value.SetUInt(uval, reg_info->byte_size))
return Status("RegisterValue::SetUInt () failed");
return WriteRegister(reg_info, value);
}
lldb::tid_t NativeRegisterContext::GetThreadID() const {
return m_thread.GetID();
}
uint32_t NativeRegisterContext::NumSupportedHardwareBreakpoints() { return 0; }
uint32_t NativeRegisterContext::SetHardwareBreakpoint(lldb::addr_t addr,
size_t size) {
return LLDB_INVALID_INDEX32;
}
Status NativeRegisterContext::ClearAllHardwareBreakpoints() {
return Status("not implemented");
}
bool NativeRegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) {
return false;
}
Status NativeRegisterContext::GetHardwareBreakHitIndex(uint32_t &bp_index,
lldb::addr_t trap_addr) {
bp_index = LLDB_INVALID_INDEX32;
return Status("not implemented");
}
uint32_t NativeRegisterContext::NumSupportedHardwareWatchpoints() { return 0; }
uint32_t NativeRegisterContext::SetHardwareWatchpoint(lldb::addr_t addr,
size_t size,
uint32_t watch_flags) {
return LLDB_INVALID_INDEX32;
}
bool NativeRegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) {
return false;
}
Status NativeRegisterContext::ClearAllHardwareWatchpoints() {
return Status("not implemented");
}
Status NativeRegisterContext::IsWatchpointHit(uint32_t wp_index, bool &is_hit) {
is_hit = false;
return Status("not implemented");
}
Status NativeRegisterContext::GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) {
wp_index = LLDB_INVALID_INDEX32;
return Status("not implemented");
}
Status NativeRegisterContext::IsWatchpointVacant(uint32_t wp_index,
bool &is_vacant) {
is_vacant = false;
return Status("not implemented");
}
lldb::addr_t NativeRegisterContext::GetWatchpointAddress(uint32_t wp_index) {
return LLDB_INVALID_ADDRESS;
}
lldb::addr_t NativeRegisterContext::GetWatchpointHitAddress(uint32_t wp_index) {
return LLDB_INVALID_ADDRESS;
}
bool NativeRegisterContext::HardwareSingleStep(bool enable) { return false; }
Status NativeRegisterContext::ReadRegisterValueFromMemory(
const RegisterInfo *reg_info, lldb::addr_t src_addr, size_t src_len,
RegisterValue &reg_value) {
Status error;
if (reg_info == nullptr) {
error.SetErrorString("invalid register info argument.");
return error;
}
// Moving from addr into a register
//
// Case 1: src_len == dst_len
//
// |AABBCCDD| Address contents
// |AABBCCDD| Register contents
//
// Case 2: src_len > dst_len
//
// Status! (The register should always be big enough to hold the data)
//
// Case 3: src_len < dst_len
//
// |AABB| Address contents
// |AABB0000| Register contents [on little-endian hardware]
// |0000AABB| Register contents [on big-endian hardware]
if (src_len > RegisterValue::kMaxRegisterByteSize) {
error.SetErrorString("register too small to receive memory data");
return error;
}
const size_t dst_len = reg_info->byte_size;
if (src_len > dst_len) {
error.SetErrorStringWithFormat(
"%" PRIu64 " bytes is too big to store in register %s (%" PRIu64
" bytes)",
static_cast<uint64_t>(src_len), reg_info->name,
static_cast<uint64_t>(dst_len));
return error;
}
NativeProcessProtocol &process = m_thread.GetProcess();
uint8_t src[RegisterValue::kMaxRegisterByteSize];
// Read the memory
size_t bytes_read;
error = process.ReadMemory(src_addr, src, src_len, bytes_read);
if (error.Fail())
return error;
// Make sure the memory read succeeded...
if (bytes_read != src_len) {
// This might happen if we read _some_ bytes but not all
error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " bytes",
static_cast<uint64_t>(bytes_read),
static_cast<uint64_t>(src_len));
return error;
}
// We now have a memory buffer that contains the part or all of the register
// value. Set the register value using this memory data.
// TODO: we might need to add a parameter to this function in case the byte
// order of the memory data doesn't match the process. For now we are assuming
// they are the same.
reg_value.SetFromMemoryData(reg_info, src, src_len, process.GetByteOrder(),
error);
return error;
}
Status NativeRegisterContext::WriteRegisterValueToMemory(
const RegisterInfo *reg_info, lldb::addr_t dst_addr, size_t dst_len,
const RegisterValue &reg_value) {
uint8_t dst[RegisterValue::kMaxRegisterByteSize];
Status error;
NativeProcessProtocol &process = m_thread.GetProcess();
// TODO: we might need to add a parameter to this function in case the byte
// order of the memory data doesn't match the process. For now we are
// assuming
// they are the same.
const size_t bytes_copied = reg_value.GetAsMemoryData(
reg_info, dst, dst_len, process.GetByteOrder(), error);
if (error.Success()) {
if (bytes_copied == 0) {
error.SetErrorString("byte copy failed.");
} else {
size_t bytes_written;
error = process.WriteMemory(dst_addr, dst, bytes_copied, bytes_written);
if (error.Fail())
return error;
if (bytes_written != bytes_copied) {
// This might happen if we read _some_ bytes but not all
error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64
" bytes",
static_cast<uint64_t>(bytes_written),
static_cast<uint64_t>(bytes_copied));
}
}
}
return error;
}
uint32_t
NativeRegisterContext::ConvertRegisterKindToRegisterNumber(uint32_t kind,
uint32_t num) const {
const uint32_t num_regs = GetRegisterCount();
assert(kind < kNumRegisterKinds);
for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) {
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_idx);
if (reg_info->kinds[kind] == num)
return reg_idx;
}
return LLDB_INVALID_REGNUM;
}

Some files were not shown because too many files have changed in this diff Show More