Index: cmake/LLDBDependencies.cmake =================================================================== --- cmake/LLDBDependencies.cmake +++ cmake/LLDBDependencies.cmake @@ -90,8 +90,10 @@ if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" ) list(APPEND LLDB_USED_LIBS lldbPluginProcessFreeBSD + lldbPluginProcessFreeBSDKernel lldbPluginProcessPOSIX lldbPluginProcessElfCore + lldbPluginDynamicLoaderFreeBSDKernel lldbPluginJITLoaderGDB ) endif () @@ -141,7 +143,7 @@ endif() # On FreeBSD backtrace() is provided by libexecinfo, not libc. if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") - list(APPEND LLDB_SYSTEM_LIBS execinfo) + list(APPEND LLDB_SYSTEM_LIBS execinfo kvm) endif() if (NOT LLDB_DISABLE_PYTHON AND NOT LLVM_BUILD_STATIC) Index: source/API/SystemInitializerFull.cpp =================================================================== --- source/API/SystemInitializerFull.cpp +++ source/API/SystemInitializerFull.cpp @@ -50,7 +50,9 @@ #endif #if defined(__FreeBSD__) +#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h" #include "Plugins/Process/FreeBSD/ProcessFreeBSD.h" +#include "Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.h" #endif #if defined(__linux__) @@ -272,7 +274,9 @@ ProcessWindows::Initialize(); #endif #if defined(__FreeBSD__) + DynamicLoaderFreeBSDKernel::Initialize(); ProcessFreeBSD::Initialize(); + ProcessFreeBSDKernel::Initialize(); #endif #if defined(__APPLE__) SymbolVendorMacOSX::Initialize(); @@ -379,7 +383,9 @@ #endif #if defined(__FreeBSD__) + DynamicLoaderFreeBSDKernel::Terminate(); ProcessFreeBSD::Terminate(); + ProcessFreeBSDKernel::Terminate(); #endif Debugger::SettingsTerminate(); Index: source/CMakeLists.txt =================================================================== --- source/CMakeLists.txt +++ source/CMakeLists.txt @@ -21,6 +21,7 @@ if ( CMAKE_SYSTEM_NAME MATCHES "FreeBSD" ) include_directories( Plugins/Process/FreeBSD + Plugins/Process/FreeBSD-Kernel Plugins/Process/POSIX ) endif () Index: source/Plugins/DynamicLoader/CMakeLists.txt =================================================================== --- source/Plugins/DynamicLoader/CMakeLists.txt +++ source/Plugins/DynamicLoader/CMakeLists.txt @@ -6,4 +6,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_subdirectory(Darwin-Kernel) endif() +if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") + add_subdirectory(FreeBSD-Kernel) +endif() Index: source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/DynamicLoader/FreeBSD-Kernel/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginDynamicLoaderFreeBSDKernel + DynamicLoaderFreeBSDKernel.cpp + ) Index: source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h =================================================================== --- /dev/null +++ source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h @@ -0,0 +1,114 @@ +//===-- DynamicLoaderFreeBSDKernel.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_DynamicLoaderFreeBSDKernel_H_ +#define liblldb_DynamicLoaderFreeBSDKernel_H_ + +// C Includes +// C++ Includes +// Other libraries and framework includes +#include "lldb/Breakpoint/StoppointCallbackContext.h" +#include "lldb/Target/DynamicLoader.h" +#include "Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.h" + +class DynamicLoaderFreeBSDKernel : public lldb_private::DynamicLoader +{ +public: + + static void + Initialize(); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + static lldb_private::DynamicLoader * + CreateInstance(lldb_private::Process *process, bool force); + + DynamicLoaderFreeBSDKernel(lldb_private::Process *process); + + virtual + ~DynamicLoaderFreeBSDKernel(); + + //------------------------------------------------------------------ + // DynamicLoader protocol + //------------------------------------------------------------------ + + virtual void + DidAttach(); + + virtual void + DidLaunch(); + + virtual lldb::ThreadPlanSP + GetStepThroughTrampolinePlan(lldb_private::Thread &thread, + bool stop_others); + + virtual lldb_private::Error + CanLoadImage(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + virtual void + GetPluginCommandHelp(const char *command, lldb_private::Stream *strm); + + virtual lldb_private::Error + ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm); + + virtual lldb_private::Log * + EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command); + + void + RefreshModules(); + + void + LoadAllCurrentModules(); + + size_t + ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); +protected: + lldb::addr_t m_kernel_load_addr, m_linker_files_addr, m_kernel_file_addr; + lldb::addr_t m_address_offset, m_filename_offset; + lldb::addr_t m_next_offset, m_pathname_offset; + std::vector m_module_paths; +private: + bool + IsKLDOK(std::string path); + + bool + CheckKLDPath(std::string path); + + bool + FindKLDPath(std::string filename, std::string& path); + + bool + FindKLDAddress(std::string kld_name, lldb::addr_t& kld_addr); + + void + InitLoadSpecs(); + + lldb::addr_t + LookUpSymbolAddressInModule(lldb::ModuleSP module, const char *name); + + DISALLOW_COPY_AND_ASSIGN(DynamicLoaderFreeBSDKernel); +}; + +#endif // liblldb_DynamicLoaderFreeBSDKernel_H_ Index: source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp =================================================================== --- /dev/null +++ source/Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.cpp @@ -0,0 +1,352 @@ +//===-- DynamicLoaderFreeBSDKernel.cpp --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "DynamicLoaderFreeBSDKernel.h" + +// C Includes +#include +#include +#include +#include +#include + +// C++ Includes + +// Other libraries and framework includes +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/Section.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlanRunToAddress.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + std::vector kld_suffixes = {".debug", ".symbols", ""}; + // http://svnweb.freebsd.org/base/head/sys/sys/linker.h +}; + +void +DynamicLoaderFreeBSDKernel::Initialize() +{ + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance); +} + +void +DynamicLoaderFreeBSDKernel::Terminate() +{ +} + +lldb_private::ConstString +DynamicLoaderFreeBSDKernel::GetPluginName() +{ + return GetPluginNameStatic(); +} + +lldb_private::ConstString +DynamicLoaderFreeBSDKernel::GetPluginNameStatic() +{ + static ConstString g_name("FreeBSDKernel-DYLD"); + return g_name; +} + +const char * +DynamicLoaderFreeBSDKernel::GetPluginDescriptionStatic() +{ + return "Dynamic loader plug-in that watches for shared library " + "loads/unloads in FreeBSD Kernel."; +} + +void +DynamicLoaderFreeBSDKernel::GetPluginCommandHelp(const char *command, Stream *strm) +{ +} + +uint32_t +DynamicLoaderFreeBSDKernel::GetPluginVersion() +{ + return 1; +} + +DynamicLoader * +DynamicLoaderFreeBSDKernel::CreateInstance(Process *process, bool force) +{ + bool create = force; + if (!create) + { + const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple(); + if (triple_ref.getOS() == llvm::Triple::FreeBSD) + create = true; + } + + if (create) + return new DynamicLoaderFreeBSDKernel(process); + return NULL; +} + +DynamicLoaderFreeBSDKernel::DynamicLoaderFreeBSDKernel(Process *process) + : DynamicLoader(process), + m_kernel_load_addr(LLDB_INVALID_ADDRESS) +{ + InitLoadSpecs(); +} + +DynamicLoaderFreeBSDKernel::~DynamicLoaderFreeBSDKernel() +{ +} + +void +DynamicLoaderFreeBSDKernel::DidAttach() +{ + LoadAllCurrentModules(); +} + +void +DynamicLoaderFreeBSDKernel::DidLaunch() +{ + ModuleSP executable = GetTargetExecutable(); + + if (executable.get()) + { + ModuleList module_list; + module_list.Append(executable); + m_process->GetTarget().ModulesDidLoad(module_list); + } +} + +Error +DynamicLoaderFreeBSDKernel::ExecutePluginCommand(Args &command, Stream *strm) +{ + return Error(); +} + +Log * +DynamicLoaderFreeBSDKernel::EnablePluginLogging(Stream *strm, Args &command) +{ + return NULL; +} + +Error +DynamicLoaderFreeBSDKernel::CanLoadImage() +{ + return Error(); +} + +ThreadPlanSP +DynamicLoaderFreeBSDKernel::GetStepThroughTrampolinePlan(Thread &thread, bool stop) +{ + ThreadPlanSP thread_plan_sp; + + return thread_plan_sp; +} + +void +DynamicLoaderFreeBSDKernel::LoadAllCurrentModules() +{ + ModuleList &module_list = m_process->GetTarget().GetImages(); + const ArchSpec &arch_spec = m_process->GetTarget().GetArchitecture(); + + char kld_filename[PATH_MAX]; + Error error; + + if (m_linker_files_addr == 0 || m_address_offset == 0 || + m_filename_offset == 0 || m_next_offset == 0) + return; + + for (addr_t kaddr = ReadPointer(m_linker_files_addr); + kaddr != 0; + kaddr = ReadPointer(kaddr + m_next_offset)) + { + if (kaddr == m_kernel_load_addr) + continue; + + ReadMemory(ReadPointer(kaddr + m_filename_offset), + kld_filename, PATH_MAX, error); + + std::string path; + if (FindKLDPath(kld_filename, path)) + { + addr_t kld_addr = ReadPointer(kaddr + m_address_offset); + FileSpec file_spec(path.c_str(), true); + ModuleSpec module_spec(file_spec, arch_spec); + module_spec.SetObjectOffset(kld_addr); + ModuleSP module_sp(new Module(module_spec)); + module_list.AppendIfNeeded(module_sp); + } + } + m_process->GetTarget().ModulesDidLoad(module_list); +} + +void +DynamicLoaderFreeBSDKernel::RefreshModules() +{ +} + +void +DynamicLoaderFreeBSDKernel::InitLoadSpecs() +{ + addr_t addr; + char buf[PATH_MAX]; + char *cp, *module_dir; + int word_bytes; + Error err; + + const ArchSpec &arch = m_process->GetTarget().GetArchitecture(); + if (arch.GetMachine() == llvm::Triple::mips64 || + arch.GetMachine() == llvm::Triple::x86_64) + word_bytes = 8; + else + word_bytes = 4; + + ModuleSP module = m_process->GetTarget().GetExecutableModule(); + + addr = LookUpSymbolAddressInModule(module, "linker_path"); + ReadMemory(addr, buf, PATH_MAX, err); + cp = buf; + + while ((module_dir = strsep(&cp, ";")) != NULL) + { + m_module_paths.push_back(module_dir); + } + + m_kernel_file_addr = LookUpSymbolAddressInModule(module, "linker_kernel_file"); + + m_kernel_load_addr = ReadPointer(m_kernel_file_addr); + + m_linker_files_addr = LookUpSymbolAddressInModule(module, "linker_files"); + + m_next_offset = word_bytes + sizeof(int) * 4; + m_filename_offset = m_next_offset + word_bytes * 2; + m_pathname_offset = m_filename_offset + word_bytes; + /// FIXME: padding issues remains, using 64 for amd64 + m_address_offset = 64; +} + +bool +DynamicLoaderFreeBSDKernel::CheckKLDPath(std::string path) +{ + for (std::vector::iterator suffix = kld_suffixes.begin(); + suffix != kld_suffixes.end(); + suffix++) + { + std::string kld_path = path + *suffix; + if (IsKLDOK(kld_path)) + return true; + suffix++; + } + return false; +} + +bool +DynamicLoaderFreeBSDKernel::IsKLDOK (std::string path) +{ + struct stat sb; + + if (stat(path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode)) + return true; + return false; +} + +bool +DynamicLoaderFreeBSDKernel::FindKLDPath (std::string filename, std::string& path) +{ + char *kernel_dir; + ModuleSP executable = GetTargetExecutable(); + if (executable) + { + kernel_dir = dirname(executable->GetSpecificationDescription().c_str()); + if (kernel_dir != NULL) + { + path = std::string(kernel_dir) + "/" + filename; + if (CheckKLDPath(path)) + return true; + } + } + for (std::vector::iterator it = m_module_paths.begin(); + it != m_module_paths.end(); + it++) + { + path = *it + "/" + filename; + if (CheckKLDPath(path)) + return true; + } + return false; +} + +bool +DynamicLoaderFreeBSDKernel::FindKLDAddress(std::string kld_name, addr_t& kld_addr) +{ + char kld_filename[PATH_MAX]; + char *filename; + Error error; + + if (m_linker_files_addr == 0 || m_address_offset == 0 || + m_filename_offset == 0 || m_next_offset == 0) + return false; + + filename = basename(kld_name.c_str()); + + for (addr_t kaddr = ReadPointer (m_linker_files_addr); kaddr != 0; + kaddr = ReadPointer (kaddr + m_next_offset)) + { + ReadMemory(ReadPointer(kaddr + m_filename_offset), kld_filename, PATH_MAX, error); + + if (strcmp(kld_filename, filename)) + continue; + + kld_addr = ReadPointer(kaddr + m_address_offset); + if (kld_addr == 0) + return false; + else + return true; + } + return false; +} + +lldb::addr_t +DynamicLoaderFreeBSDKernel::LookUpSymbolAddressInModule(lldb::ModuleSP module, const char *name) +{ + lldb_private::SymbolVendor *sym_vendor = module->GetSymbolVendor (); + if (sym_vendor) + { + lldb_private::Symtab *symtab = sym_vendor->GetSymtab(); + if (symtab) + { + std::vector match_indexes; + ConstString symbol_name (name); + uint32_t num_matches = 0; + + num_matches = symtab->AppendSymbolIndexesWithName(symbol_name, match_indexes); + + if (num_matches > 0) + { + + Symbol *symbol = symtab->SymbolAtIndex(match_indexes[0]); + return symbol->GetAddress().GetFileAddress(); + } + } + } + return LLDB_INVALID_ADDRESS; +} + +size_t +DynamicLoaderFreeBSDKernel::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) +{ + return m_process->ReadMemory(addr, buf, size, error); +} Index: source/Plugins/DynamicLoader/FreeBSD-Kernel/Makefile =================================================================== --- /dev/null +++ source/Plugins/DynamicLoader/FreeBSD-Kernel/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Disassembler/llvm/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginDynamicLoaderFreeBSDKernel +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: source/Plugins/Makefile =================================================================== --- source/Plugins/Makefile +++ source/Plugins/Makefile @@ -55,7 +55,7 @@ endif ifneq (,$(filter $(HOST_OS), FreeBSD GNU/kFreeBSD)) -PARALLEL_DIRS += Process/FreeBSD Process/POSIX +PARALLEL_DIRS += Process/FreeBSD Process/FreeBSD-Kernel Process/POSIX PARALLEL_DIRS += Process/elf-core PARALLEL_DIRS += JITLoader/GDB endif Index: source/Plugins/Process/CMakeLists.txt =================================================================== --- source/Plugins/Process/CMakeLists.txt +++ source/Plugins/Process/CMakeLists.txt @@ -3,6 +3,7 @@ add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD") add_subdirectory(FreeBSD) + add_subdirectory(FreeBSD-Kernel) add_subdirectory(POSIX) elseif (CMAKE_SYSTEM_NAME MATCHES "Windows") add_subdirectory(Windows) Index: source/Plugins/Process/FreeBSD-Kernel/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/CMakeLists.txt @@ -0,0 +1,11 @@ +set(LLVM_NO_RTTI 1) + +include_directories(.) +include_directories(../POSIX) +include_directories(../Utility) + +add_lldb_library(lldbPluginProcessFreeBSDKernel + ProcessFreeBSDKernel.cpp + RegisterContextFreeBSDKernel_x86_64.cpp + ThreadFreeBSDKernel.cpp + ) Index: source/Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.h =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.h @@ -0,0 +1,261 @@ +//===-- ProcessFreeBSDKernel.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_ProcessFreeBSDKernel_H_ +#define liblldb_ProcessFreeBSDKernel_H_ + +// C Includes +#include +#include +#include + +// C++ Includes + +// Other libraries and framework includes +#include "lldb/Core/ArchSpec.h" +#include "lldb/Core/ConstString.h" +#include "lldb/Core/Error.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ThreadSafeValue.h" +#include "lldb/Target/DynamicLoader.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/Thread.h" + +class ProcessMonitor; +class ThreadFreeBSDKernel; + +class ProcessFreeBSDKernel : public lldb_private::Process +{ +public: + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + static lldb::ProcessSP + CreateInstance(lldb_private::Target& target, + lldb_private::Listener &listener, + const lldb_private::FileSpec *crash_file_path); + + static void + Initialize(); + + static void + DebuggerInitialize(lldb_private::Debugger &debugger); + + static void + Terminate(); + + static lldb_private::ConstString + GetPluginNameStatic(); + + static const char * + GetPluginDescriptionStatic(); + + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + ProcessFreeBSDKernel(lldb_private::Target& target, + lldb_private::Listener &listener, + const lldb_private::FileSpec &crash_file_path); + + virtual + ~ProcessFreeBSDKernel(); + + virtual bool + CanDebug(lldb_private::Target &target, bool plugin_specified_by_name); + + virtual lldb_private::Error + DoLoadCore(); + + virtual lldb_private::DynamicLoader * + GetDynamicLoader(); + + virtual lldb_private::Error + WillLaunch(lldb_private::Module* module); + + virtual lldb_private::Error + DoLaunch(lldb_private::Module *exe_module, + lldb_private::ProcessLaunchInfo &launch_info); + + virtual lldb_private::Error + WillAttachToProcessWithID(lldb::pid_t pid); + + virtual lldb_private::Error + WillAttachToProcessWithName(const char *process_name, bool wait_for_launch); + + virtual lldb_private::Error + DoAttachToProcessWithID(lldb::pid_t pid); + + virtual lldb_private::Error + DoAttachToProcessWithID(lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info); + + virtual lldb_private::Error + DoAttachToProcessWithName(const char *process_name, const lldb_private::ProcessAttachInfo &attach_info); + + virtual void + DidAttach(lldb_private::ArchSpec &process_arch); + + lldb::addr_t + GetImageInfoAddress(); + + //------------------------------------------------------------------ + // PluginInterface protocol + //------------------------------------------------------------------ + virtual lldb_private::ConstString + GetPluginName(); + + virtual uint32_t + GetPluginVersion(); + + //------------------------------------------------------------------ + // Process Control + //------------------------------------------------------------------ + virtual lldb_private::Error + WillResume (); + + virtual lldb_private::Error + DoResume (); + + virtual lldb_private::Error + DoHalt (bool &caused_stop); + + virtual lldb_private::Error + DoDetach (bool keep_stopped); + + virtual lldb_private::Error + DoSignal (int signal); + + virtual lldb_private::Error + DoDestroy (); + + virtual void + RefreshStateAfterStop(); + + //------------------------------------------------------------------ + // Process Queries + //------------------------------------------------------------------ + virtual bool + IsAlive(); + + //------------------------------------------------------------------ + // Process Memory + //------------------------------------------------------------------ + virtual size_t + ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); + + virtual size_t + DoReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error); + + virtual size_t + WriteMemory(lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error); + + virtual size_t + DoWriteMemory(lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error); + + virtual lldb::addr_t + DoAllocateMemory(size_t size, uint32_t permissions, lldb_private::Error &error); + + virtual lldb_private::Error + DoDeallocateMemory(lldb::addr_t ptr); + + //---------------------------------------------------------------------- + // Process Breakpoints + //---------------------------------------------------------------------- + virtual lldb_private::Error + EnableBreakpointSite(lldb_private::BreakpointSite *bp_site); + + virtual lldb_private::Error + DisableBreakpointSite(lldb_private::BreakpointSite *bp_site); + + //---------------------------------------------------------------------- + // Process Watchpoints + //---------------------------------------------------------------------- + virtual lldb_private::Error + EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + + virtual lldb_private::Error + DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true); + + lldb::addr_t + LookUpSymbolAddressInModule(lldb::ModuleSP module, const char *sym_name); + + kvm_t * + GetKVM() {return m_kvm;} +protected: + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + bool + IsRunning(lldb::StateType state) + { + return state == lldb::eStateRunning || IsStepping(state); + } + + bool + IsStepping(lldb::StateType state) + { + return state == lldb::eStateStepping; + } + + bool + CanResume(lldb::StateType state) + { + return state == lldb::eStateStopped; + } + + bool + HasExited(lldb::StateType state) + { + return state == lldb::eStateExited; + } + + bool + ProcessIDIsValid() const; + + void + Clear(); + + virtual bool + UpdateThreadList(lldb_private::ThreadList &old_thread_list, + lldb_private::ThreadList &new_thread_list); + + ThreadFreeBSDKernel * + CreateNewThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid); + + private: + //------------------------------------------------------------------ + // For ProcessFreeBSDKernel only + //------------------------------------------------------------------ + lldb_private::ConstString m_core_file_name; + lldb_private::ConstString m_dyld_plugin_name; + lldb_private::ConstString m_kernel_image_file_name; + lldb_private::FileSpec m_core_file; + uint32_t m_dumptid; + long m_cpusetsize; + cpuset_t m_stopped_cpus; + lldb::addr_t m_kernel_load_addr, m_dumppcb, m_stoppcbs; + lldb::CommandObjectSP m_command_sp; + lldb::ThreadWP m_kernel_thread_wp; + kvm_t *m_kvm; + std::vector m_kthreads; + + + void + AddProcs(uintptr_t paddr); + + lldb::addr_t + FindCorePCB(uint32_t cpuid); + + bool + InitializeThreads(); + + DISALLOW_COPY_AND_ASSIGN (ProcessFreeBSDKernel); +}; + +#endif // liblldb_ProcessFreeBSDKernel_H_ Index: source/Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/ProcessFreeBSDKernel.cpp @@ -0,0 +1,668 @@ +//===-- ProcessFreeBSDKernel.cpp --------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ProcessFreeBSDKernel.h" + +// C Includes +#include +#include + +// C++ Includes + +// Other libraries and framework includes +#include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Interpreter/OptionValueProperties.h" +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Symbol/SymbolVendor.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" + +// Project includes +#include "ProcessPOSIXLog.h" +#include "ThreadFreeBSDKernel.h" +#include "Plugins/DynamicLoader/FreeBSD-Kernel/DynamicLoaderFreeBSDKernel.h" +#include "Plugins/DynamicLoader/Static/DynamicLoaderStatic.h" + +using namespace lldb; +using namespace lldb_private; + +namespace { + // http://svnweb.freebsd.org/base/head/sys/sys/proc.h + enum + { + TDS_INACTIVE = 0x0, + TDS_INHIBITED, + TDS_CAN_RUN, + TDS_RUNQ, + TDS_RUNNING + }; + + static int pcb_size = 320; + + static PropertyDefinition + g_properties[] = + { + {NULL, OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL} + }; + + class PluginProperties : public Properties + { + public: + static ConstString + GetSettingName () + { + return ProcessFreeBSDKernel::GetPluginNameStatic (); + } + + PluginProperties () : + Properties () + { + m_collection_sp.reset (new OptionValueProperties (GetSettingName ())); + m_collection_sp->Initialize (g_properties); + } + + virtual + ~PluginProperties () + { + } + }; + + typedef std::shared_ptr ProcessFreeBSDKernelPropertiesSP; + + static const ProcessFreeBSDKernelPropertiesSP & + GetGlobalPluginProperties () + { + static ProcessFreeBSDKernelPropertiesSP g_settings_sp; + if (!g_settings_sp) + g_settings_sp.reset (new PluginProperties ()); + return g_settings_sp; + } + +} // anonymous namespace end + +ConstString +ProcessFreeBSDKernel::GetPluginNameStatic() +{ + static ConstString g_name("FreeBSD-Kernel"); + return g_name; +} + +const char * +ProcessFreeBSDKernel::GetPluginDescriptionStatic() +{ + return "Plug-in for FreeBSD kernel debugging."; +} + +void +ProcessFreeBSDKernel::Terminate() +{ + PluginManager::UnregisterPlugin(ProcessFreeBSDKernel::CreateInstance); +} + + +lldb::ProcessSP +ProcessFreeBSDKernel::CreateInstance(Target &target, Listener &listener, const FileSpec *crash_file_path) +{ + lldb::ProcessSP process_sp; + // Check if the target is potentially a FreeBSD kernel image + lldb_private::SymbolVendor *sym_vendor = target.GetExecutableModule()->GetSymbolVendor(); + + if (sym_vendor) + { + lldb_private::Symtab *symtab = sym_vendor->GetSymtab(); + if (symtab) + { + std::vector match_indexes; + ConstString symbol_name("kern_open"); + uint32_t num_matches = 0; + + num_matches = symtab->AppendSymbolIndexesWithName(symbol_name, match_indexes); + + if (num_matches == 0) + return process_sp; + } + } + process_sp.reset(new ProcessFreeBSDKernel(target, listener, *crash_file_path)); + return process_sp; +} + +bool +ProcessFreeBSDKernel::CanDebug(Target &target, bool plugin_specified_by_name) +{ + if (plugin_specified_by_name) + return true; + + // For now we are just making sure the file exists for a given module + Module *exe_module = target.GetExecutableModulePointer(); + if (exe_module) + { + const llvm::Triple &triple_ref = target.GetArchitecture().GetTriple(); + switch (triple_ref.getOS()) + { + case llvm::Triple::FreeBSD: + { + ObjectFile *exe_objfile = exe_module->GetObjectFile(); + if (exe_objfile->GetType() == ObjectFile::eTypeExecutable) // && + // exe_objfile->GetStrata() == ObjectFile::eStrataKernel) + { + return true; + } + break; + } + default: + break; + } + } + return false; +} + +//---------------------------------------------------------------------- +// ProcessFreeBSDKernel constructor +//---------------------------------------------------------------------- +ProcessFreeBSDKernel::ProcessFreeBSDKernel(Target& target, Listener &listener, const FileSpec &crash_file_path) + : Process (target, listener), + m_core_file_name (crash_file_path.GetPath().c_str()), + m_dyld_plugin_name (), + m_kernel_image_file_name (target.GetExecutableModule()->GetFileSpec().GetPath().c_str()), + m_core_file (crash_file_path), + m_kernel_load_addr (LLDB_INVALID_ADDRESS), + m_stoppcbs (LLDB_INVALID_ADDRESS), + m_kvm (nullptr) +{ +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +ProcessFreeBSDKernel::~ProcessFreeBSDKernel() +{ + Clear(); + // We need to call finalize on the process before destroying ourselves + // to make sure all of the broadcaster cleanup goes as planned. If we + // destruct this class, then Process::~Process() might have problems + // trying to fully destroy the broadcaster. + Finalize(); +} + +//---------------------------------------------------------------------- +// PluginInterface +//---------------------------------------------------------------------- +lldb_private::ConstString +ProcessFreeBSDKernel::GetPluginName() +{ + return GetPluginNameStatic(); +} + +uint32_t +ProcessFreeBSDKernel::GetPluginVersion() +{ + return 1; +} + +Error +ProcessFreeBSDKernel::WillLaunch(Module* module) +{ + Error error; + error.SetErrorString("launching not supported in freebsd-kernel plug-in"); + return error; +} + +Error +ProcessFreeBSDKernel::WillAttachToProcessWithID(lldb::pid_t pid) +{ + Error error; + error.SetErrorString("attaching to a by process ID not supported in FreeBSD-Kernel plug-in"); + return error; +} + +Error +ProcessFreeBSDKernel::WillAttachToProcessWithName(const char *process_name, bool wait_for_launch) +{ + Error error; + error.SetErrorString("attaching to a by process name not supported in FreeBSD-Kernel plug-in"); + return error; +} + +//---------------------------------------------------------------------- +// Load core file +//---------------------------------------------------------------------- +Error +ProcessFreeBSDKernel::DoLoadCore () +{ + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + Error error; + char kvm_err[_POSIX2_LINE_MAX]; + if (m_core_file.Exists()) + { + m_kvm = kvm_openfiles(m_kernel_image_file_name.AsCString(), + m_core_file_name.AsCString(), nullptr, + O_RDONLY, kvm_err); + if (m_kvm == nullptr) + { + if (log) + log->Printf("ProcessFreeBSDKernel::DoLoadCore() error %s", kvm_err); + error.SetErrorString("Open core file failed in FreeBSD Kernel"); + } else { + InitializeThreads(); + } + } + return error; +} + +Error +ProcessFreeBSDKernel::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) +{ + Error error; + error.SetErrorString("launching not supported in FreeBSD-kernel plug-in"); + return error; +} + + +Error +ProcessFreeBSDKernel::DoAttachToProcessWithID(lldb::pid_t attach_pid) +{ + Error error; + error.SetErrorString("attach to process by ID is not suppported in FreeBSD kernel debugging"); + return error; +} + +Error +ProcessFreeBSDKernel::DoAttachToProcessWithID(lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) +{ + return DoAttachToProcessWithID(attach_pid); +} + +Error +ProcessFreeBSDKernel::DoAttachToProcessWithName(const char *process_name, const ProcessAttachInfo &attach_info) +{ + Error error; + error.SetErrorString("attach to process by name is not suppported in freebsd kernel debugging"); + return error; +} + + +void +ProcessFreeBSDKernel::DidAttach(ArchSpec &process_arch) +{ + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + if (log) + log->Printf("ProcessFreeBSDKernel::DidAttach()"); + if (GetID() != LLDB_INVALID_PROCESS_ID) + { + // XXX default to dumping thread + } +} + +addr_t +ProcessFreeBSDKernel::GetImageInfoAddress() +{ + Target *target = &GetTarget(); + ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile(); + Address addr = obj_file->GetImageInfoAddress(target); + + if (addr.IsValid()) + return addr.GetLoadAddress(target); + return LLDB_INVALID_ADDRESS; +} + +lldb_private::DynamicLoader * +ProcessFreeBSDKernel::GetDynamicLoader() +{ + if (m_dyld_ap.get() == nullptr) + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, DynamicLoaderFreeBSDKernel::GetPluginNameStatic().GetCString())); + + return m_dyld_ap.get(); +} + +Error +ProcessFreeBSDKernel::WillResume() +{ + return Error(); +} + +Error +ProcessFreeBSDKernel::DoResume() +{ + Error error; + // Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + // Only start the async thread if we try to do any process control + + return error; +} + +ThreadFreeBSDKernel * +ProcessFreeBSDKernel::CreateNewThreadFreeBSDKernel(lldb_private::Process &process, + lldb::tid_t tid) +{ + return new ThreadFreeBSDKernel(process, tid); +} + +bool +ProcessFreeBSDKernel::UpdateThreadList(ThreadList &old_thread_list, + ThreadList &new_thread_list) +{ + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_THREAD)); + if (log && log->GetMask().Test(POSIX_LOG_VERBOSE)) + log->Printf ("ProcessFreeBSDKernel::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); + + for (size_t i = 0; i < m_kthreads.size(); i++) + { + new_thread_list.AddThread(m_kthreads[i]); + } + return new_thread_list.GetSize(false) > 0; +} + +void +ProcessFreeBSDKernel::RefreshStateAfterStop() +{ + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + // m_thread_list.RefreshStateAfterStop(); +} + +Error +ProcessFreeBSDKernel::DoHalt(bool &caused_stop) +{ + Error error; + return error; +} + +Error +ProcessFreeBSDKernel::DoDetach(bool keep_stopped) +{ + Error error; + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + if (log) + log->Printf("ProcessFreeBSDKernel::DoDetach(keep_stopped = %i)", keep_stopped); + + return error; +} + +Error +ProcessFreeBSDKernel::DoDestroy() +{ + bool keep_stopped = false; + return DoDetach(keep_stopped); +} + +//------------------------------------------------------------------ +// Process Queries +//------------------------------------------------------------------ + +bool +ProcessFreeBSDKernel::IsAlive() +{ + return (m_kvm != nullptr); +} + +//------------------------------------------------------------------ +// Process Memory +//------------------------------------------------------------------ +size_t +ProcessFreeBSDKernel::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error) +{ + return DoReadMemory (addr, buf, size, error); +} + +size_t +ProcessFreeBSDKernel::DoReadMemory(addr_t addr, void *buf, size_t size, Error &error) +{ + if (!m_kvm) + return 0; + else + return kvm_read(m_kvm, addr, buf, size); +} + +size_t +ProcessFreeBSDKernel::WriteMemory(addr_t addr, const void *buf, size_t size, Error &error) +{ + return DoWriteMemory(addr, buf, size, error); +} + +size_t +ProcessFreeBSDKernel::DoWriteMemory(addr_t addr, const void *buf, size_t size, Error &error) +{ + if (!m_kvm) + return 0; + else + return kvm_write(m_kvm, addr, buf, size); +} + +lldb::addr_t +ProcessFreeBSDKernel::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) +{ + error.SetErrorString ("memory allocation not suppported in freebsd kernel debugging"); + return LLDB_INVALID_ADDRESS; +} + +Error +ProcessFreeBSDKernel::DoDeallocateMemory (lldb::addr_t addr) +{ + Error error; + error.SetErrorString ("memory deallocation not suppported in freebsd kernel debugging"); + return error; +} + +Error +ProcessFreeBSDKernel::EnableBreakpointSite (BreakpointSite *bp_site) +{ + return EnableSoftwareBreakpoint (bp_site); +} + +Error +ProcessFreeBSDKernel::DisableBreakpointSite (BreakpointSite *bp_site) +{ + return DisableSoftwareBreakpoint (bp_site); +} + +Error +ProcessFreeBSDKernel::EnableWatchpoint (Watchpoint *wp, bool notify) +{ + Error error; + error.SetErrorString ("watchpoints are not suppported in freebsd kernel debugging"); + return error; +} + +Error +ProcessFreeBSDKernel::DisableWatchpoint (Watchpoint *wp, bool notify) +{ + Error error; + error.SetErrorString ("watchpoints are not suppported in FreeBSD kernel debugging"); + return error; +} + +void +ProcessFreeBSDKernel::Clear() +{ + if (m_kvm) + { + kvm_close(m_kvm); + m_kvm = nullptr; + } + m_thread_list.Clear(); +} + +Error +ProcessFreeBSDKernel::DoSignal(int signo) +{ + Error error; + error.SetErrorString("sending signals is not suppported in FreeBSD kernel debugging"); + return error; +} + +void +ProcessFreeBSDKernel::Initialize() +{ + static bool g_initialized = false; + + if (g_initialized == false) + { + g_initialized = true; + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), + CreateInstance, + DebuggerInitialize); + + Log::Callbacks log_callbacks = + { + ProcessPOSIXLog::DisableLog, + ProcessPOSIXLog::EnableLog, + ProcessPOSIXLog::ListLogCategories + }; + + Log::RegisterLogChannel(ProcessFreeBSDKernel::GetPluginNameStatic(), log_callbacks); + } +} + +void +ProcessFreeBSDKernel::DebuggerInitialize(lldb_private::Debugger &debugger) +{ + if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) + { + const bool is_global_setting = true; + PluginManager::CreateSettingForProcessPlugin(debugger, + GetGlobalPluginProperties()->GetValueProperties(), + ConstString("Properties for the FreeBSD kernel process plug-in."), + is_global_setting); + } +} + +lldb::addr_t ProcessFreeBSDKernel::LookUpSymbolAddressInModule(lldb::ModuleSP module, const char *name) +{ + lldb_private::SymbolVendor *sym_vendor = module->GetSymbolVendor(); + if (sym_vendor) + { + lldb_private::Symtab *symtab = sym_vendor->GetSymtab(); + if (symtab) + { + std::vector match_indexes; + ConstString symbol_name(name); + uint32_t num_matches = 0; + + num_matches = symtab->AppendSymbolIndexesWithName(symbol_name, + match_indexes); + + if (num_matches > 0) + { + + Symbol *symbol = symtab->SymbolAtIndex(match_indexes[0]); + return symbol->GetAddress().GetFileAddress(); + } + } + } + return LLDB_INVALID_ADDRESS; +} + +bool ProcessFreeBSDKernel::InitializeThreads() +{ + ModuleSP module = GetTarget().GetExecutableModule(); + lldb::addr_t addr, paddr; + + addr = LookUpSymbolAddressInModule(module, "allproc"); + if (addr == LLDB_INVALID_ADDRESS) + return false; + kvm_read(m_kvm, addr, &paddr, sizeof(paddr)); + + m_dumppcb = LookUpSymbolAddressInModule(module, "dumppcb"); + if (m_dumppcb == LLDB_INVALID_ADDRESS) + return false; + + addr = LookUpSymbolAddressInModule(module, "dumptid"); + if (addr == LLDB_INVALID_ADDRESS) + m_dumptid = -1; + else + kvm_read(m_kvm, addr, &m_dumptid, sizeof(m_dumptid)); + + addr = LookUpSymbolAddressInModule(module, "stopped_cpus"); + CPU_ZERO(&m_stopped_cpus); + m_cpusetsize = sysconf(_SC_CPUSET_SIZE); + if (m_cpusetsize != -1 && (unsigned long)m_cpusetsize <= sizeof(cpuset_t) && + addr != 0) + kvm_read(m_kvm, addr, &m_stopped_cpus, m_cpusetsize); + + AddProcs(paddr); + addr = LookUpSymbolAddressInModule(module, "zombproc"); + if (addr != LLDB_INVALID_ADDRESS) + { + kvm_read(m_kvm, addr, &paddr, sizeof(paddr)); + AddProcs(paddr); + } + // curkthr = kgdb_thr_lookup_tid(dumptid); + // if (curkthr == NULL) + // curkthr = first; + return true; +} + +void +ProcessFreeBSDKernel::AddProcs(uintptr_t paddr) +{ + Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); + struct proc p; + struct thread td; + addr_t addr; + + while (paddr != 0) + { + if (kvm_read(m_kvm, paddr, &p, sizeof(p)) != sizeof(p)) + { + if (log) + log->Printf("kvm_read: %s", kvm_geterr(m_kvm)); + break; + } + + addr = (addr_t)TAILQ_FIRST(&p.p_threads); + while (addr != 0) + { + if (kvm_read(m_kvm, addr, &td, sizeof(td)) != sizeof(td)) + { + if (log) + log->Printf("kvm_read: %s", kvm_geterr(m_kvm)); + break; + } + + ThreadSP thread_sp; + ThreadFreeBSDKernel * kthread = CreateNewThreadFreeBSDKernel(*this, td.td_tid); + + kthread->m_kaddr = addr; + if ((lldb::tid_t)td.td_tid == m_dumptid) + kthread->m_pcb = m_dumppcb; + else if (TD_IS_RUNNING(&td) && CPU_ISSET(td.td_oncpu, &m_stopped_cpus)) + kthread->m_pcb = FindCorePCB(td.td_oncpu); + else + kthread->m_pcb = (addr_t)td.td_pcb; + + kthread->m_kstack = td.td_kstack; + kthread->m_pid = p.p_pid; + kthread->m_tid = td.td_tid; + kthread->m_paddr = paddr; + kthread->m_cpu = td.td_oncpu; + thread_sp.reset(kthread); + m_kthreads.push_back(thread_sp); + addr = reinterpret_cast(TAILQ_NEXT(&td, td_plist)); + } + paddr = reinterpret_cast(LIST_NEXT(&p, p_list)); + } +} + +addr_t +ProcessFreeBSDKernel::FindCorePCB(uint32_t cpuid) +{ + ModuleSP module = GetTarget().GetExecutableModule(); + if (m_stoppcbs == LLDB_INVALID_ADDRESS) + m_stoppcbs = LookUpSymbolAddressInModule(module, "stoppcbs"); + + if (m_stoppcbs == LLDB_INVALID_ADDRESS) + return 0; + + return m_stoppcbs + cpuid * pcb_size; +} Index: source/Plugins/Process/FreeBSD-Kernel/RegisterContextFreeBSDKernel_x86_64.h =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/RegisterContextFreeBSDKernel_x86_64.h @@ -0,0 +1,89 @@ +//===-- RegisterContextFreBSDKernel_x86_64.h --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// + +#ifndef liblldb_RegisterContextFreeBSDKernel_x86_64_H_ +#define liblldb_RegisterContextFreeBSDKernel_x86_64_H_ + +#include "Plugins/Process/Utility/RegisterContextPOSIX_x86.h" + +namespace { + typedef struct _GPR + { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rdi; + uint64_t rsi; + uint64_t rbp; + uint64_t rbx; + uint64_t rdx; + uint64_t rcx; + uint64_t rax; + uint32_t trapno; + uint16_t fs; + uint16_t gs; + uint32_t err; + uint16_t es; + uint16_t ds; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; + } GPR; +} + +class RegisterContextFreeBSDKernel_x86_64 : public RegisterContextPOSIX_x86 +{ +public: + RegisterContextFreeBSDKernel_x86_64(lldb_private::Thread &thread, + lldb_private::RegisterInfoInterface *register_info); + + ~RegisterContextFreeBSDKernel_x86_64(); + + virtual bool + ReadRegister(const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value); + + virtual bool + WriteRegister(const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value); + + bool + ReadAllRegisterValues(lldb::DataBufferSP &data_sp); + + bool + WriteAllRegisterValues(const lldb::DataBufferSP &data_sp); + + bool + HardwareSingleStep(bool enable); + + size_t + GetGPRSize(); +protected: + bool + ReadGPR(); + + bool + ReadFPR(); + + bool + WriteGPR(); + + bool + WriteFPR(); + +private: + GPR * m_gpr; +}; + +#endif // liblldb_RegisterContextFreeBSDKernel_x86_64_H_ Index: source/Plugins/Process/FreeBSD-Kernel/RegisterContextFreeBSDKernel_x86_64.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/RegisterContextFreeBSDKernel_x86_64.cpp @@ -0,0 +1,133 @@ +//===-- RegisterContextFreeBSDKernel_x86_64.cpp -----------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "RegisterContextFreeBSDKernel_x86_64.h" + +// C Includes +#include +#include + +// C++ Includes + +// Other libraries and framework includes +#include "lldb/Core/DataExtractor.h" +#include "lldb/Core/RegisterValue.h" +#include "lldb/Target/Thread.h" + +// Project includes +#include "ProcessFreeBSDKernel.h" +#include "RegisterContextPOSIX.h" +#include "ThreadFreeBSDKernel.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextFreeBSDKernel_x86_64::RegisterContextFreeBSDKernel_x86_64(Thread &thread, + RegisterInfoInterface *register_info) + : RegisterContextPOSIX_x86(thread, 0, register_info), + m_gpr(nullptr) +{ + ProcessSP process_sp(CalculateProcess()); + Error error; + struct pcb pcb; + if (process_sp) + { + ThreadFreeBSDKernel *kthread = static_cast(&m_thread); + if (process_sp->ReadMemory(kthread->GetPCB(), &pcb, sizeof(pcb), error) != sizeof(pcb)) + { + return; + } + else + { + m_gpr = new GPR; + memset(m_gpr, 0, sizeof(GPR)); + m_gpr->rbx = static_cast(pcb.pcb_rbx); + m_gpr->rbp = static_cast(pcb.pcb_rbp); + m_gpr->rsp = static_cast(pcb.pcb_rsp); + m_gpr->r12 = static_cast(pcb.pcb_r12); + m_gpr->r13 = static_cast(pcb.pcb_r13); + m_gpr->r14 = static_cast(pcb.pcb_r14); + m_gpr->r15 = static_cast(pcb.pcb_r15); + m_gpr->rip = static_cast(pcb.pcb_rip); + } + } +} + +RegisterContextFreeBSDKernel_x86_64::~RegisterContextFreeBSDKernel_x86_64() +{ + delete m_gpr; +} + +bool +RegisterContextFreeBSDKernel_x86_64::ReadGPR() +{ + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::ReadFPR() +{ + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::WriteGPR() +{ + assert(0); + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::WriteFPR() +{ + assert(0); + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value) +{ + if (m_gpr) + { + value = *(reinterpret_cast(reinterpret_cast(m_gpr) + reg_info->byte_offset)); + return true; + } + + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) +{ + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) +{ + return false; +} + +bool +RegisterContextFreeBSDKernel_x86_64::HardwareSingleStep(bool enable) +{ + return false; +} + +size_t +RegisterContextFreeBSDKernel_x86_64::GetGPRSize() +{ + return sizeof(GPR); +} Index: source/Plugins/Process/FreeBSD-Kernel/ThreadFreeBSDKernel.h =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/ThreadFreeBSDKernel.h @@ -0,0 +1,94 @@ +//===-- ThreadFreeBSD.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_ThreadFreeBSDKernel_H_ +#define liblldb_ThreadFreeBSDKernel_H_ + +#include + +#include "lldb/Target/Thread.h" + +class ThreadFreeBSDKernel : public lldb_private::Thread +{ +public: + ThreadFreeBSDKernel(lldb_private::Process &process, lldb::tid_t tid); + + virtual + ~ThreadFreeBSDKernel(); + + virtual void + RefreshStateAfterStop(); + + virtual lldb::RegisterContextSP + GetRegisterContext(); + + virtual lldb::RegisterContextSP + CreateRegisterContextForFrame(lldb_private::StackFrame *frame); + + static bool + ThreadIDIsValid(lldb::tid_t thread) + { + return thread != 0; + } + + virtual const char * + GetName() + { + if (m_thread_name.empty()) + return NULL; + return m_thread_name.c_str(); + } + + void + SetName(const char *name) + { + if (name && name[0]) + m_thread_name.assign(name); + else + m_thread_name.clear(); + } + + const char * + GetQueueName() + { + return NULL; + } + + void + Dump(lldb_private::Log *log, uint32_t index); + + bool + ShouldStop(bool &step_more); + + lldb::addr_t GetPCB() + { + return m_pcb; + } +protected: + friend class ProcessFreeBSDKernel; + //------------------------------------------------------------------ + // Member variables. + //------------------------------------------------------------------ + std::string m_thread_name; + lldb::RegisterContextSP m_thread_reg_ctx_sp; + lldb::addr_t m_paddr; + lldb::addr_t m_kaddr; + lldb::addr_t m_kstack; + lldb::addr_t m_pcb; + lldb::tid_t m_tid; + lldb::pid_t m_pid; + unsigned char m_cpu; + int m_signo; + lldb::StopInfoSP m_cached_stop_info_sp; + + virtual bool CalculateStopInfo(); + +}; + +#endif // liblldb_ThreadFreeBSDKernel_H_ Index: source/Plugins/Process/FreeBSD-Kernel/ThreadFreeBSDKernel.cpp =================================================================== --- /dev/null +++ source/Plugins/Process/FreeBSD-Kernel/ThreadFreeBSDKernel.cpp @@ -0,0 +1,138 @@ +//===-- ThreadFreeBSD.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "ThreadFreeBSDKernel.h" + +#include "lldb/Core/ArchSpec.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/StopInfo.h" +#include "lldb/Target/Target.h" + +#include "ProcessFreeBSDKernel.h" +#include "RegisterContextFreeBSD_x86_64.h" +#include "RegisterContextFreeBSDKernel_x86_64.h" + +using namespace lldb; +using namespace lldb_private; + +//---------------------------------------------------------------------- +// Thread Registers +//---------------------------------------------------------------------- + +ThreadFreeBSDKernel::ThreadFreeBSDKernel(Process &process, tid_t tid) + : Thread(process, tid), + m_thread_name () +{ +} + +ThreadFreeBSDKernel::~ThreadFreeBSDKernel() +{ + DestroyThread(); +} + +void +ThreadFreeBSDKernel::RefreshStateAfterStop() +{ + // Invalidate all registers in our register context. We don't set "force" to + // true because the stop reply packet might have had some register values + // that were expedited and these will already be copied into the register + // context by the time this function gets called. The KDPRegisterContext + // class has been made smart enough to detect when it needs to invalidate + // which registers are valid by putting hooks in the register read and + // register supply functions where they check the process stop ID and do + // the right thing. + const bool force = false; + lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); + if (reg_ctx_sp) + reg_ctx_sp->InvalidateIfNeeded(force); +} + +void +ThreadFreeBSDKernel::Dump(Log *log, uint32_t index) +{ +} + + +bool +ThreadFreeBSDKernel::ShouldStop(bool &step_more) +{ + return true; +} + +lldb::RegisterContextSP +ThreadFreeBSDKernel::GetRegisterContext() +{ + if (!m_reg_context_sp) + m_reg_context_sp = CreateRegisterContextForFrame(NULL); + + return m_reg_context_sp; +} + +lldb::RegisterContextSP +ThreadFreeBSDKernel::CreateRegisterContextForFrame(StackFrame *frame) +{ + lldb::RegisterContextSP reg_ctx_sp; + RegisterInfoInterface *reg_interface = NULL; + uint32_t concrete_frame_idx = 0; + + if (frame) + concrete_frame_idx = frame->GetConcreteFrameIndex(); + + const ArchSpec &target_arch = GetProcess()->GetTarget().GetArchitecture(); + + if (concrete_frame_idx == 0) + { + ProcessSP process_sp (CalculateProcess()); + ProcessFreeBSDKernel * process = + static_cast(process_sp.get()); + if (process) + { + switch (process->GetTarget().GetArchitecture().GetMachine()) + { + case llvm::Triple::x86_64: + reg_interface = new RegisterContextFreeBSD_x86_64(target_arch); + break; + default: + assert (!"Add CPU type support in FreeBSD Kernel"); + break; + } + } + } + assert(reg_interface && "OS or CPU not supported!"); + switch (target_arch.GetMachine()) + { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + { + RegisterContextFreeBSDKernel_x86_64 *reg_ctx = + new RegisterContextFreeBSDKernel_x86_64(*this, reg_interface); + m_reg_context_sp.reset(reg_ctx); + break; + } + default: + break; + } + return m_reg_context_sp; +} + +bool +ThreadFreeBSDKernel::CalculateStopInfo() +{ + ProcessSP process_sp(GetProcess()); + if (process_sp) + { + if (m_cached_stop_info_sp) + SetStopInfo(m_cached_stop_info_sp); + else + SetStopInfo(StopInfo::CreateStopReasonWithSignal(*this, SIGSTOP)); + return true; + } + return false; +}