Index: lldb/trunk/include/lldb/Host/Config.h =================================================================== --- lldb/trunk/include/lldb/Host/Config.h +++ lldb/trunk/include/lldb/Host/Config.h @@ -22,10 +22,14 @@ #include "lldb/Host/linux/Config.h" -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__OpenBSD__) #include "lldb/Host/freebsd/Config.h" +#elif defined(__NetBSD__) + +#include "lldb/Host/netbsd/Config.h" + #elif defined(__MINGW__) || defined (__MINGW32__) #include "lldb/Host/mingw/Config.h" Index: lldb/trunk/include/lldb/Host/HostInfo.h =================================================================== --- lldb/trunk/include/lldb/Host/HostInfo.h +++ lldb/trunk/include/lldb/Host/HostInfo.h @@ -48,6 +48,9 @@ #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include "lldb/Host/freebsd/HostInfoFreeBSD.h" #define HOST_INFO_TYPE HostInfoFreeBSD +#elif defined(__NetBSD__) +#include "lldb/Host/netbsd/HostInfoNetBSD.h" +#define HOST_INFO_TYPE HostInfoNetBSD #elif defined(__APPLE__) #include "lldb/Host/macosx/HostInfoMacOSX.h" #define HOST_INFO_TYPE HostInfoMacOSX Index: lldb/trunk/include/lldb/Host/HostNativeThread.h =================================================================== --- lldb/trunk/include/lldb/Host/HostNativeThread.h +++ lldb/trunk/include/lldb/Host/HostNativeThread.h @@ -18,6 +18,8 @@ #include "lldb/Host/linux/HostThreadLinux.h" #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) #include "lldb/Host/freebsd/HostThreadFreeBSD.h" +#elif defined(__NetBSD__) +#include "lldb/Host/netbsd/HostThreadNetBSD.h" #elif defined(__APPLE__) #include "lldb/Host/macosx/HostThreadMacOSX.h" #endif Index: lldb/trunk/include/lldb/Host/HostNativeThreadForward.h =================================================================== --- lldb/trunk/include/lldb/Host/HostNativeThreadForward.h +++ lldb/trunk/include/lldb/Host/HostNativeThreadForward.h @@ -21,6 +21,9 @@ #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) class HostThreadFreeBSD; typedef HostThreadFreeBSD HostNativeThread; +#elif defined(__NetBSD__) +class HostThreadNetBSD; +typedef HostThreadNetBSD HostNativeThread; #elif defined(__APPLE__) class HostThreadMacOSX; typedef HostThreadMacOSX HostNativeThread; Index: lldb/trunk/include/lldb/Host/netbsd/Config.h =================================================================== --- lldb/trunk/include/lldb/Host/netbsd/Config.h +++ lldb/trunk/include/lldb/Host/netbsd/Config.h @@ -0,0 +1,28 @@ +//===-- Config.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//---------------------------------------------------------------------- +// LLDB currently doesn't have a dynamic configuration mechanism, so we +// are going to hardcode things for now. Eventually these files will +// be auto generated by some configuration script that can detect +// platform functionality availability. +//---------------------------------------------------------------------- + +#ifndef liblldb_Platform_Config_h_ +#define liblldb_Platform_Config_h_ + +#define LLDB_CONFIG_TERMIOS_SUPPORTED 1 + +#define LLDB_CONFIG_TILDE_RESOLVES_TO_USER 1 + +//#define LLDB_CONFIG_DLOPEN_RTLD_FIRST_SUPPORTED 1 + +//#define LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED 1 + +#endif // #ifndef liblldb_Platform_Config_h_ Index: lldb/trunk/include/lldb/Host/netbsd/HostInfoNetBSD.h =================================================================== --- lldb/trunk/include/lldb/Host/netbsd/HostInfoNetBSD.h +++ lldb/trunk/include/lldb/Host/netbsd/HostInfoNetBSD.h @@ -0,0 +1,30 @@ +//===-- HostInfoNetBSD.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_netbsd_HostInfoNetBSD_h_ +#define lldb_Host_netbsd_HostInfoNetBSD_h_ + +#include "lldb/Host/FileSpec.h" +#include "lldb/Host/posix/HostInfoPosix.h" + +namespace lldb_private +{ + +class HostInfoNetBSD : public HostInfoPosix +{ + public: + static uint32_t GetMaxThreadNameLength(); + static bool GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update); + static bool GetOSBuildString(std::string &s); + static bool GetOSKernelDescription(std::string &s); + static FileSpec GetProgramFileSpec(); +}; +} + +#endif Index: lldb/trunk/include/lldb/Host/netbsd/HostThreadNetBSD.h =================================================================== --- lldb/trunk/include/lldb/Host/netbsd/HostThreadNetBSD.h +++ lldb/trunk/include/lldb/Host/netbsd/HostThreadNetBSD.h @@ -0,0 +1,32 @@ +//===-- HostThreadNetBSD.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_netbsd_HostThreadNetBSD_h_ +#define lldb_Host_netbsd_HostThreadNetBSD_h_ + +#include "lldb/Host/posix/HostThreadPosix.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/SmallString.h" + +namespace lldb_private +{ + +class HostThreadNetBSD : public HostThreadPosix +{ + public: + HostThreadNetBSD(); + HostThreadNetBSD(lldb::thread_t thread); + + static void SetName(lldb::thread_t tid, llvm::StringRef &name); + static void GetName(lldb::thread_t tid, llvm::SmallVectorImpl &name); +}; +} + +#endif Index: lldb/trunk/source/Host/netbsd/Host.cpp =================================================================== --- lldb/trunk/source/Host/netbsd/Host.cpp +++ lldb/trunk/source/Host/netbsd/Host.cpp @@ -0,0 +1,287 @@ +//===-- source/Host/netbsd/Host.cpp ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// C Includes +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Core/Error.h" +#include "lldb/Host/Endian.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/StreamFile.h" +#include "lldb/Core/StreamString.h" +#include "lldb/Core/Log.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Platform.h" + +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Core/DataExtractor.h" +#include "lldb/Utility/CleanUp.h" +#include "lldb/Utility/NameMatches.h" + +#include "llvm/Support/Host.h" + +extern "C" { + extern char **environ; +} + +using namespace lldb; +using namespace lldb_private; + +size_t +Host::GetEnvironment (StringList &env) +{ + char *v; + char **var = environ; + for (; var != NULL && *var != NULL; ++var) + { + v = ::strchr(*var, (int)'-'); + if (v == NULL) + continue; + env.AppendString(v); + } + return env.GetSize(); +} + +static bool +GetNetBSDProcessArgs (const ProcessInstanceInfoMatch *match_info_ptr, + ProcessInstanceInfo &process_info) +{ + if (!process_info.ProcessIDIsValid()) + return false; + + int pid = process_info.GetProcessID(); + + int mib[4] = { CTL_KERN, KERN_PROC_ARGS, pid, KERN_PROC_ARGV }; + + char arg_data[8192]; + size_t arg_data_size = sizeof(arg_data); + if (::sysctl (mib, 4, arg_data, &arg_data_size , NULL, 0) != 0) + return false; + + DataExtractor data (arg_data, arg_data_size, lldb::endian::InlHostByteOrder(), sizeof(void *)); + lldb::offset_t offset = 0; + const char *cstr; + + cstr = data.GetCStr (&offset); + if (!cstr) + return false; + + process_info.GetExecutableFile().SetFile(cstr, false); + + if (!(match_info_ptr == NULL || + NameMatches (process_info.GetExecutableFile().GetFilename().GetCString(), + match_info_ptr->GetNameMatchType(), + match_info_ptr->GetProcessInfo().GetName()))) + return false; + + Args &proc_args = process_info.GetArguments(); + while (1) + { + const uint8_t *p = data.PeekData(offset, 1); + while ((p != NULL) && (*p == '\0') && offset < arg_data_size) + { + ++offset; + p = data.PeekData(offset, 1); + } + if (p == NULL || offset >= arg_data_size) + break; + + cstr = data.GetCStr(&offset); + if (!cstr) + break; + + proc_args.AppendArgument(cstr); + } + + return true; +} + +static bool +GetNetBSDProcessCPUType (ProcessInstanceInfo &process_info) +{ + if (process_info.ProcessIDIsValid()) + { + process_info.GetArchitecture() = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + return true; + } + process_info.GetArchitecture().Clear(); + return false; +} + +static bool +GetNetBSDProcessUserAndGroup(ProcessInstanceInfo &process_info) +{ + ::kvm_t *kdp; + char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */ + + struct ::kinfo_proc2 *proc_kinfo; + const int pid = process_info.GetProcessID(); + int nproc; + + if (!process_info.ProcessIDIsValid()) + goto error; + + if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) + goto error; + + if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_PID, pid, + sizeof(struct ::kinfo_proc2), + &nproc)) == NULL) { + ::kvm_close(kdp); + goto error; + } + + if (nproc < 1) { + ::kvm_close(kdp); /* XXX: we don't check for error here */ + goto error; + } + + process_info.SetParentProcessID (proc_kinfo->p_ppid); + process_info.SetUserID (proc_kinfo->p_ruid); + process_info.SetGroupID (proc_kinfo->p_rgid); + process_info.SetEffectiveUserID (proc_kinfo->p_uid); + process_info.SetEffectiveGroupID (proc_kinfo->p_gid); + + ::kvm_close(kdp); /* XXX: we don't check for error here */ + + return true; + +error: + process_info.SetParentProcessID (LLDB_INVALID_PROCESS_ID); + process_info.SetUserID (UINT32_MAX); + process_info.SetGroupID (UINT32_MAX); + process_info.SetEffectiveUserID (UINT32_MAX); + process_info.SetEffectiveGroupID (UINT32_MAX); + return false; +} + +uint32_t +Host::FindProcesses (const ProcessInstanceInfoMatch &match_info, ProcessInstanceInfoList &process_infos) +{ + const ::pid_t our_pid = ::getpid(); + const ::uid_t our_uid = ::getuid(); + + const bool all_users = match_info.GetMatchAllUsers() || + // Special case, if lldb is being run as root we can attach to anything + (our_uid == 0); + + kvm_t *kdp; + char errbuf[_POSIX2_LINE_MAX]; /* XXX: error string unused */ + if ((kdp = ::kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, errbuf)) == NULL) + return 0; + + struct ::kinfo_proc2 *proc_kinfo; + int nproc; + if ((proc_kinfo = ::kvm_getproc2(kdp, KERN_PROC_ALL, 0, + sizeof(struct ::kinfo_proc2), + &nproc)) == NULL) { + ::kvm_close(kdp); + return 0; + } + + for (int i = 0; i < nproc; i++) { + if (proc_kinfo[i].p_pid < 1) + continue; /* not valid */ + /* Make sure the user is acceptable */ + if (!all_users && proc_kinfo[i].p_ruid != our_uid) + continue; + + if (proc_kinfo[i].p_pid == our_pid || // Skip this process + proc_kinfo[i].p_pid == 0 || // Skip kernel (kernel pid is 0) + proc_kinfo[i].p_stat == LSZOMB || // Zombies are bad + proc_kinfo[i].p_flag & P_TRACED || // Being debugged? + proc_kinfo[i].p_flag & P_WEXIT) // Working on exiting + continue; + + + // Every thread is a process in NetBSD, but all the threads of a single + // process have the same pid. Do not store the process info in the + // result list if a process with given identifier is already registered + // there. + if (proc_kinfo[i].p_nlwps > 1) { + bool already_registered = false; + for (size_t pi = 0; pi < process_infos.GetSize(); pi++) { + if (process_infos.GetProcessIDAtIndex(pi) == + proc_kinfo[i].p_pid) { + already_registered = true; + break; + } + } + + if (already_registered) + continue; + } + ProcessInstanceInfo process_info; + process_info.SetProcessID (proc_kinfo[i].p_pid); + process_info.SetParentProcessID (proc_kinfo[i].p_ppid); + process_info.SetUserID (proc_kinfo[i].p_ruid); + process_info.SetGroupID (proc_kinfo[i].p_rgid); + process_info.SetEffectiveUserID (proc_kinfo[i].p_uid); + process_info.SetEffectiveGroupID (proc_kinfo[i].p_gid); + // Make sure our info matches before we go fetch the name and cpu type + if (match_info.Matches (process_info) && + GetNetBSDProcessArgs (&match_info, process_info)) + { + GetNetBSDProcessCPUType (process_info); + if (match_info.Matches (process_info)) + process_infos.Append (process_info); + } + } + + kvm_close(kdp); /* XXX: we don't check for error here */ + + return process_infos.GetSize(); +} + +bool +Host::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ + process_info.SetProcessID(pid); + + if (GetNetBSDProcessArgs(NULL, process_info)) + { + GetNetBSDProcessCPUType(process_info); + GetNetBSDProcessUserAndGroup(process_info); + return true; + } + + process_info.Clear(); + return false; +} + +lldb::DataBufferSP +Host::GetAuxvData(lldb_private::Process *process) +{ + return lldb::DataBufferSP(); +} + +Error +Host::ShellExpandArguments (ProcessLaunchInfo &launch_info) +{ + return Error("unimplemented"); +} Index: lldb/trunk/source/Host/netbsd/HostInfoNetBSD.cpp =================================================================== --- lldb/trunk/source/Host/netbsd/HostInfoNetBSD.cpp +++ lldb/trunk/source/Host/netbsd/HostInfoNetBSD.cpp @@ -0,0 +1,112 @@ +//===-- HostInfoNetBSD.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/netbsd/HostInfoNetBSD.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace lldb_private; + +uint32_t +HostInfoNetBSD::GetMaxThreadNameLength() +{ + return PTHREAD_MAX_NAMELEN_NP; +} + +bool +HostInfoNetBSD::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) +{ + struct utsname un; + + ::memset(&un, 0, sizeof(un)); + if (::uname(&un) < 0) + return false; + + /* Accept versions like 7.99.21 and 6.1_STABLE */ + int status = ::sscanf(un.release, "%" PRIu32 ".%" PRIu32 ".%" PRIu32, &major, &minor, &update); + switch(status) { + case 0: + return false; + case 1: + minor = 0; + /* FALLTHROUGH */ + case 2: + update = 0; + /* FALLTHROUGH */ + case 3: + default: + return true; + } +} + +bool +HostInfoNetBSD::GetOSBuildString(std::string &s) +{ + int mib[2] = {CTL_KERN, KERN_OSREV}; + char osrev_str[12]; + int osrev = 0; + size_t osrev_len = sizeof(osrev); + + if (::sysctl(mib, 2, &osrev, &osrev_len, NULL, 0) == 0) + { + ::snprintf(osrev_str, sizeof(osrev_str), "%-10.10d", osrev); + s.assign(osrev_str); + return true; + } + + s.clear(); + return false; +} + +bool +HostInfoNetBSD::GetOSKernelDescription(std::string &s) +{ + struct utsname un; + + ::memset(&un, 0, sizeof(un)); + s.clear(); + + if (::uname(&un) < 0) + return false; + + s.assign(un.version); + + return true; +} + +FileSpec +HostInfoNetBSD::GetProgramFileSpec() +{ + static FileSpec g_program_filespec; + + if (!g_program_filespec) + { + ssize_t len; + static char buf[PATH_MAX]; + char name[PATH_MAX]; + + ::snprintf(name, PATH_MAX, "/proc/%d/exe", ::getpid()); + len = ::readlink(name, buf, PATH_MAX - 1); + if (len != -1) + { + buf[len] = '\0'; + g_program_filespec.SetFile(buf, false); + } + } + return g_program_filespec; +} Index: lldb/trunk/source/Host/netbsd/HostThreadNetBSD.cpp =================================================================== --- lldb/trunk/source/Host/netbsd/HostThreadNetBSD.cpp +++ lldb/trunk/source/Host/netbsd/HostThreadNetBSD.cpp @@ -0,0 +1,50 @@ +//===-- HostThreadNetBSD.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// lldb Includes +#include "lldb/Host/netbsd/HostThreadNetBSD.h" +#include "lldb/Host/Host.h" + +// C includes +#include +#include +#include +#include +#include +#include + +// C++ includes +#include + +using namespace lldb_private; + +HostThreadNetBSD::HostThreadNetBSD() +{ +} + +HostThreadNetBSD::HostThreadNetBSD(lldb::thread_t thread) + : HostThreadPosix(thread) +{ +} + +void +HostThreadNetBSD::SetName(lldb::thread_t thread, llvm::StringRef &name) +{ + ::pthread_setname_np(thread, "%s", const_cast(name.data())); +} + +void +HostThreadNetBSD::GetName(lldb::thread_t thread, llvm::SmallVectorImpl &name) +{ + char buf[PTHREAD_MAX_NAMELEN_NP]; + ::pthread_getname_np(thread, buf, PTHREAD_MAX_NAMELEN_NP); + + name.clear(); + name.append(buf, buf + strlen(buf)); +} Index: lldb/trunk/source/Host/netbsd/ThisThread.cpp =================================================================== --- lldb/trunk/source/Host/netbsd/ThisThread.cpp +++ lldb/trunk/source/Host/netbsd/ThisThread.cpp @@ -0,0 +1,30 @@ +//===-- ThisThread.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/HostNativeThread.h" +#include "lldb/Host/ThisThread.h" + +#include "llvm/ADT/SmallVector.h" + +#include +#include + +using namespace lldb_private; + +void +ThisThread::SetName(llvm::StringRef name) +{ + HostNativeThread::SetName(::pthread_self(), name); +} + +void +ThisThread::GetName(llvm::SmallVectorImpl &name) +{ + HostNativeThread::GetName(::pthread_self(), name); +} Index: lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.h =================================================================== --- lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.h +++ lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.h @@ -0,0 +1,182 @@ +//===-- PlatformNetBSD.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_PlatformNetBSD_h_ +#define liblldb_PlatformNetBSD_h_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Target/Platform.h" + +namespace lldb_private { +namespace platform_netbsd { + + class PlatformNetBSD : public Platform + { + public: + + //------------------------------------------------------------ + // Class functions + //------------------------------------------------------------ + static lldb::PlatformSP + CreateInstance(bool force, const ArchSpec *arch); + + static void + Initialize (); + + static void + Terminate (); + + static ConstString + GetPluginNameStatic (bool is_host); + + static const char * + GetDescriptionStatic (bool is_host); + + //------------------------------------------------------------ + // Class Methods + //------------------------------------------------------------ + PlatformNetBSD (bool is_host); + + virtual + ~PlatformNetBSD() override = default; + + //------------------------------------------------------------ + // lldb_private::PluginInterface functions + //------------------------------------------------------------ + ConstString + GetPluginName() override + { + return GetPluginNameStatic (IsHost()); + } + + uint32_t + GetPluginVersion() override + { + return 1; + } + + const char * + GetDescription () override + { + return GetDescriptionStatic(IsHost()); + } + + //------------------------------------------------------------ + // lldb_private::Platform functions + //------------------------------------------------------------ + bool + GetModuleSpec(const FileSpec& module_file_spec, + const ArchSpec& arch, + ModuleSpec &module_spec) override; + + Error + RunShellCommand(const char *command, + const FileSpec &working_dir, + int *status_ptr, + int *signo_ptr, + std::string *command_output, + uint32_t timeout_sec) override; + + Error + ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr) override; + + size_t + GetSoftwareBreakpointTrapOpcode(Target &target, + BreakpointSite *bp_site) override; + + bool + GetRemoteOSVersion () override; + + bool + GetRemoteOSBuildString (std::string &s) override; + + bool + GetRemoteOSKernelDescription (std::string &s) override; + + // Remote Platform subclasses need to override this function + ArchSpec + GetRemoteSystemArchitecture() override; + + bool + IsConnected () const override; + + Error + ConnectRemote(Args& args) override; + + Error + DisconnectRemote() override; + + const char * + GetHostname () override; + + const char * + GetUserName (uint32_t uid) override; + + const char * + GetGroupName (uint32_t gid) override; + + bool + GetProcessInfo(lldb::pid_t pid, + ProcessInstanceInfo &proc_info) override; + + uint32_t + FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) override; + + Error + LaunchProcess(ProcessLaunchInfo &launch_info) override; + + lldb::ProcessSP + Attach(ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, + Error &error) override; + + // NetBSD processes can not be launched by spawning and attaching. + bool + CanDebugProcess () override { return false; } + + // Only on PlatformMacOSX: + Error + GetFileWithUUID(const FileSpec &platform_file, + const UUID* uuid, FileSpec &local_file) override; + + Error + GetSharedModule(const ModuleSpec &module_spec, + Process* process, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + lldb::ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) override; + + bool + GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override; + + void + GetStatus(Stream &strm) override; + + void + CalculateTrapHandlerSymbolNames () override; + + protected: + lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote netbsd OS + + private: + DISALLOW_COPY_AND_ASSIGN (PlatformNetBSD); + }; + +} // namespace platform_netbsd +} // namespace lldb_private + +#endif // liblldb_PlatformNetBSD_h_ Index: lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp =================================================================== --- lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp +++ lldb/trunk/source/Plugins/Platform/NetBSD/PlatformNetBSD.cpp @@ -0,0 +1,696 @@ +//===-- PlatformNetBSD.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "PlatformNetBSD.h" +#include "lldb/Host/Config.h" + +// C Includes +#include +#ifndef LLDB_DISABLE_POSIX +#include +#endif + +// C++ Includes +// Other libraries and framework includes +// Project includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointSite.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Debugger.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Host/Host.h" +#include "lldb/Host/HostInfo.h" +#include "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::platform_netbsd; + +PlatformSP +PlatformNetBSD::CreateInstance(bool force, const ArchSpec *arch) +{ + // The only time we create an instance is when we are creating a remote + // netbsd platform + const bool is_host = false; + + bool create = force; + if (create == false && arch && arch->IsValid()) + { + const llvm::Triple &triple = arch->GetTriple(); + switch (triple.getOS()) + { + case llvm::Triple::NetBSD: + create = true; + break; + + default: + break; + } + } + if (create) + return PlatformSP(new PlatformNetBSD (is_host)); + return PlatformSP(); + +} + +ConstString +PlatformNetBSD::GetPluginNameStatic(bool is_host) +{ + if (is_host) + { + static ConstString g_host_name(Platform::GetHostPlatformName ()); + return g_host_name; + } + else + { + static ConstString g_remote_name("remote-netbsd"); + return g_remote_name; + } +} + +const char * +PlatformNetBSD::GetDescriptionStatic (bool is_host) +{ + if (is_host) + return "Local NetBSD user platform plug-in."; + else + return "Remote NetBSD user platform plug-in."; +} + +static uint32_t g_initialize_count = 0; + +void +PlatformNetBSD::Initialize () +{ + Platform::Initialize (); + + if (g_initialize_count++ == 0) + { + // Force a host flag to true for the default platform object. + PlatformSP default_platform_sp (new PlatformNetBSD(true)); + default_platform_sp->SetSystemArchitecture(HostInfo::GetArchitecture()); + Platform::SetHostPlatform (default_platform_sp); + PluginManager::RegisterPlugin(PlatformNetBSD::GetPluginNameStatic(false), + PlatformNetBSD::GetDescriptionStatic(false), + PlatformNetBSD::CreateInstance); + } +} + +void +PlatformNetBSD::Terminate () +{ + if (g_initialize_count > 0 && --g_initialize_count == 0) + PluginManager::UnregisterPlugin (PlatformNetBSD::CreateInstance); + + Platform::Terminate (); +} + +bool +PlatformNetBSD::GetModuleSpec (const FileSpec& module_file_spec, + const ArchSpec& arch, + ModuleSpec &module_spec) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetModuleSpec (module_file_spec, arch, module_spec); + + return Platform::GetModuleSpec (module_file_spec, arch, module_spec); +} + +Error +PlatformNetBSD::RunShellCommand(const char *command, + const FileSpec &working_dir, + int *status_ptr, + int *signo_ptr, + std::string *command_output, + uint32_t timeout_sec) +{ + if (IsHost()) + return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + { + if (m_remote_platform_sp) + return m_remote_platform_sp->RunShellCommand(command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); + else + return Error("unable to run a remote command without a platform"); + } +} + +Error +PlatformNetBSD::ResolveExecutable (const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) +{ + Error error; + // Nothing special to do here, just use the actual file and architecture + + char exe_path[PATH_MAX]; + ModuleSpec resolved_module_spec(module_spec); + + if (IsHost()) + { + // If we have "ls" as the module_spec's file, resolve the executable location based on + // the current path variables + if (!resolved_module_spec.GetFileSpec().Exists()) + { + module_spec.GetFileSpec().GetPath(exe_path, sizeof(exe_path)); + resolved_module_spec.GetFileSpec().SetFile(exe_path, true); + } + + if (!resolved_module_spec.GetFileSpec().Exists()) + resolved_module_spec.GetFileSpec().ResolveExecutableLocation (); + + if (resolved_module_spec.GetFileSpec().Exists()) + error.Clear(); + else + { + error.SetErrorStringWithFormat("unable to find executable for '%s'", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + else + { + if (m_remote_platform_sp) + { + error = GetCachedExecutable (resolved_module_spec, exe_module_sp, module_search_paths_ptr, *m_remote_platform_sp); + } + else + { + // We may connect to a process and use the provided executable (Don't use local $PATH). + + // Resolve any executable within a bundle on MacOSX + Host::ResolveExecutableInBundle (resolved_module_spec.GetFileSpec()); + + if (resolved_module_spec.GetFileSpec().Exists()) + { + error.Clear(); + } + else + { + error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + } + + if (error.Success()) + { + if (resolved_module_spec.GetArchitecture().IsValid()) + { + error = ModuleList::GetSharedModule (resolved_module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + + if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL) + { + exe_module_sp.reset(); + error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s", + resolved_module_spec.GetFileSpec().GetPath().c_str(), + resolved_module_spec.GetArchitecture().GetArchitectureName()); + } + } + else + { + // No valid architecture was specified, ask the platform for + // the architectures that we should be using (in the correct order) + // and see if we can find a match that way + StreamString arch_names; + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, resolved_module_spec.GetArchitecture()); ++idx) + { + error = ModuleList::GetSharedModule (resolved_module_spec, + exe_module_sp, + module_search_paths_ptr, + NULL, + NULL); + // Did we find an executable using one of the + if (error.Success()) + { + if (exe_module_sp && exe_module_sp->GetObjectFile()) + break; + else + error.SetErrorToGenericError(); + } + + if (idx > 0) + arch_names.PutCString (", "); + arch_names.PutCString (resolved_module_spec.GetArchitecture().GetArchitectureName()); + } + + if (error.Fail() || !exe_module_sp) + { + if (resolved_module_spec.GetFileSpec().Readable()) + { + error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s", + resolved_module_spec.GetFileSpec().GetPath().c_str(), + GetPluginName().GetCString(), + arch_names.GetString().c_str()); + } + else + { + error.SetErrorStringWithFormat("'%s' is not readable", resolved_module_spec.GetFileSpec().GetPath().c_str()); + } + } + } + } + + return error; +} + +// From PlatformMacOSX only +Error +PlatformNetBSD::GetFileWithUUID (const FileSpec &platform_file, + const UUID *uuid_ptr, + FileSpec &local_file) +{ + if (IsRemote()) + { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetFileWithUUID (platform_file, uuid_ptr, local_file); + } + + // Default to the local case + local_file = platform_file; + return Error(); +} + + +//------------------------------------------------------------------ +/// Default Constructor +//------------------------------------------------------------------ +PlatformNetBSD::PlatformNetBSD (bool is_host) : + Platform(is_host), + m_remote_platform_sp() +{ +} + +//------------------------------------------------------------------ +/// Destructor. +/// +/// The destructor is virtual since this class is designed to be +/// inherited from by the plug-in instance. +//------------------------------------------------------------------ +PlatformNetBSD::~PlatformNetBSD() +{ +} + +//TODO:VK: inherit PlatformPOSIX + + +bool +PlatformNetBSD::GetRemoteOSVersion () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetOSVersion (m_major_os_version, + m_minor_os_version, + m_update_os_version); + return false; +} + +bool +PlatformNetBSD::GetRemoteOSBuildString (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSBuildString (s); + s.clear(); + return false; +} + +bool +PlatformNetBSD::GetRemoteOSKernelDescription (std::string &s) +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteOSKernelDescription (s); + s.clear(); + return false; +} + +// Remote Platform subclasses need to override this function +ArchSpec +PlatformNetBSD::GetRemoteSystemArchitecture () +{ + if (m_remote_platform_sp) + return m_remote_platform_sp->GetRemoteSystemArchitecture (); + return ArchSpec(); +} + + +const char * +PlatformNetBSD::GetHostname () +{ + if (IsHost()) + return Platform::GetHostname(); + + if (m_remote_platform_sp) + return m_remote_platform_sp->GetHostname (); + return NULL; +} + +bool +PlatformNetBSD::IsConnected () const +{ + if (IsHost()) + return true; + else if (m_remote_platform_sp) + return m_remote_platform_sp->IsConnected(); + return false; +} + +Error +PlatformNetBSD::ConnectRemote (Args& args) +{ + Error error; + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (!m_remote_platform_sp) + m_remote_platform_sp = Platform::Create (ConstString("remote-gdb-server"), error); + + if (m_remote_platform_sp) + { + if (error.Success()) + { + if (m_remote_platform_sp) + { + error = m_remote_platform_sp->ConnectRemote (args); + } + else + { + error.SetErrorString ("\"platform connect\" takes a single argument: "); + } + } + } + else + error.SetErrorString ("failed to create a 'remote-gdb-server' platform"); + + if (error.Fail()) + m_remote_platform_sp.reset(); + } + + return error; +} + +Error +PlatformNetBSD::DisconnectRemote () +{ + Error error; + + if (IsHost()) + { + error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString()); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->DisconnectRemote (); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +bool +PlatformNetBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) +{ + bool success = false; + if (IsHost()) + { + success = Platform::GetProcessInfo (pid, process_info); + } + else if (m_remote_platform_sp) + { + success = m_remote_platform_sp->GetProcessInfo (pid, process_info); + } + return success; +} + +uint32_t +PlatformNetBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) +{ + uint32_t match_count = 0; + if (IsHost()) + { + // Let the base class figure out the host details + match_count = Platform::FindProcesses (match_info, process_infos); + } + else + { + // If we are remote, we can only return results if we are connected + if (m_remote_platform_sp) + match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos); + } + return match_count; +} + +const char * +PlatformNetBSD::GetUserName (uint32_t uid) +{ + // Check the cache in Platform in case we have already looked this uid up + const char *user_name = Platform::GetUserName(uid); + if (user_name) + return user_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetUserName(uid); + return NULL; +} + +const char * +PlatformNetBSD::GetGroupName (uint32_t gid) +{ + const char *group_name = Platform::GetGroupName(gid); + if (group_name) + return group_name; + + if (IsRemote() && m_remote_platform_sp) + return m_remote_platform_sp->GetGroupName(gid); + return NULL; +} + + +Error +PlatformNetBSD::GetSharedModule (const ModuleSpec &module_spec, + Process* process, + ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) +{ + Error error; + module_sp.reset(); + + if (IsRemote()) + { + // If we have a remote platform always, let it try and locate + // the shared module first. + if (m_remote_platform_sp) + { + error = m_remote_platform_sp->GetSharedModule (module_spec, + process, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); + } + } + + if (!module_sp) + { + // Fall back to the local platform and find the file locally + error = Platform::GetSharedModule (module_spec, + process, + module_sp, + module_search_paths_ptr, + old_module_sp_ptr, + did_create_ptr); + } + if (module_sp) + module_sp->SetPlatformFileSpec(module_spec.GetFileSpec()); + return error; +} + + +bool +PlatformNetBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch) +{ + if (IsHost()) + { + ArchSpec hostArch = HostInfo::GetArchitecture(HostInfo::eArchKindDefault); + if (hostArch.GetTriple().isOSNetBSD()) + { + if (idx == 0) + { + arch = hostArch; + return arch.IsValid(); + } + else if (idx == 1) + { + // If the default host architecture is 64-bit, look for a 32-bit variant + if (hostArch.IsValid() && hostArch.GetTriple().isArch64Bit()) + { + arch = HostInfo::GetArchitecture(HostInfo::eArchKind32); + return arch.IsValid(); + } + } + } + } + else + { + if (m_remote_platform_sp) + return m_remote_platform_sp->GetSupportedArchitectureAtIndex(idx, arch); + + llvm::Triple triple; + // Set the OS to NetBSD + triple.setOS(llvm::Triple::NetBSD); + // Set the architecture + switch (idx) + { + case 0: triple.setArchName("x86_64"); break; + case 1: triple.setArchName("i386"); break; + default: return false; + } + // Leave the vendor as "llvm::Triple:UnknownVendor" and don't specify the vendor by + // calling triple.SetVendorName("unknown") so that it is a "unspecified unknown". + // This means when someone calls triple.GetVendorName() it will return an empty string + // which indicates that the vendor can be set when two architectures are merged + + // Now set the triple into "arch" and return true + arch.SetTriple(triple); + return true; + } + return false; +} + +void +PlatformNetBSD::GetStatus (Stream &strm) +{ +#ifndef LLDB_DISABLE_POSIX + struct ::utsname un; + + strm << " Host: "; + + ::memset(&un, 0, sizeof(utsname)); + if (::uname(&un) == -1) { + strm << "NetBSD" << '\n'; + } else { + strm << un.sysname << ' ' << un.release; + if (un.nodename[0] != '\0') + strm << " (" << un.nodename << ')'; + strm << '\n'; + + // Dump a common information about the platform status. + strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n'; + } +#endif + + Platform::GetStatus(strm); +} + +size_t +PlatformNetBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site) +{ + ArchSpec arch = target.GetArchitecture(); + const uint8_t *trap_opcode = NULL; + size_t trap_opcode_size = 0; + + switch (arch.GetMachine()) + { + default: + assert(false && "Unhandled architecture in PlatformNetBSD::GetSoftwareBreakpointTrapOpcode()"); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + { + static const uint8_t g_i386_opcode[] = { 0xCC }; + trap_opcode = g_i386_opcode; + trap_opcode_size = sizeof(g_i386_opcode); + } + break; + } + + if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) + return trap_opcode_size; + return 0; +} + + +void +PlatformNetBSD::CalculateTrapHandlerSymbolNames () +{ + m_trap_handlers.push_back (ConstString ("_sigtramp")); +} + +Error +PlatformNetBSD::LaunchProcess (ProcessLaunchInfo &launch_info) +{ + Error error; + if (IsHost()) + { + error = Platform::LaunchProcess (launch_info); + } + else + { + if (m_remote_platform_sp) + error = m_remote_platform_sp->LaunchProcess (launch_info); + else + error.SetErrorString ("the platform is not currently connected"); + } + return error; +} + +lldb::ProcessSP +PlatformNetBSD::Attach(ProcessAttachInfo &attach_info, + Debugger &debugger, + Target *target, + Error &error) +{ + lldb::ProcessSP process_sp; + if (IsHost()) + { + if (target == NULL) + { + TargetSP new_target_sp; + ArchSpec emptyArchSpec; + + error = debugger.GetTargetList().CreateTarget (debugger, + NULL, + emptyArchSpec, + false, + m_remote_platform_sp, + new_target_sp); + target = new_target_sp.get(); + } + else + error.Clear(); + + if (target && error.Success()) + { + debugger.GetTargetList().SetSelectedTarget(target); + // The netbsd always currently uses the GDB remote debugger plug-in + // so even when debugging locally we are debugging remotely! + // Just like the darwin plugin. + process_sp = target->CreateProcess (attach_info.GetListenerForProcess(debugger), "gdb-remote", NULL); + + if (process_sp) + error = process_sp->Attach (attach_info); + } + } + else + { + if (m_remote_platform_sp) + process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, error); + else + error.SetErrorString ("the platform is not currently connected"); + } + return process_sp; +}