Index: vendor/lldb/dist/include/lldb/Host/android/Android.h =================================================================== --- vendor/lldb/dist/include/lldb/Host/android/Android.h (revision 304307) +++ vendor/lldb/dist/include/lldb/Host/android/Android.h (revision 304308) @@ -1,31 +1,28 @@ //===-- lldb-android.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_lldb_android_h_ #define LLDB_lldb_android_h_ #include #include #include -#define _isatty isatty -#define SYS_tgkill __NR_tgkill - namespace std { template std::string to_string(T value) { std::ostringstream os ; os << value ; return os.str() ; } } #endif // LLDB_lldb_android_h_ Index: vendor/lldb/dist/include/lldb/Host/linux/Ptrace.h =================================================================== --- vendor/lldb/dist/include/lldb/Host/linux/Ptrace.h (revision 304307) +++ vendor/lldb/dist/include/lldb/Host/linux/Ptrace.h (revision 304308) @@ -1,66 +1,57 @@ //===-- Ptrace.h ------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // This file defines ptrace functions & structures #ifndef liblldb_Host_linux_Ptrace_h_ #define liblldb_Host_linux_Ptrace_h_ #include -#ifdef __ANDROID_NDK__ -#define PT_DETACH PTRACE_DETACH +#ifndef __GLIBC__ typedef int __ptrace_request; #endif #define DEBUG_PTRACE_MAXBYTES 20 // Support ptrace extensions even when compiled without required kernel support -#ifndef PT_GETREGS - #ifndef PTRACE_GETREGS - #define PTRACE_GETREGS 12 - #endif +#ifndef PTRACE_GETREGS + #define PTRACE_GETREGS 12 #endif -#ifndef PT_SETREGS - #ifndef PTRACE_SETREGS - #define PTRACE_SETREGS 13 - #endif +#ifndef PTRACE_SETREGS + #define PTRACE_SETREGS 13 #endif -#ifndef PT_GETFPREGS - #ifndef PTRACE_GETFPREGS - #define PTRACE_GETFPREGS 14 - #endif +#ifndef PTRACE_GETFPREGS + #define PTRACE_GETFPREGS 14 #endif -#ifndef PT_SETFPREGS - #ifndef PTRACE_SETFPREGS - #define PTRACE_SETFPREGS 15 - #endif +#ifndef PTRACE_SETFPREGS + #define PTRACE_SETFPREGS 15 #endif #ifndef PTRACE_GETREGSET #define PTRACE_GETREGSET 0x4204 #endif #ifndef PTRACE_SETREGSET #define PTRACE_SETREGSET 0x4205 #endif #ifndef PTRACE_GET_THREAD_AREA #define PTRACE_GET_THREAD_AREA 25 #endif #ifndef PTRACE_ARCH_PRCTL #define PTRACE_ARCH_PRCTL 30 #endif #ifndef ARCH_GET_FS #define ARCH_SET_GS 0x1001 #define ARCH_SET_FS 0x1002 #define ARCH_GET_FS 0x1003 #define ARCH_GET_GS 0x1004 #endif #define LLDB_PTRACE_NT_ARM_TLS 0x401 // ARM TLS register #endif // liblldb_Host_linux_Ptrace_h_ Index: vendor/lldb/dist/include/lldb/Target/RegisterContext.h =================================================================== --- vendor/lldb/dist/include/lldb/Target/RegisterContext.h (revision 304307) +++ vendor/lldb/dist/include/lldb/Target/RegisterContext.h (revision 304308) @@ -1,265 +1,270 @@ //===-- RegisterContext.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_RegisterContext_h_ #define liblldb_RegisterContext_h_ // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" #include "lldb/Target/ExecutionContextScope.h" namespace lldb_private { class RegisterContext : public std::enable_shared_from_this, public ExecutionContextScope { public: //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ RegisterContext (Thread &thread, uint32_t concrete_frame_idx); ~RegisterContext() override; void InvalidateIfNeeded (bool force); //------------------------------------------------------------------ // Subclasses must override these functions //------------------------------------------------------------------ virtual void InvalidateAllRegisters () = 0; virtual size_t GetRegisterCount () = 0; virtual const RegisterInfo * GetRegisterInfoAtIndex (size_t reg) = 0; + // Detect the register size dynamically. + uint32_t + UpdateDynamicRegisterSize (const lldb_private::ArchSpec &arch, + RegisterInfo* reg_info); + virtual size_t GetRegisterSetCount () = 0; virtual const RegisterSet * GetRegisterSet (size_t reg_set) = 0; virtual bool ReadRegister (const RegisterInfo *reg_info, RegisterValue ®_value) = 0; virtual bool WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) = 0; virtual bool ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { return false; } virtual bool WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { return false; } // These two functions are used to implement "push" and "pop" of register states. They are used primarily // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues. // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation, // so these API's should only be used when this behavior is needed. virtual bool ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint); virtual bool WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint); bool CopyFromRegisterContext (lldb::RegisterContextSP context); //------------------------------------------------------------------ /// Convert from a given register numbering scheme to the lldb register /// numbering scheme /// /// There may be multiple ways to enumerate the registers for a given /// architecture. ABI references will specify one to be used with /// DWARF, the register numberings from process plugin, there may /// be a variation used for eh_frame unwind instructions (e.g. on Darwin), /// and so on. Register 5 by itself is meaningless - RegisterKind /// enumeration tells you what context that number should be translated as. /// /// Inside lldb, register numbers are in the eRegisterKindLLDB scheme; /// arguments which take a register number should take one in that /// scheme. /// /// eRegisterKindGeneric is a special numbering scheme which gives us /// constant values for the pc, frame register, stack register, etc., for /// use within lldb. They may not be defined for all architectures but /// it allows generic code to translate these common registers into the /// lldb numbering scheme. /// /// This method translates a given register kind + register number into /// the eRegisterKindLLDB register numbering. /// /// @param [in] kind /// The register numbering scheme (RegisterKind) that the following /// register number is in. /// /// @param [in] num /// A register number in the 'kind' register numbering scheme. /// /// @return /// The equivalent register number in the eRegisterKindLLDB /// numbering scheme, if possible, else LLDB_INVALID_REGNUM. //------------------------------------------------------------------ virtual uint32_t ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) = 0; //------------------------------------------------------------------ // Subclasses can override these functions if desired //------------------------------------------------------------------ virtual uint32_t NumSupportedHardwareBreakpoints (); virtual uint32_t SetHardwareBreakpoint (lldb::addr_t addr, size_t size); virtual bool ClearHardwareBreakpoint (uint32_t hw_idx); virtual uint32_t NumSupportedHardwareWatchpoints (); virtual uint32_t SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write); virtual bool ClearHardwareWatchpoint (uint32_t hw_index); virtual bool HardwareSingleStep (bool enable); virtual Error ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue ®_value); virtual Error WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value); //------------------------------------------------------------------ // Subclasses should not override these //------------------------------------------------------------------ virtual lldb::tid_t GetThreadID() const; virtual Thread & GetThread () { return m_thread; } const RegisterInfo * GetRegisterInfoByName (const char *reg_name, uint32_t start_idx = 0); const RegisterInfo * GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num); uint64_t GetPC (uint64_t fail_value = LLDB_INVALID_ADDRESS); bool SetPC (uint64_t pc); bool SetPC (Address addr); uint64_t GetSP (uint64_t fail_value = LLDB_INVALID_ADDRESS); bool SetSP (uint64_t sp); uint64_t GetFP (uint64_t fail_value = LLDB_INVALID_ADDRESS); bool SetFP (uint64_t fp); const char * GetRegisterName (uint32_t reg); uint64_t GetReturnAddress (uint64_t fail_value = LLDB_INVALID_ADDRESS); uint64_t GetFlags (uint64_t fail_value = 0); uint64_t ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value); uint64_t ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value); bool WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval); bool WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval); bool ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum); //------------------------------------------------------------------ // lldb::ExecutionContextScope pure virtual functions //------------------------------------------------------------------ lldb::TargetSP CalculateTarget() override; lldb::ProcessSP CalculateProcess() override; lldb::ThreadSP CalculateThread() override; lldb::StackFrameSP CalculateStackFrame() override; void CalculateExecutionContext(ExecutionContext &exe_ctx) override; uint32_t GetStopID () const { return m_stop_id; } void SetStopID (uint32_t stop_id) { m_stop_id = stop_id; } protected: //------------------------------------------------------------------ // Classes that inherit from RegisterContext can see and modify these //------------------------------------------------------------------ Thread &m_thread; // The thread that this register context belongs to. uint32_t m_concrete_frame_idx; // The concrete frame index for this register context uint32_t m_stop_id; // The stop ID that any data in this context is valid for private: //------------------------------------------------------------------ // For RegisterContext only //------------------------------------------------------------------ DISALLOW_COPY_AND_ASSIGN (RegisterContext); }; } // namespace lldb_private #endif // liblldb_RegisterContext_h_ Index: vendor/lldb/dist/include/lldb/lldb-private-types.h =================================================================== --- vendor/lldb/dist/include/lldb/lldb-private-types.h (revision 304307) +++ vendor/lldb/dist/include/lldb/lldb-private-types.h (revision 304308) @@ -1,112 +1,116 @@ //===-- lldb-private-types.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_lldb_private_types_h_ #define liblldb_lldb_private_types_h_ #if defined(__cplusplus) #include "lldb/lldb-private.h" namespace llvm { namespace sys { class DynamicLibrary; } } namespace lldb_private { class Platform; class ExecutionContext; typedef llvm::sys::DynamicLibrary (*LoadPluginCallbackType)(const lldb::DebuggerSP &debugger_sp, const FileSpec &spec, Error &error); //---------------------------------------------------------------------- // Every register is described in detail including its name, alternate // name (optional), encoding, size in bytes and the default display // format. //---------------------------------------------------------------------- struct RegisterInfo { const char *name; // Name of this register, can't be NULL const char *alt_name; // Alternate name of this register, can be NULL uint32_t byte_size; // Size in bytes of the register uint32_t byte_offset; // The byte offset in the register context data where this register's value is found. // This is optional, and can be 0 if a particular RegisterContext does not need to // address its registers by byte offset. lldb::Encoding encoding; // Encoding of the register bits lldb::Format format; // Default display format uint32_t kinds[lldb::kNumRegisterKinds]; // Holds all of the various register numbers for all register kinds uint32_t *value_regs; // List of registers (terminated with LLDB_INVALID_REGNUM). If this value is not // null, all registers in this list will be read first, at which point the value // for this register will be valid. For example, the value list for ah // would be eax (x86) or rax (x64). uint32_t *invalidate_regs; // List of registers (terminated with LLDB_INVALID_REGNUM). If this value is not // null, all registers in this list will be invalidated when the value of this // register changes. For example, the invalidate list for eax would be rax // ax, ah, and al. + const uint8_t *dynamic_size_dwarf_expr_bytes; // A DWARF expression that when evaluated gives + // the byte size of this register. + size_t dynamic_size_dwarf_len; // The length of the DWARF expression in bytes + // in the dynamic_size_dwarf_expr_bytes member. }; //---------------------------------------------------------------------- // Registers are grouped into register sets //---------------------------------------------------------------------- struct RegisterSet { const char *name; // Name of this register set const char *short_name; // A short name for this register set size_t num_registers; // The number of registers in REGISTERS array below const uint32_t *registers; // An array of register indices in this set. The values in this array are // *indices* (not register numbers) into a particular RegisterContext's // register array. For example, if eax is defined at index 4 for a // particular RegisterContext, eax would be included in this RegisterSet // by adding the value 4. Not by adding the value lldb_eax_i386. }; struct OptionEnumValueElement { int64_t value; const char *string_value; const char *usage; }; struct OptionValidator { virtual ~OptionValidator() { } virtual bool IsValid(Platform &platform, const ExecutionContext &target) const = 0; virtual const char * ShortConditionString() const = 0; virtual const char * LongConditionString() const = 0; }; struct OptionDefinition { uint32_t usage_mask; // Used to mark options that can be used together. If (1 << n & usage_mask) != 0 // then this option belongs to option set n. bool required; // This option is required (in the current usage level) const char *long_option; // Full name for this option. int short_option; // Single character for this option. int option_has_arg; // no_argument, required_argument or optional_argument OptionValidator* validator; // If non-NULL, option is valid iff |validator->IsValid()|, otherwise always valid. OptionEnumValueElement *enum_values; // If non-NULL an array of enum values. uint32_t completion_type; // Cookie the option class can use to do define the argument completion. lldb::CommandArgumentType argument_type; // Type of argument this option takes const char *usage_text; // Full text explaining what this options does and what (if any) argument to // pass it. }; typedef struct type128 { uint64_t x[2]; } type128; typedef struct type256 { uint64_t x[4]; } type256; } // namespace lldb_private #endif // #if defined(__cplusplus) #endif // liblldb_lldb_private_types_h_ Index: vendor/lldb/dist/scripts/Xcode/build-llvm.py =================================================================== --- vendor/lldb/dist/scripts/Xcode/build-llvm.py (revision 304307) +++ vendor/lldb/dist/scripts/Xcode/build-llvm.py (revision 304308) @@ -1,373 +1,373 @@ #!/usr/bin/env python import errno import hashlib import fnmatch import os import platform import subprocess import sys from lldbbuild import * #### SETTINGS #### def LLVM_HASH_INCLUDES_DIFFS (): return False # The use of "x = "..."; return x" here is important because tooling looks for # it with regexps. Only change how this works if you know what you are doing. def LLVM_REF (): - llvm_ref = "master" + llvm_ref = "release_39" return llvm_ref def CLANG_REF (): - clang_ref = "master" + clang_ref = "release_39" return clang_ref # For use with Xcode-style builds def XCODE_REPOSITORIES (): return [ { 'name': "llvm", 'vcs': VCS.git, 'root': llvm_source_path(), 'url': "http://llvm.org/git/llvm.git", 'ref': LLVM_REF() }, { 'name': "clang", 'vcs': VCS.git, 'root': clang_source_path(), 'url': "http://llvm.org/git/clang.git", 'ref': CLANG_REF() }, { 'name': "ninja", 'vcs': VCS.git, 'root': ninja_source_path(), 'url': "https://github.com/ninja-build/ninja.git", 'ref': "master" } ] def get_c_compiler (): return subprocess.check_output([ 'xcrun', '--sdk', 'macosx', '-find', 'clang' ]).rstrip() def get_cxx_compiler (): return subprocess.check_output([ 'xcrun', '--sdk', 'macosx', '-find', 'clang++' ]).rstrip() # CFLAGS="-isysroot $(xcrun --sdk macosx --show-sdk-path) -mmacosx-version-min=${DARWIN_DEPLOYMENT_VERSION_OSX}" \ # LDFLAGS="-mmacosx-version-min=${DARWIN_DEPLOYMENT_VERSION_OSX}" \ def get_deployment_target (): return os.environ.get('MACOSX_DEPLOYMENT_TARGET', None) def get_c_flags (): cflags = '' # sdk_path = subprocess.check_output([ # 'xcrun', # '--sdk', 'macosx', # '--show-sdk-path']).rstrip() # cflags += '-isysroot {}'.format(sdk_path) deployment_target = get_deployment_target() if deployment_target: # cflags += ' -mmacosx-version-min={}'.format(deployment_target) pass return cflags def get_cxx_flags (): return get_c_flags() def get_common_linker_flags (): linker_flags = "" deployment_target = get_deployment_target() if deployment_target: # if len(linker_flags) > 0: # linker_flags += ' ' # linker_flags += '-mmacosx-version-min={}'.format(deployment_target) pass return linker_flags def get_exe_linker_flags (): return get_common_linker_flags() def get_shared_linker_flags (): return get_common_linker_flags() def CMAKE_FLAGS (): return { "Debug": [ "-DCMAKE_BUILD_TYPE=RelWithDebInfo", "-DLLVM_ENABLE_ASSERTIONS=ON", ], "DebugClang": [ "-DCMAKE_BUILD_TYPE=Debug", "-DLLVM_ENABLE_ASSERTIONS=ON", ], "Release": [ "-DCMAKE_BUILD_TYPE=Release", "-DLLVM_ENABLE_ASSERTIONS=ON", ], "BuildAndIntegration": [ "-DCMAKE_BUILD_TYPE=Release", "-DLLVM_ENABLE_ASSERTIONS=OFF", ], } def CMAKE_ENVIRONMENT (): return { } #### COLLECTING ALL ARCHIVES #### def collect_archives_in_path (path): files = os.listdir(path) return [os.path.join(path, file) for file in files if file.endswith(".a")] def archive_list (): paths = library_paths() archive_lists = [collect_archives_in_path(path) for path in paths] return [archive for archive_list in archive_lists for archive in archive_list] def write_archives_txt (): f = open(archives_txt(), 'w') for archive in archive_list(): f.write(archive + "\n") f.close() #### COLLECTING REPOSITORY MD5S #### def source_control_status (spec): vcs_for_spec = vcs(spec) if LLVM_HASH_INCLUDES_DIFFS(): return vcs_for_spec.status() + vcs_for_spec.diff() else: return vcs_for_spec.status() def source_control_status_for_specs (specs): statuses = [source_control_status(spec) for spec in specs] return "".join(statuses) def all_source_control_status (): return source_control_status_for_specs(XCODE_REPOSITORIES()) def md5 (string): m = hashlib.md5() m.update(string) return m.hexdigest() def all_source_control_status_md5 (): return md5(all_source_control_status()) #### CHECKING OUT AND BUILDING LLVM #### def apply_patches(spec): files = os.listdir(os.path.join(lldb_source_path(), 'scripts')) patches = [f for f in files if fnmatch.fnmatch(f, spec['name'] + '.*.diff')] for p in patches: run_in_directory(["patch", "-p0", "-i", os.path.join(lldb_source_path(), 'scripts', p)], spec['root']) def check_out_if_needed(spec): if not os.path.isdir(spec['root']): vcs(spec).check_out() apply_patches(spec) def all_check_out_if_needed (): map (check_out_if_needed, XCODE_REPOSITORIES()) def should_build_llvm (): if build_type() == BuildType.Xcode: # TODO use md5 sums return True def do_symlink (source_path, link_path): print "Symlinking " + source_path + " to " + link_path if not os.path.exists(link_path): os.symlink(source_path, link_path) def setup_source_symlink (repo): source_path = repo["root"] link_path = os.path.join(lldb_source_path(), os.path.basename(source_path)) do_symlink(source_path, link_path) def setup_source_symlinks (): map(setup_source_symlink, XCODE_REPOSITORIES()) def setup_build_symlink (): # We don't use the build symlinks in llvm.org Xcode-based builds. if build_type() != BuildType.Xcode: source_path = package_build_path() link_path = expected_package_build_path() do_symlink(source_path, link_path) def should_run_cmake (cmake_build_dir): # We need to run cmake if our llvm build directory doesn't yet exist. if not os.path.exists(cmake_build_dir): return True # Wee also need to run cmake if for some reason we don't have a ninja # build file. (Perhaps the cmake invocation failed, which this current # build may have fixed). ninja_path = os.path.join(cmake_build_dir, "build.ninja") return not os.path.exists(ninja_path) def cmake_environment (): cmake_env = join_dicts(os.environ, CMAKE_ENVIRONMENT()) return cmake_env def is_executable(path): return os.path.isfile(path) and os.access(path, os.X_OK) def find_executable_in_paths (program, paths_to_check): program_dir, program_name = os.path.split(program) if program_dir: if is_executable(program): return program else: for path_dir in paths_to_check: path_dir = path_dir.strip('"') executable_file = os.path.join(path_dir, program) if is_executable(executable_file): return executable_file return None def find_cmake (): # First check the system PATH env var for cmake cmake_binary = find_executable_in_paths("cmake", os.environ["PATH"].split(os.pathsep)) if cmake_binary: # We found it there, use it. return cmake_binary # Check a few more common spots. Xcode launched from Finder # will have the default environment, and may not have # all the normal places present. extra_cmake_dirs = [ "/usr/local/bin", "/opt/local/bin", os.path.join(os.path.expanduser("~"), "bin") ] if platform.system() == "Darwin": # Add locations where an official CMake.app package may be installed. extra_cmake_dirs.extend([ os.path.join( os.path.expanduser("~"), "Applications", "CMake.app", "Contents", "bin"), os.path.join( os.sep, "Applications", "CMake.app", "Contents", "bin")]) cmake_binary = find_executable_in_paths("cmake", extra_cmake_dirs) if cmake_binary: # We found it in one of the usual places. Use that. return cmake_binary # We couldn't find cmake. Tell the user what to do. raise Exception( "could not find cmake in PATH ({}) or in any of these locations ({}), " "please install cmake or add a link to it in one of those locations".format( os.environ["PATH"], extra_cmake_dirs)) def cmake_flags (): cmake_flags = CMAKE_FLAGS()[lldb_configuration()] cmake_flags += [ "-GNinja", "-DCMAKE_C_COMPILER={}".format(get_c_compiler()), "-DCMAKE_CXX_COMPILER={}".format(get_cxx_compiler()), "-DCMAKE_INSTALL_PREFIX={}".format(expected_package_build_path_for("llvm")), "-DCMAKE_C_FLAGS={}".format(get_c_flags()), "-DCMAKE_CXX_FLAGS={}".format(get_cxx_flags()), "-DCMAKE_EXE_LINKER_FLAGS={}".format(get_exe_linker_flags()), "-DCMAKE_SHARED_LINKER_FLAGS={}".format(get_shared_linker_flags()) ] deployment_target = get_deployment_target() if deployment_target: cmake_flags.append("-DCMAKE_OSX_DEPLOYMENT_TARGET={}".format(deployment_target)) return cmake_flags def run_cmake (cmake_build_dir, ninja_binary_path): cmake_binary = find_cmake() print "found cmake binary: using \"{}\"".format(cmake_binary) command_line = [cmake_binary] + cmake_flags() + [ "-DCMAKE_MAKE_PROGRAM={}".format(ninja_binary_path), llvm_source_path()] print "running cmake like so: ({}) in dir ({})".format(command_line, cmake_build_dir) subprocess.check_call(command_line, cwd=cmake_build_dir, env=cmake_environment()) def create_directories_as_needed (path): try: os.makedirs(path) except OSError as error: # An error indicating that the directory exists already is fine. # Anything else should be passed along. if error.errno != errno.EEXIST: raise error def run_cmake_if_needed (ninja_binary_path): cmake_build_dir = package_build_path() if should_run_cmake(cmake_build_dir): # Create the build directory as needed create_directories_as_needed (cmake_build_dir) run_cmake(cmake_build_dir, ninja_binary_path) def build_ninja_if_needed (): # First check if ninja is in our path. If so, there's nothing to do. ninja_binary_path = find_executable_in_paths("ninja", os.environ["PATH"].split(os.pathsep)) if ninja_binary_path: # It's on the path. cmake will find it. We're good. print "found ninja here: \"{}\"".format(ninja_binary_path) return ninja_binary_path # Figure out if we need to build it. ninja_build_dir = ninja_source_path() ninja_binary_path = os.path.join(ninja_build_dir, "ninja") if not is_executable(ninja_binary_path): # Build ninja command_line = ["python", "configure.py", "--bootstrap"] print "building ninja like so: ({}) in dir ({})".format(command_line, ninja_build_dir) subprocess.check_call(command_line, cwd=ninja_build_dir, env=os.environ) return ninja_binary_path def join_dicts (dict1, dict2): d = dict1.copy() d.update(dict2) return d def build_llvm (ninja_binary_path): cmake_build_dir = package_build_path() subprocess.check_call([ninja_binary_path], cwd=cmake_build_dir, env=cmake_environment()) def build_llvm_if_needed (): if should_build_llvm(): ninja_binary_path = build_ninja_if_needed() run_cmake_if_needed(ninja_binary_path) build_llvm(ninja_binary_path) setup_build_symlink() #### MAIN LOGIC #### all_check_out_if_needed() build_llvm_if_needed() write_archives_txt() sys.exit(0) Index: vendor/lldb/dist/source/Host/common/File.cpp =================================================================== --- vendor/lldb/dist/source/Host/common/File.cpp (revision 304307) +++ vendor/lldb/dist/source/Host/common/File.cpp (revision 304308) @@ -1,1061 +1,1061 @@ //===-- File.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/File.h" #include #include #include #include #include #ifdef _WIN32 #include "lldb/Host/windows/windows.h" #else #include #endif #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Process.h" // for llvm::sys::Process::FileDescriptorHasColors() #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/Error.h" #include "lldb/Core/Log.h" #include "lldb/Host/Config.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" using namespace lldb; using namespace lldb_private; static const char * GetStreamOpenModeFromOptions (uint32_t options) { if (options & File::eOpenOptionAppend) { if (options & File::eOpenOptionRead) { if (options & File::eOpenOptionCanCreateNewOnly) return "a+x"; else return "a+"; } else if (options & File::eOpenOptionWrite) { if (options & File::eOpenOptionCanCreateNewOnly) return "ax"; else return "a"; } } else if (options & File::eOpenOptionRead && options & File::eOpenOptionWrite) { if (options & File::eOpenOptionCanCreate) { if (options & File::eOpenOptionCanCreateNewOnly) return "w+x"; else return "w+"; } else return "r+"; } else if (options & File::eOpenOptionRead) { return "r"; } else if (options & File::eOpenOptionWrite) { return "w"; } return NULL; } int File::kInvalidDescriptor = -1; FILE * File::kInvalidStream = NULL; File::File(const char *path, uint32_t options, uint32_t permissions) : IOObject(eFDTypeFile, false), m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (), m_own_stream (false), m_is_interactive (eLazyBoolCalculate), m_is_real_terminal (eLazyBoolCalculate) { Open (path, options, permissions); } File::File (const FileSpec& filespec, uint32_t options, uint32_t permissions) : IOObject(eFDTypeFile, false), m_descriptor (kInvalidDescriptor), m_stream (kInvalidStream), m_options (0), m_own_stream (false), m_is_interactive (eLazyBoolCalculate), m_is_real_terminal (eLazyBoolCalculate) { if (filespec) { Open (filespec.GetPath().c_str(), options, permissions); } } File::~File() { Close (); } int File::GetDescriptor() const { if (DescriptorIsValid()) return m_descriptor; // Don't open the file descriptor if we don't need to, just get it from the // stream if we have one. if (StreamIsValid()) { #if defined(LLVM_ON_WIN32) return _fileno(m_stream); #else return fileno(m_stream); #endif } // Invalid descriptor and invalid stream, return invalid descriptor. return kInvalidDescriptor; } IOObject::WaitableHandle File::GetWaitableHandle() { return m_descriptor; } void File::SetDescriptor (int fd, bool transfer_ownership) { if (IsValid()) Close(); m_descriptor = fd; m_should_close_fd = transfer_ownership; } FILE * File::GetStream () { if (!StreamIsValid()) { if (DescriptorIsValid()) { const char *mode = GetStreamOpenModeFromOptions (m_options); if (mode) { if (!m_should_close_fd) { // We must duplicate the file descriptor if we don't own it because // when you call fdopen, the stream will own the fd #ifdef _WIN32 m_descriptor = ::_dup(GetDescriptor()); #else m_descriptor = dup(GetDescriptor()); #endif m_should_close_fd = true; } do { m_stream = ::fdopen (m_descriptor, mode); } while (m_stream == NULL && errno == EINTR); // If we got a stream, then we own the stream and should no // longer own the descriptor because fclose() will close it for us if (m_stream) { m_own_stream = true; m_should_close_fd = false; } } } } return m_stream; } void File::SetStream (FILE *fh, bool transfer_ownership) { if (IsValid()) Close(); m_stream = fh; m_own_stream = transfer_ownership; } Error File::Open (const char *path, uint32_t options, uint32_t permissions) { Error error; if (IsValid()) Close (); int oflag = 0; const bool read = options & eOpenOptionRead; const bool write = options & eOpenOptionWrite; if (write) { if (read) oflag |= O_RDWR; else oflag |= O_WRONLY; if (options & eOpenOptionAppend) oflag |= O_APPEND; if (options & eOpenOptionTruncate) oflag |= O_TRUNC; if (options & eOpenOptionCanCreate) oflag |= O_CREAT; if (options & eOpenOptionCanCreateNewOnly) oflag |= O_CREAT | O_EXCL; } else if (read) { oflag |= O_RDONLY; #ifndef _WIN32 if (options & eOpenOptionDontFollowSymlinks) oflag |= O_NOFOLLOW; #endif } #ifndef _WIN32 if (options & eOpenOptionNonBlocking) oflag |= O_NONBLOCK; if (options & eOpenOptionCloseOnExec) oflag |= O_CLOEXEC; #else oflag |= O_BINARY; #endif mode_t mode = 0; if (oflag & O_CREAT) { if (permissions & lldb::eFilePermissionsUserRead) mode |= S_IRUSR; if (permissions & lldb::eFilePermissionsUserWrite) mode |= S_IWUSR; if (permissions & lldb::eFilePermissionsUserExecute) mode |= S_IXUSR; if (permissions & lldb::eFilePermissionsGroupRead) mode |= S_IRGRP; if (permissions & lldb::eFilePermissionsGroupWrite) mode |= S_IWGRP; if (permissions & lldb::eFilePermissionsGroupExecute) mode |= S_IXGRP; if (permissions & lldb::eFilePermissionsWorldRead) mode |= S_IROTH; if (permissions & lldb::eFilePermissionsWorldWrite) mode |= S_IWOTH; if (permissions & lldb::eFilePermissionsWorldExecute) mode |= S_IXOTH; } do { #ifdef _WIN32 std::wstring wpath; if (!llvm::ConvertUTF8toWide(path, wpath)) { m_descriptor = -1; error.SetErrorString("Error converting path to UTF-16"); return error; } ::_wsopen_s(&m_descriptor, wpath.c_str(), oflag, _SH_DENYNO, mode); #else m_descriptor = ::open(path, oflag, mode); #endif } while (m_descriptor < 0 && errno == EINTR); if (!DescriptorIsValid()) error.SetErrorToErrno(); else { m_should_close_fd = true; m_options = options; } return error; } uint32_t File::GetPermissions(const FileSpec &file_spec, Error &error) { if (file_spec) { struct stat file_stats; int stat_result = FileSystem::Stat(file_spec.GetCString(), &file_stats); if (stat_result == -1) error.SetErrorToErrno(); else { error.Clear(); return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } } else error.SetErrorString ("empty file spec"); return 0; } uint32_t File::GetPermissions(Error &error) const { int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { struct stat file_stats; if (::fstat (fd, &file_stats) == -1) error.SetErrorToErrno(); else { error.Clear(); return file_stats.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); } } else { error.SetErrorString ("invalid file descriptor"); } return 0; } Error File::Close () { Error error; if (StreamIsValid() && m_own_stream) { if (::fclose (m_stream) == EOF) error.SetErrorToErrno(); } if (DescriptorIsValid() && m_should_close_fd) { if (::close (m_descriptor) != 0) error.SetErrorToErrno(); } m_descriptor = kInvalidDescriptor; m_stream = kInvalidStream; m_options = 0; m_own_stream = false; m_should_close_fd = false; m_is_interactive = eLazyBoolCalculate; m_is_real_terminal = eLazyBoolCalculate; return error; } void File::Clear () { m_stream = nullptr; m_descriptor = -1; m_options = 0; m_own_stream = false; m_is_interactive = m_supports_colors = m_is_real_terminal = eLazyBoolCalculate; } Error File::GetFileSpec (FileSpec &file_spec) const { Error error; #ifdef LLDB_CONFIG_FCNTL_GETPATH_SUPPORTED if (IsValid ()) { char path[PATH_MAX]; if (::fcntl(GetDescriptor(), F_GETPATH, path) == -1) error.SetErrorToErrno(); else file_spec.SetFile (path, false); } else { error.SetErrorString("invalid file handle"); } #elif defined(__linux__) char proc[64]; char path[PATH_MAX]; if (::snprintf(proc, sizeof(proc), "/proc/self/fd/%d", GetDescriptor()) < 0) error.SetErrorString ("cannot resolve file descriptor"); else { ssize_t len; if ((len = ::readlink(proc, path, sizeof(path) - 1)) == -1) error.SetErrorToErrno(); else { path[len] = '\0'; file_spec.SetFile (path, false); } } #else error.SetErrorString ("File::GetFileSpec is not supported on this platform"); #endif if (error.Fail()) file_spec.Clear(); return error; } off_t File::SeekFromStart (off_t offset, Error *error_ptr) { off_t result = 0; if (DescriptorIsValid()) { result = ::lseek (m_descriptor, offset, SEEK_SET); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (StreamIsValid ()) { result = ::fseek(m_stream, offset, SEEK_SET); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (error_ptr) { error_ptr->SetErrorString("invalid file handle"); } return result; } off_t File::SeekFromCurrent (off_t offset, Error *error_ptr) { off_t result = -1; if (DescriptorIsValid()) { result = ::lseek (m_descriptor, offset, SEEK_CUR); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (StreamIsValid ()) { result = ::fseek(m_stream, offset, SEEK_CUR); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (error_ptr) { error_ptr->SetErrorString("invalid file handle"); } return result; } off_t File::SeekFromEnd (off_t offset, Error *error_ptr) { off_t result = -1; if (DescriptorIsValid()) { result = ::lseek (m_descriptor, offset, SEEK_END); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (StreamIsValid ()) { result = ::fseek(m_stream, offset, SEEK_END); if (error_ptr) { if (result == -1) error_ptr->SetErrorToErrno(); else error_ptr->Clear(); } } else if (error_ptr) { error_ptr->SetErrorString("invalid file handle"); } return result; } Error File::Flush () { Error error; if (StreamIsValid()) { int err = 0; do { err = ::fflush (m_stream); } while (err == EOF && errno == EINTR); if (err == EOF) error.SetErrorToErrno(); } else if (!DescriptorIsValid()) { error.SetErrorString("invalid file handle"); } return error; } Error File::Sync () { Error error; if (DescriptorIsValid()) { #ifdef _WIN32 int err = FlushFileBuffers((HANDLE)_get_osfhandle(m_descriptor)); if (err == 0) error.SetErrorToGenericError(); #else int err = 0; do { err = ::fsync (m_descriptor); } while (err == -1 && errno == EINTR); if (err == -1) error.SetErrorToErrno(); #endif } else { error.SetErrorString("invalid file handle"); } return error; } #if defined (__APPLE__) // Darwin kernels only can read/write <= INT_MAX bytes #define MAX_READ_SIZE INT_MAX #define MAX_WRITE_SIZE INT_MAX #endif Error File::Read (void *buf, size_t &num_bytes) { Error error; #if defined (MAX_READ_SIZE) if (num_bytes > MAX_READ_SIZE) { uint8_t *p = (uint8_t *)buf; size_t bytes_left = num_bytes; // Init the num_bytes read to zero num_bytes = 0; while (bytes_left > 0) { size_t curr_num_bytes; if (bytes_left > MAX_READ_SIZE) curr_num_bytes = MAX_READ_SIZE; else curr_num_bytes = bytes_left; error = Read (p + num_bytes, curr_num_bytes); // Update how many bytes were read num_bytes += curr_num_bytes; if (bytes_left < curr_num_bytes) bytes_left = 0; else bytes_left -= curr_num_bytes; if (error.Fail()) break; } return error; } #endif ssize_t bytes_read = -1; if (DescriptorIsValid()) { do { bytes_read = ::read (m_descriptor, buf, num_bytes); } while (bytes_read < 0 && errno == EINTR); if (bytes_read == -1) { error.SetErrorToErrno(); num_bytes = 0; } else num_bytes = bytes_read; } else if (StreamIsValid()) { bytes_read = ::fread (buf, 1, num_bytes, m_stream); if (bytes_read == 0) { if (::feof(m_stream)) error.SetErrorString ("feof"); else if (::ferror (m_stream)) error.SetErrorString ("ferror"); num_bytes = 0; } else num_bytes = bytes_read; } else { num_bytes = 0; error.SetErrorString("invalid file handle"); } return error; } Error File::Write (const void *buf, size_t &num_bytes) { Error error; #if defined (MAX_WRITE_SIZE) if (num_bytes > MAX_WRITE_SIZE) { const uint8_t *p = (const uint8_t *)buf; size_t bytes_left = num_bytes; // Init the num_bytes written to zero num_bytes = 0; while (bytes_left > 0) { size_t curr_num_bytes; if (bytes_left > MAX_WRITE_SIZE) curr_num_bytes = MAX_WRITE_SIZE; else curr_num_bytes = bytes_left; error = Write (p + num_bytes, curr_num_bytes); // Update how many bytes were read num_bytes += curr_num_bytes; if (bytes_left < curr_num_bytes) bytes_left = 0; else bytes_left -= curr_num_bytes; if (error.Fail()) break; } return error; } #endif ssize_t bytes_written = -1; if (DescriptorIsValid()) { do { bytes_written = ::write (m_descriptor, buf, num_bytes); } while (bytes_written < 0 && errno == EINTR); if (bytes_written == -1) { error.SetErrorToErrno(); num_bytes = 0; } else num_bytes = bytes_written; } else if (StreamIsValid()) { bytes_written = ::fwrite (buf, 1, num_bytes, m_stream); if (bytes_written == 0) { if (::feof(m_stream)) error.SetErrorString ("feof"); else if (::ferror (m_stream)) error.SetErrorString ("ferror"); num_bytes = 0; } else num_bytes = bytes_written; } else { num_bytes = 0; error.SetErrorString("invalid file handle"); } return error; } Error File::Read (void *buf, size_t &num_bytes, off_t &offset) { Error error; #if defined (MAX_READ_SIZE) if (num_bytes > MAX_READ_SIZE) { uint8_t *p = (uint8_t *)buf; size_t bytes_left = num_bytes; // Init the num_bytes read to zero num_bytes = 0; while (bytes_left > 0) { size_t curr_num_bytes; if (bytes_left > MAX_READ_SIZE) curr_num_bytes = MAX_READ_SIZE; else curr_num_bytes = bytes_left; error = Read (p + num_bytes, curr_num_bytes, offset); // Update how many bytes were read num_bytes += curr_num_bytes; if (bytes_left < curr_num_bytes) bytes_left = 0; else bytes_left -= curr_num_bytes; if (error.Fail()) break; } return error; } #endif #ifndef _WIN32 int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { ssize_t bytes_read = -1; do { bytes_read = ::pread (fd, buf, num_bytes, offset); } while (bytes_read < 0 && errno == EINTR); if (bytes_read < 0) { num_bytes = 0; error.SetErrorToErrno(); } else { offset += bytes_read; num_bytes = bytes_read; } } else { num_bytes = 0; error.SetErrorString("invalid file handle"); } #else long cur = ::lseek(m_descriptor, 0, SEEK_CUR); SeekFromStart(offset); error = Read(buf, num_bytes); if (!error.Fail()) SeekFromStart(cur); #endif return error; } Error File::Read (size_t &num_bytes, off_t &offset, bool null_terminate, DataBufferSP &data_buffer_sp) { Error error; if (num_bytes > 0) { int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { struct stat file_stats; if (::fstat (fd, &file_stats) == 0) { if (file_stats.st_size > offset) { const size_t bytes_left = file_stats.st_size - offset; if (num_bytes > bytes_left) num_bytes = bytes_left; size_t num_bytes_plus_nul_char = num_bytes + (null_terminate ? 1 : 0); std::unique_ptr data_heap_ap; data_heap_ap.reset(new DataBufferHeap()); data_heap_ap->SetByteSize(num_bytes_plus_nul_char); if (data_heap_ap.get()) { error = Read (data_heap_ap->GetBytes(), num_bytes, offset); if (error.Success()) { // Make sure we read exactly what we asked for and if we got // less, adjust the array if (num_bytes_plus_nul_char < data_heap_ap->GetByteSize()) data_heap_ap->SetByteSize(num_bytes_plus_nul_char); data_buffer_sp.reset(data_heap_ap.release()); return error; } } } else error.SetErrorString("file is empty"); } else error.SetErrorToErrno(); } else error.SetErrorString("invalid file handle"); } else error.SetErrorString("invalid file handle"); num_bytes = 0; data_buffer_sp.reset(); return error; } Error File::Write (const void *buf, size_t &num_bytes, off_t &offset) { Error error; #if defined (MAX_WRITE_SIZE) if (num_bytes > MAX_WRITE_SIZE) { const uint8_t *p = (const uint8_t *)buf; size_t bytes_left = num_bytes; // Init the num_bytes written to zero num_bytes = 0; while (bytes_left > 0) { size_t curr_num_bytes; if (bytes_left > MAX_WRITE_SIZE) curr_num_bytes = MAX_WRITE_SIZE; else curr_num_bytes = bytes_left; error = Write (p + num_bytes, curr_num_bytes, offset); // Update how many bytes were read num_bytes += curr_num_bytes; if (bytes_left < curr_num_bytes) bytes_left = 0; else bytes_left -= curr_num_bytes; if (error.Fail()) break; } return error; } #endif int fd = GetDescriptor(); if (fd != kInvalidDescriptor) { #ifndef _WIN32 ssize_t bytes_written = -1; do { bytes_written = ::pwrite (m_descriptor, buf, num_bytes, offset); } while (bytes_written < 0 && errno == EINTR); if (bytes_written < 0) { num_bytes = 0; error.SetErrorToErrno(); } else { offset += bytes_written; num_bytes = bytes_written; } #else long cur = ::lseek(m_descriptor, 0, SEEK_CUR); error = Write(buf, num_bytes); long after = ::lseek(m_descriptor, 0, SEEK_CUR); if (!error.Fail()) SeekFromStart(cur); offset = after; #endif } else { num_bytes = 0; error.SetErrorString("invalid file handle"); } return error; } //------------------------------------------------------------------ // Print some formatted output to the stream. //------------------------------------------------------------------ size_t File::Printf (const char *format, ...) { va_list args; va_start (args, format); size_t result = PrintfVarArg (format, args); va_end (args); return result; } //------------------------------------------------------------------ // Print some formatted output to the stream. //------------------------------------------------------------------ size_t File::PrintfVarArg (const char *format, va_list args) { size_t result = 0; if (DescriptorIsValid()) { char *s = NULL; result = vasprintf(&s, format, args); if (s != NULL) { if (result > 0) { size_t s_len = result; Write (s, s_len); result = s_len; } free (s); } } else if (StreamIsValid()) { result = ::vfprintf (m_stream, format, args); } return result; } mode_t File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options) { mode_t mode = 0; if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite) mode |= O_RDWR; else if (open_options & eOpenOptionWrite) mode |= O_WRONLY; if (open_options & eOpenOptionAppend) mode |= O_APPEND; if (open_options & eOpenOptionTruncate) mode |= O_TRUNC; if (open_options & eOpenOptionNonBlocking) mode |= O_NONBLOCK; if (open_options & eOpenOptionCanCreateNewOnly) mode |= O_CREAT | O_EXCL; else if (open_options & eOpenOptionCanCreate) mode |= O_CREAT; return mode; } void File::CalculateInteractiveAndTerminal () { const int fd = GetDescriptor(); if (fd >= 0) { m_is_interactive = eLazyBoolNo; m_is_real_terminal = eLazyBoolNo; -#if (defined(_WIN32) || defined(__ANDROID_NDK__)) +#if defined(_WIN32) if (_isatty(fd)) { m_is_interactive = eLazyBoolYes; m_is_real_terminal = eLazyBoolYes; } #else if (isatty(fd)) { m_is_interactive = eLazyBoolYes; struct winsize window_size; if (::ioctl (fd, TIOCGWINSZ, &window_size) == 0) { if (window_size.ws_col > 0) { m_is_real_terminal = eLazyBoolYes; if (llvm::sys::Process::FileDescriptorHasColors(fd)) m_supports_colors = eLazyBoolYes; } } } #endif } } bool File::GetIsInteractive () { if (m_is_interactive == eLazyBoolCalculate) CalculateInteractiveAndTerminal (); return m_is_interactive == eLazyBoolYes; } bool File::GetIsRealTerminal () { if (m_is_real_terminal == eLazyBoolCalculate) CalculateInteractiveAndTerminal(); return m_is_real_terminal == eLazyBoolYes; } bool File::GetIsTerminalWithColors () { if (m_supports_colors == eLazyBoolCalculate) CalculateInteractiveAndTerminal(); return m_supports_colors == eLazyBoolYes; } Index: vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp (revision 304308) @@ -1,2776 +1,2900 @@ //===-- EmulateInstructionMIPS.cpp -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "EmulateInstructionMIPS.h" #include #include "llvm-c/Disassembler.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCContext.h" #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Stream.h" #include "lldb/Symbol/UnwindPlan.h" #include "lldb/Target/Target.h" #include "llvm/ADT/STLExtras.h" #include "Plugins/Process/Utility/InstructionUtils.h" #include "Plugins/Process/Utility/RegisterContext_mips.h" //mips32 has same registers nos as mips64 using namespace lldb; using namespace lldb_private; #define UInt(x) ((uint64_t)x) #define integer int64_t //---------------------------------------------------------------------- // // EmulateInstructionMIPS implementation // //---------------------------------------------------------------------- #ifdef __mips__ extern "C" { void LLVMInitializeMipsTargetInfo (); void LLVMInitializeMipsTarget (); void LLVMInitializeMipsAsmPrinter (); void LLVMInitializeMipsTargetMC (); void LLVMInitializeMipsDisassembler (); } #endif EmulateInstructionMIPS::EmulateInstructionMIPS (const lldb_private::ArchSpec &arch) : EmulateInstruction (arch) { /* Create instance of llvm::MCDisassembler */ std::string Error; llvm::Triple triple = arch.GetTriple(); const llvm::Target *target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); /* * If we fail to get the target then we haven't registered it. The SystemInitializerCommon * does not initialize targets, MCs and disassemblers. However we need the MCDisassembler * to decode the instructions so that the decoding complexity stays with LLVM. * Initialize the MIPS targets and disassemblers. */ #ifdef __mips__ if (!target) { LLVMInitializeMipsTargetInfo (); LLVMInitializeMipsTarget (); LLVMInitializeMipsAsmPrinter (); LLVMInitializeMipsTargetMC (); LLVMInitializeMipsDisassembler (); target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); } #endif assert (target); llvm::StringRef cpu; switch (arch.GetCore()) { case ArchSpec::eCore_mips32: case ArchSpec::eCore_mips32el: cpu = "mips32"; break; case ArchSpec::eCore_mips32r2: case ArchSpec::eCore_mips32r2el: cpu = "mips32r2"; break; case ArchSpec::eCore_mips32r3: case ArchSpec::eCore_mips32r3el: cpu = "mips32r3"; break; case ArchSpec::eCore_mips32r5: case ArchSpec::eCore_mips32r5el: cpu = "mips32r5"; break; case ArchSpec::eCore_mips32r6: case ArchSpec::eCore_mips32r6el: cpu = "mips32r6"; break; case ArchSpec::eCore_mips64: case ArchSpec::eCore_mips64el: cpu = "mips64"; break; case ArchSpec::eCore_mips64r2: case ArchSpec::eCore_mips64r2el: cpu = "mips64r2"; break; case ArchSpec::eCore_mips64r3: case ArchSpec::eCore_mips64r3el: cpu = "mips64r3"; break; case ArchSpec::eCore_mips64r5: case ArchSpec::eCore_mips64r5el: cpu = "mips64r5"; break; case ArchSpec::eCore_mips64r6: case ArchSpec::eCore_mips64r6el: cpu = "mips64r6"; break; default: cpu = "generic"; break; } std::string features = ""; uint32_t arch_flags = arch.GetFlags (); if (arch_flags & ArchSpec::eMIPSAse_msa) features += "+msa,"; if (arch_flags & ArchSpec::eMIPSAse_dsp) features += "+dsp,"; if (arch_flags & ArchSpec::eMIPSAse_dspr2) features += "+dspr2,"; m_reg_info.reset (target->createMCRegInfo (triple.getTriple())); assert (m_reg_info.get()); m_insn_info.reset (target->createMCInstrInfo()); assert (m_insn_info.get()); m_asm_info.reset (target->createMCAsmInfo (*m_reg_info, triple.getTriple())); m_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, features)); assert (m_asm_info.get() && m_subtype_info.get()); m_context.reset (new llvm::MCContext (m_asm_info.get(), m_reg_info.get(), nullptr)); assert (m_context.get()); m_disasm.reset (target->createMCDisassembler (*m_subtype_info, *m_context)); assert (m_disasm.get()); /* Create alternate disassembler for microMIPS */ if (arch_flags & ArchSpec::eMIPSAse_mips16) features += "+mips16,"; else if (arch_flags & ArchSpec::eMIPSAse_micromips) features += "+micromips,"; m_alt_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, features)); assert (m_alt_subtype_info.get()); m_alt_disasm.reset (target->createMCDisassembler (*m_alt_subtype_info, *m_context)); assert (m_alt_disasm.get()); m_next_inst_size = 0; m_use_alt_disaasm = false; } void EmulateInstructionMIPS::Initialize () { PluginManager::RegisterPlugin (GetPluginNameStatic (), GetPluginDescriptionStatic (), CreateInstance); } void EmulateInstructionMIPS::Terminate () { PluginManager::UnregisterPlugin (CreateInstance); } ConstString EmulateInstructionMIPS::GetPluginNameStatic () { ConstString g_plugin_name ("lldb.emulate-instruction.mips32"); return g_plugin_name; } lldb_private::ConstString EmulateInstructionMIPS::GetPluginName() { static ConstString g_plugin_name ("EmulateInstructionMIPS"); return g_plugin_name; } const char * EmulateInstructionMIPS::GetPluginDescriptionStatic () { return "Emulate instructions for the MIPS32 architecture."; } EmulateInstruction * EmulateInstructionMIPS::CreateInstance (const ArchSpec &arch, InstructionType inst_type) { if (EmulateInstructionMIPS::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) { if (arch.GetTriple().getArch() == llvm::Triple::mips || arch.GetTriple().getArch() == llvm::Triple::mipsel) { std::auto_ptr emulate_insn_ap (new EmulateInstructionMIPS (arch)); if (emulate_insn_ap.get()) return emulate_insn_ap.release(); } } return NULL; } bool EmulateInstructionMIPS::SetTargetTriple (const ArchSpec &arch) { if (arch.GetTriple().getArch () == llvm::Triple::mips || arch.GetTriple().getArch () == llvm::Triple::mipsel) return true; return false; } const char * EmulateInstructionMIPS::GetRegisterName (unsigned reg_num, bool alternate_name) { if (alternate_name) { switch (reg_num) { case dwarf_sp_mips: return "r29"; case dwarf_r30_mips: return "r30"; case dwarf_ra_mips: return "r31"; case dwarf_f0_mips: return "f0"; case dwarf_f1_mips: return "f1"; case dwarf_f2_mips: return "f2"; case dwarf_f3_mips: return "f3"; case dwarf_f4_mips: return "f4"; case dwarf_f5_mips: return "f5"; case dwarf_f6_mips: return "f6"; case dwarf_f7_mips: return "f7"; case dwarf_f8_mips: return "f8"; case dwarf_f9_mips: return "f9"; case dwarf_f10_mips: return "f10"; case dwarf_f11_mips: return "f11"; case dwarf_f12_mips: return "f12"; case dwarf_f13_mips: return "f13"; case dwarf_f14_mips: return "f14"; case dwarf_f15_mips: return "f15"; case dwarf_f16_mips: return "f16"; case dwarf_f17_mips: return "f17"; case dwarf_f18_mips: return "f18"; case dwarf_f19_mips: return "f19"; case dwarf_f20_mips: return "f20"; case dwarf_f21_mips: return "f21"; case dwarf_f22_mips: return "f22"; case dwarf_f23_mips: return "f23"; case dwarf_f24_mips: return "f24"; case dwarf_f25_mips: return "f25"; case dwarf_f26_mips: return "f26"; case dwarf_f27_mips: return "f27"; case dwarf_f28_mips: return "f28"; case dwarf_f29_mips: return "f29"; case dwarf_f30_mips: return "f30"; case dwarf_f31_mips: return "f31"; case dwarf_w0_mips: return "w0"; case dwarf_w1_mips: return "w1"; case dwarf_w2_mips: return "w2"; case dwarf_w3_mips: return "w3"; case dwarf_w4_mips: return "w4"; case dwarf_w5_mips: return "w5"; case dwarf_w6_mips: return "w6"; case dwarf_w7_mips: return "w7"; case dwarf_w8_mips: return "w8"; case dwarf_w9_mips: return "w9"; case dwarf_w10_mips: return "w10"; case dwarf_w11_mips: return "w11"; case dwarf_w12_mips: return "w12"; case dwarf_w13_mips: return "w13"; case dwarf_w14_mips: return "w14"; case dwarf_w15_mips: return "w15"; case dwarf_w16_mips: return "w16"; case dwarf_w17_mips: return "w17"; case dwarf_w18_mips: return "w18"; case dwarf_w19_mips: return "w19"; case dwarf_w20_mips: return "w20"; case dwarf_w21_mips: return "w21"; case dwarf_w22_mips: return "w22"; case dwarf_w23_mips: return "w23"; case dwarf_w24_mips: return "w24"; case dwarf_w25_mips: return "w25"; case dwarf_w26_mips: return "w26"; case dwarf_w27_mips: return "w27"; case dwarf_w28_mips: return "w28"; case dwarf_w29_mips: return "w29"; case dwarf_w30_mips: return "w30"; case dwarf_w31_mips: return "w31"; case dwarf_mir_mips: return "mir"; case dwarf_mcsr_mips: return "mcsr"; case dwarf_config5_mips: return "config5"; default: break; } return nullptr; } switch (reg_num) { case dwarf_zero_mips: return "r0"; case dwarf_r1_mips: return "r1"; case dwarf_r2_mips: return "r2"; case dwarf_r3_mips: return "r3"; case dwarf_r4_mips: return "r4"; case dwarf_r5_mips: return "r5"; case dwarf_r6_mips: return "r6"; case dwarf_r7_mips: return "r7"; case dwarf_r8_mips: return "r8"; case dwarf_r9_mips: return "r9"; case dwarf_r10_mips: return "r10"; case dwarf_r11_mips: return "r11"; case dwarf_r12_mips: return "r12"; case dwarf_r13_mips: return "r13"; case dwarf_r14_mips: return "r14"; case dwarf_r15_mips: return "r15"; case dwarf_r16_mips: return "r16"; case dwarf_r17_mips: return "r17"; case dwarf_r18_mips: return "r18"; case dwarf_r19_mips: return "r19"; case dwarf_r20_mips: return "r20"; case dwarf_r21_mips: return "r21"; case dwarf_r22_mips: return "r22"; case dwarf_r23_mips: return "r23"; case dwarf_r24_mips: return "r24"; case dwarf_r25_mips: return "r25"; case dwarf_r26_mips: return "r26"; case dwarf_r27_mips: return "r27"; case dwarf_gp_mips: return "gp"; case dwarf_sp_mips: return "sp"; case dwarf_r30_mips: return "fp"; case dwarf_ra_mips: return "ra"; case dwarf_sr_mips: return "sr"; case dwarf_lo_mips: return "lo"; case dwarf_hi_mips: return "hi"; case dwarf_bad_mips: return "bad"; case dwarf_cause_mips: return "cause"; case dwarf_pc_mips: return "pc"; case dwarf_f0_mips: return "f0"; case dwarf_f1_mips: return "f1"; case dwarf_f2_mips: return "f2"; case dwarf_f3_mips: return "f3"; case dwarf_f4_mips: return "f4"; case dwarf_f5_mips: return "f5"; case dwarf_f6_mips: return "f6"; case dwarf_f7_mips: return "f7"; case dwarf_f8_mips: return "f8"; case dwarf_f9_mips: return "f9"; case dwarf_f10_mips: return "f10"; case dwarf_f11_mips: return "f11"; case dwarf_f12_mips: return "f12"; case dwarf_f13_mips: return "f13"; case dwarf_f14_mips: return "f14"; case dwarf_f15_mips: return "f15"; case dwarf_f16_mips: return "f16"; case dwarf_f17_mips: return "f17"; case dwarf_f18_mips: return "f18"; case dwarf_f19_mips: return "f19"; case dwarf_f20_mips: return "f20"; case dwarf_f21_mips: return "f21"; case dwarf_f22_mips: return "f22"; case dwarf_f23_mips: return "f23"; case dwarf_f24_mips: return "f24"; case dwarf_f25_mips: return "f25"; case dwarf_f26_mips: return "f26"; case dwarf_f27_mips: return "f27"; case dwarf_f28_mips: return "f28"; case dwarf_f29_mips: return "f29"; case dwarf_f30_mips: return "f30"; case dwarf_f31_mips: return "f31"; case dwarf_fcsr_mips: return "fcsr"; case dwarf_fir_mips: return "fir"; case dwarf_w0_mips: return "w0"; case dwarf_w1_mips: return "w1"; case dwarf_w2_mips: return "w2"; case dwarf_w3_mips: return "w3"; case dwarf_w4_mips: return "w4"; case dwarf_w5_mips: return "w5"; case dwarf_w6_mips: return "w6"; case dwarf_w7_mips: return "w7"; case dwarf_w8_mips: return "w8"; case dwarf_w9_mips: return "w9"; case dwarf_w10_mips: return "w10"; case dwarf_w11_mips: return "w11"; case dwarf_w12_mips: return "w12"; case dwarf_w13_mips: return "w13"; case dwarf_w14_mips: return "w14"; case dwarf_w15_mips: return "w15"; case dwarf_w16_mips: return "w16"; case dwarf_w17_mips: return "w17"; case dwarf_w18_mips: return "w18"; case dwarf_w19_mips: return "w19"; case dwarf_w20_mips: return "w20"; case dwarf_w21_mips: return "w21"; case dwarf_w22_mips: return "w22"; case dwarf_w23_mips: return "w23"; case dwarf_w24_mips: return "w24"; case dwarf_w25_mips: return "w25"; case dwarf_w26_mips: return "w26"; case dwarf_w27_mips: return "w27"; case dwarf_w28_mips: return "w28"; case dwarf_w29_mips: return "w29"; case dwarf_w30_mips: return "w30"; case dwarf_w31_mips: return "w31"; case dwarf_mcsr_mips: return "mcsr"; case dwarf_mir_mips: return "mir"; case dwarf_config5_mips: return "config5"; } return nullptr; } bool EmulateInstructionMIPS::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info) { if (reg_kind == eRegisterKindGeneric) { switch (reg_num) { case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc_mips; break; case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp_mips; break; case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_r30_mips; break; case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = dwarf_ra_mips; break; case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sr_mips; break; default: return false; } } if (reg_kind == eRegisterKindDWARF) { ::memset (®_info, 0, sizeof(RegisterInfo)); ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds)); if (reg_num == dwarf_sr_mips || reg_num == dwarf_fcsr_mips || reg_num == dwarf_fir_mips || reg_num == dwarf_mcsr_mips || reg_num == dwarf_mir_mips || reg_num == dwarf_config5_mips) { reg_info.byte_size = 4; reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if ((int)reg_num >= dwarf_zero_mips && (int)reg_num <= dwarf_f31_mips) { reg_info.byte_size = 4; reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if ((int)reg_num >= dwarf_w0_mips && (int)reg_num <= dwarf_w31_mips) { reg_info.byte_size = 16; reg_info.format = eFormatVectorOfUInt8; reg_info.encoding = eEncodingVector; } else { return false; } reg_info.name = GetRegisterName (reg_num, false); reg_info.alt_name = GetRegisterName (reg_num, true); reg_info.kinds[eRegisterKindDWARF] = reg_num; switch (reg_num) { case dwarf_r30_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break; case dwarf_ra_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break; case dwarf_sp_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break; case dwarf_pc_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break; case dwarf_sr_mips: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break; default: break; } return true; } return false; } EmulateInstructionMIPS::MipsOpcode* EmulateInstructionMIPS::GetOpcodeForInstruction (const char *op_name) { static EmulateInstructionMIPS::MipsOpcode g_opcodes[] = { //---------------------------------------------------------------------- // Prologue/Epilogue instructions //---------------------------------------------------------------------- - { "ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu, "ADDIU rt,rs,immediate" }, - { "SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt,offset(rs)" }, - { "LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt,offset(base)" }, + { "ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu, "ADDIU rt, rs, immediate" }, + { "SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt, offset(rs)" }, + { "LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt, offset(base)" }, + { "SUBU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "SUBU rd, rs, rt" }, + { "ADDU", &EmulateInstructionMIPS::Emulate_SUBU_ADDU, "ADDU rd, rs, rt" }, + { "LUI", &EmulateInstructionMIPS::Emulate_LUI, "LUI rt, immediate" }, + //---------------------------------------------------------------------- // MicroMIPS Prologue/Epilogue instructions //---------------------------------------------------------------------- { "ADDIUSP_MM", &EmulateInstructionMIPS::Emulate_ADDIUSP, "ADDIU immediate" }, { "ADDIUS5_MM", &EmulateInstructionMIPS::Emulate_ADDIUS5, "ADDIUS5 rd,immediate" }, { "SWSP_MM", &EmulateInstructionMIPS::Emulate_SWSP, "SWSP rt,offset(sp)" }, { "SWM16_MM", &EmulateInstructionMIPS::Emulate_SWM16_32, "SWM16 reglist,offset(sp)" }, { "SWM32_MM", &EmulateInstructionMIPS::Emulate_SWM16_32, "SWM32 reglist,offset(base)" }, { "SWP_MM", &EmulateInstructionMIPS::Emulate_SWM16_32, "SWP rs1,offset(base)" }, { "LWSP_MM", &EmulateInstructionMIPS::Emulate_LWSP, "LWSP rt,offset(sp)" }, { "LWM16_MM", &EmulateInstructionMIPS::Emulate_LWM16_32, "LWM16 reglist,offset(sp)" }, { "LWM32_MM", &EmulateInstructionMIPS::Emulate_LWM16_32, "LWM32 reglist,offset(base)" }, { "LWP_MM", &EmulateInstructionMIPS::Emulate_LWM16_32, "LWP rd,offset(base)" }, { "JRADDIUSP", &EmulateInstructionMIPS::Emulate_JRADDIUSP, "JRADDIUSP immediate" }, //---------------------------------------------------------------------- // Load/Store instructions //---------------------------------------------------------------------- /* Following list of emulated instructions are required by implementation of hardware watchpoint for MIPS in lldb. As we just need the address accessed by instructions, we have generalised all these instructions in 2 functions depending on their addressing modes */ { "LB", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LB rt, offset(base)" }, { "LBE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LBE rt, offset(base)" }, { "LBU", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LBU rt, offset(base)" }, { "LBUE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LBUE rt, offset(base)" }, { "LDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LDC1 ft, offset(base)" }, { "LD", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LD rt, offset(base)" }, { "LDL", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LDL rt, offset(base)" }, { "LDR", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LDR rt, offset(base)" }, { "LLD", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LLD rt, offset(base)" }, { "LDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LDC2 rt, offset(base)" }, { "LDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "LDXC1 fd, index (base)" }, { "LH", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LH rt, offset(base)" }, { "LHE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LHE rt, offset(base)" }, { "LHU", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LHU rt, offset(base)" }, { "LHUE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LHUE rt, offset(base)" }, { "LL", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LL rt, offset(base)" }, { "LLE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LLE rt, offset(base)" }, { "LUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "LUXC1 fd, index (base)" }, { "LW", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LW rt, offset(base)" }, { "LWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWC1 ft, offset(base)" }, { "LWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWC2 rt, offset(base)" }, { "LWE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWE rt, offset(base)" }, { "LWL", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWL rt, offset(base)" }, { "LWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWLE rt, offset(base)" }, { "LWR", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWR rt, offset(base)" }, { "LWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWRE rt, offset(base)" }, { "LWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "LWXC1 fd, index (base)" }, { "LLX", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LLX rt, offset(base)" }, { "LLXE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LLXE rt, offset(base)" }, { "LLDX", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LLDX rt, offset(base)" }, { "SB", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SB rt, offset(base)" }, { "SBE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SBE rt, offset(base)" }, { "SC", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SC rt, offset(base)" }, { "SCE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SCE rt, offset(base)" }, { "SCD", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SCD rt, offset(base)" }, { "SD", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SD rt, offset(base)" }, { "SDL", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SDL rt, offset(base)" }, { "SDR", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SDR rt, offset(base)" }, { "SDC1", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SDC1 ft, offset(base)" }, { "SDC2", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SDC2 rt, offset(base)" }, { "SDXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "SDXC1 fs, index(base)" }, { "SH", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SH rt, offset(base)" }, { "SHE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SHE rt, offset(base)" }, { "SUXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "SUXC1 fs, index (base)" }, { "SWC1", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWC1 ft, offset(base)" }, { "SWC2", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWC2 rt, offset(base)" }, { "SWE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWE rt, offset(base)" }, { "SWL", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWL rt, offset(base)" }, { "SWLE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWLE rt, offset(base)" }, { "SWR", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWR rt, offset(base)" }, { "SWRE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWRE rt, offset(base)" }, { "SWXC1", &EmulateInstructionMIPS::Emulate_LDST_Reg, "SWXC1 fs, index (base)" }, { "SCX", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SCX rt, offset(base)" }, { "SCXE", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SCXE rt, offset(base)" }, { "SCDX", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SCDX rt, offset(base)" }, //---------------------------------------------------------------------- // MicroMIPS Load/Store instructions //---------------------------------------------------------------------- { "LBU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LBU16 rt, decoded_offset(base)" }, { "LHU16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LHU16 rt, left_shifted_offset(base)" }, { "LW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LW16 rt, left_shifted_offset(base)" }, { "LWGP_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "LWGP rt, left_shifted_offset(gp)" }, { "SH16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SH16 rt, left_shifted_offset(base)" }, { "SW16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SW16 rt, left_shifted_offset(base)" }, { "SW_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SWSP rt, left_shifted_offset(base)" }, { "SB16_MM", &EmulateInstructionMIPS::Emulate_LDST_Imm, "SB16 rt, offset(base)" }, //---------------------------------------------------------------------- // Branch instructions //---------------------------------------------------------------------- { "BEQ", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQ rs,rt,offset" }, { "BNE", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNE rs,rt,offset" }, { "BEQL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BEQL rs,rt,offset" }, { "BNEL", &EmulateInstructionMIPS::Emulate_BXX_3ops, "BNEL rs,rt,offset" }, { "BGEZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BGEZALL rt,offset" }, { "BAL", &EmulateInstructionMIPS::Emulate_BAL, "BAL offset" }, { "BGEZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BGEZAL rs,offset" }, { "BALC", &EmulateInstructionMIPS::Emulate_BALC, "BALC offset" }, { "BC", &EmulateInstructionMIPS::Emulate_BC, "BC offset" }, { "BGEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZ rs,offset" }, { "BLEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BLEZALC rs,offset" }, { "BGEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BGEZALC rs,offset" }, { "BLTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BLTZALC rs,offset" }, { "BGTZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BGTZALC rs,offset" }, { "BEQZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BEQZALC rs,offset" }, { "BNEZALC", &EmulateInstructionMIPS::Emulate_Bcond_Link_C,"BNEZALC rs,offset" }, { "BEQC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BEQC rs,rt,offset" }, { "BNEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BNEC rs,rt,offset" }, { "BLTC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BLTC rs,rt,offset" }, { "BGEC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BGEC rs,rt,offset" }, { "BLTUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BLTUC rs,rt,offset" }, { "BGEUC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BGEUC rs,rt,offset" }, { "BLTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLTZC rt,offset" }, { "BLEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BLEZC rt,offset" }, { "BGEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGEZC rt,offset" }, { "BGTZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BGTZC rt,offset" }, { "BEQZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BEQZC rt,offset" }, { "BNEZC", &EmulateInstructionMIPS::Emulate_BXX_2ops_C, "BNEZC rt,offset" }, { "BGEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGEZL rt,offset" }, { "BGTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZ rt,offset" }, { "BGTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BGTZL rt,offset" }, { "BLEZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZ rt,offset" }, { "BLEZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLEZL rt,offset" }, { "BLTZ", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZ rt,offset" }, { "BLTZAL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BLTZAL rt,offset" }, { "BLTZALL", &EmulateInstructionMIPS::Emulate_Bcond_Link, "BLTZALL rt,offset" }, { "BLTZL", &EmulateInstructionMIPS::Emulate_BXX_2ops, "BLTZL rt,offset" }, { "BOVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BOVC rs,rt,offset" }, { "BNVC", &EmulateInstructionMIPS::Emulate_BXX_3ops_C, "BNVC rs,rt,offset" }, { "J", &EmulateInstructionMIPS::Emulate_J, "J target" }, { "JAL", &EmulateInstructionMIPS::Emulate_JAL, "JAL target" }, { "JALX", &EmulateInstructionMIPS::Emulate_JAL, "JALX target" }, { "JALR", &EmulateInstructionMIPS::Emulate_JALR, "JALR target" }, { "JALR_HB", &EmulateInstructionMIPS::Emulate_JALR, "JALR.HB target" }, { "JIALC", &EmulateInstructionMIPS::Emulate_JIALC, "JIALC rt,offset" }, { "JIC", &EmulateInstructionMIPS::Emulate_JIC, "JIC rt,offset" }, { "JR", &EmulateInstructionMIPS::Emulate_JR, "JR target" }, { "JR_HB", &EmulateInstructionMIPS::Emulate_JR, "JR.HB target" }, { "BC1F", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1F cc, offset" }, { "BC1T", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1T cc, offset" }, { "BC1FL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1FL cc, offset" }, { "BC1TL", &EmulateInstructionMIPS::Emulate_FP_branch, "BC1TL cc, offset" }, { "BC1EQZ", &EmulateInstructionMIPS::Emulate_BC1EQZ, "BC1EQZ ft, offset" }, { "BC1NEZ", &EmulateInstructionMIPS::Emulate_BC1NEZ, "BC1NEZ ft, offset" }, { "BC1ANY2F", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY2F cc, offset" }, { "BC1ANY2T", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY2T cc, offset" }, { "BC1ANY4F", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY4F cc, offset" }, { "BC1ANY4T", &EmulateInstructionMIPS::Emulate_3D_branch, "BC1ANY4T cc, offset" }, { "BNZ_B", &EmulateInstructionMIPS::Emulate_BNZB, "BNZ.b wt,s16" }, { "BNZ_H", &EmulateInstructionMIPS::Emulate_BNZH, "BNZ.h wt,s16" }, { "BNZ_W", &EmulateInstructionMIPS::Emulate_BNZW, "BNZ.w wt,s16" }, { "BNZ_D", &EmulateInstructionMIPS::Emulate_BNZD, "BNZ.d wt,s16" }, { "BZ_B", &EmulateInstructionMIPS::Emulate_BZB, "BZ.b wt,s16" }, { "BZ_H", &EmulateInstructionMIPS::Emulate_BZH, "BZ.h wt,s16" }, { "BZ_W", &EmulateInstructionMIPS::Emulate_BZW, "BZ.w wt,s16" }, { "BZ_D", &EmulateInstructionMIPS::Emulate_BZD, "BZ.d wt,s16" }, { "BNZ_V", &EmulateInstructionMIPS::Emulate_BNZV, "BNZ.V wt,s16" }, { "BZ_V", &EmulateInstructionMIPS::Emulate_BZV, "BZ.V wt,s16" }, //---------------------------------------------------------------------- // MicroMIPS Branch instructions //---------------------------------------------------------------------- { "B16_MM", &EmulateInstructionMIPS::Emulate_B16_MM, "B16 offset" }, { "BEQZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BEQZ16 rs, offset" }, { "BNEZ16_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BNEZ16 rs, offset" }, { "BEQZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BEQZC rs, offset" }, { "BNEZC_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BNEZC rs, offset" }, { "BGEZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BGEZALS rs, offset" }, { "BLTZALS_MM", &EmulateInstructionMIPS::Emulate_Branch_MM, "BLTZALS rs, offset" }, { "JALR16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALR16 rs" }, { "JALRS16_MM", &EmulateInstructionMIPS::Emulate_JALRx16_MM, "JALRS16 rs" }, { "JR16_MM", &EmulateInstructionMIPS::Emulate_JR, "JR16 rs rs" }, { "JRC16_MM", &EmulateInstructionMIPS::Emulate_JR, "JRC16 rs rs" }, { "JALS_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALS target" }, { "JALX_MM", &EmulateInstructionMIPS::Emulate_JALx, "JALX target" }, { "JALRS_MM", &EmulateInstructionMIPS::Emulate_JALRS, "JALRS rt, rs" }, }; static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes); for (size_t i = 0; i < k_num_mips_opcodes; ++i) { if (! strcasecmp (g_opcodes[i].op_name, op_name)) return &g_opcodes[i]; } return NULL; } uint32_t EmulateInstructionMIPS::GetSizeOfInstruction (lldb_private::DataExtractor& data, uint64_t inst_addr) { uint64_t next_inst_size = 0; llvm::MCInst mc_insn; llvm::MCDisassembler::DecodeStatus decode_status; llvm::ArrayRef raw_insn (data.GetDataStart(), data.GetByteSize()); if (m_use_alt_disaasm) decode_status = m_alt_disasm->getInstruction (mc_insn, next_inst_size, raw_insn, inst_addr, llvm::nulls(), llvm::nulls()); else decode_status = m_disasm->getInstruction (mc_insn, next_inst_size, raw_insn, inst_addr, llvm::nulls(), llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; return m_insn_info->get(mc_insn.getOpcode()).getSize(); } bool EmulateInstructionMIPS::SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target) { m_use_alt_disaasm = false; if (EmulateInstruction::SetInstruction (insn_opcode, inst_addr, target)) { if (inst_addr.GetAddressClass() == eAddressClassCodeAlternateISA) { Error error; lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; /* * The address belongs to microMIPS function. To find the size of * next instruction use microMIPS disassembler. */ m_use_alt_disaasm = true; uint32_t current_inst_size = insn_opcode.GetByteSize(); uint8_t buf[sizeof(uint32_t)]; uint64_t next_inst_addr = (m_addr & (~1ull)) + current_inst_size; Address next_addr (next_inst_addr); const size_t bytes_read = target->ReadMemory (next_addr, /* Address of next instruction */ true, /* prefer_file_cache */ buf, sizeof(uint32_t), error, &load_addr); if (bytes_read == 0) return true; DataExtractor data (buf, sizeof(uint32_t), GetByteOrder(), GetAddressByteSize()); m_next_inst_size = GetSizeOfInstruction (data, next_inst_addr); return true; } else { /* * If the address class is not eAddressClassCodeAlternateISA then * the function is not microMIPS. In this case instruction size is * always 4 bytes. */ m_next_inst_size = 4; return true; } } return false; } bool EmulateInstructionMIPS::ReadInstruction () { bool success = false; m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success); if (success) { Context read_inst_context; read_inst_context.type = eContextReadOpcode; read_inst_context.SetNoArgs (); m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder()); } if (!success) m_addr = LLDB_INVALID_ADDRESS; return success; } bool EmulateInstructionMIPS::EvaluateInstruction (uint32_t evaluate_options) { bool success = false; llvm::MCInst mc_insn; uint64_t insn_size; DataExtractor data; /* Keep the complexity of the decode logic with the llvm::MCDisassembler class. */ if (m_opcode.GetData (data)) { llvm::MCDisassembler::DecodeStatus decode_status; llvm::ArrayRef raw_insn (data.GetDataStart(), data.GetByteSize()); if (m_use_alt_disaasm) decode_status = m_alt_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); else decode_status = m_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; } /* * mc_insn.getOpcode() returns decoded opcode. However to make use * of llvm::Mips:: we would need "MipsGenInstrInfo.inc". */ const char *op_name = m_insn_info->getName (mc_insn.getOpcode ()); if (op_name == NULL) return false; /* * Decoding has been done already. Just get the call-back function * and emulate the instruction. */ MipsOpcode *opcode_data = GetOpcodeForInstruction (op_name); if (opcode_data == NULL) return false; uint64_t old_pc = 0, new_pc = 0; const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; if (auto_advance_pc) { old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; } /* emulate instruction */ success = (this->*opcode_data->callback) (mc_insn); if (!success) return false; if (auto_advance_pc) { new_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; /* If we haven't changed the PC, change it here */ if (old_pc == new_pc) { new_pc += 4; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, new_pc)) return false; } } return true; } bool EmulateInstructionMIPS::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind (eRegisterKindDWARF); UnwindPlan::RowSP row(new UnwindPlan::Row); const bool can_replace = false; // Our previous Call Frame Address is the stack pointer row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp_mips, 0); // Our previous PC is in the RA row->SetRegisterLocationToRegister(dwarf_pc_mips, dwarf_ra_mips, can_replace); unwind_plan.AppendRow (row); // All other registers are the same. unwind_plan.SetSourceName ("EmulateInstructionMIPS"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); unwind_plan.SetReturnAddressRegister (dwarf_ra_mips); return true; } bool EmulateInstructionMIPS::nonvolatile_reg_p (uint32_t regnum) { switch (regnum) { case dwarf_r16_mips: case dwarf_r17_mips: case dwarf_r18_mips: case dwarf_r19_mips: case dwarf_r20_mips: case dwarf_r21_mips: case dwarf_r22_mips: case dwarf_r23_mips: case dwarf_gp_mips: case dwarf_sp_mips: case dwarf_r30_mips: case dwarf_ra_mips: return true; default: return false; } return false; } bool EmulateInstructionMIPS::Emulate_ADDiu (llvm::MCInst& insn) { + // ADDIU rt, rs, immediate + // GPR[rt] <- GPR[rs] + sign_extend(immediate) + + uint8_t dst, src; bool success = false; const uint32_t imm16 = insn.getOperand(2).getImm(); - uint32_t imm = SignedBits(imm16, 15, 0); - uint64_t result; - uint32_t src, dst; + int64_t imm = SignedBits(imm16, 15, 0); dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - /* Check if this is addiu sp,,imm16 */ - if (dst == dwarf_sp_mips) + // If immediate value is greater then 2^16 - 1 then clang generate + // LUI, ADDIU, SUBU instructions in prolog. + // Example + // lui $1, 0x2 + // addiu $1, $1, -0x5920 + // subu $sp, $sp, $1 + // In this case, ADDIU dst and src will be same and not equal to sp + if (dst == src) { + Context context; + /* read register */ - uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success); + const int64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success); if (!success) return false; - result = src_opd_val + imm; + /* Check if this is daddiu sp, sp, imm16 */ + if (dst == dwarf_sp_mips) + { + uint64_t result = src_opd_val + imm; + RegisterInfo reg_info_sp; - Context context; - RegisterInfo reg_info_sp; - if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) - context.SetRegisterPlusOffset (reg_info_sp, imm); + if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, imm); - /* We are allocating bytes on stack */ - context.type = eContextAdjustStackPointer; + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; - WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result); + WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result); + return true; + } + + imm += src_opd_val; + context.SetImmediateSigned (imm); + context.type = eContextImmediate; + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips + dst, imm)) + return false; } - + return true; } bool EmulateInstructionMIPS::Emulate_SW (llvm::MCInst& insn) { bool success = false; uint32_t imm16 = insn.getOperand(2).getImm(); uint32_t imm = SignedBits(imm16, 15, 0); uint32_t src, base; int32_t address; Context bad_vaddr_context; RegisterInfo reg_info_base; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; /* read base register */ address = (int32_t)ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); /* We look for sp based non-volatile register stores */ - if (base == dwarf_sp_mips && nonvolatile_reg_p (src)) + if (nonvolatile_reg_p (src)) { RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + src, reg_info_src)) return false; Context context; RegisterValue data_src; context.type = eContextPushRegisterOnStack; context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; Error error; if (!ReadRegister (®_info_base, data_src)) return false; if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) return false; if (!WriteMemory (context, address, buffer, reg_info_src.byte_size)) return false; return true; } return false; } bool EmulateInstructionMIPS::Emulate_LW (llvm::MCInst& insn) { bool success =false; uint32_t src, base; int32_t imm, address; Context bad_vaddr_context; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); imm = insn.getOperand(2).getImm(); RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; /* read base register */ address = (int32_t)ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); - if (base == dwarf_sp_mips && nonvolatile_reg_p (src)) + if (nonvolatile_reg_p (src)) { RegisterValue data_src; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + src, reg_info_src)) return false; Context context; context.type = eContextPopRegisterOffStack; context.SetAddress (address); if (!WriteRegister (context, ®_info_src, data_src)) return false; return true; } + + return false; +} + +bool +EmulateInstructionMIPS::Emulate_SUBU_ADDU (llvm::MCInst& insn) +{ + // SUBU sp, , + // ADDU sp, , + // ADDU dst, sp, + + bool success = false; + uint64_t result; + uint8_t src, dst, rt; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); + + dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); + + /* Check if sp is destination register */ + if (dst == dwarf_sp_mips) + { + rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); + + /* read register */ + uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success); + if (!success) + return false; + + /* read register */ + uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); + if (!success) + return false; + + if (!strcasecmp (op_name, "SUBU")) + result = src_opd_val - rt_opd_val; + else + result = src_opd_val + rt_opd_val; + + Context context; + RegisterInfo reg_info_sp; + if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, rt_opd_val); + + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; + + WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result); + + return true; + } + else if (src == dwarf_sp_mips) + { + rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); + + /* read register */ + uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + src, 0, &success); + if (!success) + return false; + + /* read register */ + uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); + if (!success) + return false; + + Context context; + + if (!strcasecmp (op_name, "SUBU")) + result = src_opd_val - rt_opd_val; + else + result = src_opd_val + rt_opd_val; + + context.SetImmediateSigned (result); + context.type = eContextImmediate; + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips + dst, result)) + return false; + } + + return true; +} + +bool +EmulateInstructionMIPS::Emulate_LUI (llvm::MCInst& insn) +{ + // LUI rt, immediate + // GPR[rt] <- sign_extend(immediate << 16) + + const uint32_t imm32 = insn.getOperand(1).getImm() << 16; + int64_t imm = SignedBits(imm32, 31, 0); + uint8_t rt; + Context context; + + rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + context.SetImmediateSigned (imm); + context.type = eContextImmediate; + + if (WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips + rt, imm)) + return true; return false; } bool EmulateInstructionMIPS::Emulate_ADDIUSP (llvm::MCInst& insn) { bool success = false; const uint32_t imm9 = insn.getOperand(0).getImm(); uint64_t result; // This instruction operates implicitly on stack pointer, so read register. uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_sp_mips, 0, &success); if (!success) return false; result = src_opd_val + imm9; Context context; RegisterInfo reg_info_sp; if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) context.SetRegisterPlusOffset (reg_info_sp, imm9); // We are adjusting the stack. context.type = eContextAdjustStackPointer; WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result); return true; } bool EmulateInstructionMIPS::Emulate_ADDIUS5 (llvm::MCInst& insn) { bool success = false; uint32_t base; const uint32_t imm4 = insn.getOperand(2).getImm(); uint64_t result; // The source and destination register is same for this instruction. base = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); // We are looking for stack adjustment only if (base == dwarf_sp_mips) { // Read stack pointer register uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; result = src_opd_val + imm4; Context context; RegisterInfo reg_info_sp; if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) context.SetRegisterPlusOffset (reg_info_sp, imm4); // We are adjusting the stack. context.type = eContextAdjustStackPointer; WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result); } return true; } bool EmulateInstructionMIPS::Emulate_SWSP (llvm::MCInst& insn) { bool success = false; uint32_t imm5 = insn.getOperand(2).getImm(); uint32_t src, base; Context bad_vaddr_context; uint32_t address; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; // read base register address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; // destination address address = address + imm5; // We use bad_vaddr_context to store base address which is used by H/W watchpoint // Set the bad_vaddr register with base address used in the instruction bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); // We look for sp based non-volatile register stores. if (base == dwarf_sp_mips && nonvolatile_reg_p (src)) { RegisterInfo reg_info_src = {}; Context context; RegisterValue data_src; context.type = eContextPushRegisterOnStack; context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; Error error; if (!ReadRegister (®_info_base, data_src)) return false; if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) return false; if (!WriteMemory (context, address, buffer, reg_info_src.byte_size)) return false; return true; } return false; } /* Emulate SWM16,SWM32 and SWP instruction. SWM16 always has stack pointer as a base register (but it is still available in MCInst as an operand). SWM32 and SWP can have base register other than stack pointer. */ bool EmulateInstructionMIPS::Emulate_SWM16_32 (llvm::MCInst& insn) { bool success = false; uint32_t src, base; uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on no of regs to store. // Base register is second last operand of the instruction. base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); // We are looking for sp based stores so if base is not a stack pointer then don't proceed. if (base != dwarf_sp_mips) return false; // offset is always the last operand. uint32_t offset = insn.getOperand(num_operands-1).getImm(); RegisterInfo reg_info_base; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; // read SP uint32_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; // Resulting base addrss base_address = base_address + offset; // Total no of registers to be stored are num_operands-2. for (uint32_t i = 0; i < num_operands - 2; i++) { // Get the register number to be stored. src = m_reg_info->getEncodingValue (insn.getOperand(i).getReg()); /* Record only non-volatile stores. This check is required for SWP instruction because source operand could be any register. SWM16 and SWM32 instruction always has saved registers as source operands. */ if (!nonvolatile_reg_p (src)) return false; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + src, reg_info_src)) return false; Context context; RegisterValue data_src; context.type = eContextPushRegisterOnStack; context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; Error error; if (!ReadRegister (®_info_base, data_src)) return false; if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) return false; if (!WriteMemory (context, base_address, buffer, reg_info_src.byte_size)) return false; // Stack address for next register base_address = base_address + reg_info_src.byte_size; } return true; } bool EmulateInstructionMIPS::Emulate_LWSP (llvm::MCInst& insn) { bool success = false; uint32_t src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); uint32_t base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); uint32_t imm5 = insn.getOperand(2).getImm(); Context bad_vaddr_context; RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; // read base register uint32_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; base_address = base_address + imm5; // We use bad_vaddr_context to store base address which is used by H/W watchpoint // Set the bad_vaddr register with base address used in the instruction bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, base_address); if (base == dwarf_sp_mips && nonvolatile_reg_p (src)) { RegisterValue data_src; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + src, reg_info_src)) return false; Context context; context.type = eContextPopRegisterOffStack; context.SetAddress (base_address); if (!WriteRegister (context, ®_info_src, data_src)) return false; return true; } return false; } /* Emulate LWM16, LWM32 and LWP instructions. LWM16 always has stack pointer as a base register (but it is still available in MCInst as an operand). LWM32 and LWP can have base register other than stack pointer. */ bool EmulateInstructionMIPS::Emulate_LWM16_32 (llvm::MCInst& insn) { bool success = false; uint32_t dst, base; uint32_t num_operands = insn.getNumOperands(); // No of operands vary based on no of regs to store. uint32_t imm = insn.getOperand(num_operands-1).getImm(); // imm is the last operand in the instruction. // Base register is second last operand of the instruction. base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); // We are looking for sp based loads so if base is not a stack pointer then don't proceed. if (base != dwarf_sp_mips) return false; uint32_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; base_address = base_address + imm; RegisterValue data_dst; RegisterInfo reg_info_dst; // Total no of registers to be re-stored are num_operands-2. for (uint32_t i = 0; i < num_operands - 2; i++) { // Get the register number to be re-stored. dst = m_reg_info->getEncodingValue (insn.getOperand(i).getReg()); /* Record only non-volatile loads. This check is required for LWP instruction because destination operand could be any register. LWM16 and LWM32 instruction always has saved registers as destination operands. */ if (!nonvolatile_reg_p (dst)) return false; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + dst, reg_info_dst)) return false; Context context; context.type = eContextPopRegisterOffStack; context.SetAddress (base_address + (i*4)); if (!WriteRegister (context, ®_info_dst, data_dst)) return false; } return true; } bool EmulateInstructionMIPS::Emulate_JRADDIUSP (llvm::MCInst& insn) { bool success = false; int32_t imm5 = insn.getOperand(0).getImm(); /* JRADDIUSP immediate * PC <- RA * SP <- SP + zero_extend(Immediate << 2) */ // This instruction operates implicitly on stack pointer, so read register. int32_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_sp_mips, 0, &success); if (!success) return false; int32_t ra_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_ra_mips, 0, &success); if (!success) return false; int32_t result = src_opd_val + imm5; Context context; // Update the PC if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, ra_val)) return false; RegisterInfo reg_info_sp; if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips, reg_info_sp)) context.SetRegisterPlusOffset (reg_info_sp, imm5); // We are adjusting stack context.type = eContextAdjustStackPointer; // update SP if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips, result)) return false; return true; } static int IsAdd64bitOverflow (int32_t a, int32_t b) { int32_t r = (uint32_t) a + (uint32_t) b; return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0); } /* Emulate below MIPS branch instructions. BEQ, BNE : Branch on condition BEQL, BNEL : Branch likely */ bool EmulateInstructionMIPS::Emulate_BXX_3ops (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; int32_t offset, pc, target = 0, rs_val, rt_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BEQ") || !strcasecmp (op_name, "BEQL")) { if (rs_val == rt_val) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BNE") || !strcasecmp (op_name, "BNEL")) { if (rs_val != rt_val) target = pc + offset; else target = pc + 8; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } /* Emulate below MIPS branch instructions. BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch instructions with no delay slot */ bool EmulateInstructionMIPS::Emulate_BXX_3ops_C (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; int32_t offset, pc, target = 0, rs_val, rt_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BEQC")) { if (rs_val == rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEC")) { if (rs_val != rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTC")) { if (rs_val < rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEC")) { if (rs_val >= rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTUC")) { if (rs_val < rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEUC")) { if ((uint32_t)rs_val >= (uint32_t)rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BOVC")) { if (IsAdd64bitOverflow (rs_val, rt_val)) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNVC")) { if (!IsAdd64bitOverflow (rs_val, rt_val)) target = pc + offset; else target = pc + 4; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } /* Emulate below MIPS conditional branch and link instructions. BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches */ bool EmulateInstructionMIPS::Emulate_Bcond_Link_C (llvm::MCInst& insn) { bool success = false; uint32_t rs; int32_t offset, pc, target = 0; int32_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLEZALC")) { if (rs_val <= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEZALC")) { if (rs_val >= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTZALC")) { if (rs_val < 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGTZALC")) { if (rs_val > 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BEQZALC")) { if (rs_val == 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEZALC")) { if (rs_val != 0) target = pc + offset; else target = pc + 4; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4)) return false; return true; } /* Emulate below MIPS Non-Compact conditional branch and link instructions. BLTZAL, BGEZAL : BLTZALL, BGEZALL : Branch likely */ bool EmulateInstructionMIPS::Emulate_Bcond_Link (llvm::MCInst& insn) { bool success = false; uint32_t rs; int32_t offset, pc, target = 0; int32_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZAL") || !strcasecmp (op_name, "BLTZALL")) { if ((int32_t) rs_val < 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGEZAL") || !strcasecmp (op_name, "BGEZALL")) { if ((int32_t) rs_val >= 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8)) return false; return true; } /* Emulate below MIPS branch instructions. BLTZL, BGEZL, BGTZL, BLEZL : Branch likely BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches */ bool EmulateInstructionMIPS::Emulate_BXX_2ops (llvm::MCInst& insn) { bool success = false; uint32_t rs; int32_t offset, pc, target = 0; int32_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZL") || !strcasecmp (op_name, "BLTZ")) { if (rs_val < 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGEZL") || !strcasecmp (op_name, "BGEZ")) { if (rs_val >= 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGTZL") || !strcasecmp (op_name, "BGTZ")) { if (rs_val > 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BLEZL") || !strcasecmp (op_name, "BLEZ")) { if (rs_val <= 0) target = pc + offset; else target = pc + 8; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } /* Emulate below MIPS branch instructions. BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches */ bool EmulateInstructionMIPS::Emulate_BXX_2ops_C (llvm::MCInst& insn) { bool success = false; uint32_t rs; int32_t offset, pc, target = 0; int32_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZC")) { if (rs_val < 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLEZC")) { if (rs_val <= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEZC")) { if (rs_val >= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGTZC")) { if (rs_val > 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BEQZC")) { if (rs_val == 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEZC")) { if (rs_val != 0) target = pc + offset; else target = pc + 4; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_B16_MM (llvm::MCInst& insn) { bool success = false; int32_t offset, pc, target; uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; // unconditional branch target = pc + offset; Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } /* BEQZC, BNEZC are 32 bit compact instructions without a delay slot. BEQZ16, BNEZ16 are 16 bit instructions with delay slot. BGEZALS, BLTZALS are 16 bit instructions with short (2-byte) delay slot. */ bool EmulateInstructionMIPS::Emulate_Branch_MM (llvm::MCInst& insn) { bool success = false; int32_t target = 0; uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); const char *op_name = m_insn_info->getName (insn.getOpcode ()); bool update_ra = false; uint32_t ra_offset = 0; /* * BEQZ16 rs, offset * condition <- (GPR[rs] = 0) * if condition then * PC = PC + sign_ext (offset || 0) * * BNEZ16 rs, offset * condition <- (GPR[rs] != 0) * if condition then * PC = PC + sign_ext (offset || 0) * * BEQZC rs, offset (compact instruction: No delay slot) * condition <- (GPR[rs] == 0) * if condition then * PC = PC + 4 + sign_ext (offset || 0) */ uint32_t rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); int32_t offset = insn.getOperand(1).getImm(); int32_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; int32_t rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BEQZ16_MM")) { if (rs_val == 0) target = pc + offset; else target = pc + current_inst_size + m_next_inst_size; // Skip delay slot instruction. } else if (!strcasecmp (op_name, "BNEZ16_MM")) { if (rs_val != 0) target = pc + offset; else target = pc + current_inst_size + m_next_inst_size; // Skip delay slot instruction. } else if (!strcasecmp (op_name, "BEQZC_MM")) { if (rs_val == 0) target = pc + 4 + offset; else target = pc + 4; // 32 bit instruction and does not have delay slot instruction. } else if (!strcasecmp (op_name, "BNEZC_MM")) { if (rs_val != 0) target = pc + 4 + offset; else target = pc + 4; // 32 bit instruction and does not have delay slot instruction. } else if (!strcasecmp (op_name, "BGEZALS_MM")) { if (rs_val >= 0) target = pc + offset; else target = pc + 6; // 32 bit instruction with short (2-byte) delay slot update_ra = true; ra_offset = 6; } else if (!strcasecmp (op_name, "BLTZALS_MM")) { if (rs_val >= 0) target = pc + offset; else target = pc + 6; // 32 bit instruction with short (2-byte) delay slot update_ra = true; ra_offset = 6; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (update_ra) { if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + ra_offset)) return false; } return true; } /* Emulate micromips jump instructions. JALR16,JALRS16 */ bool EmulateInstructionMIPS::Emulate_JALRx16_MM (llvm::MCInst& insn) { bool success = false; uint32_t ra_offset = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); uint32_t rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); uint32_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; uint32_t rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "JALR16_MM")) ra_offset = 6; // 2-byte instruction with 4-byte delay slot. else if (!strcasecmp (op_name, "JALRS16_MM")) ra_offset = 4; // 2-byte instruction with 2-byte delay slot. Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, rs_val)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + ra_offset)) return false; return true; } /* Emulate JALS and JALX instructions. JALS 32 bit instruction with short (2-byte) delay slot. JALX 32 bit instruction with 4-byte delay slot. */ bool EmulateInstructionMIPS::Emulate_JALx (llvm::MCInst& insn) { bool success = false; uint32_t offset=0, target=0, pc=0, ra_offset=0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); /* * JALS target * RA = PC + 6 * offset = sign_ext (offset << 1) * PC = PC[31-27] | offset * JALX target * RA = PC + 8 * offset = sign_ext (offset << 2) * PC = PC[31-28] | offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; // These are PC-region branches and not PC-relative. if (!strcasecmp (op_name, "JALS_MM")) { // target address is in the “current” 128 MB-aligned region target = (pc & 0xF8000000UL) | offset; ra_offset = 6; } else if (!strcasecmp (op_name, "JALX_MM")) { // target address is in the “current” 256 MB-aligned region target = (pc & 0xF0000000UL) | offset; ra_offset = 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + ra_offset)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JALRS (llvm::MCInst& insn) { bool success = false; uint32_t rs=0, rt=0; int32_t pc=0, rs_val=0; /* JALRS rt, rs GPR[rt] <- PC + 6 PC <- GPR[rs] */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); rs_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, rs_val)) return false; // This is 4-byte instruction with 2-byte delay slot. if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips + rt, pc + 6)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BAL (llvm::MCInst& insn) { bool success = false; int32_t offset, pc, target; /* * BAL offset * offset = sign_ext (offset << 2) * RA = PC + 8 * PC = PC + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BALC (llvm::MCInst& insn) { bool success = false; int32_t offset, pc, target; /* * BALC offset * offset = sign_ext (offset << 2) * RA = PC + 4 * PC = PC + 4 + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BC (llvm::MCInst& insn) { bool success = false; int32_t offset, pc, target; /* * BC offset * offset = sign_ext (offset << 2) * PC = PC + 4 + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_J (llvm::MCInst& insn) { bool success = false; uint32_t offset, pc; /* * J offset * offset = sign_ext (offset << 2) * PC = PC[63-28] | offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; /* This is a PC-region branch and not PC-relative */ pc = (pc & 0xF0000000UL) | offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, pc)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JAL (llvm::MCInst& insn) { bool success = false; uint32_t offset, target, pc; /* * JAL offset * offset = sign_ext (offset << 2) * PC = PC[63-28] | offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; /* This is a PC-region branch and not PC-relative */ target = (pc & 0xF0000000UL) | offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 8)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JALR (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; uint32_t pc, rs_val; /* * JALR rt, rs * GPR[rt] = PC + 8 * PC = GPR[rs] */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, rs_val)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips + rt, pc + 8)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JIALC (llvm::MCInst& insn) { bool success = false; uint32_t rt; int32_t target, offset, pc, rt_val; /* * JIALC rt, offset * offset = sign_ext (offset) * PC = GPR[rt] + offset * RA = PC + 4 */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); if (!success) return false; target = rt_val + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips, pc + 4)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JIC (llvm::MCInst& insn) { bool success = false; uint32_t rt; int32_t target, offset, rt_val; /* * JIC rt, offset * offset = sign_ext (offset) * PC = GPR[rt] + offset */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); rt_val = (int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rt, 0, &success); if (!success) return false; target = rt_val + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_JR (llvm::MCInst& insn) { bool success = false; uint32_t rs; uint32_t rs_val; /* * JR rs * PC = GPR[rs] */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + rs, 0, &success); if (!success) return false; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, rs_val)) return false; return true; } /* Emulate Branch on FP True/False BC1F, BC1FL : Branch on FP False (L stands for branch likely) BC1T, BC1TL : Branch on FP True (L stands for branch likely) */ bool EmulateInstructionMIPS::Emulate_FP_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; int32_t pc, offset, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success); if (!success) return false; /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); if (!strcasecmp (op_name, "BC1F") || !strcasecmp (op_name, "BC1FL")) { if ((fcsr & (1 << cc)) == 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1T") || !strcasecmp (op_name, "BC1TL")) { if ((fcsr & (1 << cc)) != 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BC1EQZ (llvm::MCInst& insn) { bool success = false; uint32_t ft; uint32_t ft_val; int32_t target, pc, offset; /* * BC1EQZ ft, offset * condition <- (FPR[ft].bit0 == 0) * if condition then * offset = sign_ext (offset) * PC = PC + 4 + offset */ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + ft, 0, &success); if (!success) return false; if ((ft_val & 1) == 0) target = pc + 4 + offset; else target = pc + 8; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BC1NEZ (llvm::MCInst& insn) { bool success = false; uint32_t ft; uint32_t ft_val; int32_t target, pc, offset; /* * BC1NEZ ft, offset * condition <- (FPR[ft].bit0 != 0) * if condition then * offset = sign_ext (offset) * PC = PC + 4 + offset */ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + ft, 0, &success); if (!success) return false; if ((ft_val & 1) != 0) target = pc + 4 + offset; else target = pc + 8; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } /* Emulate MIPS-3D Branch instructions BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes False/True BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes False/True */ bool EmulateInstructionMIPS::Emulate_3D_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; int32_t pc, offset, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips, 0, &success); if (!success) return false; /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); if (!strcasecmp (op_name, "BC1ANY2F")) { /* if any one bit is 0 */ if (((fcsr >> cc) & 3) != 3) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY2T")) { /* if any one bit is 1 */ if (((fcsr >> cc) & 3) != 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY4F")) { /* if any one bit is 0 */ if (((fcsr >> cc) & 0xf) != 0xf) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY4T")) { /* if any one bit is 1 */ if (((fcsr >> cc) & 0xf) != 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BNZB (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 1, true); } bool EmulateInstructionMIPS::Emulate_BNZH (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 2, true); } bool EmulateInstructionMIPS::Emulate_BNZW (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 4, true); } bool EmulateInstructionMIPS::Emulate_BNZD (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 8, true); } bool EmulateInstructionMIPS::Emulate_BZB (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 1, false); } bool EmulateInstructionMIPS::Emulate_BZH (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 2, false); } bool EmulateInstructionMIPS::Emulate_BZW (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 4, false); } bool EmulateInstructionMIPS::Emulate_BZD (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 8, false); } bool EmulateInstructionMIPS::Emulate_MSA_Branch_DF (llvm::MCInst& insn, int element_byte_size, bool bnz) { bool success = false, branch_hit = true; int32_t target = 0; RegisterValue reg_value; const uint8_t *ptr = NULL; uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); int32_t offset = insn.getOperand(1).getImm(); int32_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value)) ptr = (const uint8_t *)reg_value.GetBytes(); else return false; for(int i = 0; i < 16 / element_byte_size; i++) { switch(element_byte_size) { case 1: if((*ptr == 0 && bnz) || (*ptr != 0 && !bnz) ) branch_hit = false; break; case 2: if ((*(const uint16_t *)ptr == 0 && bnz) || (*(const uint16_t *)ptr != 0 && !bnz)) branch_hit = false; break; case 4: if ((*(const uint32_t *)ptr == 0 && bnz) || (*(const uint32_t *)ptr != 0 && !bnz)) branch_hit = false; break; case 8: if ((*(const uint64_t *)ptr == 0 && bnz) || (*(const uint64_t *)ptr != 0 && !bnz)) branch_hit = false; break; } if(!branch_hit) break; ptr = ptr + element_byte_size; } if(branch_hit) target = pc + offset; else target = pc + 8; Context context; context.type = eContextRelativeBranchImmediate; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_BNZV (llvm::MCInst& insn) { return Emulate_MSA_Branch_V (insn, true); } bool EmulateInstructionMIPS::Emulate_BZV (llvm::MCInst& insn) { return Emulate_MSA_Branch_V (insn, false); } bool EmulateInstructionMIPS::Emulate_MSA_Branch_V (llvm::MCInst& insn, bool bnz) { bool success = false; int32_t target = 0; llvm::APInt wr_val = llvm::APInt::getNullValue(128); llvm::APInt fail_value = llvm::APInt::getMaxValue(128); llvm::APInt zero_value = llvm::APInt::getNullValue(128); RegisterValue reg_value; uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); int32_t offset = insn.getOperand(1).getImm(); int32_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips, 0, &success); if (!success) return false; if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips + wt, reg_value)) wr_val = reg_value.GetAsUInt128(fail_value); else return false; if((llvm::APInt::isSameValue(zero_value, wr_val) && !bnz) || (!llvm::APInt::isSameValue(zero_value, wr_val) && bnz)) target = pc + offset; else target = pc + 8; Context context; context.type = eContextRelativeBranchImmediate; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips, target)) return false; return true; } bool EmulateInstructionMIPS::Emulate_LDST_Imm (llvm::MCInst& insn) { bool success = false; uint32_t base; int32_t imm, address; Context bad_vaddr_context; uint32_t num_operands = insn.getNumOperands(); base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); imm = insn.getOperand(num_operands-1).getImm(); RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; /* read base register */ address =(int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); return true; } bool EmulateInstructionMIPS::Emulate_LDST_Reg (llvm::MCInst& insn) { bool success = false; uint32_t base, index; int32_t address, index_address; Context bad_vaddr_context; uint32_t num_operands = insn.getNumOperands(); base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); index = m_reg_info->getEncodingValue (insn.getOperand(num_operands-1).getReg()); RegisterInfo reg_info_base, reg_info_index; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + index, reg_info_index)) return false; /* read base register */ address =(int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* read index register */ index_address =(int32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + index, 0, &success); if (!success) return false; /* destination address */ address = address + index_address; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); return true; } Index: vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h =================================================================== --- vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h (revision 304308) @@ -1,289 +1,295 @@ //===-- EmulateInstructionMIPS.h ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef EmulateInstructionMIPS_h_ #define EmulateInstructionMIPS_h_ namespace llvm { class MCDisassembler; class MCSubtargetInfo; class MCRegisterInfo; class MCAsmInfo; class MCContext; class MCInstrInfo; class MCInst; } #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Error.h" #include "lldb/Interpreter/OptionValue.h" class EmulateInstructionMIPS : public lldb_private::EmulateInstruction { public: static void Initialize (); static void Terminate (); static lldb_private::ConstString GetPluginNameStatic (); static const char * GetPluginDescriptionStatic (); static lldb_private::EmulateInstruction * CreateInstance (const lldb_private::ArchSpec &arch, lldb_private::InstructionType inst_type); static bool SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type) { switch (inst_type) { case lldb_private::eInstructionTypeAny: case lldb_private::eInstructionTypePrologueEpilogue: case lldb_private::eInstructionTypePCModifying: return true; case lldb_private::eInstructionTypeAll: return false; } return false; } lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override { return 1; } bool SetTargetTriple (const lldb_private::ArchSpec &arch) override; EmulateInstructionMIPS (const lldb_private::ArchSpec &arch); bool SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type) override { return SupportsEmulatingInstructionsOfTypeStatic (inst_type); } bool ReadInstruction () override; bool EvaluateInstruction (uint32_t evaluate_options) override; bool SetInstruction (const lldb_private::Opcode &insn_opcode, const lldb_private::Address &inst_addr, lldb_private::Target *target) override; bool TestEmulation (lldb_private::Stream *out_stream, lldb_private::ArchSpec &arch, lldb_private::OptionValueDictionary *test_data) override { return false; } bool GetRegisterInfo (lldb::RegisterKind reg_kind, uint32_t reg_num, lldb_private::RegisterInfo ®_info) override; bool CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan) override; protected: typedef struct { const char *op_name; bool (EmulateInstructionMIPS::*callback) (llvm::MCInst& insn); const char *insn_name; } MipsOpcode; static MipsOpcode* GetOpcodeForInstruction (const char *op_name); uint32_t GetSizeOfInstruction (lldb_private::DataExtractor& data, uint64_t inst_addr); bool Emulate_ADDiu (llvm::MCInst& insn); bool + Emulate_SUBU_ADDU (llvm::MCInst& insn); + + bool + Emulate_LUI (llvm::MCInst& insn); + + bool Emulate_SW (llvm::MCInst& insn); bool Emulate_LW (llvm::MCInst& insn); bool Emulate_ADDIUSP (llvm::MCInst& insn); bool Emulate_ADDIUS5 (llvm::MCInst& insn); bool Emulate_SWSP (llvm::MCInst& insn); bool Emulate_SWM16_32 (llvm::MCInst& insn); bool Emulate_LWSP (llvm::MCInst& insn); bool Emulate_LWM16_32 (llvm::MCInst& insn); bool Emulate_JRADDIUSP (llvm::MCInst& insn); bool Emulate_LDST_Imm (llvm::MCInst& insn); bool Emulate_LDST_Reg (llvm::MCInst& insn); bool Emulate_BXX_3ops (llvm::MCInst& insn); bool Emulate_BXX_3ops_C (llvm::MCInst& insn); bool Emulate_BXX_2ops (llvm::MCInst& insn); bool Emulate_BXX_2ops_C (llvm::MCInst& insn); bool Emulate_Bcond_Link_C (llvm::MCInst& insn); bool Emulate_Bcond_Link (llvm::MCInst& insn); bool Emulate_FP_branch (llvm::MCInst& insn); bool Emulate_3D_branch (llvm::MCInst& insn); bool Emulate_BAL (llvm::MCInst& insn); bool Emulate_BALC (llvm::MCInst& insn); bool Emulate_BC (llvm::MCInst& insn); bool Emulate_J (llvm::MCInst& insn); bool Emulate_JAL (llvm::MCInst& insn); bool Emulate_JALR (llvm::MCInst& insn); bool Emulate_JIALC (llvm::MCInst& insn); bool Emulate_JIC (llvm::MCInst& insn); bool Emulate_JR (llvm::MCInst& insn); bool Emulate_BC1EQZ (llvm::MCInst& insn); bool Emulate_BC1NEZ (llvm::MCInst& insn); bool Emulate_BNZB (llvm::MCInst& insn); bool Emulate_BNZH (llvm::MCInst& insn); bool Emulate_BNZW (llvm::MCInst& insn); bool Emulate_BNZD (llvm::MCInst& insn); bool Emulate_BZB (llvm::MCInst& insn); bool Emulate_BZH (llvm::MCInst& insn); bool Emulate_BZW (llvm::MCInst& insn); bool Emulate_BZD (llvm::MCInst& insn); bool Emulate_MSA_Branch_DF (llvm::MCInst& insn, int element_byte_size, bool bnz); bool Emulate_BNZV (llvm::MCInst& insn); bool Emulate_BZV (llvm::MCInst& insn); bool Emulate_MSA_Branch_V (llvm::MCInst& insn, bool bnz); bool Emulate_B16_MM (llvm::MCInst& insn); bool Emulate_Branch_MM (llvm::MCInst& insn); bool Emulate_JALRx16_MM (llvm::MCInst& insn); bool Emulate_JALx (llvm::MCInst& insn); bool Emulate_JALRS (llvm::MCInst& insn); bool nonvolatile_reg_p (uint32_t regnum); const char * GetRegisterName (unsigned reg_num, bool altnernate_name); private: std::unique_ptr m_disasm; std::unique_ptr m_alt_disasm; std::unique_ptr m_subtype_info; std::unique_ptr m_alt_subtype_info; std::unique_ptr m_reg_info; std::unique_ptr m_asm_info; std::unique_ptr m_context; std::unique_ptr m_insn_info; uint32_t m_next_inst_size; bool m_use_alt_disaasm; }; #endif // EmulateInstructionMIPS_h_ Index: vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp (revision 304308) @@ -1,2048 +1,2172 @@ //===-- EmulateInstructionMIPS64.cpp -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "EmulateInstructionMIPS64.h" #include #include "llvm-c/Disassembler.h" #include "llvm/Support/TargetSelect.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCContext.h" #include "lldb/Core/Address.h" #include "lldb/Core/Opcode.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Stream.h" #include "lldb/Symbol/UnwindPlan.h" #include "llvm/ADT/STLExtras.h" #include "Plugins/Process/Utility/InstructionUtils.h" #include "Plugins/Process/Utility/RegisterContext_mips.h" using namespace lldb; using namespace lldb_private; #define UInt(x) ((uint64_t)x) #define integer int64_t //---------------------------------------------------------------------- // // EmulateInstructionMIPS64 implementation // //---------------------------------------------------------------------- #ifdef __mips__ extern "C" { void LLVMInitializeMipsTargetInfo (); void LLVMInitializeMipsTarget (); void LLVMInitializeMipsAsmPrinter (); void LLVMInitializeMipsTargetMC (); void LLVMInitializeMipsDisassembler (); } #endif EmulateInstructionMIPS64::EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch) : EmulateInstruction (arch) { /* Create instance of llvm::MCDisassembler */ std::string Error; llvm::Triple triple = arch.GetTriple(); const llvm::Target *target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); /* * If we fail to get the target then we haven't registered it. The SystemInitializerCommon * does not initialize targets, MCs and disassemblers. However we need the MCDisassembler * to decode the instructions so that the decoding complexity stays with LLVM. * Initialize the MIPS targets and disassemblers. */ #ifdef __mips__ if (!target) { LLVMInitializeMipsTargetInfo (); LLVMInitializeMipsTarget (); LLVMInitializeMipsAsmPrinter (); LLVMInitializeMipsTargetMC (); LLVMInitializeMipsDisassembler (); target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); } #endif assert (target); llvm::StringRef cpu; switch (arch.GetCore()) { case ArchSpec::eCore_mips32: case ArchSpec::eCore_mips32el: cpu = "mips32"; break; case ArchSpec::eCore_mips32r2: case ArchSpec::eCore_mips32r2el: cpu = "mips32r2"; break; case ArchSpec::eCore_mips32r3: case ArchSpec::eCore_mips32r3el: cpu = "mips32r3"; break; case ArchSpec::eCore_mips32r5: case ArchSpec::eCore_mips32r5el: cpu = "mips32r5"; break; case ArchSpec::eCore_mips32r6: case ArchSpec::eCore_mips32r6el: cpu = "mips32r6"; break; case ArchSpec::eCore_mips64: case ArchSpec::eCore_mips64el: cpu = "mips64"; break; case ArchSpec::eCore_mips64r2: case ArchSpec::eCore_mips64r2el: cpu = "mips64r2"; break; case ArchSpec::eCore_mips64r3: case ArchSpec::eCore_mips64r3el: cpu = "mips64r3"; break; case ArchSpec::eCore_mips64r5: case ArchSpec::eCore_mips64r5el: cpu = "mips64r5"; break; case ArchSpec::eCore_mips64r6: case ArchSpec::eCore_mips64r6el: cpu = "mips64r6"; break; default: cpu = "generic"; break; } std::string features = ""; uint32_t arch_flags = arch.GetFlags (); if (arch_flags & ArchSpec::eMIPSAse_msa) features += "+msa,"; if (arch_flags & ArchSpec::eMIPSAse_dsp) features += "+dsp,"; if (arch_flags & ArchSpec::eMIPSAse_dspr2) features += "+dspr2,"; if (arch_flags & ArchSpec::eMIPSAse_mips16) features += "+mips16,"; if (arch_flags & ArchSpec::eMIPSAse_micromips) features += "+micromips,"; m_reg_info.reset (target->createMCRegInfo (triple.getTriple())); assert (m_reg_info.get()); m_insn_info.reset (target->createMCInstrInfo()); assert (m_insn_info.get()); m_asm_info.reset (target->createMCAsmInfo (*m_reg_info, triple.getTriple())); m_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, features)); assert (m_asm_info.get() && m_subtype_info.get()); m_context.reset (new llvm::MCContext (m_asm_info.get(), m_reg_info.get(), nullptr)); assert (m_context.get()); m_disasm.reset (target->createMCDisassembler (*m_subtype_info, *m_context)); assert (m_disasm.get()); } void EmulateInstructionMIPS64::Initialize () { PluginManager::RegisterPlugin (GetPluginNameStatic (), GetPluginDescriptionStatic (), CreateInstance); } void EmulateInstructionMIPS64::Terminate () { PluginManager::UnregisterPlugin (CreateInstance); } ConstString EmulateInstructionMIPS64::GetPluginNameStatic () { ConstString g_plugin_name ("lldb.emulate-instruction.mips64"); return g_plugin_name; } lldb_private::ConstString EmulateInstructionMIPS64::GetPluginName() { static ConstString g_plugin_name ("EmulateInstructionMIPS64"); return g_plugin_name; } const char * EmulateInstructionMIPS64::GetPluginDescriptionStatic () { return "Emulate instructions for the MIPS64 architecture."; } EmulateInstruction * EmulateInstructionMIPS64::CreateInstance (const ArchSpec &arch, InstructionType inst_type) { if (EmulateInstructionMIPS64::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) { if (arch.GetTriple().getArch() == llvm::Triple::mips64 || arch.GetTriple().getArch() == llvm::Triple::mips64el) { std::auto_ptr emulate_insn_ap (new EmulateInstructionMIPS64 (arch)); if (emulate_insn_ap.get()) return emulate_insn_ap.release(); } } return NULL; } bool EmulateInstructionMIPS64::SetTargetTriple (const ArchSpec &arch) { if (arch.GetTriple().getArch () == llvm::Triple::mips64 || arch.GetTriple().getArch () == llvm::Triple::mips64el) return true; return false; } const char * EmulateInstructionMIPS64::GetRegisterName (unsigned reg_num, bool alternate_name) { if (alternate_name) { switch (reg_num) { case dwarf_sp_mips64: return "r29"; case dwarf_r30_mips64: return "r30"; case dwarf_ra_mips64: return "r31"; case dwarf_f0_mips64: return "f0"; case dwarf_f1_mips64: return "f1"; case dwarf_f2_mips64: return "f2"; case dwarf_f3_mips64: return "f3"; case dwarf_f4_mips64: return "f4"; case dwarf_f5_mips64: return "f5"; case dwarf_f6_mips64: return "f6"; case dwarf_f7_mips64: return "f7"; case dwarf_f8_mips64: return "f8"; case dwarf_f9_mips64: return "f9"; case dwarf_f10_mips64: return "f10"; case dwarf_f11_mips64: return "f11"; case dwarf_f12_mips64: return "f12"; case dwarf_f13_mips64: return "f13"; case dwarf_f14_mips64: return "f14"; case dwarf_f15_mips64: return "f15"; case dwarf_f16_mips64: return "f16"; case dwarf_f17_mips64: return "f17"; case dwarf_f18_mips64: return "f18"; case dwarf_f19_mips64: return "f19"; case dwarf_f20_mips64: return "f20"; case dwarf_f21_mips64: return "f21"; case dwarf_f22_mips64: return "f22"; case dwarf_f23_mips64: return "f23"; case dwarf_f24_mips64: return "f24"; case dwarf_f25_mips64: return "f25"; case dwarf_f26_mips64: return "f26"; case dwarf_f27_mips64: return "f27"; case dwarf_f28_mips64: return "f28"; case dwarf_f29_mips64: return "f29"; case dwarf_f30_mips64: return "f30"; case dwarf_f31_mips64: return "f31"; case dwarf_w0_mips64: return "w0"; case dwarf_w1_mips64: return "w1"; case dwarf_w2_mips64: return "w2"; case dwarf_w3_mips64: return "w3"; case dwarf_w4_mips64: return "w4"; case dwarf_w5_mips64: return "w5"; case dwarf_w6_mips64: return "w6"; case dwarf_w7_mips64: return "w7"; case dwarf_w8_mips64: return "w8"; case dwarf_w9_mips64: return "w9"; case dwarf_w10_mips64: return "w10"; case dwarf_w11_mips64: return "w11"; case dwarf_w12_mips64: return "w12"; case dwarf_w13_mips64: return "w13"; case dwarf_w14_mips64: return "w14"; case dwarf_w15_mips64: return "w15"; case dwarf_w16_mips64: return "w16"; case dwarf_w17_mips64: return "w17"; case dwarf_w18_mips64: return "w18"; case dwarf_w19_mips64: return "w19"; case dwarf_w20_mips64: return "w20"; case dwarf_w21_mips64: return "w21"; case dwarf_w22_mips64: return "w22"; case dwarf_w23_mips64: return "w23"; case dwarf_w24_mips64: return "w24"; case dwarf_w25_mips64: return "w25"; case dwarf_w26_mips64: return "w26"; case dwarf_w27_mips64: return "w27"; case dwarf_w28_mips64: return "w28"; case dwarf_w29_mips64: return "w29"; case dwarf_w30_mips64: return "w30"; case dwarf_w31_mips64: return "w31"; case dwarf_mir_mips64: return "mir"; case dwarf_mcsr_mips64: return "mcsr"; case dwarf_config5_mips64: return "config5"; default: break; } return nullptr; } switch (reg_num) { case dwarf_zero_mips64: return "r0"; case dwarf_r1_mips64: return "r1"; case dwarf_r2_mips64: return "r2"; case dwarf_r3_mips64: return "r3"; case dwarf_r4_mips64: return "r4"; case dwarf_r5_mips64: return "r5"; case dwarf_r6_mips64: return "r6"; case dwarf_r7_mips64: return "r7"; case dwarf_r8_mips64: return "r8"; case dwarf_r9_mips64: return "r9"; case dwarf_r10_mips64: return "r10"; case dwarf_r11_mips64: return "r11"; case dwarf_r12_mips64: return "r12"; case dwarf_r13_mips64: return "r13"; case dwarf_r14_mips64: return "r14"; case dwarf_r15_mips64: return "r15"; case dwarf_r16_mips64: return "r16"; case dwarf_r17_mips64: return "r17"; case dwarf_r18_mips64: return "r18"; case dwarf_r19_mips64: return "r19"; case dwarf_r20_mips64: return "r20"; case dwarf_r21_mips64: return "r21"; case dwarf_r22_mips64: return "r22"; case dwarf_r23_mips64: return "r23"; case dwarf_r24_mips64: return "r24"; case dwarf_r25_mips64: return "r25"; case dwarf_r26_mips64: return "r26"; case dwarf_r27_mips64: return "r27"; case dwarf_gp_mips64: return "gp"; case dwarf_sp_mips64: return "sp"; case dwarf_r30_mips64: return "fp"; case dwarf_ra_mips64: return "ra"; case dwarf_sr_mips64: return "sr"; case dwarf_lo_mips64: return "lo"; case dwarf_hi_mips64: return "hi"; case dwarf_bad_mips64: return "bad"; case dwarf_cause_mips64: return "cause"; case dwarf_pc_mips64: return "pc"; case dwarf_f0_mips64: return "f0"; case dwarf_f1_mips64: return "f1"; case dwarf_f2_mips64: return "f2"; case dwarf_f3_mips64: return "f3"; case dwarf_f4_mips64: return "f4"; case dwarf_f5_mips64: return "f5"; case dwarf_f6_mips64: return "f6"; case dwarf_f7_mips64: return "f7"; case dwarf_f8_mips64: return "f8"; case dwarf_f9_mips64: return "f9"; case dwarf_f10_mips64: return "f10"; case dwarf_f11_mips64: return "f11"; case dwarf_f12_mips64: return "f12"; case dwarf_f13_mips64: return "f13"; case dwarf_f14_mips64: return "f14"; case dwarf_f15_mips64: return "f15"; case dwarf_f16_mips64: return "f16"; case dwarf_f17_mips64: return "f17"; case dwarf_f18_mips64: return "f18"; case dwarf_f19_mips64: return "f19"; case dwarf_f20_mips64: return "f20"; case dwarf_f21_mips64: return "f21"; case dwarf_f22_mips64: return "f22"; case dwarf_f23_mips64: return "f23"; case dwarf_f24_mips64: return "f24"; case dwarf_f25_mips64: return "f25"; case dwarf_f26_mips64: return "f26"; case dwarf_f27_mips64: return "f27"; case dwarf_f28_mips64: return "f28"; case dwarf_f29_mips64: return "f29"; case dwarf_f30_mips64: return "f30"; case dwarf_f31_mips64: return "f31"; case dwarf_fcsr_mips64: return "fcsr"; case dwarf_fir_mips64: return "fir"; case dwarf_w0_mips64: return "w0"; case dwarf_w1_mips64: return "w1"; case dwarf_w2_mips64: return "w2"; case dwarf_w3_mips64: return "w3"; case dwarf_w4_mips64: return "w4"; case dwarf_w5_mips64: return "w5"; case dwarf_w6_mips64: return "w6"; case dwarf_w7_mips64: return "w7"; case dwarf_w8_mips64: return "w8"; case dwarf_w9_mips64: return "w9"; case dwarf_w10_mips64: return "w10"; case dwarf_w11_mips64: return "w11"; case dwarf_w12_mips64: return "w12"; case dwarf_w13_mips64: return "w13"; case dwarf_w14_mips64: return "w14"; case dwarf_w15_mips64: return "w15"; case dwarf_w16_mips64: return "w16"; case dwarf_w17_mips64: return "w17"; case dwarf_w18_mips64: return "w18"; case dwarf_w19_mips64: return "w19"; case dwarf_w20_mips64: return "w20"; case dwarf_w21_mips64: return "w21"; case dwarf_w22_mips64: return "w22"; case dwarf_w23_mips64: return "w23"; case dwarf_w24_mips64: return "w24"; case dwarf_w25_mips64: return "w25"; case dwarf_w26_mips64: return "w26"; case dwarf_w27_mips64: return "w27"; case dwarf_w28_mips64: return "w28"; case dwarf_w29_mips64: return "w29"; case dwarf_w30_mips64: return "w30"; case dwarf_w31_mips64: return "w31"; case dwarf_mcsr_mips64: return "mcsr"; case dwarf_mir_mips64: return "mir"; case dwarf_config5_mips64: return "config5"; } return nullptr; } bool EmulateInstructionMIPS64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info) { if (reg_kind == eRegisterKindGeneric) { switch (reg_num) { case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc_mips64; break; case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp_mips64; break; case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_r30_mips64; break; case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = dwarf_ra_mips64; break; case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sr_mips64; break; default: return false; } } if (reg_kind == eRegisterKindDWARF) { ::memset (®_info, 0, sizeof(RegisterInfo)); ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds)); if (reg_num == dwarf_sr_mips64 || reg_num == dwarf_fcsr_mips64 || reg_num == dwarf_fir_mips64 || reg_num == dwarf_mcsr_mips64 || reg_num == dwarf_mir_mips64 || reg_num == dwarf_config5_mips64) { reg_info.byte_size = 4; reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if ((int)reg_num >= dwarf_zero_mips64 && (int)reg_num <= dwarf_f31_mips64) { reg_info.byte_size = 8; reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if ((int)reg_num >= dwarf_w0_mips64 && (int)reg_num <= dwarf_w31_mips64) { reg_info.byte_size = 16; reg_info.format = eFormatVectorOfUInt8; reg_info.encoding = eEncodingVector; } else { return false; } reg_info.name = GetRegisterName (reg_num, false); reg_info.alt_name = GetRegisterName (reg_num, true); reg_info.kinds[eRegisterKindDWARF] = reg_num; switch (reg_num) { case dwarf_r30_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break; case dwarf_ra_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break; case dwarf_sp_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break; case dwarf_pc_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break; case dwarf_sr_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break; default: break; } return true; } return false; } EmulateInstructionMIPS64::MipsOpcode* EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name) { static EmulateInstructionMIPS64::MipsOpcode g_opcodes[] = { //---------------------------------------------------------------------- // Prologue/Epilogue instructions //---------------------------------------------------------------------- - { "DADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "DADDIU rt,rs,immediate" }, - { "ADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "ADDIU rt,rs,immediate" }, - { "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt,offset(rs)" }, - { "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt,offset(base)" }, + { "DADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "DADDIU rt, rs, immediate" }, + { "ADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "ADDIU rt, rs, immediate" }, + { "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt, offset(rs)" }, + { "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt, offset(base)" }, + { "DSUBU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "DSUBU rd, rs, rt" }, + { "SUBU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "SUBU rd, rs, rt" }, + { "DADDU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "DADDU rd, rs, rt" }, + { "ADDU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "ADDU rd, rs, rt" }, + { "LUI", &EmulateInstructionMIPS64::Emulate_LUI, "LUI rt, immediate" }, //---------------------------------------------------------------------- // Load/Store instructions //---------------------------------------------------------------------- /* Following list of emulated instructions are required by implementation of hardware watchpoint for MIPS in lldb. As we just need the address accessed by instructions, we have generalised all these instructions in 2 functions depending on their addressing modes */ { "LB", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LB rt, offset(base)" }, { "LBE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBE rt, offset(base)" }, { "LBU", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBU rt, offset(base)" }, { "LBUE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBUE rt, offset(base)" }, { "LDC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDC1 ft, offset(base)" }, { "LDL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDL rt, offset(base)" }, { "LDR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDR rt, offset(base)" }, { "LLD", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LLD rt, offset(base)" }, { "LDC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDC2 rt, offset(base)" }, { "LDXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LDXC1 fd, index (base)" }, { "LH", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LH rt, offset(base)" }, { "LHE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHE rt, offset(base)" }, { "LHU", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHU rt, offset(base)" }, { "LHUE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHUE rt, offset(base)" }, { "LL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LL rt, offset(base)" }, { "LLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LLE rt, offset(base)" }, { "LUXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LUXC1 fd, index (base)" }, { "LW", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LW rt, offset(rs)" }, { "LWC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWC1 ft, offset(base)" }, { "LWC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWC2 rt, offset(base)" }, { "LWE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWE rt, offset(base)" }, { "LWL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWL rt, offset(base)" }, { "LWLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWLE rt, offset(base)" }, { "LWR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWR rt, offset(base)" }, { "LWRE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWRE rt, offset(base)" }, { "LWXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LWXC1 fd, index (base)" }, { "SB", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SB rt, offset(base)" }, { "SBE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SBE rt, offset(base)" }, { "SC", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SC rt, offset(base)" }, { "SCE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SCE rt, offset(base)" }, { "SCD", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SCD rt, offset(base)" }, { "SDL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDL rt, offset(base)" }, { "SDR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDR rt, offset(base)" }, { "SDC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDC1 ft, offset(base)" }, { "SDC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDC2 rt, offset(base)" }, { "SDXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SDXC1 fs, index (base)" }, { "SH", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SH rt, offset(base)" }, { "SHE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SHE rt, offset(base)" }, { "SUXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SUXC1 fs, index (base)" }, { "SW", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SW rt, offset(rs)" }, { "SWC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWC1 ft, offset(base)" }, { "SWC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWC2 rt, offset(base)" }, { "SWE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWE rt, offset(base)" }, { "SWL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWL rt, offset(base)" }, { "SWLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWLE rt, offset(base)" }, { "SWR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWR rt, offset(base)" }, { "SWRE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWRE rt, offset(base)" }, { "SWXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SWXC1 fs, index (base)" }, //---------------------------------------------------------------------- // Branch instructions //---------------------------------------------------------------------- { "BEQ", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQ rs,rt,offset" }, { "BNE", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNE rs,rt,offset" }, { "BEQL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQL rs,rt,offset" }, { "BNEL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNEL rs,rt,offset" }, { "BGEZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZALL rt,offset" }, { "BAL", &EmulateInstructionMIPS64::Emulate_BAL, "BAL offset" }, { "BGEZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZAL rs,offset" }, { "BALC", &EmulateInstructionMIPS64::Emulate_BALC, "BALC offset" }, { "BC", &EmulateInstructionMIPS64::Emulate_BC, "BC offset" }, { "BGEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZ rs,offset" }, { "BLEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLEZALC rs,offset" }, { "BGEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGEZALC rs,offset" }, { "BLTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLTZALC rs,offset" }, { "BGTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGTZALC rs,offset" }, { "BEQZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BEQZALC rs,offset" }, { "BNEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BNEZALC rs,offset" }, { "BEQC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BEQC rs,rt,offset" }, { "BNEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNEC rs,rt,offset" }, { "BLTC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTC rs,rt,offset" }, { "BGEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEC rs,rt,offset" }, { "BLTUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTUC rs,rt,offset" }, { "BGEUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEUC rs,rt,offset" }, { "BLTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLTZC rt,offset" }, { "BLEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLEZC rt,offset" }, { "BGEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGEZC rt,offset" }, { "BGTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGTZC rt,offset" }, { "BEQZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BEQZC rt,offset" }, { "BNEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BNEZC rt,offset" }, { "BGEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZL rt,offset" }, { "BGTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZ rt,offset" }, { "BGTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZL rt,offset" }, { "BLEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZ rt,offset" }, { "BLEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZL rt,offset" }, { "BLTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZ rt,offset" }, { "BLTZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZAL rt,offset" }, { "BLTZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZALL rt,offset" }, { "BLTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZL rt,offset" }, { "BOVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BOVC rs,rt,offset" }, { "BNVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNVC rs,rt,offset" }, { "J", &EmulateInstructionMIPS64::Emulate_J, "J target" }, { "JAL", &EmulateInstructionMIPS64::Emulate_JAL, "JAL target" }, { "JALX", &EmulateInstructionMIPS64::Emulate_JAL, "JALX target" }, { "JALR", &EmulateInstructionMIPS64::Emulate_JALR, "JALR target" }, { "JALR_HB", &EmulateInstructionMIPS64::Emulate_JALR, "JALR.HB target" }, { "JIALC", &EmulateInstructionMIPS64::Emulate_JIALC, "JIALC rt,offset" }, { "JIC", &EmulateInstructionMIPS64::Emulate_JIC, "JIC rt,offset" }, { "JR", &EmulateInstructionMIPS64::Emulate_JR, "JR target" }, { "JR_HB", &EmulateInstructionMIPS64::Emulate_JR, "JR.HB target" }, { "BC1F", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1F cc, offset" }, { "BC1T", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1T cc, offset" }, { "BC1FL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1FL cc, offset" }, { "BC1TL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1TL cc, offset" }, { "BC1EQZ", &EmulateInstructionMIPS64::Emulate_BC1EQZ, "BC1EQZ ft, offset" }, { "BC1NEZ", &EmulateInstructionMIPS64::Emulate_BC1NEZ, "BC1NEZ ft, offset" }, { "BC1ANY2F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2F cc, offset" }, { "BC1ANY2T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2T cc, offset" }, { "BC1ANY4F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4F cc, offset" }, { "BC1ANY4T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4T cc, offset" }, { "BNZ_B", &EmulateInstructionMIPS64::Emulate_BNZB, "BNZ.b wt,s16" }, { "BNZ_H", &EmulateInstructionMIPS64::Emulate_BNZH, "BNZ.h wt,s16" }, { "BNZ_W", &EmulateInstructionMIPS64::Emulate_BNZW, "BNZ.w wt,s16" }, { "BNZ_D", &EmulateInstructionMIPS64::Emulate_BNZD, "BNZ.d wt,s16" }, { "BZ_B", &EmulateInstructionMIPS64::Emulate_BZB, "BZ.b wt,s16" }, { "BZ_H", &EmulateInstructionMIPS64::Emulate_BZH, "BZ.h wt,s16" }, { "BZ_W", &EmulateInstructionMIPS64::Emulate_BZW, "BZ.w wt,s16" }, { "BZ_D", &EmulateInstructionMIPS64::Emulate_BZD, "BZ.d wt,s16" }, { "BNZ_V", &EmulateInstructionMIPS64::Emulate_BNZV, "BNZ.V wt,s16" }, { "BZ_V", &EmulateInstructionMIPS64::Emulate_BZV, "BZ.V wt,s16" }, }; static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes); for (size_t i = 0; i < k_num_mips_opcodes; ++i) { if (! strcasecmp (g_opcodes[i].op_name, op_name)) return &g_opcodes[i]; } return NULL; } bool EmulateInstructionMIPS64::ReadInstruction () { bool success = false; m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success); if (success) { Context read_inst_context; read_inst_context.type = eContextReadOpcode; read_inst_context.SetNoArgs (); m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder()); } if (!success) m_addr = LLDB_INVALID_ADDRESS; return success; } bool EmulateInstructionMIPS64::EvaluateInstruction (uint32_t evaluate_options) { bool success = false; llvm::MCInst mc_insn; uint64_t insn_size; DataExtractor data; /* Keep the complexity of the decode logic with the llvm::MCDisassembler class. */ if (m_opcode.GetData (data)) { llvm::MCDisassembler::DecodeStatus decode_status; llvm::ArrayRef raw_insn (data.GetDataStart(), data.GetByteSize()); decode_status = m_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); if (decode_status != llvm::MCDisassembler::Success) return false; } /* * mc_insn.getOpcode() returns decoded opcode. However to make use * of llvm::Mips:: we would need "MipsGenInstrInfo.inc". */ const char *op_name = m_insn_info->getName (mc_insn.getOpcode ()); if (op_name == NULL) return false; /* * Decoding has been done already. Just get the call-back function * and emulate the instruction. */ MipsOpcode *opcode_data = GetOpcodeForInstruction (op_name); if (opcode_data == NULL) return false; uint64_t old_pc = 0, new_pc = 0; const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; if (auto_advance_pc) { old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; } /* emulate instruction */ success = (this->*opcode_data->callback) (mc_insn); if (!success) return false; if (auto_advance_pc) { new_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; /* If we haven't changed the PC, change it here */ if (old_pc == new_pc) { new_pc += 4; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, new_pc)) return false; } } return true; } bool EmulateInstructionMIPS64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) { unwind_plan.Clear(); unwind_plan.SetRegisterKind (eRegisterKindDWARF); UnwindPlan::RowSP row(new UnwindPlan::Row); const bool can_replace = false; // Our previous Call Frame Address is the stack pointer row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp_mips64, 0); // Our previous PC is in the RA row->SetRegisterLocationToRegister(dwarf_pc_mips64, dwarf_ra_mips64, can_replace); unwind_plan.AppendRow (row); // All other registers are the same. unwind_plan.SetSourceName ("EmulateInstructionMIPS64"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); unwind_plan.SetReturnAddressRegister (dwarf_ra_mips64); return true; } bool EmulateInstructionMIPS64::nonvolatile_reg_p (uint64_t regnum) { switch (regnum) { case dwarf_r16_mips64: case dwarf_r17_mips64: case dwarf_r18_mips64: case dwarf_r19_mips64: case dwarf_r20_mips64: case dwarf_r21_mips64: case dwarf_r22_mips64: case dwarf_r23_mips64: case dwarf_gp_mips64: case dwarf_sp_mips64: case dwarf_r30_mips64: case dwarf_ra_mips64: return true; default: return false; } return false; } bool EmulateInstructionMIPS64::Emulate_DADDiu (llvm::MCInst& insn) { + // DADDIU rt, rs, immediate + // GPR[rt] <- GPR[rs] + sign_extend(immediate) + + uint8_t dst, src; bool success = false; const uint32_t imm16 = insn.getOperand(2).getImm(); - uint64_t imm = SignedBits(imm16, 15, 0); - uint64_t result; - uint32_t src, dst; + int64_t imm = SignedBits(imm16, 15, 0); dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - /* Check if this is daddiu sp,,imm16 */ - if (dst == dwarf_sp_mips64) + // If immediate is greater than 2^16 - 1 then clang generate + // LUI, (D)ADDIU,(D)SUBU instructions in prolog. + // Example + // lui $1, 0x2 + // daddiu $1, $1, -0x5920 + // dsubu $sp, $sp, $1 + // In this case, (D)ADDIU dst and src will be same and not equal to sp + if (dst == src) { + Context context; + /* read register */ - uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); + const int64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); if (!success) return false; - result = src_opd_val + imm; + /* Check if this is daddiu sp, sp, imm16 */ + if (dst == dwarf_sp_mips64) + { + uint64_t result = src_opd_val + imm; + RegisterInfo reg_info_sp; - Context context; - RegisterInfo reg_info_sp; - if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips64, reg_info_sp)) - context.SetRegisterPlusOffset (reg_info_sp, imm); + if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips64, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, imm); - /* We are allocating bytes on stack */ - context.type = eContextAdjustStackPointer; + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; - WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips64, result); + WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips64, result); + return true; + } + + imm += src_opd_val; + context.SetImmediateSigned (imm); + context.type = eContextImmediate; + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + dst, imm)) + return false; } - + return true; } bool EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn) { uint64_t address; RegisterInfo reg_info_base; RegisterInfo reg_info_src; bool success = false; uint32_t imm16 = insn.getOperand(2).getImm(); uint64_t imm = SignedBits(imm16, 15, 0); uint32_t src, base; Context bad_vaddr_context; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + base, reg_info_base) || !GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + src, reg_info_src)) return false; /* read SP */ address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* We look for sp based non-volatile register stores */ - if (base == dwarf_sp_mips64 && nonvolatile_reg_p (src)) + if (nonvolatile_reg_p (src)) { Context context; RegisterValue data_src; context.type = eContextPushRegisterOnStack; context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; Error error; if (!ReadRegister (®_info_base, data_src)) return false; if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) return false; if (!WriteMemory (context, address, buffer, reg_info_src.byte_size)) return false; } /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips64, address); return true; } bool EmulateInstructionMIPS64::Emulate_LD (llvm::MCInst& insn) { bool success =false; uint32_t src, base; int64_t imm, address; Context bad_vaddr_context; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); imm = insn.getOperand(2).getImm(); RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + base, reg_info_base)) return false; /* read base register */ address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips64, address); - if (base == dwarf_sp_mips64 && nonvolatile_reg_p (src)) + if (nonvolatile_reg_p (src)) { RegisterValue data_src; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + src, reg_info_src)) return false; Context context; context.type = eContextRegisterLoad; if (!WriteRegister (context, ®_info_src, data_src)) return false; return true; } return false; } +bool +EmulateInstructionMIPS64::Emulate_LUI (llvm::MCInst& insn) +{ + // LUI rt, immediate + // GPR[rt] <- sign_extend(immediate << 16) + + const uint32_t imm32 = insn.getOperand(1).getImm() << 16; + int64_t imm = SignedBits(imm32, 31, 0); + uint8_t rt; + Context context; + + rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + context.SetImmediateSigned (imm); + context.type = eContextImmediate; + + if (WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + rt, imm)) + return true; + + return false; +} + +bool +EmulateInstructionMIPS64::Emulate_DSUBU_DADDU (llvm::MCInst& insn) +{ + // DSUBU sp, , + // DADDU sp, , + // DADDU dst, sp, + + bool success = false; + uint64_t result; + uint8_t src, dst, rt; + const char *op_name = m_insn_info->getName (insn.getOpcode ()); + + dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); + + /* Check if sp is destination register */ + if (dst == dwarf_sp_mips64) + { + rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); + + /* read register */ + uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); + if (!success) + return false; + + /* read register */ + uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); + if (!success) + return false; + + if (!strcasecmp (op_name, "DSUBU") || !strcasecmp (op_name, "SUBU")) + result = src_opd_val - rt_opd_val; + else + result = src_opd_val + rt_opd_val; + + Context context; + RegisterInfo reg_info_sp; + if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips64, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, rt_opd_val); + + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; + + WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips64, result); + + return true; + } + else if (src == dwarf_sp_mips64) + { + rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); + + /* read register */ + uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); + if (!success) + return false; + + /* read register */ + uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); + if (!success) + return false; + + Context context; + + if (!strcasecmp (op_name, "DSUBU") || !strcasecmp (op_name, "SUBU")) + result = src_opd_val - rt_opd_val; + else + result = src_opd_val + rt_opd_val; + + context.SetImmediateSigned (result); + context.type = eContextImmediate; + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + dst, result)) + return false; + } + + return true; +} /* Emulate below MIPS branch instructions. BEQ, BNE : Branch on condition BEQL, BNEL : Branch likely */ bool EmulateInstructionMIPS64::Emulate_BXX_3ops (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; int64_t offset, pc, rs_val, rt_val, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BEQ") || !strcasecmp (op_name, "BEQL")) { if (rs_val == rt_val) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BNE") || !strcasecmp (op_name, "BNEL")) { if (rs_val != rt_val) target = pc + offset; else target = pc + 8; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } /* Emulate below MIPS Non-Compact conditional branch and link instructions. BLTZAL, BGEZAL : BLTZALL, BGEZALL : Branch likely */ bool EmulateInstructionMIPS64::Emulate_Bcond_Link (llvm::MCInst& insn) { bool success = false; uint32_t rs; int64_t offset, pc, target = 0; int64_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZAL") || !strcasecmp (op_name, "BLTZALL")) { if (rs_val < 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGEZAL") || !strcasecmp (op_name, "BGEZALL")) { if (rs_val >= 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BAL (llvm::MCInst& insn) { bool success = false; int64_t offset, pc, target; /* * BAL offset * offset = sign_ext (offset << 2) * RA = PC + 8 * PC = PC + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BALC (llvm::MCInst& insn) { bool success = false; int64_t offset, pc, target; /* * BALC offset * offset = sign_ext (offset << 2) * RA = PC + 4 * PC = PC + 4 + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) return false; return true; } /* Emulate below MIPS conditional branch and link instructions. BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches */ bool EmulateInstructionMIPS64::Emulate_Bcond_Link_C (llvm::MCInst& insn) { bool success = false; uint32_t rs; int64_t offset, pc, rs_val, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLEZALC")) { if (rs_val <= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEZALC")) { if (rs_val >= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTZALC")) { if (rs_val < 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGTZALC")) { if (rs_val > 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BEQZALC")) { if (rs_val == 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEZALC")) { if (rs_val != 0) target = pc + offset; else target = pc + 4; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) return false; return true; } /* Emulate below MIPS branch instructions. BLTZL, BGEZL, BGTZL, BLEZL : Branch likely BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches */ bool EmulateInstructionMIPS64::Emulate_BXX_2ops (llvm::MCInst& insn) { bool success = false; uint32_t rs; int64_t offset, pc, rs_val, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZL") || !strcasecmp (op_name, "BLTZ")) { if (rs_val < 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGEZL") || !strcasecmp (op_name, "BGEZ")) { if (rs_val >= 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BGTZL") || !strcasecmp (op_name, "BGTZ")) { if (rs_val > 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BLEZL") || !strcasecmp (op_name, "BLEZ")) { if (rs_val <= 0) target = pc + offset; else target = pc + 8; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BC (llvm::MCInst& insn) { bool success = false; int64_t offset, pc, target; /* * BC offset * offset = sign_ext (offset << 2) * PC = PC + 4 + offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; target = pc + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } static int IsAdd64bitOverflow (int64_t a, int64_t b) { int64_t r = (uint64_t) a + (uint64_t) b; return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0); } /* Emulate below MIPS branch instructions. BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch instructions with no delay slot */ bool EmulateInstructionMIPS64::Emulate_BXX_3ops_C (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; int64_t offset, pc, rs_val, rt_val, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); offset = insn.getOperand(2).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BEQC")) { if (rs_val == rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEC")) { if (rs_val != rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTC")) { if (rs_val < rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEC")) { if (rs_val >= rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLTUC")) { if (rs_val < rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEUC")) { if ((uint32_t)rs_val >= (uint32_t)rt_val) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BOVC")) { if (IsAdd64bitOverflow (rs_val, rt_val)) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNVC")) { if (!IsAdd64bitOverflow (rs_val, rt_val)) target = pc + offset; else target = pc + 4; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } /* Emulate below MIPS branch instructions. BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches */ bool EmulateInstructionMIPS64::Emulate_BXX_2ops_C (llvm::MCInst& insn) { bool success = false; uint32_t rs; int64_t offset, pc, target = 0; int64_t rs_val; const char *op_name = m_insn_info->getName (insn.getOpcode ()); uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; if (!strcasecmp (op_name, "BLTZC")) { if (rs_val < 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BLEZC")) { if (rs_val <= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGEZC")) { if (rs_val >= 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BGTZC")) { if (rs_val > 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BEQZC")) { if (rs_val == 0) target = pc + offset; else target = pc + 4; } else if (!strcasecmp (op_name, "BNEZC")) { if (rs_val != 0) target = pc + offset; else target = pc + 4; } Context context; context.type = eContextRelativeBranchImmediate; context.SetImmediate (current_inst_size + offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_J (llvm::MCInst& insn) { bool success = false; uint64_t offset, pc; /* * J offset * offset = sign_ext (offset << 2) * PC = PC[63-28] | offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; /* This is a PC-region branch and not PC-relative */ pc = (pc & 0xFFFFFFFFF0000000ULL) | offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, pc)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_JAL (llvm::MCInst& insn) { bool success = false; uint64_t offset, target, pc; /* * JAL offset * offset = sign_ext (offset << 2) * PC = PC[63-28] | offset */ offset = insn.getOperand(0).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; /* This is a PC-region branch and not PC-relative */ target = (pc & 0xFFFFFFFFF0000000ULL) | offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_JALR (llvm::MCInst& insn) { bool success = false; uint32_t rs, rt; uint64_t pc, rs_val; /* * JALR rt, rs * GPR[rt] = PC + 8 * PC = GPR[rs] */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, rs_val)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + rt, pc + 8)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_JIALC (llvm::MCInst& insn) { bool success = false; uint32_t rt; int64_t target, offset, pc, rt_val; /* * JIALC rt, offset * offset = sign_ext (offset) * PC = GPR[rt] + offset * RA = PC + 4 */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); if (!success) return false; target = rt_val + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_JIC (llvm::MCInst& insn) { bool success = false; uint32_t rt; int64_t target, offset, rt_val; /* * JIC rt, offset * offset = sign_ext (offset) * PC = GPR[rt] + offset */ rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); if (!success) return false; target = rt_val + offset; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_JR (llvm::MCInst& insn) { bool success = false; uint32_t rs; uint64_t rs_val; /* * JR rs * PC = GPR[rs] */ rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); if (!success) return false; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, rs_val)) return false; return true; } /* Emulate Branch on FP True/False BC1F, BC1FL : Branch on FP False (L stands for branch likely) BC1T, BC1TL : Branch on FP True (L stands for branch likely) */ bool EmulateInstructionMIPS64::Emulate_FP_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; int64_t pc, offset, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); /* * BC1F cc, offset * condition <- (FPConditionCode(cc) == 0) * if condition then * offset = sign_ext (offset) * PC = PC + offset */ cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); if (!success) return false; /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); if (!strcasecmp (op_name, "BC1F") || !strcasecmp (op_name, "BC1FL")) { if ((fcsr & (1 << cc)) == 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1T") || !strcasecmp (op_name, "BC1TL")) { if ((fcsr & (1 << cc)) != 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BC1EQZ (llvm::MCInst& insn) { bool success = false; uint32_t ft; uint64_t ft_val; int64_t target, pc, offset; /* * BC1EQZ ft, offset * condition <- (FPR[ft].bit0 == 0) * if condition then * offset = sign_ext (offset) * PC = PC + 4 + offset */ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + ft, 0, &success); if (!success) return false; if ((ft_val & 1) == 0) target = pc + 4 + offset; else target = pc + 8; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BC1NEZ (llvm::MCInst& insn) { bool success = false; uint32_t ft; uint64_t ft_val; int64_t target, pc, offset; /* * BC1NEZ ft, offset * condition <- (FPR[ft].bit0 != 0) * if condition then * offset = sign_ext (offset) * PC = PC + 4 + offset */ ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + ft, 0, &success); if (!success) return false; if ((ft_val & 1) != 0) target = pc + 4 + offset; else target = pc + 8; Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } /* Emulate MIPS-3D Branch instructions BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes False/True BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes False/True */ bool EmulateInstructionMIPS64::Emulate_3D_branch (llvm::MCInst& insn) { bool success = false; uint32_t cc, fcsr; int64_t pc, offset, target = 0; const char *op_name = m_insn_info->getName (insn.getOpcode ()); cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); offset = insn.getOperand(1).getImm(); pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); if (!success) return false; /* fcsr[23], fcsr[25-31] are vaild condition bits */ fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); if (!strcasecmp (op_name, "BC1ANY2F")) { /* if any one bit is 0 */ if (((fcsr >> cc) & 3) != 3) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY2T")) { /* if any one bit is 1 */ if (((fcsr >> cc) & 3) != 0) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY4F")) { /* if any one bit is 0 */ if (((fcsr >> cc) & 0xf) != 0xf) target = pc + offset; else target = pc + 8; } else if (!strcasecmp (op_name, "BC1ANY4T")) { /* if any one bit is 1 */ if (((fcsr >> cc) & 0xf) != 0) target = pc + offset; else target = pc + 8; } Context context; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BNZB (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 1, true); } bool EmulateInstructionMIPS64::Emulate_BNZH (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 2, true); } bool EmulateInstructionMIPS64::Emulate_BNZW (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 4, true); } bool EmulateInstructionMIPS64::Emulate_BNZD (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 8, true); } bool EmulateInstructionMIPS64::Emulate_BZB (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 1, false); } bool EmulateInstructionMIPS64::Emulate_BZH (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 2, false); } bool EmulateInstructionMIPS64::Emulate_BZW (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 4, false); } bool EmulateInstructionMIPS64::Emulate_BZD (llvm::MCInst& insn) { return Emulate_MSA_Branch_DF(insn, 8, false); } bool EmulateInstructionMIPS64::Emulate_MSA_Branch_DF (llvm::MCInst& insn, int element_byte_size, bool bnz) { bool success = false, branch_hit = true; int64_t target = 0; RegisterValue reg_value; const uint8_t *ptr = NULL; uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); int64_t offset = insn.getOperand(1).getImm(); int64_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips64 + wt, reg_value)) ptr = (const uint8_t *)reg_value.GetBytes(); else return false; for(int i = 0; i < 16 / element_byte_size; i++) { switch(element_byte_size) { case 1: if((*ptr == 0 && bnz) || (*ptr != 0 && !bnz) ) branch_hit = false; break; case 2: if ((*(const uint16_t *)ptr == 0 && bnz) || (*(const uint16_t *)ptr != 0 && !bnz)) branch_hit = false; break; case 4: if ((*(const uint32_t *)ptr == 0 && bnz) || (*(const uint32_t *)ptr != 0 && !bnz)) branch_hit = false; break; case 8: if ((*(const uint64_t *)ptr == 0 && bnz) || (*(const uint64_t *)ptr != 0 && !bnz)) branch_hit = false; break; } if(!branch_hit) break; ptr = ptr + element_byte_size; } if(branch_hit) target = pc + offset; else target = pc + 8; Context context; context.type = eContextRelativeBranchImmediate; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_BNZV (llvm::MCInst& insn) { return Emulate_MSA_Branch_V (insn, true); } bool EmulateInstructionMIPS64::Emulate_BZV (llvm::MCInst& insn) { return Emulate_MSA_Branch_V (insn, false); } bool EmulateInstructionMIPS64::Emulate_MSA_Branch_V (llvm::MCInst& insn, bool bnz) { bool success = false; int64_t target = 0; llvm::APInt wr_val = llvm::APInt::getNullValue(128); llvm::APInt fail_value = llvm::APInt::getMaxValue(128); llvm::APInt zero_value = llvm::APInt::getNullValue(128); RegisterValue reg_value; uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); int64_t offset = insn.getOperand(1).getImm(); int64_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); if (!success) return false; if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips64 + wt, reg_value)) wr_val = reg_value.GetAsUInt128(fail_value); else return false; if((llvm::APInt::isSameValue(zero_value, wr_val) && !bnz) || (!llvm::APInt::isSameValue(zero_value, wr_val) && bnz)) target = pc + offset; else target = pc + 8; Context context; context.type = eContextRelativeBranchImmediate; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) return false; return true; } bool EmulateInstructionMIPS64::Emulate_LDST_Imm (llvm::MCInst& insn) { bool success = false; uint32_t base; int64_t imm, address; Context bad_vaddr_context; uint32_t num_operands = insn.getNumOperands(); base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); imm = insn.getOperand(num_operands-1).getImm(); RegisterInfo reg_info_base; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; /* read base register */ address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); return true; } bool EmulateInstructionMIPS64::Emulate_LDST_Reg (llvm::MCInst& insn) { bool success = false; uint32_t base, index; int64_t address, index_address; Context bad_vaddr_context; uint32_t num_operands = insn.getNumOperands(); base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); index = m_reg_info->getEncodingValue (insn.getOperand(num_operands-1).getReg()); RegisterInfo reg_info_base, reg_info_index; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) return false; if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + index, reg_info_index)) return false; /* read base register */ address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); if (!success) return false; /* read index register */ index_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + index, 0, &success); if (!success) return false; /* destination address */ address = address + index_address; /* Set the bad_vaddr register with base address used in the instruction */ bad_vaddr_context.type = eContextInvalid; WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); return true; } Index: vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h =================================================================== --- vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h (revision 304308) @@ -1,243 +1,249 @@ //===-- EmulateInstructionMIPS64.h ------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef EmulateInstructionMIPS64_h_ #define EmulateInstructionMIPS64_h_ // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Error.h" #include "lldb/Interpreter/OptionValue.h" namespace llvm { class MCDisassembler; class MCSubtargetInfo; class MCRegisterInfo; class MCAsmInfo; class MCContext; class MCInstrInfo; class MCInst; } // namespace llvm class EmulateInstructionMIPS64 : public lldb_private::EmulateInstruction { public: EmulateInstructionMIPS64(const lldb_private::ArchSpec &arch); static void Initialize (); static void Terminate (); static lldb_private::ConstString GetPluginNameStatic (); static const char * GetPluginDescriptionStatic (); static lldb_private::EmulateInstruction * CreateInstance (const lldb_private::ArchSpec &arch, lldb_private::InstructionType inst_type); static bool SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type) { switch (inst_type) { case lldb_private::eInstructionTypeAny: case lldb_private::eInstructionTypePrologueEpilogue: case lldb_private::eInstructionTypePCModifying: return true; case lldb_private::eInstructionTypeAll: return false; } return false; } lldb_private::ConstString GetPluginName() override; uint32_t GetPluginVersion() override { return 1; } bool SetTargetTriple(const lldb_private::ArchSpec &arch) override; bool SupportsEmulatingInstructionsOfType(lldb_private::InstructionType inst_type) override { return SupportsEmulatingInstructionsOfTypeStatic (inst_type); } bool ReadInstruction() override; bool EvaluateInstruction(uint32_t evaluate_options) override; bool TestEmulation(lldb_private::Stream *out_stream, lldb_private::ArchSpec &arch, lldb_private::OptionValueDictionary *test_data) override { return false; } bool GetRegisterInfo(lldb::RegisterKind reg_kind, uint32_t reg_num, lldb_private::RegisterInfo ®_info) override; bool CreateFunctionEntryUnwind(lldb_private::UnwindPlan &unwind_plan) override; protected: typedef struct { const char *op_name; bool (EmulateInstructionMIPS64::*callback) (llvm::MCInst& insn); const char *insn_name; } MipsOpcode; static MipsOpcode* GetOpcodeForInstruction (const char *op_name); bool Emulate_DADDiu (llvm::MCInst& insn); bool + Emulate_DSUBU_DADDU (llvm::MCInst& insn); + + bool + Emulate_LUI (llvm::MCInst& insn); + + bool Emulate_SD (llvm::MCInst& insn); bool Emulate_LD (llvm::MCInst& insn); bool Emulate_LDST_Imm (llvm::MCInst& insn); bool Emulate_LDST_Reg (llvm::MCInst& insn); bool Emulate_BXX_3ops (llvm::MCInst& insn); bool Emulate_BXX_3ops_C (llvm::MCInst& insn); bool Emulate_BXX_2ops (llvm::MCInst& insn); bool Emulate_BXX_2ops_C (llvm::MCInst& insn); bool Emulate_Bcond_Link_C (llvm::MCInst& insn); bool Emulate_Bcond_Link (llvm::MCInst& insn); bool Emulate_FP_branch (llvm::MCInst& insn); bool Emulate_3D_branch (llvm::MCInst& insn); bool Emulate_BAL (llvm::MCInst& insn); bool Emulate_BALC (llvm::MCInst& insn); bool Emulate_BC (llvm::MCInst& insn); bool Emulate_J (llvm::MCInst& insn); bool Emulate_JAL (llvm::MCInst& insn); bool Emulate_JALR (llvm::MCInst& insn); bool Emulate_JIALC (llvm::MCInst& insn); bool Emulate_JIC (llvm::MCInst& insn); bool Emulate_JR (llvm::MCInst& insn); bool Emulate_BC1EQZ (llvm::MCInst& insn); bool Emulate_BC1NEZ (llvm::MCInst& insn); bool Emulate_BNZB (llvm::MCInst& insn); bool Emulate_BNZH (llvm::MCInst& insn); bool Emulate_BNZW (llvm::MCInst& insn); bool Emulate_BNZD (llvm::MCInst& insn); bool Emulate_BZB (llvm::MCInst& insn); bool Emulate_BZH (llvm::MCInst& insn); bool Emulate_BZW (llvm::MCInst& insn); bool Emulate_BZD (llvm::MCInst& insn); bool Emulate_MSA_Branch_DF (llvm::MCInst& insn, int element_byte_size, bool bnz); bool Emulate_BNZV (llvm::MCInst& insn); bool Emulate_BZV (llvm::MCInst& insn); bool Emulate_MSA_Branch_V (llvm::MCInst& insn, bool bnz); bool nonvolatile_reg_p (uint64_t regnum); const char * GetRegisterName (unsigned reg_num, bool altnernate_name); private: std::unique_ptr m_disasm; std::unique_ptr m_subtype_info; std::unique_ptr m_reg_info; std::unique_ptr m_asm_info; std::unique_ptr m_context; std::unique_ptr m_insn_info; }; #endif // EmulateInstructionMIPS64_h_ Index: vendor/lldb/dist/source/Plugins/Process/Linux/NativeProcessLinux.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Linux/NativeProcessLinux.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Linux/NativeProcessLinux.cpp (revision 304308) @@ -1,2986 +1,2985 @@ //===-- NativeProcessLinux.cpp -------------------------------- -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "NativeProcessLinux.h" // C Includes #include #include #include #include // C++ Includes #include #include #include #include #include // Other libraries and framework includes #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Error.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Target/Target.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StringExtractor.h" #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" #include "NativeThreadLinux.h" #include "ProcFileReader.h" #include "Procfs.h" // System includes - They have to be included after framework includes because they define some // macros which collide with variable names in other modules #include #include #include #include #include #include #include "lldb/Host/linux/Personality.h" #include "lldb/Host/linux/Ptrace.h" #include "lldb/Host/linux/Uio.h" -#include "lldb/Host/android/Android.h" #define LLDB_PERSONALITY_GET_CURRENT_SETTINGS 0xffffffff // Support hardware breakpoints in case it has not been defined #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 4 #endif using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; using namespace llvm; // Private bits we only need internally. static bool ProcessVmReadvSupported() { static bool is_supported; static std::once_flag flag; std::call_once(flag, [] { Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); uint32_t source = 0x47424742; uint32_t dest = 0; struct iovec local, remote; remote.iov_base = &source; local.iov_base = &dest; remote.iov_len = local.iov_len = sizeof source; // We shall try if cross-process-memory reads work by attempting to read a value from our own process. ssize_t res = process_vm_readv(getpid(), &local, 1, &remote, 1, 0); is_supported = (res == sizeof(source) && source == dest); if (log) { if (is_supported) log->Printf("%s: Detected kernel support for process_vm_readv syscall. Fast memory reads enabled.", __FUNCTION__); else log->Printf("%s: syscall process_vm_readv failed (error: %s). Fast memory reads disabled.", __FUNCTION__, strerror(errno)); } }); return is_supported; } namespace { Error ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch) { // Grab process info for the running process. ProcessInstanceInfo process_info; if (!Host::GetProcessInfo(pid, process_info)) return Error("failed to get process info"); // Resolve the executable module. ModuleSpecList module_specs; if (!ObjectFile::GetModuleSpecifications(process_info.GetExecutableFile(), 0, 0, module_specs)) return Error("failed to get module specifications"); assert(module_specs.GetSize() == 1); arch = module_specs.GetModuleSpecRefAtIndex(0).GetArchitecture(); if (arch.IsValid()) return Error(); else return Error("failed to retrieve a valid architecture from the exe module"); } // Used to notify the parent about which part of the launch sequence failed. enum LaunchCallSpecifier { ePtraceFailed, eDupStdinFailed, eDupStdoutFailed, eDupStderrFailed, eChdirFailed, eExecFailed, eSetGidFailed, eSetSigMaskFailed, eLaunchCallMax = eSetSigMaskFailed }; static uint8_t LLVM_ATTRIBUTE_NORETURN ExitChildAbnormally(LaunchCallSpecifier spec) { static_assert(eLaunchCallMax < 0x8, "Have more launch calls than we are able to represent"); // This may truncate the topmost bits of the errno because the exit code is only 8 bits wide. // However, it should still give us a pretty good indication of what went wrong. (And the // most common errors have small numbers anyway). _exit(unsigned(spec) | (errno << 3)); } // The second member is the errno (or its 5 lowermost bits anyway). inline std::pair DecodeChildExitCode(int exit_code) { return std::make_pair(LaunchCallSpecifier(exit_code & 0x7), exit_code >> 3); } void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (!log) return; if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) log->Printf("%s: setting STDIN to '%s'", __FUNCTION__, action->GetFileSpec().GetCString()); else log->Printf("%s leaving STDIN as is", __FUNCTION__); if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) log->Printf("%s setting STDOUT to '%s'", __FUNCTION__, action->GetFileSpec().GetCString()); else log->Printf("%s leaving STDOUT as is", __FUNCTION__); if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) log->Printf("%s setting STDERR to '%s'", __FUNCTION__, action->GetFileSpec().GetCString()); else log->Printf("%s leaving STDERR as is", __FUNCTION__); int i = 0; for (const char **args = info.GetArguments().GetConstArgumentVector(); *args; ++args, ++i) log->Printf("%s arg %d: \"%s\"", __FUNCTION__, i, *args ? *args : "nullptr"); } void DisplayBytes(StreamString &s, void *bytes, uint32_t count) { uint8_t *ptr = (uint8_t *)bytes; const uint32_t loop_count = std::min(DEBUG_PTRACE_MAXBYTES, count); for (uint32_t i = 0; i < loop_count; i++) { s.Printf("[%x]", *ptr); ptr++; } } void PtraceDisplayBytes(int &req, void *data, size_t data_size) { StreamString buf; Log *verbose_log (ProcessPOSIXLog::GetLogIfAllCategoriesSet ( POSIX_LOG_PTRACE | POSIX_LOG_VERBOSE)); if (verbose_log) { switch(req) { case PTRACE_POKETEXT: { DisplayBytes(buf, &data, 8); verbose_log->Printf("PTRACE_POKETEXT %s", buf.GetData()); break; } case PTRACE_POKEDATA: { DisplayBytes(buf, &data, 8); verbose_log->Printf("PTRACE_POKEDATA %s", buf.GetData()); break; } case PTRACE_POKEUSER: { DisplayBytes(buf, &data, 8); verbose_log->Printf("PTRACE_POKEUSER %s", buf.GetData()); break; } case PTRACE_SETREGS: { DisplayBytes(buf, data, data_size); verbose_log->Printf("PTRACE_SETREGS %s", buf.GetData()); break; } case PTRACE_SETFPREGS: { DisplayBytes(buf, data, data_size); verbose_log->Printf("PTRACE_SETFPREGS %s", buf.GetData()); break; } case PTRACE_SETSIGINFO: { DisplayBytes(buf, data, sizeof(siginfo_t)); verbose_log->Printf("PTRACE_SETSIGINFO %s", buf.GetData()); break; } case PTRACE_SETREGSET: { // Extract iov_base from data, which is a pointer to the struct IOVEC DisplayBytes(buf, *(void **)data, data_size); verbose_log->Printf("PTRACE_SETREGSET %s", buf.GetData()); break; } default: { } } } } static constexpr unsigned k_ptrace_word_size = sizeof(void*); static_assert(sizeof(long) >= k_ptrace_word_size, "Size of long must be larger than ptrace word size"); } // end of anonymous namespace // Simple helper function to ensure flags are enabled on the given file // descriptor. static Error EnsureFDFlags(int fd, int flags) { Error error; int status = fcntl(fd, F_GETFL); if (status == -1) { error.SetErrorToErrno(); return error; } if (fcntl(fd, F_SETFL, status | flags) == -1) { error.SetErrorToErrno(); return error; } return error; } // ----------------------------------------------------------------------------- // Public Static Methods // ----------------------------------------------------------------------------- Error NativeProcessProtocol::Launch ( ProcessLaunchInfo &launch_info, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); Error error; // Verify the working directory is valid if one was specified. FileSpec working_dir{launch_info.GetWorkingDirectory()}; if (working_dir && (!working_dir.ResolvePath() || working_dir.GetFileType() != FileSpec::eFileTypeDirectory)) { error.SetErrorStringWithFormat ("No such file or directory: %s", working_dir.GetCString()); return error; } // Create the NativeProcessLinux in launch mode. native_process_sp.reset (new NativeProcessLinux ()); if (!native_process_sp->RegisterNativeDelegate (native_delegate)) { native_process_sp.reset (); error.SetErrorStringWithFormat ("failed to register the native delegate"); return error; } error = std::static_pointer_cast(native_process_sp)->LaunchInferior(mainloop, launch_info); if (error.Fail ()) { native_process_sp.reset (); if (log) log->Printf ("NativeProcessLinux::%s failed to launch process: %s", __FUNCTION__, error.AsCString ()); return error; } launch_info.SetProcessID (native_process_sp->GetID ()); return error; } Error NativeProcessProtocol::Attach ( lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate, MainLoop &mainloop, NativeProcessProtocolSP &native_process_sp) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log && log->GetMask ().Test (POSIX_LOG_VERBOSE)) log->Printf ("NativeProcessLinux::%s(pid = %" PRIi64 ")", __FUNCTION__, pid); // Retrieve the architecture for the running process. ArchSpec process_arch; Error error = ResolveProcessArchitecture(pid, process_arch); if (!error.Success ()) return error; std::shared_ptr native_process_linux_sp (new NativeProcessLinux ()); if (!native_process_linux_sp->RegisterNativeDelegate (native_delegate)) { error.SetErrorStringWithFormat ("failed to register the native delegate"); return error; } native_process_linux_sp->AttachToInferior (mainloop, pid, error); if (!error.Success ()) return error; native_process_sp = native_process_linux_sp; return error; } // ----------------------------------------------------------------------------- // Public Instance Methods // ----------------------------------------------------------------------------- NativeProcessLinux::NativeProcessLinux () : NativeProcessProtocol (LLDB_INVALID_PROCESS_ID), m_arch (), m_supports_mem_region (eLazyBoolCalculate), m_mem_region_cache (), m_pending_notification_tid(LLDB_INVALID_THREAD_ID) { } void NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error &error) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ")", __FUNCTION__, pid); m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD, [this] (MainLoopBase &) { SigchldHandler(); }, error); if (! m_sigchld_handle) return; error = ResolveProcessArchitecture(pid, m_arch); if (!error.Success()) return; // Set the architecture to the exe architecture. if (log) log->Printf ("NativeProcessLinux::%s (pid = %" PRIi64 ") detected architecture %s", __FUNCTION__, pid, m_arch.GetArchitectureName ()); m_pid = pid; SetState(eStateAttaching); Attach(pid, error); } void NativeProcessLinux::ChildFunc(const ProcessLaunchInfo &info) { // Start tracing this child that is about to exec. if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) ExitChildAbnormally(ePtraceFailed); // Do not inherit setgid powers. if (setgid(getgid()) != 0) ExitChildAbnormally(eSetGidFailed); // Attempt to have our own process group. if (setpgid(0, 0) != 0) { // FIXME log that this failed. This is common. // Don't allow this to prevent an inferior exec. } // Dup file descriptors if needed. if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) if (!DupDescriptor(action->GetFileSpec(), STDIN_FILENO, O_RDONLY)) ExitChildAbnormally(eDupStdinFailed); if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) if (!DupDescriptor(action->GetFileSpec(), STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) ExitChildAbnormally(eDupStdoutFailed); if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) if (!DupDescriptor(action->GetFileSpec(), STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) ExitChildAbnormally(eDupStderrFailed); // Close everything besides stdin, stdout, and stderr that has no file // action to avoid leaking for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd) if (!info.GetFileActionForFD(fd)) close(fd); // Change working directory if (info.GetWorkingDirectory() && 0 != ::chdir(info.GetWorkingDirectory().GetCString())) ExitChildAbnormally(eChdirFailed); // Disable ASLR if requested. if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) { const int old_personality = personality(LLDB_PERSONALITY_GET_CURRENT_SETTINGS); if (old_personality == -1) { // Can't retrieve Linux personality. Cannot disable ASLR. } else { const int new_personality = personality(ADDR_NO_RANDOMIZE | old_personality); if (new_personality == -1) { // Disabling ASLR failed. } else { // Disabling ASLR succeeded. } } } // Clear the signal mask to prevent the child from being affected by // any masking done by the parent. sigset_t set; if (sigemptyset(&set) != 0 || pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0) ExitChildAbnormally(eSetSigMaskFailed); const char **argv = info.GetArguments().GetConstArgumentVector(); // Propagate the environment if one is not supplied. const char **envp = info.GetEnvironmentEntries().GetConstArgumentVector(); if (envp == NULL || envp[0] == NULL) envp = const_cast(environ); // Execute. We should never return... execve(argv[0], const_cast(argv), const_cast(envp)); if (errno == ETXTBSY) { // On android M and earlier we can get this error because the adb deamon can hold a write // handle on the executable even after it has finished uploading it. This state lasts // only a short time and happens only when there are many concurrent adb commands being // issued, such as when running the test suite. (The file remains open when someone does // an "adb shell" command in the fork() child before it has had a chance to exec.) Since // this state should clear up quickly, wait a while and then give it one more go. usleep(50000); execve(argv[0], const_cast(argv), const_cast(envp)); } // ...unless exec fails. In which case we definitely need to end the child here. ExitChildAbnormally(eExecFailed); } Error NativeProcessLinux::LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info) { Error error; m_sigchld_handle = mainloop.RegisterSignal(SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, error); if (!m_sigchld_handle) return error; SetState(eStateLaunching); lldb_utility::PseudoTerminal terminal; const size_t err_len = 1024; char err_str[err_len]; lldb::pid_t pid; MaybeLogLaunchInfo(launch_info); if ((pid = terminal.Fork(err_str, err_len)) == static_cast (-1)) { error.SetErrorToGenericError(); error.SetErrorStringWithFormat("Process fork failed: %s", err_str); return error; } // Child process. if (pid == 0) { // First, make sure we disable all logging. If we are logging to stdout, our logs can be // mistaken for inferior output. Log::DisableAllLogChannels(nullptr); // terminal has already dupped the tty descriptors to stdin/out/err. // This closes original fd from which they were copied (and avoids // leaking descriptors to the debugged process. terminal.CloseSlaveFileDescriptor(); ChildFunc(launch_info); } Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); // Wait for the child process to trap on its call to execve. ::pid_t wpid; int status; if ((wpid = waitpid(pid, &status, 0)) < 0) { error.SetErrorToErrno(); if (log) log->Printf ("NativeProcessLinux::%s waitpid for inferior failed with %s", __FUNCTION__, error.AsCString ()); // Mark the inferior as invalid. // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. SetState (StateType::eStateInvalid); return error; } else if (WIFEXITED(status)) { auto p = DecodeChildExitCode(WEXITSTATUS(status)); Error child_error(p.second, eErrorTypePOSIX); const char *failure_reason; switch (p.first) { case ePtraceFailed: failure_reason = "Child ptrace failed"; break; case eDupStdinFailed: failure_reason = "Child open stdin failed"; break; case eDupStdoutFailed: failure_reason = "Child open stdout failed"; break; case eDupStderrFailed: failure_reason = "Child open stderr failed"; break; case eChdirFailed: failure_reason = "Child failed to set working directory"; break; case eExecFailed: failure_reason = "Child exec failed"; break; case eSetGidFailed: failure_reason = "Child setgid failed"; break; case eSetSigMaskFailed: failure_reason = "Child failed to set signal mask"; break; } error.SetErrorStringWithFormat("%s: %d - %s (error code truncated)", failure_reason, child_error.GetError(), child_error.AsCString()); if (log) { log->Printf ("NativeProcessLinux::%s inferior exited with status %d before issuing a STOP", __FUNCTION__, WEXITSTATUS(status)); } // Mark the inferior as invalid. // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. SetState (StateType::eStateInvalid); return error; } assert(WIFSTOPPED(status) && (wpid == static_cast< ::pid_t> (pid)) && "Could not sync with inferior process."); if (log) log->Printf ("NativeProcessLinux::%s inferior started, now in stopped state", __FUNCTION__); error = SetDefaultPtraceOpts(pid); if (error.Fail()) { if (log) log->Printf ("NativeProcessLinux::%s inferior failed to set default ptrace options: %s", __FUNCTION__, error.AsCString ()); // Mark the inferior as invalid. // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. SetState (StateType::eStateInvalid); return error; } // Release the master terminal descriptor and pass it off to the // NativeProcessLinux instance. Similarly stash the inferior pid. m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); m_pid = pid; launch_info.SetProcessID(pid); // Set the terminal fd to be in non blocking mode (it simplifies the // implementation of ProcessLinux::GetSTDOUT to have a non-blocking // descriptor to read from). error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); if (error.Fail()) { if (log) log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s", __FUNCTION__, error.AsCString ()); // Mark the inferior as invalid. // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. SetState (StateType::eStateInvalid); return error; } if (log) log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid); ResolveProcessArchitecture(m_pid, m_arch); NativeThreadLinuxSP thread_sp = AddThread(pid); assert (thread_sp && "AddThread() returned a nullptr thread"); thread_sp->SetStoppedBySignal(SIGSTOP); ThreadWasCreated(*thread_sp); // Let our process instance know the thread has stopped. SetCurrentThreadID (thread_sp->GetID ()); SetState (StateType::eStateStopped); if (log) { if (error.Success ()) log->Printf("NativeProcessLinux::%s inferior launching succeeded", __FUNCTION__); else log->Printf("NativeProcessLinux::%s inferior launching failed: %s", __FUNCTION__, error.AsCString()); } return error; } ::pid_t NativeProcessLinux::Attach(lldb::pid_t pid, Error &error) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); // Use a map to keep track of the threads which we have attached/need to attach. Host::TidMap tids_to_attach; if (pid <= 1) { error.SetErrorToGenericError(); error.SetErrorString("Attaching to process 1 is not allowed."); return -1; } while (Host::FindProcessThreads(pid, tids_to_attach)) { for (Host::TidMap::iterator it = tids_to_attach.begin(); it != tids_to_attach.end();) { if (it->second == false) { lldb::tid_t tid = it->first; // Attach to the requested process. // An attach will cause the thread to stop with a SIGSTOP. error = PtraceWrapper(PTRACE_ATTACH, tid); if (error.Fail()) { // No such thread. The thread may have exited. // More error handling may be needed. if (error.GetError() == ESRCH) { it = tids_to_attach.erase(it); continue; } else return -1; } int status; // Need to use __WALL otherwise we receive an error with errno=ECHLD // At this point we should have a thread stopped if waitpid succeeds. if ((status = waitpid(tid, NULL, __WALL)) < 0) { // No such thread. The thread may have exited. // More error handling may be needed. if (errno == ESRCH) { it = tids_to_attach.erase(it); continue; } else { error.SetErrorToErrno(); return -1; } } error = SetDefaultPtraceOpts(tid); if (error.Fail()) return -1; if (log) log->Printf ("NativeProcessLinux::%s() adding tid = %" PRIu64, __FUNCTION__, tid); it->second = true; // Create the thread, mark it as stopped. NativeThreadLinuxSP thread_sp (AddThread(static_cast(tid))); assert (thread_sp && "AddThread() returned a nullptr"); // This will notify this is a new thread and tell the system it is stopped. thread_sp->SetStoppedBySignal(SIGSTOP); ThreadWasCreated(*thread_sp); SetCurrentThreadID (thread_sp->GetID ()); } // move the loop forward ++it; } } if (tids_to_attach.size() > 0) { m_pid = pid; // Let our process instance know the thread has stopped. SetState (StateType::eStateStopped); } else { error.SetErrorToGenericError(); error.SetErrorString("No such process."); return -1; } return pid; } Error NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { long ptrace_opts = 0; // Have the child raise an event on exit. This is used to keep the child in // limbo until it is destroyed. ptrace_opts |= PTRACE_O_TRACEEXIT; // Have the tracer trace threads which spawn in the inferior process. // TODO: if we want to support tracing the inferiors' child, add the // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK) ptrace_opts |= PTRACE_O_TRACECLONE; // Have the tracer notify us before execve returns // (needed to disable legacy SIGTRAP generation) ptrace_opts |= PTRACE_O_TRACEEXEC; return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void*)ptrace_opts); } static ExitType convert_pid_status_to_exit_type (int status) { if (WIFEXITED (status)) return ExitType::eExitTypeExit; else if (WIFSIGNALED (status)) return ExitType::eExitTypeSignal; else if (WIFSTOPPED (status)) return ExitType::eExitTypeStop; else { // We don't know what this is. return ExitType::eExitTypeInvalid; } } static int convert_pid_status_to_return_code (int status) { if (WIFEXITED (status)) return WEXITSTATUS (status); else if (WIFSIGNALED (status)) return WTERMSIG (status); else if (WIFSTOPPED (status)) return WSTOPSIG (status); else { // We don't know what this is. return ExitType::eExitTypeInvalid; } } // Handles all waitpid events from the inferior process. void NativeProcessLinux::MonitorCallback(lldb::pid_t pid, bool exited, int signal, int status) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); // Certain activities differ based on whether the pid is the tid of the main thread. const bool is_main_thread = (pid == GetID ()); // Handle when the thread exits. if (exited) { if (log) log->Printf ("NativeProcessLinux::%s() got exit signal(%d) , tid = %" PRIu64 " (%s main thread)", __FUNCTION__, signal, pid, is_main_thread ? "is" : "is not"); // This is a thread that exited. Ensure we're not tracking it anymore. const bool thread_found = StopTrackingThread (pid); if (is_main_thread) { // We only set the exit status and notify the delegate if we haven't already set the process // state to an exited state. We normally should have received a SIGTRAP | (PTRACE_EVENT_EXIT << 8) // for the main thread. const bool already_notified = (GetState() == StateType::eStateExited) || (GetState () == StateType::eStateCrashed); if (!already_notified) { if (log) log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling main thread exit (%s), expected exit state already set but state was %s instead, setting exit state now", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found", StateAsCString (GetState ())); // The main thread exited. We're done monitoring. Report to delegate. SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true); // Notify delegate that our process has exited. SetState (StateType::eStateExited, true); } else { if (log) log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " main thread now exited (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found"); } } else { // Do we want to report to the delegate in this case? I think not. If this was an orderly // thread exit, we would already have received the SIGTRAP | (PTRACE_EVENT_EXIT << 8) signal, // and we would have done an all-stop then. if (log) log->Printf ("NativeProcessLinux::%s() tid = %" PRIu64 " handling non-main thread exit (%s)", __FUNCTION__, pid, thread_found ? "stopped tracking thread metadata" : "thread metadata not found"); } return; } siginfo_t info; const auto info_err = GetSignalInfo(pid, &info); auto thread_sp = GetThreadByID(pid); if (! thread_sp) { // Normally, the only situation when we cannot find the thread is if we have just // received a new thread notification. This is indicated by GetSignalInfo() returning // si_code == SI_USER and si_pid == 0 if (log) log->Printf("NativeProcessLinux::%s received notification about an unknown tid %" PRIu64 ".", __FUNCTION__, pid); if (info_err.Fail()) { if (log) log->Printf("NativeProcessLinux::%s (tid %" PRIu64 ") GetSignalInfo failed (%s). Ingoring this notification.", __FUNCTION__, pid, info_err.AsCString()); return; } if (log && (info.si_code != SI_USER || info.si_pid != 0)) log->Printf("NativeProcessLinux::%s (tid %" PRIu64 ") unexpected signal info (si_code: %d, si_pid: %d). Treating as a new thread notification anyway.", __FUNCTION__, pid, info.si_code, info.si_pid); auto thread_sp = AddThread(pid); // Resume the newly created thread. ResumeThread(*thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); ThreadWasCreated(*thread_sp); return; } // Get details on the signal raised. if (info_err.Success()) { // We have retrieved the signal info. Dispatch appropriately. if (info.si_signo == SIGTRAP) MonitorSIGTRAP(info, *thread_sp); else MonitorSignal(info, *thread_sp, exited); } else { if (info_err.GetError() == EINVAL) { // This is a group stop reception for this tid. // We can reach here if we reinject SIGSTOP, SIGSTP, SIGTTIN or SIGTTOU into the // tracee, triggering the group-stop mechanism. Normally receiving these would stop // the process, pending a SIGCONT. Simulating this state in a debugger is hard and is // generally not needed (one use case is debugging background task being managed by a // shell). For general use, it is sufficient to stop the process in a signal-delivery // stop which happens before the group stop. This done by MonitorSignal and works // correctly for all signals. if (log) log->Printf("NativeProcessLinux::%s received a group stop for pid %" PRIu64 " tid %" PRIu64 ". Transparent handling of group stops not supported, resuming the thread.", __FUNCTION__, GetID (), pid); ResumeThread(*thread_sp, thread_sp->GetState(), LLDB_INVALID_SIGNAL_NUMBER); } else { // ptrace(GETSIGINFO) failed (but not due to group-stop). // A return value of ESRCH means the thread/process is no longer on the system, // so it was killed somehow outside of our control. Either way, we can't do anything // with it anymore. // Stop tracking the metadata for the thread since it's entirely off the system now. const bool thread_found = StopTrackingThread (pid); if (log) log->Printf ("NativeProcessLinux::%s GetSignalInfo failed: %s, tid = %" PRIu64 ", signal = %d, status = %d (%s, %s, %s)", __FUNCTION__, info_err.AsCString(), pid, signal, status, info_err.GetError() == ESRCH ? "thread/process killed" : "unknown reason", is_main_thread ? "is main thread" : "is not main thread", thread_found ? "thread metadata removed" : "thread metadata not found"); if (is_main_thread) { // Notify the delegate - our process is not available but appears to have been killed outside // our control. Is eStateExited the right exit state in this case? SetExitStatus (convert_pid_status_to_exit_type (status), convert_pid_status_to_return_code (status), nullptr, true); SetState (StateType::eStateExited, true); } else { // This thread was pulled out from underneath us. Anything to do here? Do we want to do an all stop? if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 " non-main thread exit occurred, didn't tell delegate anything since thread disappeared out from underneath us", __FUNCTION__, GetID (), pid); } } } } void NativeProcessLinux::WaitForNewThread(::pid_t tid) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); NativeThreadLinuxSP new_thread_sp = GetThreadByID(tid); if (new_thread_sp) { // We are already tracking the thread - we got the event on the new thread (see // MonitorSignal) before this one. We are done. return; } // The thread is not tracked yet, let's wait for it to appear. int status = -1; ::pid_t wait_pid; do { if (log) log->Printf ("NativeProcessLinux::%s() received thread creation event for tid %" PRIu32 ". tid not tracked yet, waiting for thread to appear...", __FUNCTION__, tid); wait_pid = waitpid(tid, &status, __WALL); } while (wait_pid == -1 && errno == EINTR); // Since we are waiting on a specific tid, this must be the creation event. But let's do // some checks just in case. if (wait_pid != tid) { if (log) log->Printf ("NativeProcessLinux::%s() waiting for tid %" PRIu32 " failed. Assuming the thread has disappeared in the meantime", __FUNCTION__, tid); // The only way I know of this could happen is if the whole process was // SIGKILLed in the mean time. In any case, we can't do anything about that now. return; } if (WIFEXITED(status)) { if (log) log->Printf ("NativeProcessLinux::%s() waiting for tid %" PRIu32 " returned an 'exited' event. Not tracking the thread.", __FUNCTION__, tid); // Also a very improbable event. return; } siginfo_t info; Error error = GetSignalInfo(tid, &info); if (error.Fail()) { if (log) log->Printf ("NativeProcessLinux::%s() GetSignalInfo for tid %" PRIu32 " failed. Assuming the thread has disappeared in the meantime.", __FUNCTION__, tid); return; } if (((info.si_pid != 0) || (info.si_code != SI_USER)) && log) { // We should be getting a thread creation signal here, but we received something // else. There isn't much we can do about it now, so we will just log that. Since the // thread is alive and we are receiving events from it, we shall pretend that it was // created properly. log->Printf ("NativeProcessLinux::%s() GetSignalInfo for tid %" PRIu32 " received unexpected signal with code %d from pid %d.", __FUNCTION__, tid, info.si_code, info.si_pid); } if (log) log->Printf ("NativeProcessLinux::%s() pid = %" PRIu64 ": tracking new thread tid %" PRIu32, __FUNCTION__, GetID (), tid); new_thread_sp = AddThread(tid); ResumeThread(*new_thread_sp, eStateRunning, LLDB_INVALID_SIGNAL_NUMBER); ThreadWasCreated(*new_thread_sp); } void NativeProcessLinux::MonitorSIGTRAP(const siginfo_t &info, NativeThreadLinux &thread) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); const bool is_main_thread = (thread.GetID() == GetID ()); assert(info.si_signo == SIGTRAP && "Unexpected child signal!"); switch (info.si_code) { // TODO: these two cases are required if we want to support tracing of the inferiors' children. We'd need this to debug a monitor. // case (SIGTRAP | (PTRACE_EVENT_FORK << 8)): // case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)): case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)): { // This is the notification on the parent thread which informs us of new thread // creation. // We don't want to do anything with the parent thread so we just resume it. In case we // want to implement "break on thread creation" functionality, we would need to stop // here. unsigned long event_message = 0; if (GetEventMessage(thread.GetID(), &event_message).Fail()) { if (log) log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " received thread creation event but GetEventMessage failed so we don't know the new tid", __FUNCTION__, thread.GetID()); } else WaitForNewThread(event_message); ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); break; } case (SIGTRAP | (PTRACE_EVENT_EXEC << 8)): { NativeThreadLinuxSP main_thread_sp; if (log) log->Printf ("NativeProcessLinux::%s() received exec event, code = %d", __FUNCTION__, info.si_code ^ SIGTRAP); // Exec clears any pending notifications. m_pending_notification_tid = LLDB_INVALID_THREAD_ID; // Remove all but the main thread here. Linux fork creates a new process which only copies the main thread. if (log) log->Printf ("NativeProcessLinux::%s exec received, stop tracking all but main thread", __FUNCTION__); for (auto thread_sp : m_threads) { const bool is_main_thread = thread_sp && thread_sp->GetID () == GetID (); if (is_main_thread) { main_thread_sp = std::static_pointer_cast(thread_sp); if (log) log->Printf ("NativeProcessLinux::%s found main thread with tid %" PRIu64 ", keeping", __FUNCTION__, main_thread_sp->GetID ()); } else { if (log) log->Printf ("NativeProcessLinux::%s discarding non-main-thread tid %" PRIu64 " due to exec", __FUNCTION__, thread_sp->GetID ()); } } m_threads.clear (); if (main_thread_sp) { m_threads.push_back (main_thread_sp); SetCurrentThreadID (main_thread_sp->GetID ()); main_thread_sp->SetStoppedByExec(); } else { SetCurrentThreadID (LLDB_INVALID_THREAD_ID); if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 "no main thread found, discarded all threads, we're in a no-thread state!", __FUNCTION__, GetID ()); } // Tell coordinator about about the "new" (since exec) stopped main thread. ThreadWasCreated(*main_thread_sp); // Let our delegate know we have just exec'd. NotifyDidExec (); // If we have a main thread, indicate we are stopped. assert (main_thread_sp && "exec called during ptraced process but no main thread metadata tracked"); // Let the process know we're stopped. StopRunningThreads(main_thread_sp->GetID()); break; } case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)): { // The inferior process or one of its threads is about to exit. // We don't want to do anything with the thread so we just resume it. In case we // want to implement "break on thread exit" functionality, we would need to stop // here. unsigned long data = 0; if (GetEventMessage(thread.GetID(), &data).Fail()) data = -1; if (log) { log->Printf ("NativeProcessLinux::%s() received PTRACE_EVENT_EXIT, data = %lx (WIFEXITED=%s,WIFSIGNALED=%s), pid = %" PRIu64 " (%s)", __FUNCTION__, data, WIFEXITED (data) ? "true" : "false", WIFSIGNALED (data) ? "true" : "false", thread.GetID(), is_main_thread ? "is main thread" : "not main thread"); } if (is_main_thread) { SetExitStatus (convert_pid_status_to_exit_type (data), convert_pid_status_to_return_code (data), nullptr, true); } StateType state = thread.GetState(); if (! StateIsRunningState(state)) { // Due to a kernel bug, we may sometimes get this stop after the inferior gets a // SIGKILL. This confuses our state tracking logic in ResumeThread(), since normally, // we should not be receiving any ptrace events while the inferior is stopped. This // makes sure that the inferior is resumed and exits normally. state = eStateRunning; } ResumeThread(thread, state, LLDB_INVALID_SIGNAL_NUMBER); break; } case 0: case TRAP_TRACE: // We receive this on single stepping. case TRAP_HWBKPT: // We receive this on watchpoint hit { // If a watchpoint was hit, report it uint32_t wp_index; Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(wp_index, (uintptr_t)info.si_addr); if (error.Fail() && log) log->Printf("NativeProcessLinux::%s() " "received error while checking for watchpoint hits, " "pid = %" PRIu64 " error = %s", __FUNCTION__, thread.GetID(), error.AsCString()); if (wp_index != LLDB_INVALID_INDEX32) { MonitorWatchpoint(thread, wp_index); break; } // Otherwise, report step over MonitorTrace(thread); break; } case SI_KERNEL: #if defined __mips__ // For mips there is no special signal for watchpoint // So we check for watchpoint in kernel trap { // If a watchpoint was hit, report it uint32_t wp_index; Error error = thread.GetRegisterContext()->GetWatchpointHitIndex(wp_index, LLDB_INVALID_ADDRESS); if (error.Fail() && log) log->Printf("NativeProcessLinux::%s() " "received error while checking for watchpoint hits, " "pid = %" PRIu64 " error = %s", __FUNCTION__, thread.GetID(), error.AsCString()); if (wp_index != LLDB_INVALID_INDEX32) { MonitorWatchpoint(thread, wp_index); break; } } // NO BREAK #endif case TRAP_BRKPT: MonitorBreakpoint(thread); break; case SIGTRAP: case (SIGTRAP | 0x80): if (log) log->Printf ("NativeProcessLinux::%s() received unknown SIGTRAP system call stop event, pid %" PRIu64 "tid %" PRIu64 ", resuming", __FUNCTION__, GetID (), thread.GetID()); // Ignore these signals until we know more about them. ResumeThread(thread, thread.GetState(), LLDB_INVALID_SIGNAL_NUMBER); break; default: assert(false && "Unexpected SIGTRAP code!"); if (log) log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 "tid %" PRIu64 " received unhandled SIGTRAP code: 0x%d", __FUNCTION__, GetID(), thread.GetID(), info.si_code); break; } } void NativeProcessLinux::MonitorTrace(NativeThreadLinux &thread) { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf("NativeProcessLinux::%s() received trace event, pid = %" PRIu64 " (single stepping)", __FUNCTION__, thread.GetID()); // This thread is currently stopped. thread.SetStoppedByTrace(); StopRunningThreads(thread.GetID()); } void NativeProcessLinux::MonitorBreakpoint(NativeThreadLinux &thread) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf("NativeProcessLinux::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, thread.GetID()); // Mark the thread as stopped at breakpoint. thread.SetStoppedByBreakpoint(); Error error = FixupBreakpointPCAsNeeded(thread); if (error.Fail()) if (log) log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " fixup: %s", __FUNCTION__, thread.GetID(), error.AsCString()); if (m_threads_stepping_with_breakpoint.find(thread.GetID()) != m_threads_stepping_with_breakpoint.end()) thread.SetStoppedByTrace(); StopRunningThreads(thread.GetID()); } void NativeProcessLinux::MonitorWatchpoint(NativeThreadLinux &thread, uint32_t wp_index) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_WATCHPOINTS)); if (log) log->Printf("NativeProcessLinux::%s() received watchpoint event, " "pid = %" PRIu64 ", wp_index = %" PRIu32, __FUNCTION__, thread.GetID(), wp_index); // Mark the thread as stopped at watchpoint. // The address is at (lldb::addr_t)info->si_addr if we need it. thread.SetStoppedByWatchpoint(wp_index); // We need to tell all other running threads before we notify the delegate about this stop. StopRunningThreads(thread.GetID()); } void NativeProcessLinux::MonitorSignal(const siginfo_t &info, NativeThreadLinux &thread, bool exited) { const int signo = info.si_signo; const bool is_from_llgs = info.si_pid == getpid (); Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); // POSIX says that process behaviour is undefined after it ignores a SIGFPE, // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a // kill(2) or raise(3). Similarly for tgkill(2) on Linux. // // IOW, user generated signals never generate what we consider to be a // "crash". // // Similarly, ACK signals generated by this monitor. // Handle the signal. if (info.si_code == SI_TKILL || info.si_code == SI_USER) { if (log) log->Printf ("NativeProcessLinux::%s() received signal %s (%d) with code %s, (siginfo pid = %d (%s), waitpid pid = %" PRIu64 ")", __FUNCTION__, Host::GetSignalAsCString(signo), signo, (info.si_code == SI_TKILL ? "SI_TKILL" : "SI_USER"), info.si_pid, is_from_llgs ? "from llgs" : "not from llgs", thread.GetID()); } // Check for thread stop notification. if (is_from_llgs && (info.si_code == SI_TKILL) && (signo == SIGSTOP)) { // This is a tgkill()-based stop. if (log) log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", thread stopped", __FUNCTION__, GetID (), thread.GetID()); // Check that we're not already marked with a stop reason. // Note this thread really shouldn't already be marked as stopped - if we were, that would imply that // the kernel signaled us with the thread stopping which we handled and marked as stopped, // and that, without an intervening resume, we received another stop. It is more likely // that we are missing the marking of a run state somewhere if we find that the thread was // marked as stopped. const StateType thread_state = thread.GetState(); if (!StateIsStoppedState (thread_state, false)) { // An inferior thread has stopped because of a SIGSTOP we have sent it. // Generally, these are not important stops and we don't want to report them as // they are just used to stop other threads when one thread (the one with the // *real* stop reason) hits a breakpoint (watchpoint, etc...). However, in the // case of an asynchronous Interrupt(), this *is* the real stop reason, so we // leave the signal intact if this is the thread that was chosen as the // triggering thread. if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID) { if (m_pending_notification_tid == thread.GetID()) thread.SetStoppedBySignal(SIGSTOP, &info); else thread.SetStoppedWithNoReason(); SetCurrentThreadID (thread.GetID ()); SignalIfAllThreadsStopped(); } else { // We can end up here if stop was initiated by LLGS but by this time a // thread stop has occurred - maybe initiated by another event. Error error = ResumeThread(thread, thread.GetState(), 0); if (error.Fail() && log) { log->Printf("NativeProcessLinux::%s failed to resume thread tid %" PRIu64 ": %s", __FUNCTION__, thread.GetID(), error.AsCString()); } } } else { if (log) { // Retrieve the signal name if the thread was stopped by a signal. int stop_signo = 0; const bool stopped_by_signal = thread.IsStopped(&stop_signo); const char *signal_name = stopped_by_signal ? Host::GetSignalAsCString(stop_signo) : ""; if (!signal_name) signal_name = ""; log->Printf ("NativeProcessLinux::%s() pid %" PRIu64 " tid %" PRIu64 ", thread was already marked as a stopped state (state=%s, signal=%d (%s)), leaving stop signal as is", __FUNCTION__, GetID (), thread.GetID(), StateAsCString (thread_state), stop_signo, signal_name); } SignalIfAllThreadsStopped(); } // Done handling. return; } if (log) log->Printf ("NativeProcessLinux::%s() received signal %s", __FUNCTION__, Host::GetSignalAsCString(signo)); // This thread is stopped. thread.SetStoppedBySignal(signo, &info); // Send a stop to the debugger after we get all other threads to stop. StopRunningThreads(thread.GetID()); } namespace { struct EmulatorBaton { NativeProcessLinux* m_process; NativeRegisterContext* m_reg_context; // eRegisterKindDWARF -> RegsiterValue std::unordered_map m_register_values; EmulatorBaton(NativeProcessLinux* process, NativeRegisterContext* reg_context) : m_process(process), m_reg_context(reg_context) {} }; } // anonymous namespace static size_t ReadMemoryCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst, size_t length) { EmulatorBaton* emulator_baton = static_cast(baton); size_t bytes_read; emulator_baton->m_process->ReadMemory(addr, dst, length, bytes_read); return bytes_read; } static bool ReadRegisterCallback (EmulateInstruction *instruction, void *baton, const RegisterInfo *reg_info, RegisterValue ®_value) { EmulatorBaton* emulator_baton = static_cast(baton); auto it = emulator_baton->m_register_values.find(reg_info->kinds[eRegisterKindDWARF]); if (it != emulator_baton->m_register_values.end()) { reg_value = it->second; return true; } // The emulator only fill in the dwarf regsiter numbers (and in some case // the generic register numbers). Get the full register info from the // register context based on the dwarf register numbers. const RegisterInfo* full_reg_info = emulator_baton->m_reg_context->GetRegisterInfo( eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); Error error = emulator_baton->m_reg_context->ReadRegister(full_reg_info, reg_value); if (error.Success()) return true; return false; } static bool WriteRegisterCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, const RegisterInfo *reg_info, const RegisterValue ®_value) { EmulatorBaton* emulator_baton = static_cast(baton); emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = reg_value; return true; } static size_t WriteMemoryCallback (EmulateInstruction *instruction, void *baton, const EmulateInstruction::Context &context, lldb::addr_t addr, const void *dst, size_t length) { return length; } static lldb::addr_t ReadFlags (NativeRegisterContext* regsiter_context) { const RegisterInfo* flags_info = regsiter_context->GetRegisterInfo( eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); return regsiter_context->ReadRegisterAsUnsigned(flags_info, LLDB_INVALID_ADDRESS); } Error NativeProcessLinux::SetupSoftwareSingleStepping(NativeThreadLinux &thread) { Error error; NativeRegisterContextSP register_context_sp = thread.GetRegisterContext(); std::unique_ptr emulator_ap( EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, nullptr)); if (emulator_ap == nullptr) return Error("Instruction emulator not found!"); EmulatorBaton baton(this, register_context_sp.get()); emulator_ap->SetBaton(&baton); emulator_ap->SetReadMemCallback(&ReadMemoryCallback); emulator_ap->SetReadRegCallback(&ReadRegisterCallback); emulator_ap->SetWriteMemCallback(&WriteMemoryCallback); emulator_ap->SetWriteRegCallback(&WriteRegisterCallback); if (!emulator_ap->ReadInstruction()) return Error("Read instruction failed!"); bool emulation_result = emulator_ap->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); const RegisterInfo* reg_info_pc = register_context_sp->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); const RegisterInfo* reg_info_flags = register_context_sp->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); auto pc_it = baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); auto flags_it = baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); lldb::addr_t next_pc; lldb::addr_t next_flags; if (emulation_result) { assert(pc_it != baton.m_register_values.end() && "Emulation was successfull but PC wasn't updated"); next_pc = pc_it->second.GetAsUInt64(); if (flags_it != baton.m_register_values.end()) next_flags = flags_it->second.GetAsUInt64(); else next_flags = ReadFlags (register_context_sp.get()); } else if (pc_it == baton.m_register_values.end()) { // Emulate instruction failed and it haven't changed PC. Advance PC // with the size of the current opcode because the emulation of all // PC modifying instruction should be successful. The failure most // likely caused by a not supported instruction which don't modify PC. next_pc = register_context_sp->GetPC() + emulator_ap->GetOpcode().GetByteSize(); next_flags = ReadFlags (register_context_sp.get()); } else { // The instruction emulation failed after it modified the PC. It is an // unknown error where we can't continue because the next instruction is // modifying the PC but we don't know how. return Error ("Instruction emulation failed unexpectedly."); } if (m_arch.GetMachine() == llvm::Triple::arm) { if (next_flags & 0x20) { // Thumb mode error = SetSoftwareBreakpoint(next_pc, 2); } else { // Arm mode error = SetSoftwareBreakpoint(next_pc, 4); } } else if (m_arch.GetMachine() == llvm::Triple::mips64 || m_arch.GetMachine() == llvm::Triple::mips64el || m_arch.GetMachine() == llvm::Triple::mips || m_arch.GetMachine() == llvm::Triple::mipsel) error = SetSoftwareBreakpoint(next_pc, 4); else { // No size hint is given for the next breakpoint error = SetSoftwareBreakpoint(next_pc, 0); } if (error.Fail()) return error; m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); return Error(); } bool NativeProcessLinux::SupportHardwareSingleStepping() const { if (m_arch.GetMachine() == llvm::Triple::arm || m_arch.GetMachine() == llvm::Triple::mips64 || m_arch.GetMachine() == llvm::Triple::mips64el || m_arch.GetMachine() == llvm::Triple::mips || m_arch.GetMachine() == llvm::Triple::mipsel) return false; return true; } Error NativeProcessLinux::Resume (const ResumeActionList &resume_actions) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); if (log) log->Printf ("NativeProcessLinux::%s called: pid %" PRIu64, __FUNCTION__, GetID ()); bool software_single_step = !SupportHardwareSingleStepping(); if (software_single_step) { for (auto thread_sp : m_threads) { assert (thread_sp && "thread list should not contain NULL threads"); const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true); if (action == nullptr) continue; if (action->state == eStateStepping) { Error error = SetupSoftwareSingleStepping(static_cast(*thread_sp)); if (error.Fail()) return error; } } } for (auto thread_sp : m_threads) { assert (thread_sp && "thread list should not contain NULL threads"); const ResumeAction *const action = resume_actions.GetActionForThread (thread_sp->GetID (), true); if (action == nullptr) { if (log) log->Printf ("NativeProcessLinux::%s no action specified for pid %" PRIu64 " tid %" PRIu64, __FUNCTION__, GetID (), thread_sp->GetID ()); continue; } if (log) { log->Printf ("NativeProcessLinux::%s processing resume action state %s for pid %" PRIu64 " tid %" PRIu64, __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ()); } switch (action->state) { case eStateRunning: case eStateStepping: { // Run the thread, possibly feeding it the signal. const int signo = action->signal; ResumeThread(static_cast(*thread_sp), action->state, signo); break; } case eStateSuspended: case eStateStopped: lldbassert(0 && "Unexpected state"); default: return Error ("NativeProcessLinux::%s (): unexpected state %s specified for pid %" PRIu64 ", tid %" PRIu64, __FUNCTION__, StateAsCString (action->state), GetID (), thread_sp->GetID ()); } } return Error(); } Error NativeProcessLinux::Halt () { Error error; if (kill (GetID (), SIGSTOP) != 0) error.SetErrorToErrno (); return error; } Error NativeProcessLinux::Detach () { Error error; // Stop monitoring the inferior. m_sigchld_handle.reset(); // Tell ptrace to detach from the process. if (GetID () == LLDB_INVALID_PROCESS_ID) return error; for (auto thread_sp : m_threads) { Error e = Detach(thread_sp->GetID()); if (e.Fail()) error = e; // Save the error, but still attempt to detach from other threads. } return error; } Error NativeProcessLinux::Signal (int signo) { Error error; Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s: sending signal %d (%s) to pid %" PRIu64, __FUNCTION__, signo, Host::GetSignalAsCString(signo), GetID()); if (kill(GetID(), signo)) error.SetErrorToErrno(); return error; } Error NativeProcessLinux::Interrupt () { // Pick a running thread (or if none, a not-dead stopped thread) as // the chosen thread that will be the stop-reason thread. Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); NativeThreadProtocolSP running_thread_sp; NativeThreadProtocolSP stopped_thread_sp; if (log) log->Printf ("NativeProcessLinux::%s selecting running thread for interrupt target", __FUNCTION__); for (auto thread_sp : m_threads) { // The thread shouldn't be null but lets just cover that here. if (!thread_sp) continue; // If we have a running or stepping thread, we'll call that the // target of the interrupt. const auto thread_state = thread_sp->GetState (); if (thread_state == eStateRunning || thread_state == eStateStepping) { running_thread_sp = thread_sp; break; } else if (!stopped_thread_sp && StateIsStoppedState (thread_state, true)) { // Remember the first non-dead stopped thread. We'll use that as a backup if there are no running threads. stopped_thread_sp = thread_sp; } } if (!running_thread_sp && !stopped_thread_sp) { Error error("found no running/stepping or live stopped threads as target for interrupt"); if (log) log->Printf ("NativeProcessLinux::%s skipping due to error: %s", __FUNCTION__, error.AsCString ()); return error; } NativeThreadProtocolSP deferred_signal_thread_sp = running_thread_sp ? running_thread_sp : stopped_thread_sp; if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " %s tid %" PRIu64 " chosen for interrupt target", __FUNCTION__, GetID (), running_thread_sp ? "running" : "stopped", deferred_signal_thread_sp->GetID ()); StopRunningThreads(deferred_signal_thread_sp->GetID()); return Error(); } Error NativeProcessLinux::Kill () { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s called for PID %" PRIu64, __FUNCTION__, GetID ()); Error error; switch (m_state) { case StateType::eStateInvalid: case StateType::eStateExited: case StateType::eStateCrashed: case StateType::eStateDetached: case StateType::eStateUnloaded: // Nothing to do - the process is already dead. if (log) log->Printf ("NativeProcessLinux::%s ignored for PID %" PRIu64 " due to current state: %s", __FUNCTION__, GetID (), StateAsCString (m_state)); return error; case StateType::eStateConnected: case StateType::eStateAttaching: case StateType::eStateLaunching: case StateType::eStateStopped: case StateType::eStateRunning: case StateType::eStateStepping: case StateType::eStateSuspended: // We can try to kill a process in these states. break; } if (kill (GetID (), SIGKILL) != 0) { error.SetErrorToErrno (); return error; } return error; } static Error ParseMemoryRegionInfoFromProcMapsLine (const std::string &maps_line, MemoryRegionInfo &memory_region_info) { memory_region_info.Clear(); StringExtractor line_extractor (maps_line.c_str ()); // Format: {address_start_hex}-{address_end_hex} perms offset dev inode pathname // perms: rwxp (letter is present if set, '-' if not, final character is p=private, s=shared). // Parse out the starting address lldb::addr_t start_address = line_extractor.GetHexMaxU64 (false, 0); // Parse out hyphen separating start and end address from range. if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != '-')) return Error ("malformed /proc/{pid}/maps entry, missing dash between address range"); // Parse out the ending address lldb::addr_t end_address = line_extractor.GetHexMaxU64 (false, start_address); // Parse out the space after the address. if (!line_extractor.GetBytesLeft () || (line_extractor.GetChar () != ' ')) return Error ("malformed /proc/{pid}/maps entry, missing space after range"); // Save the range. memory_region_info.GetRange ().SetRangeBase (start_address); memory_region_info.GetRange ().SetRangeEnd (end_address); // Any memory region in /proc/{pid}/maps is by definition mapped into the process. memory_region_info.SetMapped(MemoryRegionInfo::OptionalBool::eYes); // Parse out each permission entry. if (line_extractor.GetBytesLeft () < 4) return Error ("malformed /proc/{pid}/maps entry, missing some portion of permissions"); // Handle read permission. const char read_perm_char = line_extractor.GetChar (); if (read_perm_char == 'r') memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eYes); else if (read_perm_char == '-') memory_region_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo); else return Error ("unexpected /proc/{pid}/maps read permission char"); // Handle write permission. const char write_perm_char = line_extractor.GetChar (); if (write_perm_char == 'w') memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eYes); else if (write_perm_char == '-') memory_region_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo); else return Error ("unexpected /proc/{pid}/maps write permission char"); // Handle execute permission. const char exec_perm_char = line_extractor.GetChar (); if (exec_perm_char == 'x') memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eYes); else if (exec_perm_char == '-') memory_region_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo); else return Error ("unexpected /proc/{pid}/maps exec permission char"); return Error (); } Error NativeProcessLinux::GetMemoryRegionInfo (lldb::addr_t load_addr, MemoryRegionInfo &range_info) { // FIXME review that the final memory region returned extends to the end of the virtual address space, // with no perms if it is not mapped. // Use an approach that reads memory regions from /proc/{pid}/maps. // Assume proc maps entries are in ascending order. // FIXME assert if we find differently. Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); Error error; if (m_supports_mem_region == LazyBool::eLazyBoolNo) { // We're done. error.SetErrorString ("unsupported"); return error; } // If our cache is empty, pull the latest. There should always be at least one memory region // if memory region handling is supported. if (m_mem_region_cache.empty ()) { error = ProcFileReader::ProcessLineByLine (GetID (), "maps", [&] (const std::string &line) -> bool { MemoryRegionInfo info; const Error parse_error = ParseMemoryRegionInfoFromProcMapsLine (line, info); if (parse_error.Success ()) { m_mem_region_cache.push_back (info); return true; } else { if (log) log->Printf ("NativeProcessLinux::%s failed to parse proc maps line '%s': %s", __FUNCTION__, line.c_str (), error.AsCString ()); return false; } }); // If we had an error, we'll mark unsupported. if (error.Fail ()) { m_supports_mem_region = LazyBool::eLazyBoolNo; return error; } else if (m_mem_region_cache.empty ()) { // No entries after attempting to read them. This shouldn't happen if /proc/{pid}/maps // is supported. Assume we don't support map entries via procfs. if (log) log->Printf ("NativeProcessLinux::%s failed to find any procfs maps entries, assuming no support for memory region metadata retrieval", __FUNCTION__); m_supports_mem_region = LazyBool::eLazyBoolNo; error.SetErrorString ("not supported"); return error; } if (log) log->Printf ("NativeProcessLinux::%s read %" PRIu64 " memory region entries from /proc/%" PRIu64 "/maps", __FUNCTION__, static_cast (m_mem_region_cache.size ()), GetID ()); // We support memory retrieval, remember that. m_supports_mem_region = LazyBool::eLazyBoolYes; } else { if (log) log->Printf ("NativeProcessLinux::%s reusing %" PRIu64 " cached memory region entries", __FUNCTION__, static_cast (m_mem_region_cache.size ())); } lldb::addr_t prev_base_address = 0; // FIXME start by finding the last region that is <= target address using binary search. Data is sorted. // There can be a ton of regions on pthreads apps with lots of threads. for (auto it = m_mem_region_cache.begin(); it != m_mem_region_cache.end (); ++it) { MemoryRegionInfo &proc_entry_info = *it; // Sanity check assumption that /proc/{pid}/maps entries are ascending. assert ((proc_entry_info.GetRange ().GetRangeBase () >= prev_base_address) && "descending /proc/pid/maps entries detected, unexpected"); prev_base_address = proc_entry_info.GetRange ().GetRangeBase (); // If the target address comes before this entry, indicate distance to next region. if (load_addr < proc_entry_info.GetRange ().GetRangeBase ()) { range_info.GetRange ().SetRangeBase (load_addr); range_info.GetRange ().SetByteSize (proc_entry_info.GetRange ().GetRangeBase () - load_addr); range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); return error; } else if (proc_entry_info.GetRange ().Contains (load_addr)) { // The target address is within the memory region we're processing here. range_info = proc_entry_info; return error; } // The target memory address comes somewhere after the region we just parsed. } // If we made it here, we didn't find an entry that contained the given address. Return the // load_addr as start and the amount of bytes betwwen load address and the end of the memory as // size. range_info.GetRange ().SetRangeBase (load_addr); range_info.GetRange ().SetRangeEnd(LLDB_INVALID_ADDRESS); range_info.SetReadable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetWritable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetExecutable (MemoryRegionInfo::OptionalBool::eNo); range_info.SetMapped(MemoryRegionInfo::OptionalBool::eNo); return error; } void NativeProcessLinux::DoStopIDBumped (uint32_t newBumpId) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s(newBumpId=%" PRIu32 ") called", __FUNCTION__, newBumpId); if (log) log->Printf ("NativeProcessLinux::%s clearing %" PRIu64 " entries from the cache", __FUNCTION__, static_cast (m_mem_region_cache.size ())); m_mem_region_cache.clear (); } Error NativeProcessLinux::AllocateMemory(size_t size, uint32_t permissions, lldb::addr_t &addr) { // FIXME implementing this requires the equivalent of // InferiorCallPOSIX::InferiorCallMmap, which depends on // functional ThreadPlans working with Native*Protocol. #if 1 return Error ("not implemented yet"); #else addr = LLDB_INVALID_ADDRESS; unsigned prot = 0; if (permissions & lldb::ePermissionsReadable) prot |= eMmapProtRead; if (permissions & lldb::ePermissionsWritable) prot |= eMmapProtWrite; if (permissions & lldb::ePermissionsExecutable) prot |= eMmapProtExec; // TODO implement this directly in NativeProcessLinux // (and lift to NativeProcessPOSIX if/when that class is // refactored out). if (InferiorCallMmap(this, addr, 0, size, prot, eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) { m_addr_to_mmap_size[addr] = size; return Error (); } else { addr = LLDB_INVALID_ADDRESS; return Error("unable to allocate %" PRIu64 " bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions)); } #endif } Error NativeProcessLinux::DeallocateMemory (lldb::addr_t addr) { // FIXME see comments in AllocateMemory - required lower-level // bits not in place yet (ThreadPlans) return Error ("not implemented"); } lldb::addr_t NativeProcessLinux::GetSharedLibraryInfoAddress () { // punt on this for now return LLDB_INVALID_ADDRESS; } size_t NativeProcessLinux::UpdateThreads () { // The NativeProcessLinux monitoring threads are always up to date // with respect to thread state and they keep the thread list // populated properly. All this method needs to do is return the // thread count. return m_threads.size (); } bool NativeProcessLinux::GetArchitecture (ArchSpec &arch) const { arch = m_arch; return true; } Error NativeProcessLinux::GetSoftwareBreakpointPCOffset(uint32_t &actual_opcode_size) { // FIXME put this behind a breakpoint protocol class that can be // set per architecture. Need ARM, MIPS support here. static const uint8_t g_i386_opcode [] = { 0xCC }; static const uint8_t g_s390x_opcode[] = { 0x00, 0x01 }; switch (m_arch.GetMachine ()) { case llvm::Triple::x86: case llvm::Triple::x86_64: actual_opcode_size = static_cast (sizeof(g_i386_opcode)); return Error (); case llvm::Triple::systemz: actual_opcode_size = static_cast (sizeof(g_s390x_opcode)); return Error (); case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::mips: case llvm::Triple::mipsel: // On these architectures the PC don't get updated for breakpoint hits actual_opcode_size = 0; return Error (); default: assert(false && "CPU type not supported!"); return Error ("CPU type not supported"); } } Error NativeProcessLinux::SetBreakpoint (lldb::addr_t addr, uint32_t size, bool hardware) { if (hardware) return Error ("NativeProcessLinux does not support hardware breakpoints"); else return SetSoftwareBreakpoint (addr, size); } Error NativeProcessLinux::GetSoftwareBreakpointTrapOpcode (size_t trap_opcode_size_hint, size_t &actual_opcode_size, const uint8_t *&trap_opcode_bytes) { // FIXME put this behind a breakpoint protocol class that can be set per // architecture. Need MIPS support here. static const uint8_t g_aarch64_opcode[] = { 0x00, 0x00, 0x20, 0xd4 }; // The ARM reference recommends the use of 0xe7fddefe and 0xdefe but the // linux kernel does otherwise. static const uint8_t g_arm_breakpoint_opcode[] = { 0xf0, 0x01, 0xf0, 0xe7 }; static const uint8_t g_i386_opcode [] = { 0xCC }; static const uint8_t g_mips64_opcode[] = { 0x00, 0x00, 0x00, 0x0d }; static const uint8_t g_mips64el_opcode[] = { 0x0d, 0x00, 0x00, 0x00 }; static const uint8_t g_s390x_opcode[] = { 0x00, 0x01 }; static const uint8_t g_thumb_breakpoint_opcode[] = { 0x01, 0xde }; switch (m_arch.GetMachine ()) { case llvm::Triple::aarch64: trap_opcode_bytes = g_aarch64_opcode; actual_opcode_size = sizeof(g_aarch64_opcode); return Error (); case llvm::Triple::arm: switch (trap_opcode_size_hint) { case 2: trap_opcode_bytes = g_thumb_breakpoint_opcode; actual_opcode_size = sizeof(g_thumb_breakpoint_opcode); return Error (); case 4: trap_opcode_bytes = g_arm_breakpoint_opcode; actual_opcode_size = sizeof(g_arm_breakpoint_opcode); return Error (); default: assert(false && "Unrecognised trap opcode size hint!"); return Error ("Unrecognised trap opcode size hint!"); } case llvm::Triple::x86: case llvm::Triple::x86_64: trap_opcode_bytes = g_i386_opcode; actual_opcode_size = sizeof(g_i386_opcode); return Error (); case llvm::Triple::mips: case llvm::Triple::mips64: trap_opcode_bytes = g_mips64_opcode; actual_opcode_size = sizeof(g_mips64_opcode); return Error (); case llvm::Triple::mipsel: case llvm::Triple::mips64el: trap_opcode_bytes = g_mips64el_opcode; actual_opcode_size = sizeof(g_mips64el_opcode); return Error (); case llvm::Triple::systemz: trap_opcode_bytes = g_s390x_opcode; actual_opcode_size = sizeof(g_s390x_opcode); return Error (); default: assert(false && "CPU type not supported!"); return Error ("CPU type not supported"); } } #if 0 ProcessMessage::CrashReason NativeProcessLinux::GetCrashReasonForSIGSEGV(const siginfo_t *info) { ProcessMessage::CrashReason reason; assert(info->si_signo == SIGSEGV); reason = ProcessMessage::eInvalidCrashReason; switch (info->si_code) { default: assert(false && "unexpected si_code for SIGSEGV"); break; case SI_KERNEL: // Linux will occasionally send spurious SI_KERNEL codes. // (this is poorly documented in sigaction) // One way to get this is via unaligned SIMD loads. reason = ProcessMessage::eInvalidAddress; // for lack of anything better break; case SEGV_MAPERR: reason = ProcessMessage::eInvalidAddress; break; case SEGV_ACCERR: reason = ProcessMessage::ePrivilegedAddress; break; } return reason; } #endif #if 0 ProcessMessage::CrashReason NativeProcessLinux::GetCrashReasonForSIGILL(const siginfo_t *info) { ProcessMessage::CrashReason reason; assert(info->si_signo == SIGILL); reason = ProcessMessage::eInvalidCrashReason; switch (info->si_code) { default: assert(false && "unexpected si_code for SIGILL"); break; case ILL_ILLOPC: reason = ProcessMessage::eIllegalOpcode; break; case ILL_ILLOPN: reason = ProcessMessage::eIllegalOperand; break; case ILL_ILLADR: reason = ProcessMessage::eIllegalAddressingMode; break; case ILL_ILLTRP: reason = ProcessMessage::eIllegalTrap; break; case ILL_PRVOPC: reason = ProcessMessage::ePrivilegedOpcode; break; case ILL_PRVREG: reason = ProcessMessage::ePrivilegedRegister; break; case ILL_COPROC: reason = ProcessMessage::eCoprocessorError; break; case ILL_BADSTK: reason = ProcessMessage::eInternalStackError; break; } return reason; } #endif #if 0 ProcessMessage::CrashReason NativeProcessLinux::GetCrashReasonForSIGFPE(const siginfo_t *info) { ProcessMessage::CrashReason reason; assert(info->si_signo == SIGFPE); reason = ProcessMessage::eInvalidCrashReason; switch (info->si_code) { default: assert(false && "unexpected si_code for SIGFPE"); break; case FPE_INTDIV: reason = ProcessMessage::eIntegerDivideByZero; break; case FPE_INTOVF: reason = ProcessMessage::eIntegerOverflow; break; case FPE_FLTDIV: reason = ProcessMessage::eFloatDivideByZero; break; case FPE_FLTOVF: reason = ProcessMessage::eFloatOverflow; break; case FPE_FLTUND: reason = ProcessMessage::eFloatUnderflow; break; case FPE_FLTRES: reason = ProcessMessage::eFloatInexactResult; break; case FPE_FLTINV: reason = ProcessMessage::eFloatInvalidOperation; break; case FPE_FLTSUB: reason = ProcessMessage::eFloatSubscriptRange; break; } return reason; } #endif #if 0 ProcessMessage::CrashReason NativeProcessLinux::GetCrashReasonForSIGBUS(const siginfo_t *info) { ProcessMessage::CrashReason reason; assert(info->si_signo == SIGBUS); reason = ProcessMessage::eInvalidCrashReason; switch (info->si_code) { default: assert(false && "unexpected si_code for SIGBUS"); break; case BUS_ADRALN: reason = ProcessMessage::eIllegalAlignment; break; case BUS_ADRERR: reason = ProcessMessage::eIllegalAddress; break; case BUS_OBJERR: reason = ProcessMessage::eHardwareError; break; } return reason; } #endif Error NativeProcessLinux::ReadMemory (lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) { if (ProcessVmReadvSupported()) { // The process_vm_readv path is about 50 times faster than ptrace api. We want to use // this syscall if it is supported. const ::pid_t pid = GetID(); struct iovec local_iov, remote_iov; local_iov.iov_base = buf; local_iov.iov_len = size; remote_iov.iov_base = reinterpret_cast(addr); remote_iov.iov_len = size; bytes_read = process_vm_readv(pid, &local_iov, 1, &remote_iov, 1, 0); const bool success = bytes_read == size; Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("NativeProcessLinux::%s using process_vm_readv to read %zd bytes from inferior address 0x%" PRIx64": %s", __FUNCTION__, size, addr, success ? "Success" : strerror(errno)); if (success) return Error(); // else // the call failed for some reason, let's retry the read using ptrace api. } unsigned char *dst = static_cast(buf); size_t remainder; long data; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); if (log) ProcessPOSIXLog::IncNestLevel(); if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) log->Printf ("NativeProcessLinux::%s(%p, %p, %zd, _)", __FUNCTION__, (void*)addr, buf, size); for (bytes_read = 0; bytes_read < size; bytes_read += remainder) { Error error = NativeProcessLinux::PtraceWrapper(PTRACE_PEEKDATA, GetID(), (void*)addr, nullptr, 0, &data); if (error.Fail()) { if (log) ProcessPOSIXLog::DecNestLevel(); return error; } remainder = size - bytes_read; remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; // Copy the data into our buffer memcpy(dst, &data, remainder); if (log && ProcessPOSIXLog::AtTopNestLevel() && (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && size <= POSIX_LOG_MEMORY_SHORT_BYTES))) { uintptr_t print_dst = 0; // Format bytes from data by moving into print_dst for log output for (unsigned i = 0; i < remainder; ++i) print_dst |= (((data >> i*8) & 0xFF) << i*8); log->Printf ("NativeProcessLinux::%s() [0x%" PRIx64 "]:0x%" PRIx64 " (0x%" PRIx64 ")", __FUNCTION__, addr, uint64_t(print_dst), uint64_t(data)); } addr += k_ptrace_word_size; dst += k_ptrace_word_size; } if (log) ProcessPOSIXLog::DecNestLevel(); return Error(); } Error NativeProcessLinux::ReadMemoryWithoutTrap(lldb::addr_t addr, void *buf, size_t size, size_t &bytes_read) { Error error = ReadMemory(addr, buf, size, bytes_read); if (error.Fail()) return error; return m_breakpoint_list.RemoveTrapsFromBuffer(addr, buf, size); } Error NativeProcessLinux::WriteMemory(lldb::addr_t addr, const void *buf, size_t size, size_t &bytes_written) { const unsigned char *src = static_cast(buf); size_t remainder; Error error; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_ALL)); if (log) ProcessPOSIXLog::IncNestLevel(); if (log && ProcessPOSIXLog::AtTopNestLevel() && log->GetMask().Test(POSIX_LOG_MEMORY)) log->Printf ("NativeProcessLinux::%s(0x%" PRIx64 ", %p, %zu)", __FUNCTION__, addr, buf, size); for (bytes_written = 0; bytes_written < size; bytes_written += remainder) { remainder = size - bytes_written; remainder = remainder > k_ptrace_word_size ? k_ptrace_word_size : remainder; if (remainder == k_ptrace_word_size) { unsigned long data = 0; memcpy(&data, src, k_ptrace_word_size); if (log && ProcessPOSIXLog::AtTopNestLevel() && (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && size <= POSIX_LOG_MEMORY_SHORT_BYTES))) log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, (void*)addr, *(const unsigned long*)src, data); error = NativeProcessLinux::PtraceWrapper(PTRACE_POKEDATA, GetID(), (void*)addr, (void*)data); if (error.Fail()) { if (log) ProcessPOSIXLog::DecNestLevel(); return error; } } else { unsigned char buff[8]; size_t bytes_read; error = ReadMemory(addr, buff, k_ptrace_word_size, bytes_read); if (error.Fail()) { if (log) ProcessPOSIXLog::DecNestLevel(); return error; } memcpy(buff, src, remainder); size_t bytes_written_rec; error = WriteMemory(addr, buff, k_ptrace_word_size, bytes_written_rec); if (error.Fail()) { if (log) ProcessPOSIXLog::DecNestLevel(); return error; } if (log && ProcessPOSIXLog::AtTopNestLevel() && (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_LONG) || (log->GetMask().Test(POSIX_LOG_MEMORY_DATA_SHORT) && size <= POSIX_LOG_MEMORY_SHORT_BYTES))) log->Printf ("NativeProcessLinux::%s() [%p]:0x%lx (0x%lx)", __FUNCTION__, (void*)addr, *(const unsigned long*)src, *(unsigned long*)buff); } addr += k_ptrace_word_size; src += k_ptrace_word_size; } if (log) ProcessPOSIXLog::DecNestLevel(); return error; } Error NativeProcessLinux::GetSignalInfo(lldb::tid_t tid, void *siginfo) { return PtraceWrapper(PTRACE_GETSIGINFO, tid, nullptr, siginfo); } Error NativeProcessLinux::GetEventMessage(lldb::tid_t tid, unsigned long *message) { return PtraceWrapper(PTRACE_GETEVENTMSG, tid, nullptr, message); } Error NativeProcessLinux::Detach(lldb::tid_t tid) { if (tid == LLDB_INVALID_THREAD_ID) return Error(); return PtraceWrapper(PTRACE_DETACH, tid); } bool NativeProcessLinux::DupDescriptor(const FileSpec &file_spec, int fd, int flags) { int target_fd = open(file_spec.GetCString(), flags, 0666); if (target_fd == -1) return false; if (dup2(target_fd, fd) == -1) return false; return (close(target_fd) == -1) ? false : true; } bool NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id) { for (auto thread_sp : m_threads) { assert (thread_sp && "thread list should not contain NULL threads"); if (thread_sp->GetID () == thread_id) { // We have this thread. return true; } } // We don't have this thread. return false; } bool NativeProcessLinux::StopTrackingThread (lldb::tid_t thread_id) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); if (log) log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")", __FUNCTION__, thread_id); bool found = false; for (auto it = m_threads.begin (); it != m_threads.end (); ++it) { if (*it && ((*it)->GetID () == thread_id)) { m_threads.erase (it); found = true; break; } } SignalIfAllThreadsStopped(); return found; } NativeThreadLinuxSP NativeProcessLinux::AddThread (lldb::tid_t thread_id) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); if (log) { log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " adding thread with tid %" PRIu64, __FUNCTION__, GetID (), thread_id); } assert (!HasThreadNoLock (thread_id) && "attempted to add a thread by id that already exists"); // If this is the first thread, save it as the current thread if (m_threads.empty ()) SetCurrentThreadID (thread_id); auto thread_sp = std::make_shared(this, thread_id); m_threads.push_back (thread_sp); return thread_sp; } Error NativeProcessLinux::FixupBreakpointPCAsNeeded(NativeThreadLinux &thread) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); Error error; // Find out the size of a breakpoint (might depend on where we are in the code). NativeRegisterContextSP context_sp = thread.GetRegisterContext(); if (!context_sp) { error.SetErrorString ("cannot get a NativeRegisterContext for the thread"); if (log) log->Printf ("NativeProcessLinux::%s failed: %s", __FUNCTION__, error.AsCString ()); return error; } uint32_t breakpoint_size = 0; error = GetSoftwareBreakpointPCOffset(breakpoint_size); if (error.Fail ()) { if (log) log->Printf ("NativeProcessLinux::%s GetBreakpointSize() failed: %s", __FUNCTION__, error.AsCString ()); return error; } else { if (log) log->Printf ("NativeProcessLinux::%s breakpoint size: %" PRIu32, __FUNCTION__, breakpoint_size); } // First try probing for a breakpoint at a software breakpoint location: PC - breakpoint size. const lldb::addr_t initial_pc_addr = context_sp->GetPCfromBreakpointLocation (); lldb::addr_t breakpoint_addr = initial_pc_addr; if (breakpoint_size > 0) { // Do not allow breakpoint probe to wrap around. if (breakpoint_addr >= breakpoint_size) breakpoint_addr -= breakpoint_size; } // Check if we stopped because of a breakpoint. NativeBreakpointSP breakpoint_sp; error = m_breakpoint_list.GetBreakpoint (breakpoint_addr, breakpoint_sp); if (!error.Success () || !breakpoint_sp) { // We didn't find one at a software probe location. Nothing to do. if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " no lldb breakpoint found at current pc with adjustment: 0x%" PRIx64, __FUNCTION__, GetID (), breakpoint_addr); return Error (); } // If the breakpoint is not a software breakpoint, nothing to do. if (!breakpoint_sp->IsSoftwareBreakpoint ()) { if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", not software, nothing to adjust", __FUNCTION__, GetID (), breakpoint_addr); return Error (); } // // We have a software breakpoint and need to adjust the PC. // // Sanity check. if (breakpoint_size == 0) { // Nothing to do! How did we get here? if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " breakpoint found at 0x%" PRIx64 ", it is software, but the size is zero, nothing to do (unexpected)", __FUNCTION__, GetID (), breakpoint_addr); return Error (); } // Change the program counter. if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": changing PC from 0x%" PRIx64 " to 0x%" PRIx64, __FUNCTION__, GetID(), thread.GetID(), initial_pc_addr, breakpoint_addr); error = context_sp->SetPC (breakpoint_addr); if (error.Fail ()) { if (log) log->Printf ("NativeProcessLinux::%s pid %" PRIu64 " tid %" PRIu64 ": failed to set PC: %s", __FUNCTION__, GetID(), thread.GetID(), error.AsCString ()); return error; } return error; } Error NativeProcessLinux::GetLoadedModuleFileSpec(const char* module_path, FileSpec& file_spec) { FileSpec module_file_spec(module_path, true); bool found = false; file_spec.Clear(); ProcFileReader::ProcessLineByLine(GetID(), "maps", [&] (const std::string &line) { SmallVector columns; StringRef(line).split(columns, " ", -1, false); if (columns.size() < 6) return true; // continue searching FileSpec this_file_spec(columns[5].str().c_str(), false); if (this_file_spec.GetFilename() != module_file_spec.GetFilename()) return true; // continue searching file_spec = this_file_spec; found = true; return false; // we are done }); if (! found) return Error("Module file (%s) not found in /proc/%" PRIu64 "/maps file!", module_file_spec.GetFilename().AsCString(), GetID()); return Error(); } Error NativeProcessLinux::GetFileLoadAddress(const llvm::StringRef& file_name, lldb::addr_t& load_addr) { load_addr = LLDB_INVALID_ADDRESS; Error error = ProcFileReader::ProcessLineByLine (GetID (), "maps", [&] (const std::string &line) -> bool { StringRef maps_row(line); SmallVector maps_columns; maps_row.split(maps_columns, StringRef(" "), -1, false); if (maps_columns.size() < 6) { // Return true to continue reading the proc file return true; } if (maps_columns[5] == file_name) { StringExtractor addr_extractor(maps_columns[0].str().c_str()); load_addr = addr_extractor.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); // Return false to stop reading the proc file further return false; } // Return true to continue reading the proc file return true; }); return error; } NativeThreadLinuxSP NativeProcessLinux::GetThreadByID(lldb::tid_t tid) { return std::static_pointer_cast(NativeProcessProtocol::GetThreadByID(tid)); } Error NativeProcessLinux::ResumeThread(NativeThreadLinux &thread, lldb::StateType state, int signo) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); if (log) log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")", __FUNCTION__, thread.GetID()); // Before we do the resume below, first check if we have a pending // stop notification that is currently waiting for // all threads to stop. This is potentially a buggy situation since // we're ostensibly waiting for threads to stop before we send out the // pending notification, and here we are resuming one before we send // out the pending stop notification. if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && log) { log->Printf("NativeProcessLinux::%s about to resume tid %" PRIu64 " per explicit request but we have a pending stop notification (tid %" PRIu64 ") that is actively waiting for this thread to stop. Valid sequence of events?", __FUNCTION__, thread.GetID(), m_pending_notification_tid); } // Request a resume. We expect this to be synchronous and the system // to reflect it is running after this completes. switch (state) { case eStateRunning: { const auto resume_result = thread.Resume(signo); if (resume_result.Success()) SetState(eStateRunning, true); return resume_result; } case eStateStepping: { const auto step_result = thread.SingleStep(signo); if (step_result.Success()) SetState(eStateRunning, true); return step_result; } default: if (log) log->Printf("NativeProcessLinux::%s Unhandled state %s.", __FUNCTION__, StateAsCString(state)); llvm_unreachable("Unhandled state for resume"); } } //===----------------------------------------------------------------------===// void NativeProcessLinux::StopRunningThreads(const lldb::tid_t triggering_tid) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); if (log) { log->Printf("NativeProcessLinux::%s about to process event: (triggering_tid: %" PRIu64 ")", __FUNCTION__, triggering_tid); } m_pending_notification_tid = triggering_tid; // Request a stop for all the thread stops that need to be stopped // and are not already known to be stopped. for (const auto &thread_sp: m_threads) { if (StateIsRunningState(thread_sp->GetState())) static_pointer_cast(thread_sp)->RequestStop(); } SignalIfAllThreadsStopped(); if (log) { log->Printf("NativeProcessLinux::%s event processing done", __FUNCTION__); } } void NativeProcessLinux::SignalIfAllThreadsStopped() { if (m_pending_notification_tid == LLDB_INVALID_THREAD_ID) return; // No pending notification. Nothing to do. for (const auto &thread_sp: m_threads) { if (StateIsRunningState(thread_sp->GetState())) return; // Some threads are still running. Don't signal yet. } // We have a pending notification and all threads have stopped. Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_BREAKPOINTS)); // Clear any temporary breakpoints we used to implement software single stepping. for (const auto &thread_info: m_threads_stepping_with_breakpoint) { Error error = RemoveBreakpoint (thread_info.second); if (error.Fail()) if (log) log->Printf("NativeProcessLinux::%s() pid = %" PRIu64 " remove stepping breakpoint: %s", __FUNCTION__, thread_info.first, error.AsCString()); } m_threads_stepping_with_breakpoint.clear(); // Notify the delegate about the stop SetCurrentThreadID(m_pending_notification_tid); SetState(StateType::eStateStopped, true); m_pending_notification_tid = LLDB_INVALID_THREAD_ID; } void NativeProcessLinux::ThreadWasCreated(NativeThreadLinux &thread) { Log *const log = GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD); if (log) log->Printf("NativeProcessLinux::%s (tid: %" PRIu64 ")", __FUNCTION__, thread.GetID()); if (m_pending_notification_tid != LLDB_INVALID_THREAD_ID && StateIsRunningState(thread.GetState())) { // We will need to wait for this new thread to stop as well before firing the // notification. thread.RequestStop(); } } void NativeProcessLinux::SigchldHandler() { Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); // Process all pending waitpid notifications. while (true) { int status = -1; ::pid_t wait_pid = waitpid(-1, &status, __WALL | __WNOTHREAD | WNOHANG); if (wait_pid == 0) break; // We are done. if (wait_pid == -1) { if (errno == EINTR) continue; Error error(errno, eErrorTypePOSIX); if (log) log->Printf("NativeProcessLinux::%s waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG) failed: %s", __FUNCTION__, error.AsCString()); break; } bool exited = false; int signal = 0; int exit_status = 0; const char *status_cstr = nullptr; if (WIFSTOPPED(status)) { signal = WSTOPSIG(status); status_cstr = "STOPPED"; } else if (WIFEXITED(status)) { exit_status = WEXITSTATUS(status); status_cstr = "EXITED"; exited = true; } else if (WIFSIGNALED(status)) { signal = WTERMSIG(status); status_cstr = "SIGNALED"; if (wait_pid == static_cast< ::pid_t>(GetID())) { exited = true; exit_status = -1; } } else status_cstr = "(\?\?\?)"; if (log) log->Printf("NativeProcessLinux::%s: waitpid (-1, &status, __WALL | __WNOTHREAD | WNOHANG)" "=> pid = %" PRIi32 ", status = 0x%8.8x (%s), signal = %i, exit_state = %i", __FUNCTION__, wait_pid, status, status_cstr, signal, exit_status); MonitorCallback (wait_pid, exited, signal, exit_status); } } // Wrapper for ptrace to catch errors and log calls. // Note that ptrace sets errno on error because -1 can be a valid result (i.e. for PTRACE_PEEK*) Error NativeProcessLinux::PtraceWrapper(int req, lldb::pid_t pid, void *addr, void *data, size_t data_size, long *result) { Error error; long int ret; Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PTRACE)); PtraceDisplayBytes(req, data, data_size); errno = 0; if (req == PTRACE_GETREGSET || req == PTRACE_SETREGSET) ret = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), *(unsigned int *)addr, data); else ret = ptrace(static_cast<__ptrace_request>(req), static_cast< ::pid_t>(pid), addr, data); if (ret == -1) error.SetErrorToErrno(); if (result) *result = ret; if (log) log->Printf("ptrace(%d, %" PRIu64 ", %p, %p, %zu)=%lX", req, pid, addr, data, data_size, ret); PtraceDisplayBytes(req, data, data_size); if (log && error.GetError() != 0) { const char* str; switch (error.GetError()) { case ESRCH: str = "ESRCH"; break; case EINVAL: str = "EINVAL"; break; case EBUSY: str = "EBUSY"; break; case EPERM: str = "EPERM"; break; default: str = error.AsCString(); } log->Printf("ptrace() failed; errno=%d (%s)", error.GetError(), str); } return error; } Index: vendor/lldb/dist/source/Plugins/Process/Linux/NativeThreadLinux.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Linux/NativeThreadLinux.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Linux/NativeThreadLinux.cpp (revision 304308) @@ -1,509 +1,509 @@ //===-- NativeThreadLinux.cpp --------------------------------- -*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "NativeThreadLinux.h" #include #include #include "NativeProcessLinux.h" #include "NativeRegisterContextLinux.h" #include "SingleStepCheck.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" #include "lldb/Host/HostNativeThread.h" #include "lldb/Host/linux/Ptrace.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/lldb-enumerations.h" #include "llvm/ADT/SmallString.h" #include "Plugins/Process/POSIX/CrashReason.h" #include // Try to define a macro to encapsulate the tgkill syscall #define tgkill(pid, tid, sig) \ - syscall(SYS_tgkill, static_cast< ::pid_t>(pid), static_cast< ::pid_t>(tid), sig) + syscall(__NR_tgkill, static_cast< ::pid_t>(pid), static_cast< ::pid_t>(tid), sig) using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_linux; namespace { void LogThreadStopInfo (Log &log, const ThreadStopInfo &stop_info, const char *const header) { switch (stop_info.reason) { case eStopReasonNone: log.Printf ("%s: %s no stop reason", __FUNCTION__, header); return; case eStopReasonTrace: log.Printf ("%s: %s trace, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo); return; case eStopReasonBreakpoint: log.Printf ("%s: %s breakpoint, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo); return; case eStopReasonWatchpoint: log.Printf ("%s: %s watchpoint, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo); return; case eStopReasonSignal: log.Printf ("%s: %s signal 0x%02" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo); return; case eStopReasonException: log.Printf ("%s: %s exception type 0x%02" PRIx64, __FUNCTION__, header, stop_info.details.exception.type); return; case eStopReasonExec: log.Printf ("%s: %s exec, stopping signal 0x%" PRIx32, __FUNCTION__, header, stop_info.details.signal.signo); return; case eStopReasonPlanComplete: log.Printf ("%s: %s plan complete", __FUNCTION__, header); return; case eStopReasonThreadExiting: log.Printf ("%s: %s thread exiting", __FUNCTION__, header); return; case eStopReasonInstrumentation: log.Printf ("%s: %s instrumentation", __FUNCTION__, header); return; default: log.Printf ("%s: %s invalid stop reason %" PRIu32, __FUNCTION__, header, static_cast (stop_info.reason)); } } } NativeThreadLinux::NativeThreadLinux (NativeProcessLinux *process, lldb::tid_t tid) : NativeThreadProtocol (process, tid), m_state (StateType::eStateInvalid), m_stop_info (), m_reg_context_sp (), m_stop_description () { } std::string NativeThreadLinux::GetName() { NativeProcessProtocolSP process_sp = m_process_wp.lock (); if (!process_sp) return ""; // const NativeProcessLinux *const process = reinterpret_cast (process_sp->get ()); llvm::SmallString<32> thread_name; HostNativeThread::GetName(GetID(), thread_name); return thread_name.c_str(); } lldb::StateType NativeThreadLinux::GetState () { return m_state; } bool NativeThreadLinux::GetStopReason (ThreadStopInfo &stop_info, std::string& description) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); description.clear(); switch (m_state) { case eStateStopped: case eStateCrashed: case eStateExited: case eStateSuspended: case eStateUnloaded: if (log) LogThreadStopInfo (*log, m_stop_info, "m_stop_info in thread:"); stop_info = m_stop_info; description = m_stop_description; if (log) LogThreadStopInfo (*log, stop_info, "returned stop_info:"); return true; case eStateInvalid: case eStateConnected: case eStateAttaching: case eStateLaunching: case eStateRunning: case eStateStepping: case eStateDetached: if (log) { log->Printf ("NativeThreadLinux::%s tid %" PRIu64 " in state %s cannot answer stop reason", __FUNCTION__, GetID (), StateAsCString (m_state)); } return false; } llvm_unreachable("unhandled StateType!"); } NativeRegisterContextSP NativeThreadLinux::GetRegisterContext () { // Return the register context if we already created it. if (m_reg_context_sp) return m_reg_context_sp; NativeProcessProtocolSP m_process_sp = m_process_wp.lock (); if (!m_process_sp) return NativeRegisterContextSP (); ArchSpec target_arch; if (!m_process_sp->GetArchitecture (target_arch)) return NativeRegisterContextSP (); const uint32_t concrete_frame_idx = 0; m_reg_context_sp.reset (NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(target_arch, *this, concrete_frame_idx)); return m_reg_context_sp; } Error NativeThreadLinux::SetWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags, bool hardware) { if (!hardware) return Error ("not implemented"); if (m_state == eStateLaunching) return Error (); Error error = RemoveWatchpoint(addr); if (error.Fail()) return error; NativeRegisterContextSP reg_ctx = GetRegisterContext (); uint32_t wp_index = reg_ctx->SetHardwareWatchpoint (addr, size, watch_flags); if (wp_index == LLDB_INVALID_INDEX32) return Error ("Setting hardware watchpoint failed."); m_watchpoint_index_map.insert({addr, wp_index}); return Error (); } Error NativeThreadLinux::RemoveWatchpoint (lldb::addr_t addr) { auto wp = m_watchpoint_index_map.find(addr); if (wp == m_watchpoint_index_map.end()) return Error (); uint32_t wp_index = wp->second; m_watchpoint_index_map.erase(wp); if (GetRegisterContext()->ClearHardwareWatchpoint(wp_index)) return Error (); return Error ("Clearing hardware watchpoint failed."); } Error NativeThreadLinux::Resume(uint32_t signo) { const StateType new_state = StateType::eStateRunning; MaybeLogStateChange (new_state); m_state = new_state; m_stop_info.reason = StopReason::eStopReasonNone; m_stop_description.clear(); // If watchpoints have been set, but none on this thread, // then this is a new thread. So set all existing watchpoints. if (m_watchpoint_index_map.empty()) { NativeProcessLinux &process = GetProcess(); const auto &watchpoint_map = process.GetWatchpointMap(); GetRegisterContext()->ClearAllHardwareWatchpoints(); for (const auto &pair : watchpoint_map) { const auto &wp = pair.second; SetWatchpoint(wp.m_addr, wp.m_size, wp.m_watch_flags, wp.m_hardware); } } intptr_t data = 0; if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; return NativeProcessLinux::PtraceWrapper(PTRACE_CONT, GetID(), nullptr, reinterpret_cast(data)); } void NativeThreadLinux::MaybePrepareSingleStepWorkaround() { if (!SingleStepWorkaroundNeeded()) return; Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); if (sched_getaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set, &m_original_cpu_set) != 0) { // This should really not fail. But, just in case... if (log) { Error error(errno, eErrorTypePOSIX); log->Printf("NativeThreadLinux::%s Unable to get cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, m_tid, error.AsCString()); } return; } cpu_set_t set; CPU_ZERO(&set); CPU_SET(0, &set); if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof set, &set) != 0 && log) { // This may fail in very locked down systems, if the thread is not allowed to run on // cpu 0. If that happens, only thing we can do is it log it and continue... Error error(errno, eErrorTypePOSIX); log->Printf("NativeThreadLinux::%s Unable to set cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, m_tid, error.AsCString()); } } void NativeThreadLinux::MaybeCleanupSingleStepWorkaround() { if (!SingleStepWorkaroundNeeded()) return; if (sched_setaffinity(static_cast<::pid_t>(m_tid), sizeof m_original_cpu_set, &m_original_cpu_set) != 0) { Error error(errno, eErrorTypePOSIX); Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); log->Printf("NativeThreadLinux::%s Unable to reset cpu affinity for thread %" PRIx64 ": %s", __FUNCTION__, m_tid, error.AsCString()); } } Error NativeThreadLinux::SingleStep(uint32_t signo) { const StateType new_state = StateType::eStateStepping; MaybeLogStateChange (new_state); m_state = new_state; m_stop_info.reason = StopReason::eStopReasonNone; MaybePrepareSingleStepWorkaround(); intptr_t data = 0; if (signo != LLDB_INVALID_SIGNAL_NUMBER) data = signo; // If hardware single-stepping is not supported, we just do a continue. The breakpoint on the // next instruction has been setup in NativeProcessLinux::Resume. return NativeProcessLinux::PtraceWrapper(GetProcess().SupportHardwareSingleStepping() ? PTRACE_SINGLESTEP : PTRACE_CONT, m_tid, nullptr, reinterpret_cast(data)); } void NativeThreadLinux::SetStoppedBySignal(uint32_t signo, const siginfo_t *info) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); if (log) log->Printf ("NativeThreadLinux::%s called with signal 0x%02" PRIx32, __FUNCTION__, signo); SetStopped(); m_stop_info.reason = StopReason::eStopReasonSignal; m_stop_info.details.signal.signo = signo; m_stop_description.clear(); if (info) { switch (signo) { case SIGSEGV: case SIGBUS: case SIGFPE: case SIGILL: //In case of MIPS64 target, SI_KERNEL is generated for invalid 64bit address. const auto reason = (info->si_signo == SIGBUS && info->si_code == SI_KERNEL) ? CrashReason::eInvalidAddress : GetCrashReason(*info); m_stop_description = GetCrashReasonString(reason, reinterpret_cast(info->si_addr)); break; } } } bool NativeThreadLinux::IsStopped (int *signo) { if (!StateIsStoppedState (m_state, false)) return false; // If we are stopped by a signal, return the signo. if (signo && m_state == StateType::eStateStopped && m_stop_info.reason == StopReason::eStopReasonSignal) { *signo = m_stop_info.details.signal.signo; } // Regardless, we are stopped. return true; } void NativeThreadLinux::SetStopped() { if (m_state == StateType::eStateStepping) MaybeCleanupSingleStepWorkaround(); const StateType new_state = StateType::eStateStopped; MaybeLogStateChange(new_state); m_state = new_state; m_stop_description.clear(); } void NativeThreadLinux::SetStoppedByExec () { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); if (log) log->Printf ("NativeThreadLinux::%s()", __FUNCTION__); SetStopped(); m_stop_info.reason = StopReason::eStopReasonExec; m_stop_info.details.signal.signo = SIGSTOP; } void NativeThreadLinux::SetStoppedByBreakpoint () { SetStopped(); m_stop_info.reason = StopReason::eStopReasonBreakpoint; m_stop_info.details.signal.signo = SIGTRAP; m_stop_description.clear(); } void NativeThreadLinux::SetStoppedByWatchpoint (uint32_t wp_index) { SetStopped(); lldbassert(wp_index != LLDB_INVALID_INDEX32 && "wp_index cannot be invalid"); std::ostringstream ostr; ostr << GetRegisterContext()->GetWatchpointAddress(wp_index) << " "; ostr << wp_index; /* * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For example: * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at 'm', then * watch exception is generated even when 'n' is read/written. To handle this case, * find the base address of the load/store instruction and append it in the stop-info * packet. */ ostr << " " << GetRegisterContext()->GetWatchpointHitAddress(wp_index); m_stop_description = ostr.str(); m_stop_info.reason = StopReason::eStopReasonWatchpoint; m_stop_info.details.signal.signo = SIGTRAP; } bool NativeThreadLinux::IsStoppedAtBreakpoint () { return GetState () == StateType::eStateStopped && m_stop_info.reason == StopReason::eStopReasonBreakpoint; } bool NativeThreadLinux::IsStoppedAtWatchpoint () { return GetState () == StateType::eStateStopped && m_stop_info.reason == StopReason::eStopReasonWatchpoint; } void NativeThreadLinux::SetStoppedByTrace () { SetStopped(); m_stop_info.reason = StopReason::eStopReasonTrace; m_stop_info.details.signal.signo = SIGTRAP; } void NativeThreadLinux::SetStoppedWithNoReason () { SetStopped(); m_stop_info.reason = StopReason::eStopReasonNone; m_stop_info.details.signal.signo = 0; } void NativeThreadLinux::SetExited () { const StateType new_state = StateType::eStateExited; MaybeLogStateChange (new_state); m_state = new_state; m_stop_info.reason = StopReason::eStopReasonThreadExiting; } Error NativeThreadLinux::RequestStop () { Log* log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); NativeProcessLinux &process = GetProcess(); lldb::pid_t pid = process.GetID(); lldb::tid_t tid = GetID(); if (log) log->Printf ("NativeThreadLinux::%s requesting thread stop(pid: %" PRIu64 ", tid: %" PRIu64 ")", __FUNCTION__, pid, tid); Error err; errno = 0; if (::tgkill (pid, tid, SIGSTOP) != 0) { err.SetErrorToErrno (); if (log) log->Printf ("NativeThreadLinux::%s tgkill(%" PRIu64 ", %" PRIu64 ", SIGSTOP) failed: %s", __FUNCTION__, pid, tid, err.AsCString ()); } return err; } void NativeThreadLinux::MaybeLogStateChange (lldb::StateType new_state) { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); // If we're not logging, we're done. if (!log) return; // If this is a state change to the same state, we're done. lldb::StateType old_state = m_state; if (new_state == old_state) return; NativeProcessProtocolSP m_process_sp = m_process_wp.lock (); lldb::pid_t pid = m_process_sp ? m_process_sp->GetID () : LLDB_INVALID_PROCESS_ID; // Log it. log->Printf ("NativeThreadLinux: thread (pid=%" PRIu64 ", tid=%" PRIu64 ") changing from state %s to %s", pid, GetID (), StateAsCString (old_state), StateAsCString (new_state)); } NativeProcessLinux & NativeThreadLinux::GetProcess() { auto process_sp = std::static_pointer_cast(NativeThreadProtocol::GetProcess()); assert(process_sp); return *process_sp; } Index: vendor/lldb/dist/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp (revision 304308) @@ -1,770 +1,811 @@ //===-- DynamicRegisterInfo.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "DynamicRegisterInfo.h" // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Core/ArchSpec.h" #include "lldb/Core/RegularExpression.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StructuredData.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Host/StringConvert.h" +#include "lldb/Utility/StringExtractor.h" using namespace lldb; using namespace lldb_private; DynamicRegisterInfo::DynamicRegisterInfo () : m_regs (), m_sets (), m_set_reg_nums (), m_set_names (), m_value_regs_map (), m_invalidate_regs_map (), + m_dynamic_reg_size_map (), m_reg_data_byte_size (0), m_finalized (false) { } DynamicRegisterInfo::DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, const lldb_private::ArchSpec &arch) : m_regs (), m_sets (), m_set_reg_nums (), m_set_names (), m_value_regs_map (), m_invalidate_regs_map (), + m_dynamic_reg_size_map (), m_reg_data_byte_size (0), m_finalized (false) { SetRegisterInfo (dict, arch); } DynamicRegisterInfo::~DynamicRegisterInfo () { } size_t DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict, const ArchSpec &arch) { assert(!m_finalized); StructuredData::Array *sets = nullptr; if (dict.GetValueForKeyAsArray("sets", sets)) { const uint32_t num_sets = sets->GetSize(); for (uint32_t i=0; iGetItemAtIndexAsString(i, set_name_str)) set_name.SetCString(set_name_str.c_str()); if (set_name) { RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL }; m_sets.push_back (new_set); } else { Clear(); printf("error: register sets must have valid names\n"); return 0; } } m_set_reg_nums.resize(m_sets.size()); } StructuredData::Array *regs = nullptr; if (!dict.GetValueForKeyAsArray("registers", regs)) return 0; const uint32_t num_regs = regs->GetSize(); // typedef std::map > InvalidateNameMap; // InvalidateNameMap invalidate_map; for (uint32_t i = 0; i < num_regs; ++i) { StructuredData::Dictionary *reg_info_dict = nullptr; if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) { Clear(); printf("error: items in the 'registers' array must be dictionaries\n"); regs->DumpToStdout(); return 0; } // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'ehframe' : 2, // 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, RegisterInfo reg_info; std::vector value_regs; std::vector invalidate_regs; memset(®_info, 0, sizeof(reg_info)); ConstString name_val; ConstString alt_name_val; if (!reg_info_dict->GetValueForKeyAsString("name", name_val, nullptr)) { Clear(); printf("error: registers must have valid names and offsets\n"); reg_info_dict->DumpToStdout(); return 0; } reg_info.name = name_val.GetCString(); reg_info_dict->GetValueForKeyAsString("alt-name", alt_name_val, nullptr); reg_info.alt_name = alt_name_val.GetCString(); reg_info_dict->GetValueForKeyAsInteger("offset", reg_info.byte_offset, UINT32_MAX); const ByteOrder byte_order = arch.GetByteOrder(); if (reg_info.byte_offset == UINT32_MAX) { // No offset for this register, see if the register has a value expression // which indicates this register is part of another register. Value expressions // are things like "rax[31:0]" which state that the current register's value // is in a concrete register "rax" in bits 31:0. If there is a value expression // we can calculate the offset bool success = false; std::string slice_str; if (reg_info_dict->GetValueForKeyAsString("slice", slice_str, nullptr)) { // Slices use the following format: // REGNAME[MSBIT:LSBIT] // REGNAME - name of the register to grab a slice of // MSBIT - the most significant bit at which the current register value starts at // LSBIT - the least significant bit at which the current register value ends at static RegularExpression g_bitfield_regex("([A-Za-z_][A-Za-z0-9_]*)\\[([0-9]+):([0-9]+)\\]"); RegularExpression::Match regex_match(3); if (g_bitfield_regex.Execute(slice_str.c_str(), ®ex_match)) { llvm::StringRef reg_name_str; std::string msbit_str; std::string lsbit_str; if (regex_match.GetMatchAtIndex(slice_str.c_str(), 1, reg_name_str) && regex_match.GetMatchAtIndex(slice_str.c_str(), 2, msbit_str) && regex_match.GetMatchAtIndex(slice_str.c_str(), 3, lsbit_str)) { const uint32_t msbit = StringConvert::ToUInt32(msbit_str.c_str(), UINT32_MAX); const uint32_t lsbit = StringConvert::ToUInt32(lsbit_str.c_str(), UINT32_MAX); if (msbit != UINT32_MAX && lsbit != UINT32_MAX) { if (msbit > lsbit) { const uint32_t msbyte = msbit / 8; const uint32_t lsbyte = lsbit / 8; ConstString containing_reg_name(reg_name_str); RegisterInfo *containing_reg_info = GetRegisterInfo(containing_reg_name); if (containing_reg_info) { const uint32_t max_bit = containing_reg_info->byte_size * 8; if (msbit < max_bit && lsbit < max_bit) { m_invalidate_regs_map[containing_reg_info->kinds[eRegisterKindLLDB]].push_back(i); m_value_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); m_invalidate_regs_map[i].push_back(containing_reg_info->kinds[eRegisterKindLLDB]); if (byte_order == eByteOrderLittle) { success = true; reg_info.byte_offset = containing_reg_info->byte_offset + lsbyte; } else if (byte_order == eByteOrderBig) { success = true; reg_info.byte_offset = containing_reg_info->byte_offset + msbyte; } else { assert(!"Invalid byte order"); } } else { if (msbit > max_bit) printf("error: msbit (%u) must be less than the bitsize of the register (%u)\n", msbit, max_bit); else printf("error: lsbit (%u) must be less than the bitsize of the register (%u)\n", lsbit, max_bit); } } else { printf("error: invalid concrete register \"%s\"\n", containing_reg_name.GetCString()); } } else { printf("error: msbit (%u) must be greater than lsbit (%u)\n", msbit, lsbit); } } else { printf("error: msbit (%u) and lsbit (%u) must be valid\n", msbit, lsbit); } } else { // TODO: print error invalid slice string that doesn't follow the format printf("error: failed to extract regex matches for parsing the register bitfield regex\n"); } } else { // TODO: print error invalid slice string that doesn't follow the format printf("error: failed to match against register bitfield regex\n"); } } else { StructuredData::Array *composite_reg_list = nullptr; if (reg_info_dict->GetValueForKeyAsArray("composite", composite_reg_list)) { const size_t num_composite_regs = composite_reg_list->GetSize(); if (num_composite_regs > 0) { uint32_t composite_offset = UINT32_MAX; for (uint32_t composite_idx = 0; composite_idx < num_composite_regs; ++composite_idx) { ConstString composite_reg_name; if (composite_reg_list->GetItemAtIndexAsString(composite_idx, composite_reg_name, nullptr)) { RegisterInfo *composite_reg_info = GetRegisterInfo(composite_reg_name); if (composite_reg_info) { composite_offset = std::min(composite_offset, composite_reg_info->byte_offset); m_value_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); m_invalidate_regs_map[composite_reg_info->kinds[eRegisterKindLLDB]].push_back(i); m_invalidate_regs_map[i].push_back(composite_reg_info->kinds[eRegisterKindLLDB]); } else { // TODO: print error invalid slice string that doesn't follow the format printf("error: failed to find composite register by name: \"%s\"\n", composite_reg_name.GetCString()); } } else { printf("error: 'composite' list value wasn't a python string\n"); } } if (composite_offset != UINT32_MAX) { reg_info.byte_offset = composite_offset; success = m_value_regs_map.find(i) != m_value_regs_map.end(); } else { printf("error: 'composite' registers must specify at least one real register\n"); } } else { printf("error: 'composite' list was empty\n"); } } } if (!success) { Clear(); reg_info_dict->DumpToStdout(); return 0; } } int64_t bitsize = 0; if (!reg_info_dict->GetValueForKeyAsInteger("bitsize", bitsize)) { Clear(); printf("error: invalid or missing 'bitsize' key/value pair in register dictionary\n"); reg_info_dict->DumpToStdout(); return 0; } reg_info.byte_size = bitsize / 8; + std::string dwarf_opcode_string; + if (reg_info_dict->GetValueForKeyAsString ("dynamic_size_dwarf_expr_bytes", dwarf_opcode_string)) + { + reg_info.dynamic_size_dwarf_len = dwarf_opcode_string.length () / 2; + assert (reg_info.dynamic_size_dwarf_len > 0); + + std::vector dwarf_opcode_bytes(reg_info.dynamic_size_dwarf_len); + uint32_t j; + StringExtractor opcode_extractor; + // Swap "dwarf_opcode_string" over into "opcode_extractor" + opcode_extractor.GetStringRef ().swap (dwarf_opcode_string); + uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), + reg_info.dynamic_size_dwarf_len); + assert (ret_val == reg_info.dynamic_size_dwarf_len); + + for (j = 0; j < reg_info.dynamic_size_dwarf_len; ++j) + m_dynamic_reg_size_map[i].push_back(dwarf_opcode_bytes[j]); + + reg_info.dynamic_size_dwarf_expr_bytes = m_dynamic_reg_size_map[i].data (); + } + std::string format_str; if (reg_info_dict->GetValueForKeyAsString("format", format_str, nullptr)) { if (Args::StringToFormat(format_str.c_str(), reg_info.format, NULL).Fail()) { Clear(); printf("error: invalid 'format' value in register dictionary\n"); reg_info_dict->DumpToStdout(); return 0; } } else { reg_info_dict->GetValueForKeyAsInteger("format", reg_info.format, eFormatHex); } std::string encoding_str; if (reg_info_dict->GetValueForKeyAsString("encoding", encoding_str)) reg_info.encoding = Args::StringToEncoding(encoding_str.c_str(), eEncodingUint); else reg_info_dict->GetValueForKeyAsInteger("encoding", reg_info.encoding, eEncodingUint); size_t set = 0; if (!reg_info_dict->GetValueForKeyAsInteger("set", set, -1) || set >= m_sets.size()) { Clear(); printf("error: invalid 'set' value in register dictionary, valid values are 0 - %i\n", (int)set); reg_info_dict->DumpToStdout(); return 0; } // Fill in the register numbers reg_info.kinds[lldb::eRegisterKindLLDB] = i; reg_info.kinds[lldb::eRegisterKindProcessPlugin] = i; uint32_t eh_frame_regno = LLDB_INVALID_REGNUM; reg_info_dict->GetValueForKeyAsInteger("gcc", eh_frame_regno, LLDB_INVALID_REGNUM); if (eh_frame_regno == LLDB_INVALID_REGNUM) reg_info_dict->GetValueForKeyAsInteger("ehframe", eh_frame_regno, LLDB_INVALID_REGNUM); reg_info.kinds[lldb::eRegisterKindEHFrame] = eh_frame_regno; reg_info_dict->GetValueForKeyAsInteger("dwarf", reg_info.kinds[lldb::eRegisterKindDWARF], LLDB_INVALID_REGNUM); std::string generic_str; if (reg_info_dict->GetValueForKeyAsString("generic", generic_str)) reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister(generic_str.c_str()); else reg_info_dict->GetValueForKeyAsInteger("generic", reg_info.kinds[lldb::eRegisterKindGeneric], LLDB_INVALID_REGNUM); // Check if this register invalidates any other register values when it is modified StructuredData::Array *invalidate_reg_list = nullptr; if (reg_info_dict->GetValueForKeyAsArray("invalidate-regs", invalidate_reg_list)) { const size_t num_regs = invalidate_reg_list->GetSize(); if (num_regs > 0) { for (uint32_t idx = 0; idx < num_regs; ++idx) { ConstString invalidate_reg_name; uint64_t invalidate_reg_num; if (invalidate_reg_list->GetItemAtIndexAsString(idx, invalidate_reg_name)) { RegisterInfo *invalidate_reg_info = GetRegisterInfo(invalidate_reg_name); if (invalidate_reg_info) { m_invalidate_regs_map[i].push_back(invalidate_reg_info->kinds[eRegisterKindLLDB]); } else { // TODO: print error invalid slice string that doesn't follow the format printf("error: failed to find a 'invalidate-regs' register for \"%s\" while parsing register \"%s\"\n", invalidate_reg_name.GetCString(), reg_info.name); } } else if (invalidate_reg_list->GetItemAtIndexAsInteger(idx, invalidate_reg_num)) { if (invalidate_reg_num != UINT64_MAX) m_invalidate_regs_map[i].push_back(invalidate_reg_num); else printf("error: 'invalidate-regs' list value wasn't a valid integer\n"); } else { printf("error: 'invalidate-regs' list value wasn't a python string or integer\n"); } } } else { printf("error: 'invalidate-regs' contained an empty list\n"); } } // Calculate the register offset const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; if (m_reg_data_byte_size < end_reg_offset) m_reg_data_byte_size = end_reg_offset; m_regs.push_back(reg_info); m_set_reg_nums[set].push_back(i); } Finalize(arch); return m_regs.size(); } void DynamicRegisterInfo::AddRegister (RegisterInfo ®_info, ConstString ®_name, ConstString ®_alt_name, ConstString &set_name) { assert(!m_finalized); const uint32_t reg_num = m_regs.size(); reg_info.name = reg_name.AsCString(); assert (reg_info.name); reg_info.alt_name = reg_alt_name.AsCString(NULL); uint32_t i; if (reg_info.value_regs) { for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i) m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]); } if (reg_info.invalidate_regs) { for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i) m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]); } + if (reg_info.dynamic_size_dwarf_expr_bytes) + { + for (i = 0; i < reg_info.dynamic_size_dwarf_len; ++i) + m_dynamic_reg_size_map[reg_num].push_back(reg_info.dynamic_size_dwarf_expr_bytes[i]); + + reg_info.dynamic_size_dwarf_expr_bytes = m_dynamic_reg_size_map[reg_num].data (); + } + m_regs.push_back (reg_info); uint32_t set = GetRegisterSetIndexByName (set_name, true); assert (set < m_sets.size()); assert (set < m_set_reg_nums.size()); assert (set < m_set_names.size()); m_set_reg_nums[set].push_back(reg_num); size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; if (m_reg_data_byte_size < end_reg_offset) m_reg_data_byte_size = end_reg_offset; } void DynamicRegisterInfo::Finalize (const ArchSpec &arch) { if (m_finalized) return; m_finalized = true; const size_t num_sets = m_sets.size(); for (size_t set = 0; set < num_sets; ++set) { assert (m_sets.size() == m_set_reg_nums.size()); m_sets[set].num_registers = m_set_reg_nums[set].size(); m_sets[set].registers = &m_set_reg_nums[set][0]; } // sort and unique all value registers and make sure each is terminated with // LLDB_INVALID_REGNUM for (reg_to_regs_map::iterator pos = m_value_regs_map.begin(), end = m_value_regs_map.end(); pos != end; ++pos) { if (pos->second.size() > 1) { std::sort (pos->second.begin(), pos->second.end()); reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end()); if (unique_end != pos->second.end()) pos->second.erase(unique_end, pos->second.end()); } assert (!pos->second.empty()); if (pos->second.back() != LLDB_INVALID_REGNUM) pos->second.push_back(LLDB_INVALID_REGNUM); } // Now update all value_regs with each register info as needed const size_t num_regs = m_regs.size(); for (size_t i=0; ifirst; if (m_regs[reg_num].value_regs) { reg_num_collection extra_invalid_regs; for (const uint32_t invalidate_reg_num : pos->second) { reg_to_regs_map::iterator invalidate_pos = m_invalidate_regs_map.find(invalidate_reg_num); if (invalidate_pos != m_invalidate_regs_map.end()) { for (const uint32_t concrete_invalidate_reg_num : invalidate_pos->second) { if (concrete_invalidate_reg_num != reg_num) extra_invalid_regs.push_back(concrete_invalidate_reg_num); } } } pos->second.insert(pos->second.end(), extra_invalid_regs.begin(), extra_invalid_regs.end()); } } // sort and unique all invalidate registers and make sure each is terminated with // LLDB_INVALID_REGNUM for (reg_to_regs_map::iterator pos = m_invalidate_regs_map.begin(), end = m_invalidate_regs_map.end(); pos != end; ++pos) { if (pos->second.size() > 1) { std::sort (pos->second.begin(), pos->second.end()); reg_num_collection::iterator unique_end = std::unique (pos->second.begin(), pos->second.end()); if (unique_end != pos->second.end()) pos->second.erase(unique_end, pos->second.end()); } assert (!pos->second.empty()); if (pos->second.back() != LLDB_INVALID_REGNUM) pos->second.push_back(LLDB_INVALID_REGNUM); } // Now update all invalidate_regs with each register info as needed for (size_t i=0; ikinds[kind] == num) return std::distance (m_regs.begin(), pos); } return LLDB_INVALID_REGNUM; } void DynamicRegisterInfo::Clear() { m_regs.clear(); m_sets.clear(); m_set_reg_nums.clear(); m_set_names.clear(); m_value_regs_map.clear(); m_invalidate_regs_map.clear(); + m_dynamic_reg_size_map.clear(); m_reg_data_byte_size = 0; m_finalized = false; } void DynamicRegisterInfo::Dump () const { StreamFile s(stdout, false); const size_t num_regs = m_regs.size(); s.Printf("%p: DynamicRegisterInfo contains %" PRIu64 " registers:\n", static_cast(this), static_cast(num_regs)); for (size_t i=0; i(this), static_cast(num_sets)); for (size_t i=0; i #include // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/StructuredData.h" class DynamicRegisterInfo { public: DynamicRegisterInfo (); DynamicRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, const lldb_private::ArchSpec &arch); virtual ~DynamicRegisterInfo (); size_t SetRegisterInfo(const lldb_private::StructuredData::Dictionary &dict, const lldb_private::ArchSpec &arch); void AddRegister (lldb_private::RegisterInfo ®_info, lldb_private::ConstString ®_name, lldb_private::ConstString ®_alt_name, lldb_private::ConstString &set_name); void Finalize (const lldb_private::ArchSpec &arch); size_t GetNumRegisters() const; size_t GetNumRegisterSets() const; size_t GetRegisterDataByteSize() const; const lldb_private::RegisterInfo * GetRegisterInfoAtIndex (uint32_t i) const; + lldb_private::RegisterInfo * + GetRegisterInfoAtIndex (uint32_t i); + const lldb_private::RegisterSet * GetRegisterSet (uint32_t i) const; uint32_t GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create); uint32_t ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const; void Dump () const; void Clear(); protected: //------------------------------------------------------------------ // Classes that inherit from DynamicRegisterInfo can see and modify these //------------------------------------------------------------------ typedef std::vector reg_collection; typedef std::vector set_collection; typedef std::vector reg_num_collection; typedef std::vector set_reg_num_collection; typedef std::vector name_collection; typedef std::map reg_to_regs_map; + typedef std::vector dwarf_opcode; + typedef std::map dynamic_reg_size_map; lldb_private::RegisterInfo * GetRegisterInfo (const lldb_private::ConstString ®_name); reg_collection m_regs; set_collection m_sets; set_reg_num_collection m_set_reg_nums; name_collection m_set_names; reg_to_regs_map m_value_regs_map; reg_to_regs_map m_invalidate_regs_map; + dynamic_reg_size_map m_dynamic_reg_size_map; size_t m_reg_data_byte_size; // The number of bytes required to store all registers bool m_finalized; }; #endif // lldb_DynamicRegisterInfo_h_ Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp (revision 304308) @@ -1,1230 +1,1230 @@ //===-- RegisterContextDarwin_arm.cpp ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined(__APPLE__) #include "RegisterContextDarwin_arm.h" // C Includes #include #include // C++ Includes // Other libraries and framework includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" #include "llvm/Support/Compiler.h" #include "Plugins/Process/Utility/InstructionUtils.h" // Support building against older versions of LLVM, this macro was added // recently. #ifndef LLVM_EXTENSION #define LLVM_EXTENSION #endif // Project includes #include "ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" #include "llvm/ADT/STLExtras.h" using namespace lldb; using namespace lldb_private; enum { gpr_r0 = 0, gpr_r1, gpr_r2, gpr_r3, gpr_r4, gpr_r5, gpr_r6, gpr_r7, gpr_r8, gpr_r9, gpr_r10, gpr_r11, gpr_r12, gpr_r13, gpr_sp = gpr_r13, gpr_r14, gpr_lr = gpr_r14, gpr_r15, gpr_pc = gpr_r15, gpr_cpsr, fpu_s0, fpu_s1, fpu_s2, fpu_s3, fpu_s4, fpu_s5, fpu_s6, fpu_s7, fpu_s8, fpu_s9, fpu_s10, fpu_s11, fpu_s12, fpu_s13, fpu_s14, fpu_s15, fpu_s16, fpu_s17, fpu_s18, fpu_s19, fpu_s20, fpu_s21, fpu_s22, fpu_s23, fpu_s24, fpu_s25, fpu_s26, fpu_s27, fpu_s28, fpu_s29, fpu_s30, fpu_s31, fpu_fpscr, exc_exception, exc_fsr, exc_far, dbg_bvr0, dbg_bvr1, dbg_bvr2, dbg_bvr3, dbg_bvr4, dbg_bvr5, dbg_bvr6, dbg_bvr7, dbg_bvr8, dbg_bvr9, dbg_bvr10, dbg_bvr11, dbg_bvr12, dbg_bvr13, dbg_bvr14, dbg_bvr15, dbg_bcr0, dbg_bcr1, dbg_bcr2, dbg_bcr3, dbg_bcr4, dbg_bcr5, dbg_bcr6, dbg_bcr7, dbg_bcr8, dbg_bcr9, dbg_bcr10, dbg_bcr11, dbg_bcr12, dbg_bcr13, dbg_bcr14, dbg_bcr15, dbg_wvr0, dbg_wvr1, dbg_wvr2, dbg_wvr3, dbg_wvr4, dbg_wvr5, dbg_wvr6, dbg_wvr7, dbg_wvr8, dbg_wvr9, dbg_wvr10, dbg_wvr11, dbg_wvr12, dbg_wvr13, dbg_wvr14, dbg_wvr15, dbg_wcr0, dbg_wcr1, dbg_wcr2, dbg_wcr3, dbg_wcr4, dbg_wcr5, dbg_wcr6, dbg_wcr7, dbg_wcr8, dbg_wcr9, dbg_wcr10, dbg_wcr11, dbg_wcr12, dbg_wcr13, dbg_wcr14, dbg_wcr15, k_num_registers }; #define GPR_OFFSET(idx) ((idx) * 4) #define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR)) #define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU)) #define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC))) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)) static RegisterInfo g_register_infos[] = { // General purpose registers // NAME ALT SZ OFFSET ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE REGS INVALIDATE REGS // ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== { "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r0 }, NULL, NULL}, { "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r1 }, NULL, NULL}, { "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r2 }, NULL, NULL}, { "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r3 }, NULL, NULL}, { "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r4 }, NULL, NULL}, { "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r5 }, NULL, NULL}, { "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r6 }, NULL, NULL}, { "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_r7 }, NULL, NULL}, { "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r8 }, NULL, NULL}, { "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r9 }, NULL, NULL}, { "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r10 }, NULL, NULL}, { "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r11 }, NULL, NULL}, { "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r12 }, NULL, NULL}, { "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_sp }, NULL, NULL}, { "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_lr }, NULL, NULL}, { "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc }, NULL, NULL}, { "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, gpr_cpsr }, NULL, NULL}, { "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s0 }, NULL, NULL}, { "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s1 }, NULL, NULL}, { "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s2 }, NULL, NULL}, { "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s3 }, NULL, NULL}, { "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s4 }, NULL, NULL}, { "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s5 }, NULL, NULL}, { "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s6 }, NULL, NULL}, { "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s7 }, NULL, NULL}, { "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s8 }, NULL, NULL}, { "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s9 }, NULL, NULL}, { "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s10 }, NULL, NULL}, { "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s11 }, NULL, NULL}, { "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s12 }, NULL, NULL}, { "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s13 }, NULL, NULL}, { "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s14 }, NULL, NULL}, { "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s15 }, NULL, NULL}, { "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s16 }, NULL, NULL}, { "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s17 }, NULL, NULL}, { "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s18 }, NULL, NULL}, { "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s19 }, NULL, NULL}, { "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s20 }, NULL, NULL}, { "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s21 }, NULL, NULL}, { "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s22 }, NULL, NULL}, { "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s23 }, NULL, NULL}, { "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s24 }, NULL, NULL}, { "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s25 }, NULL, NULL}, { "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s26 }, NULL, NULL}, { "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s27 }, NULL, NULL}, { "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s28 }, NULL, NULL}, { "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s29 }, NULL, NULL}, { "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s30 }, NULL, NULL}, { "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s31 }, NULL, NULL}, { "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpscr }, NULL, NULL}, { "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL}, { "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL}, { "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL}, { DEFINE_DBG (bvr, 0) }, { DEFINE_DBG (bvr, 1) }, { DEFINE_DBG (bvr, 2) }, { DEFINE_DBG (bvr, 3) }, { DEFINE_DBG (bvr, 4) }, { DEFINE_DBG (bvr, 5) }, { DEFINE_DBG (bvr, 6) }, { DEFINE_DBG (bvr, 7) }, { DEFINE_DBG (bvr, 8) }, { DEFINE_DBG (bvr, 9) }, { DEFINE_DBG (bvr, 10) }, { DEFINE_DBG (bvr, 11) }, { DEFINE_DBG (bvr, 12) }, { DEFINE_DBG (bvr, 13) }, { DEFINE_DBG (bvr, 14) }, { DEFINE_DBG (bvr, 15) }, { DEFINE_DBG (bcr, 0) }, { DEFINE_DBG (bcr, 1) }, { DEFINE_DBG (bcr, 2) }, { DEFINE_DBG (bcr, 3) }, { DEFINE_DBG (bcr, 4) }, { DEFINE_DBG (bcr, 5) }, { DEFINE_DBG (bcr, 6) }, { DEFINE_DBG (bcr, 7) }, { DEFINE_DBG (bcr, 8) }, { DEFINE_DBG (bcr, 9) }, { DEFINE_DBG (bcr, 10) }, { DEFINE_DBG (bcr, 11) }, { DEFINE_DBG (bcr, 12) }, { DEFINE_DBG (bcr, 13) }, { DEFINE_DBG (bcr, 14) }, { DEFINE_DBG (bcr, 15) }, { DEFINE_DBG (wvr, 0) }, { DEFINE_DBG (wvr, 1) }, { DEFINE_DBG (wvr, 2) }, { DEFINE_DBG (wvr, 3) }, { DEFINE_DBG (wvr, 4) }, { DEFINE_DBG (wvr, 5) }, { DEFINE_DBG (wvr, 6) }, { DEFINE_DBG (wvr, 7) }, { DEFINE_DBG (wvr, 8) }, { DEFINE_DBG (wvr, 9) }, { DEFINE_DBG (wvr, 10) }, { DEFINE_DBG (wvr, 11) }, { DEFINE_DBG (wvr, 12) }, { DEFINE_DBG (wvr, 13) }, { DEFINE_DBG (wvr, 14) }, { DEFINE_DBG (wvr, 15) }, { DEFINE_DBG (wcr, 0) }, { DEFINE_DBG (wcr, 1) }, { DEFINE_DBG (wcr, 2) }, { DEFINE_DBG (wcr, 3) }, { DEFINE_DBG (wcr, 4) }, { DEFINE_DBG (wcr, 5) }, { DEFINE_DBG (wcr, 6) }, { DEFINE_DBG (wcr, 7) }, { DEFINE_DBG (wcr, 8) }, { DEFINE_DBG (wcr, 9) }, { DEFINE_DBG (wcr, 10) }, { DEFINE_DBG (wcr, 11) }, { DEFINE_DBG (wcr, 12) }, { DEFINE_DBG (wcr, 13) }, { DEFINE_DBG (wcr, 14) }, { DEFINE_DBG (wcr, 15) } }; // General purpose registers static uint32_t g_gpr_regnums[] = { gpr_r0, gpr_r1, gpr_r2, gpr_r3, gpr_r4, gpr_r5, gpr_r6, gpr_r7, gpr_r8, gpr_r9, gpr_r10, gpr_r11, gpr_r12, gpr_sp, gpr_lr, gpr_pc, gpr_cpsr }; // Floating point registers static uint32_t g_fpu_regnums[] = { fpu_s0, fpu_s1, fpu_s2, fpu_s3, fpu_s4, fpu_s5, fpu_s6, fpu_s7, fpu_s8, fpu_s9, fpu_s10, fpu_s11, fpu_s12, fpu_s13, fpu_s14, fpu_s15, fpu_s16, fpu_s17, fpu_s18, fpu_s19, fpu_s20, fpu_s21, fpu_s22, fpu_s23, fpu_s24, fpu_s25, fpu_s26, fpu_s27, fpu_s28, fpu_s29, fpu_s30, fpu_s31, fpu_fpscr, }; // Exception registers static uint32_t g_exc_regnums[] = { exc_exception, exc_fsr, exc_far, }; static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos); RegisterContextDarwin_arm::RegisterContextDarwin_arm(Thread &thread, uint32_t concrete_frame_idx) : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() { uint32_t i; for (i=0; iPrintf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }", i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]); } } bool RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; int set = RegisterContextDarwin_arm::GetSetForNativeRegNum (reg); if (set == -1) return false; if (ReadRegisterSet(set, false) != KERN_SUCCESS) return false; switch (reg) { case gpr_r0: case gpr_r1: case gpr_r2: case gpr_r3: case gpr_r4: case gpr_r5: case gpr_r6: case gpr_r7: case gpr_r8: case gpr_r9: case gpr_r10: case gpr_r11: case gpr_r12: case gpr_sp: case gpr_lr: case gpr_pc: case gpr_cpsr: value.SetUInt32 (gpr.r[reg - gpr_r0]); break; case fpu_s0: case fpu_s1: case fpu_s2: case fpu_s3: case fpu_s4: case fpu_s5: case fpu_s6: case fpu_s7: case fpu_s8: case fpu_s9: case fpu_s10: case fpu_s11: case fpu_s12: case fpu_s13: case fpu_s14: case fpu_s15: case fpu_s16: case fpu_s17: case fpu_s18: case fpu_s19: case fpu_s20: case fpu_s21: case fpu_s22: case fpu_s23: case fpu_s24: case fpu_s25: case fpu_s26: case fpu_s27: case fpu_s28: case fpu_s29: case fpu_s30: case fpu_s31: value.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat); break; case fpu_fpscr: value.SetUInt32 (fpu.fpscr); break; case exc_exception: value.SetUInt32 (exc.exception); break; case exc_fsr: value.SetUInt32 (exc.fsr); break; case exc_far: value.SetUInt32 (exc.far); break; default: value.SetValueToInvalid(); return false; } return true; } bool RegisterContextDarwin_arm::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; int set = GetSetForNativeRegNum (reg); if (set == -1) return false; if (ReadRegisterSet(set, false) != KERN_SUCCESS) return false; switch (reg) { case gpr_r0: case gpr_r1: case gpr_r2: case gpr_r3: case gpr_r4: case gpr_r5: case gpr_r6: case gpr_r7: case gpr_r8: case gpr_r9: case gpr_r10: case gpr_r11: case gpr_r12: case gpr_sp: case gpr_lr: case gpr_pc: case gpr_cpsr: gpr.r[reg - gpr_r0] = value.GetAsUInt32(); break; case fpu_s0: case fpu_s1: case fpu_s2: case fpu_s3: case fpu_s4: case fpu_s5: case fpu_s6: case fpu_s7: case fpu_s8: case fpu_s9: case fpu_s10: case fpu_s11: case fpu_s12: case fpu_s13: case fpu_s14: case fpu_s15: case fpu_s16: case fpu_s17: case fpu_s18: case fpu_s19: case fpu_s20: case fpu_s21: case fpu_s22: case fpu_s23: case fpu_s24: case fpu_s25: case fpu_s26: case fpu_s27: case fpu_s28: case fpu_s29: case fpu_s30: case fpu_s31: fpu.floats.s[reg] = value.GetAsUInt32(); break; case fpu_fpscr: fpu.fpscr = value.GetAsUInt32(); break; case exc_exception: exc.exception = value.GetAsUInt32(); break; case exc_fsr: exc.fsr = value.GetAsUInt32(); break; case exc_far: exc.far = value.GetAsUInt32(); break; default: return false; } return WriteRegisterSet(set) == KERN_SUCCESS; } bool RegisterContextDarwin_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); if (data_sp && ReadGPR (false) == KERN_SUCCESS && ReadFPU (false) == KERN_SUCCESS && ReadEXC (false) == KERN_SUCCESS) { uint8_t *dst = data_sp->GetBytes(); ::memcpy (dst, &gpr, sizeof(gpr)); dst += sizeof(gpr); ::memcpy (dst, &fpu, sizeof(fpu)); dst += sizeof(gpr); ::memcpy (dst, &exc, sizeof(exc)); return true; } return false; } bool RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { const uint8_t *src = data_sp->GetBytes(); ::memcpy (&gpr, src, sizeof(gpr)); src += sizeof(gpr); ::memcpy (&fpu, src, sizeof(fpu)); src += sizeof(gpr); ::memcpy (&exc, src, sizeof(exc)); uint32_t success_count = 0; if (WriteGPR() == KERN_SUCCESS) ++success_count; if (WriteFPU() == KERN_SUCCESS) ++success_count; if (WriteEXC() == KERN_SUCCESS) ++success_count; return success_count == 3; } return false; } uint32_t RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { switch (reg) { case LLDB_REGNUM_GENERIC_PC: return gpr_pc; case LLDB_REGNUM_GENERIC_SP: return gpr_sp; case LLDB_REGNUM_GENERIC_FP: return gpr_r7; case LLDB_REGNUM_GENERIC_RA: return gpr_lr; case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; default: break; } } else if (kind == eRegisterKindDWARF) { switch (reg) { case dwarf_r0: return gpr_r0; case dwarf_r1: return gpr_r1; case dwarf_r2: return gpr_r2; case dwarf_r3: return gpr_r3; case dwarf_r4: return gpr_r4; case dwarf_r5: return gpr_r5; case dwarf_r6: return gpr_r6; case dwarf_r7: return gpr_r7; case dwarf_r8: return gpr_r8; case dwarf_r9: return gpr_r9; case dwarf_r10: return gpr_r10; case dwarf_r11: return gpr_r11; case dwarf_r12: return gpr_r12; case dwarf_sp: return gpr_sp; case dwarf_lr: return gpr_lr; case dwarf_pc: return gpr_pc; case dwarf_spsr: return gpr_cpsr; case dwarf_s0: return fpu_s0; case dwarf_s1: return fpu_s1; case dwarf_s2: return fpu_s2; case dwarf_s3: return fpu_s3; case dwarf_s4: return fpu_s4; case dwarf_s5: return fpu_s5; case dwarf_s6: return fpu_s6; case dwarf_s7: return fpu_s7; case dwarf_s8: return fpu_s8; case dwarf_s9: return fpu_s9; case dwarf_s10: return fpu_s10; case dwarf_s11: return fpu_s11; case dwarf_s12: return fpu_s12; case dwarf_s13: return fpu_s13; case dwarf_s14: return fpu_s14; case dwarf_s15: return fpu_s15; case dwarf_s16: return fpu_s16; case dwarf_s17: return fpu_s17; case dwarf_s18: return fpu_s18; case dwarf_s19: return fpu_s19; case dwarf_s20: return fpu_s20; case dwarf_s21: return fpu_s21; case dwarf_s22: return fpu_s22; case dwarf_s23: return fpu_s23; case dwarf_s24: return fpu_s24; case dwarf_s25: return fpu_s25; case dwarf_s26: return fpu_s26; case dwarf_s27: return fpu_s27; case dwarf_s28: return fpu_s28; case dwarf_s29: return fpu_s29; case dwarf_s30: return fpu_s30; case dwarf_s31: return fpu_s31; default: break; } } else if (kind == eRegisterKindEHFrame) { switch (reg) { case ehframe_r0: return gpr_r0; case ehframe_r1: return gpr_r1; case ehframe_r2: return gpr_r2; case ehframe_r3: return gpr_r3; case ehframe_r4: return gpr_r4; case ehframe_r5: return gpr_r5; case ehframe_r6: return gpr_r6; case ehframe_r7: return gpr_r7; case ehframe_r8: return gpr_r8; case ehframe_r9: return gpr_r9; case ehframe_r10: return gpr_r10; case ehframe_r11: return gpr_r11; case ehframe_r12: return gpr_r12; case ehframe_sp: return gpr_sp; case ehframe_lr: return gpr_lr; case ehframe_pc: return gpr_pc; case ehframe_cpsr: return gpr_cpsr; } } else if (kind == eRegisterKindLLDB) { return reg; } return LLDB_INVALID_REGNUM; } uint32_t RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints () { #if defined (__arm__) // Set the init value to something that will let us know that we need to // autodetect how many breakpoints are supported dynamically... static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX; if (g_num_supported_hw_breakpoints == UINT32_MAX) { // Set this to zero in case we can't tell if there are any HW breakpoints g_num_supported_hw_breakpoints = 0; uint32_t register_DBGDIDR; asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24); // Zero is reserved for the BRP count, so don't increment it if it is zero if (g_num_supported_hw_breakpoints > 0) g_num_supported_hw_breakpoints++; // if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints); } return g_num_supported_hw_breakpoints; #else // TODO: figure out remote case here! return 6; #endif } uint32_t RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) { // Make sure our address isn't bogus if (addr & 1) return LLDB_INVALID_INDEX32; int kret = ReadDBG (false); if (kret == KERN_SUCCESS) { const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); uint32_t i; for (i=0; iPrintf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)", // addr, // size, // i, // i, // dbg.bvr[i], // dbg.bcr[i]); } else if (size == 4) { // We have an ARM breakpoint dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA S_USER | // Which modes should this breakpoint stop in? BCR_ENABLE; // Enable this hardware breakpoint // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)", // addr, // size, // i, // i, // dbg.bvr[i], // dbg.bcr[i]); } kret = WriteDBG(); // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret); if (kret == KERN_SUCCESS) return i; } // else // { // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size); // } } return LLDB_INVALID_INDEX32; } bool RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index) { int kret = ReadDBG (false); const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); if (kret == KERN_SUCCESS) { if (hw_index < num_hw_points) { dbg.bcr[hw_index] = 0; // if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x", // hw_index, // hw_index, // dbg.bvr[hw_index], // hw_index, // dbg.bcr[hw_index]); kret = WriteDBG(); if (kret == KERN_SUCCESS) return true; } } return false; } uint32_t RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints () { #if defined (__arm__) // Set the init value to something that will let us know that we need to // autodetect how many watchpoints are supported dynamically... static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; if (g_num_supported_hw_watchpoints == UINT32_MAX) { // Set this to zero in case we can't tell if there are any HW breakpoints g_num_supported_hw_watchpoints = 0; uint32_t register_DBGDIDR; asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1; // if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints); } return g_num_supported_hw_watchpoints; #else // TODO: figure out remote case here! return 2; #endif } uint32_t RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) { // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); // Can't watch zero bytes if (size == 0) return LLDB_INVALID_INDEX32; // We must watch for either read or write if (read == false && write == false) return LLDB_INVALID_INDEX32; // Can't watch more than 4 bytes per WVR/WCR pair if (size > 4) return LLDB_INVALID_INDEX32; // We can only watch up to four bytes that follow a 4 byte aligned address // per watchpoint register pair. Since we have at most so we can only watch // until the next 4 byte boundary and we need to make sure we can properly // encode this. uint32_t addr_word_offset = addr % 4; // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); if (byte_mask > 0xfu) return LLDB_INVALID_INDEX32; // Read the debug state int kret = ReadDBG (false); if (kret == KERN_SUCCESS) { // Check to make sure we have the needed hardware support uint32_t i = 0; for (i=0; iPrintf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); if (kret == KERN_SUCCESS) return i; } else { // if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); } } return LLDB_INVALID_INDEX32; } bool RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index) { int kret = ReadDBG (false); const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); if (kret == KERN_SUCCESS) { if (hw_index < num_hw_points) { dbg.wcr[hw_index] = 0; // if (log) log->Printf ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", // hw_index, // hw_index, // dbg.wvr[hw_index], // hw_index, // dbg.wcr[hw_index]); kret = WriteDBG(); if (kret == KERN_SUCCESS) return true; } } return false; } #endif Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextDarwin_arm64.cpp (revision 304308) @@ -1,944 +1,944 @@ //===-- RegisterContextDarwin_arm64.cpp ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #if defined(__APPLE__) #include "RegisterContextDarwin_arm64.h" // C Includes #include #include #include // C++ Includes // Other libraries and framework includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include "Plugins/Process/Utility/InstructionUtils.h" // Support building against older versions of LLVM, this macro was added // recently. #ifndef LLVM_EXTENSION #define LLVM_EXTENSION #endif // Project includes #include "ARM64_DWARF_Registers.h" using namespace lldb; using namespace lldb_private; #define GPR_OFFSET(idx) ((idx) * 8) #define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::GPR, reg)) #define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextDarwin_arm64::GPR)) #define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::FPU, reg)) #define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::EXC, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU)) #define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_arm64::DBG, reg) + sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm64::GPR) + sizeof (RegisterContextDarwin_arm64::FPU) + sizeof (RegisterContextDarwin_arm64::EXC)) //----------------------------------------------------------------------------- // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. //----------------------------------------------------------------------------- #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT // General purpose registers static uint32_t g_gpr_regnums[] = { gpr_x0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6, gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13, gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20, gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27, gpr_x28, gpr_fp, gpr_lr, gpr_sp, gpr_pc, gpr_cpsr }; // Floating point registers static uint32_t g_fpu_regnums[] = { fpu_v0, fpu_v1, fpu_v2, fpu_v3, fpu_v4, fpu_v5, fpu_v6, fpu_v7, fpu_v8, fpu_v9, fpu_v10, fpu_v11, fpu_v12, fpu_v13, fpu_v14, fpu_v15, fpu_v16, fpu_v17, fpu_v18, fpu_v19, fpu_v20, fpu_v21, fpu_v22, fpu_v23, fpu_v24, fpu_v25, fpu_v26, fpu_v27, fpu_v28, fpu_v29, fpu_v30, fpu_v31, fpu_fpsr, fpu_fpcr }; // Exception registers static uint32_t g_exc_regnums[] = { exc_far, exc_esr, exc_exception }; static size_t k_num_register_infos = llvm::array_lengthof(g_register_infos_arm64); RegisterContextDarwin_arm64::RegisterContextDarwin_arm64(Thread &thread, uint32_t concrete_frame_idx) : RegisterContext(thread, concrete_frame_idx), gpr(), fpu(), exc() { uint32_t i; for (i=0; iPrintf("BVR%-2u/BCR%-2u = { 0x%8.8llx, 0x%8.8llx } WVR%-2u/WCR%-2u = { 0x%8.8llx, 0x%8.8llx }", i, i, dbg.bvr[i], dbg.bcr[i], i, i, dbg.wvr[i], dbg.wcr[i]); } } bool RegisterContextDarwin_arm64::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; int set = RegisterContextDarwin_arm64::GetSetForNativeRegNum (reg); if (set == -1) return false; if (ReadRegisterSet(set, false) != KERN_SUCCESS) return false; switch (reg) { case gpr_x0: case gpr_x1: case gpr_x2: case gpr_x3: case gpr_x4: case gpr_x5: case gpr_x6: case gpr_x7: case gpr_x8: case gpr_x9: case gpr_x10: case gpr_x11: case gpr_x12: case gpr_x13: case gpr_x14: case gpr_x15: case gpr_x16: case gpr_x17: case gpr_x18: case gpr_x19: case gpr_x20: case gpr_x21: case gpr_x22: case gpr_x23: case gpr_x24: case gpr_x25: case gpr_x26: case gpr_x27: case gpr_x28: case gpr_fp: case gpr_sp: case gpr_lr: case gpr_pc: case gpr_cpsr: value.SetUInt64 (gpr.x[reg - gpr_x0]); break; case fpu_v0: case fpu_v1: case fpu_v2: case fpu_v3: case fpu_v4: case fpu_v5: case fpu_v6: case fpu_v7: case fpu_v8: case fpu_v9: case fpu_v10: case fpu_v11: case fpu_v12: case fpu_v13: case fpu_v14: case fpu_v15: case fpu_v16: case fpu_v17: case fpu_v18: case fpu_v19: case fpu_v20: case fpu_v21: case fpu_v22: case fpu_v23: case fpu_v24: case fpu_v25: case fpu_v26: case fpu_v27: case fpu_v28: case fpu_v29: case fpu_v30: case fpu_v31: value.SetBytes(fpu.v[reg].bytes, reg_info->byte_size, endian::InlHostByteOrder()); break; case fpu_fpsr: value.SetUInt32 (fpu.fpsr); break; case fpu_fpcr: value.SetUInt32 (fpu.fpcr); break; case exc_exception: value.SetUInt32 (exc.exception); break; case exc_esr: value.SetUInt32 (exc.esr); break; case exc_far: value.SetUInt64 (exc.far); break; default: value.SetValueToInvalid(); return false; } return true; } bool RegisterContextDarwin_arm64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) { const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; int set = GetSetForNativeRegNum (reg); if (set == -1) return false; if (ReadRegisterSet(set, false) != KERN_SUCCESS) return false; switch (reg) { case gpr_x0: case gpr_x1: case gpr_x2: case gpr_x3: case gpr_x4: case gpr_x5: case gpr_x6: case gpr_x7: case gpr_x8: case gpr_x9: case gpr_x10: case gpr_x11: case gpr_x12: case gpr_x13: case gpr_x14: case gpr_x15: case gpr_x16: case gpr_x17: case gpr_x18: case gpr_x19: case gpr_x20: case gpr_x21: case gpr_x22: case gpr_x23: case gpr_x24: case gpr_x25: case gpr_x26: case gpr_x27: case gpr_x28: case gpr_fp: case gpr_sp: case gpr_lr: case gpr_pc: case gpr_cpsr: gpr.x[reg - gpr_x0] = value.GetAsUInt64(); break; case fpu_v0: case fpu_v1: case fpu_v2: case fpu_v3: case fpu_v4: case fpu_v5: case fpu_v6: case fpu_v7: case fpu_v8: case fpu_v9: case fpu_v10: case fpu_v11: case fpu_v12: case fpu_v13: case fpu_v14: case fpu_v15: case fpu_v16: case fpu_v17: case fpu_v18: case fpu_v19: case fpu_v20: case fpu_v21: case fpu_v22: case fpu_v23: case fpu_v24: case fpu_v25: case fpu_v26: case fpu_v27: case fpu_v28: case fpu_v29: case fpu_v30: case fpu_v31: ::memcpy (fpu.v[reg].bytes, value.GetBytes(), value.GetByteSize()); break; case fpu_fpsr: fpu.fpsr = value.GetAsUInt32(); break; case fpu_fpcr: fpu.fpcr = value.GetAsUInt32(); break; case exc_exception: exc.exception = value.GetAsUInt32(); break; case exc_esr: exc.esr = value.GetAsUInt32(); break; case exc_far: exc.far = value.GetAsUInt64(); break; default: return false; } return WriteRegisterSet(set) == KERN_SUCCESS; } bool RegisterContextDarwin_arm64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); if (data_sp && ReadGPR (false) == KERN_SUCCESS && ReadFPU (false) == KERN_SUCCESS && ReadEXC (false) == KERN_SUCCESS) { uint8_t *dst = data_sp->GetBytes(); ::memcpy (dst, &gpr, sizeof(gpr)); dst += sizeof(gpr); ::memcpy (dst, &fpu, sizeof(fpu)); dst += sizeof(gpr); ::memcpy (dst, &exc, sizeof(exc)); return true; } return false; } bool RegisterContextDarwin_arm64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE) { const uint8_t *src = data_sp->GetBytes(); ::memcpy (&gpr, src, sizeof(gpr)); src += sizeof(gpr); ::memcpy (&fpu, src, sizeof(fpu)); src += sizeof(gpr); ::memcpy (&exc, src, sizeof(exc)); uint32_t success_count = 0; if (WriteGPR() == KERN_SUCCESS) ++success_count; if (WriteFPU() == KERN_SUCCESS) ++success_count; if (WriteEXC() == KERN_SUCCESS) ++success_count; return success_count == 3; } return false; } uint32_t RegisterContextDarwin_arm64::ConvertRegisterKindToRegisterNumber (RegisterKind kind, uint32_t reg) { if (kind == eRegisterKindGeneric) { switch (reg) { case LLDB_REGNUM_GENERIC_PC: return gpr_pc; case LLDB_REGNUM_GENERIC_SP: return gpr_sp; case LLDB_REGNUM_GENERIC_FP: return gpr_fp; case LLDB_REGNUM_GENERIC_RA: return gpr_lr; case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr; default: break; } } else if (kind == eRegisterKindDWARF) { switch (reg) { case arm64_dwarf::x0: return gpr_x0; case arm64_dwarf::x1: return gpr_x1; case arm64_dwarf::x2: return gpr_x2; case arm64_dwarf::x3: return gpr_x3; case arm64_dwarf::x4: return gpr_x4; case arm64_dwarf::x5: return gpr_x5; case arm64_dwarf::x6: return gpr_x6; case arm64_dwarf::x7: return gpr_x7; case arm64_dwarf::x8: return gpr_x8; case arm64_dwarf::x9: return gpr_x9; case arm64_dwarf::x10: return gpr_x10; case arm64_dwarf::x11: return gpr_x11; case arm64_dwarf::x12: return gpr_x12; case arm64_dwarf::x13: return gpr_x13; case arm64_dwarf::x14: return gpr_x14; case arm64_dwarf::x15: return gpr_x15; case arm64_dwarf::x16: return gpr_x16; case arm64_dwarf::x17: return gpr_x17; case arm64_dwarf::x18: return gpr_x18; case arm64_dwarf::x19: return gpr_x19; case arm64_dwarf::x20: return gpr_x20; case arm64_dwarf::x21: return gpr_x21; case arm64_dwarf::x22: return gpr_x22; case arm64_dwarf::x23: return gpr_x23; case arm64_dwarf::x24: return gpr_x24; case arm64_dwarf::x25: return gpr_x25; case arm64_dwarf::x26: return gpr_x26; case arm64_dwarf::x27: return gpr_x27; case arm64_dwarf::x28: return gpr_x28; case arm64_dwarf::fp: return gpr_fp; case arm64_dwarf::sp: return gpr_sp; case arm64_dwarf::lr: return gpr_lr; case arm64_dwarf::pc: return gpr_pc; case arm64_dwarf::cpsr: return gpr_cpsr; case arm64_dwarf::v0: return fpu_v0; case arm64_dwarf::v1: return fpu_v1; case arm64_dwarf::v2: return fpu_v2; case arm64_dwarf::v3: return fpu_v3; case arm64_dwarf::v4: return fpu_v4; case arm64_dwarf::v5: return fpu_v5; case arm64_dwarf::v6: return fpu_v6; case arm64_dwarf::v7: return fpu_v7; case arm64_dwarf::v8: return fpu_v8; case arm64_dwarf::v9: return fpu_v9; case arm64_dwarf::v10: return fpu_v10; case arm64_dwarf::v11: return fpu_v11; case arm64_dwarf::v12: return fpu_v12; case arm64_dwarf::v13: return fpu_v13; case arm64_dwarf::v14: return fpu_v14; case arm64_dwarf::v15: return fpu_v15; case arm64_dwarf::v16: return fpu_v16; case arm64_dwarf::v17: return fpu_v17; case arm64_dwarf::v18: return fpu_v18; case arm64_dwarf::v19: return fpu_v19; case arm64_dwarf::v20: return fpu_v20; case arm64_dwarf::v21: return fpu_v21; case arm64_dwarf::v22: return fpu_v22; case arm64_dwarf::v23: return fpu_v23; case arm64_dwarf::v24: return fpu_v24; case arm64_dwarf::v25: return fpu_v25; case arm64_dwarf::v26: return fpu_v26; case arm64_dwarf::v27: return fpu_v27; case arm64_dwarf::v28: return fpu_v28; case arm64_dwarf::v29: return fpu_v29; case arm64_dwarf::v30: return fpu_v30; case arm64_dwarf::v31: return fpu_v31; default: break; } } else if (kind == eRegisterKindEHFrame) { switch (reg) { case arm64_ehframe::x0: return gpr_x0; case arm64_ehframe::x1: return gpr_x1; case arm64_ehframe::x2: return gpr_x2; case arm64_ehframe::x3: return gpr_x3; case arm64_ehframe::x4: return gpr_x4; case arm64_ehframe::x5: return gpr_x5; case arm64_ehframe::x6: return gpr_x6; case arm64_ehframe::x7: return gpr_x7; case arm64_ehframe::x8: return gpr_x8; case arm64_ehframe::x9: return gpr_x9; case arm64_ehframe::x10: return gpr_x10; case arm64_ehframe::x11: return gpr_x11; case arm64_ehframe::x12: return gpr_x12; case arm64_ehframe::x13: return gpr_x13; case arm64_ehframe::x14: return gpr_x14; case arm64_ehframe::x15: return gpr_x15; case arm64_ehframe::x16: return gpr_x16; case arm64_ehframe::x17: return gpr_x17; case arm64_ehframe::x18: return gpr_x18; case arm64_ehframe::x19: return gpr_x19; case arm64_ehframe::x20: return gpr_x20; case arm64_ehframe::x21: return gpr_x21; case arm64_ehframe::x22: return gpr_x22; case arm64_ehframe::x23: return gpr_x23; case arm64_ehframe::x24: return gpr_x24; case arm64_ehframe::x25: return gpr_x25; case arm64_ehframe::x26: return gpr_x26; case arm64_ehframe::x27: return gpr_x27; case arm64_ehframe::x28: return gpr_x28; case arm64_ehframe::fp: return gpr_fp; case arm64_ehframe::sp: return gpr_sp; case arm64_ehframe::lr: return gpr_lr; case arm64_ehframe::pc: return gpr_pc; case arm64_ehframe::cpsr: return gpr_cpsr; } } else if (kind == eRegisterKindLLDB) { return reg; } return LLDB_INVALID_REGNUM; } uint32_t RegisterContextDarwin_arm64::NumSupportedHardwareWatchpoints () { #if defined (__arm64__) || defined (__aarch64__) // autodetect how many watchpoints are supported dynamically... static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX; if (g_num_supported_hw_watchpoints == UINT32_MAX) { size_t len; uint32_t n = 0; len = sizeof (n); if (::sysctlbyname("hw.optional.watchpoint", &n, &len, NULL, 0) == 0) { g_num_supported_hw_watchpoints = n; } } return g_num_supported_hw_watchpoints; #else // TODO: figure out remote case here! return 2; #endif } uint32_t RegisterContextDarwin_arm64::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) { // if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write); const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); // Can't watch zero bytes if (size == 0) return LLDB_INVALID_INDEX32; // We must watch for either read or write if (read == false && write == false) return LLDB_INVALID_INDEX32; // Can't watch more than 4 bytes per WVR/WCR pair if (size > 4) return LLDB_INVALID_INDEX32; // We can only watch up to four bytes that follow a 4 byte aligned address // per watchpoint register pair. Since we have at most so we can only watch // until the next 4 byte boundary and we need to make sure we can properly // encode this. uint32_t addr_word_offset = addr % 4; // if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset); uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset; // if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask); if (byte_mask > 0xfu) return LLDB_INVALID_INDEX32; // Read the debug state int kret = ReadDBG (false); if (kret == KERN_SUCCESS) { // Check to make sure we have the needed hardware support uint32_t i = 0; for (i=0; iPrintf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret); if (kret == KERN_SUCCESS) return i; } else { // if (log) log->Printf ("RegisterContextDarwin_arm64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); } } return LLDB_INVALID_INDEX32; } bool RegisterContextDarwin_arm64::ClearHardwareWatchpoint (uint32_t hw_index) { int kret = ReadDBG (false); const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); if (kret == KERN_SUCCESS) { if (hw_index < num_hw_points) { dbg.wcr[hw_index] = 0; // if (log) log->Printf ("RegisterContextDarwin_arm64::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x", // hw_index, // hw_index, // dbg.wvr[hw_index], // hw_index, // dbg.wcr[hw_index]); kret = WriteDBG(); if (kret == KERN_SUCCESS) return true; } } return false; } #endif Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm.cpp (revision 304308) @@ -1,89 +1,89 @@ //===-- RegisterContextFreeBSD_arm.cpp -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// #include #include #include #include "llvm/Support/Compiler.h" #include "lldb/lldb-defines.h" #include "RegisterContextFreeBSD_arm.h" using namespace lldb; using namespace lldb_private; // Based on RegisterContextLinux_arm.cpp and // http://svnweb.freebsd.org/base/head/sys/arm/include/reg.h #define GPR_OFFSET(idx) ((idx) * 4) #define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR)) #define FPSCR_OFFSET (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm::FPU, fpscr) + sizeof (RegisterContextFreeBSD_arm::GPR)) #define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU)) #define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm::DBG, reg) + sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC))) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm::GPR) + sizeof (RegisterContextFreeBSD_arm::FPU) + sizeof (RegisterContextFreeBSD_arm::EXC)) //----------------------------------------------------------------------------- // Include RegisterInfos_arm to declare our g_register_infos_arm structure. //----------------------------------------------------------------------------- #define DECLARE_REGISTER_INFOS_ARM_STRUCT #include "RegisterInfos_arm.h" #undef DECLARE_REGISTER_INFOS_ARM_STRUCT static const lldb_private::RegisterInfo * GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: return g_register_infos_arm; default: assert(false && "Unhandled target architecture."); return NULL; } } static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: return static_cast(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0])); default: assert(false && "Unhandled target architecture."); return 0; } } RegisterContextFreeBSD_arm::RegisterContextFreeBSD_arm(const lldb_private::ArchSpec &target_arch) : lldb_private::RegisterInfoInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { } size_t RegisterContextFreeBSD_arm::GetGPRSize() const { return sizeof(struct RegisterContextFreeBSD_arm::GPR); } const lldb_private::RegisterInfo * RegisterContextFreeBSD_arm::GetRegisterInfo() const { return m_register_info_p; } uint32_t RegisterContextFreeBSD_arm::GetRegisterCount() const { return m_register_info_count; } Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextFreeBSD_arm64.cpp (revision 304308) @@ -1,86 +1,86 @@ //===-- RegisterContextFreeBSD_arm64.cpp ----------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// #include #include "RegisterContextPOSIX_arm64.h" #include "RegisterContextFreeBSD_arm64.h" using namespace lldb; // Based on RegisterContextDarwin_arm64.cpp #define GPR_OFFSET(idx) ((idx) * 8) #define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::GPR, reg)) #define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextFreeBSD_arm64::GPR)) #define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::FPU, reg)) #define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::EXC, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU)) #define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextFreeBSD_arm64::DBG, reg) + sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC)) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextFreeBSD_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextFreeBSD_arm64::GPR) + sizeof (RegisterContextFreeBSD_arm64::FPU) + sizeof (RegisterContextFreeBSD_arm64::EXC)) //----------------------------------------------------------------------------- // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. //----------------------------------------------------------------------------- #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT static const lldb_private::RegisterInfo * GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: return g_register_infos_arm64; default: assert(false && "Unhandled target architecture."); return nullptr; } } static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: return static_cast(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0])); default: assert(false && "Unhandled target architecture."); return 0; } } RegisterContextFreeBSD_arm64::RegisterContextFreeBSD_arm64(const lldb_private::ArchSpec &target_arch) : RegisterInfoInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { } size_t RegisterContextFreeBSD_arm64::GetGPRSize() const { return sizeof(struct RegisterContextFreeBSD_arm64::GPR); } const lldb_private::RegisterInfo * RegisterContextFreeBSD_arm64::GetRegisterInfo() const { return m_register_info_p; } uint32_t RegisterContextFreeBSD_arm64::GetRegisterCount() const { return m_register_info_count; } Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm.cpp (revision 304308) @@ -1,88 +1,88 @@ //===-- RegisterContextLinux_arm.cpp ---------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// #include #include #include #include "llvm/Support/Compiler.h" #include "lldb/lldb-defines.h" #include "RegisterContextLinux_arm.h" using namespace lldb; using namespace lldb_private; // Based on RegisterContextDarwin_arm.cpp #define GPR_OFFSET(idx) ((idx) * 4) #define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR)) #define FPSCR_OFFSET (LLVM_EXTENSION offsetof (RegisterContextLinux_arm::FPU, fpscr) + sizeof (RegisterContextLinux_arm::GPR)) #define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU)) #define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextLinux_arm::DBG, reg) + sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC))) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm::GPR) + sizeof (RegisterContextLinux_arm::FPU) + sizeof (RegisterContextLinux_arm::EXC)) //----------------------------------------------------------------------------- // Include RegisterInfos_arm to declare our g_register_infos_arm structure. //----------------------------------------------------------------------------- #define DECLARE_REGISTER_INFOS_ARM_STRUCT #include "RegisterInfos_arm.h" #undef DECLARE_REGISTER_INFOS_ARM_STRUCT static const lldb_private::RegisterInfo * GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: return g_register_infos_arm; default: assert(false && "Unhandled target architecture."); return NULL; } } static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::arm: return static_cast(sizeof(g_register_infos_arm) / sizeof(g_register_infos_arm[0])); default: assert(false && "Unhandled target architecture."); return 0; } } RegisterContextLinux_arm::RegisterContextLinux_arm(const lldb_private::ArchSpec &target_arch) : lldb_private::RegisterInfoInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { } size_t RegisterContextLinux_arm::GetGPRSize() const { return sizeof(struct RegisterContextLinux_arm::GPR); } const lldb_private::RegisterInfo * RegisterContextLinux_arm::GetRegisterInfo() const { return m_register_info_p; } uint32_t RegisterContextLinux_arm::GetRegisterCount() const { return m_register_info_count; } Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterContextLinux_arm64.cpp (revision 304308) @@ -1,89 +1,89 @@ //===-- RegisterContextLinux_arm64.cpp -------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// #include #include #include #include "llvm/Support/Compiler.h" #include "lldb/lldb-defines.h" #include "RegisterContextLinux_arm64.h" // Based on RegisterContextDarwin_arm64.cpp #define GPR_OFFSET(idx) ((idx) * 8) #define GPR_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::GPR, reg)) #define FPU_OFFSET(idx) ((idx) * 16 + sizeof (RegisterContextLinux_arm64::GPR)) #define FPU_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::FPU, reg) + sizeof (RegisterContextLinux_arm64::GPR)) #define EXC_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::EXC, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU)) #define DBG_OFFSET_NAME(reg) (LLVM_EXTENSION offsetof (RegisterContextLinux_arm64::DBG, reg) + sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) -#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL +#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextLinux_arm64::DBG *)NULL)->reg[i]), DBG_OFFSET_NAME(reg[i]), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL, NULL, 0 #define REG_CONTEXT_SIZE (sizeof (RegisterContextLinux_arm64::GPR) + sizeof (RegisterContextLinux_arm64::FPU) + sizeof (RegisterContextLinux_arm64::EXC)) //----------------------------------------------------------------------------- // Include RegisterInfos_arm64 to declare our g_register_infos_arm64 structure. //----------------------------------------------------------------------------- #define DECLARE_REGISTER_INFOS_ARM64_STRUCT #include "RegisterInfos_arm64.h" #undef DECLARE_REGISTER_INFOS_ARM64_STRUCT static const lldb_private::RegisterInfo * GetRegisterInfoPtr (const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: return g_register_infos_arm64; default: assert(false && "Unhandled target architecture."); return NULL; } } static uint32_t GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) { switch (target_arch.GetMachine()) { case llvm::Triple::aarch64: return static_cast(sizeof(g_register_infos_arm64) / sizeof(g_register_infos_arm64[0])); default: assert(false && "Unhandled target architecture."); return 0; } } RegisterContextLinux_arm64::RegisterContextLinux_arm64(const lldb_private::ArchSpec &target_arch) : lldb_private::RegisterInfoInterface(target_arch), m_register_info_p(GetRegisterInfoPtr(target_arch)), m_register_info_count(GetRegisterInfoCount(target_arch)) { } size_t RegisterContextLinux_arm64::GetGPRSize() const { return sizeof(struct RegisterContextLinux_arm64::GPR); } const lldb_private::RegisterInfo * RegisterContextLinux_arm64::GetRegisterInfo() const { return m_register_info_p; } uint32_t RegisterContextLinux_arm64::GetRegisterCount() const { return m_register_info_count; } Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm.h (revision 304308) @@ -1,505 +1,505 @@ //===-- RegisterInfos_arm.h -------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifdef DECLARE_REGISTER_INFOS_ARM_STRUCT // C Includes #include // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "Utility/ARM_ehframe_Registers.h" #include "Utility/ARM_DWARF_Registers.h" using namespace lldb; using namespace lldb_private; #ifndef GPR_OFFSET #error GPR_OFFSET must be defined before including this header file #endif #ifndef FPU_OFFSET #error FPU_OFFSET must be defined before including this header file #endif #ifndef FPSCR_OFFSET #error FPSCR_OFFSET must be defined before including this header file #endif #ifndef EXC_OFFSET #error EXC_OFFSET_NAME must be defined before including this header file #endif #ifndef DEFINE_DBG #error DEFINE_DBG must be defined before including this header file #endif enum { gpr_r0 = 0, gpr_r1, gpr_r2, gpr_r3, gpr_r4, gpr_r5, gpr_r6, gpr_r7, gpr_r8, gpr_r9, gpr_r10, gpr_r11, gpr_r12, gpr_r13, gpr_sp = gpr_r13, gpr_r14, gpr_lr = gpr_r14, gpr_r15, gpr_pc = gpr_r15, gpr_cpsr, fpu_s0, fpu_s1, fpu_s2, fpu_s3, fpu_s4, fpu_s5, fpu_s6, fpu_s7, fpu_s8, fpu_s9, fpu_s10, fpu_s11, fpu_s12, fpu_s13, fpu_s14, fpu_s15, fpu_s16, fpu_s17, fpu_s18, fpu_s19, fpu_s20, fpu_s21, fpu_s22, fpu_s23, fpu_s24, fpu_s25, fpu_s26, fpu_s27, fpu_s28, fpu_s29, fpu_s30, fpu_s31, fpu_fpscr, fpu_d0, fpu_d1, fpu_d2, fpu_d3, fpu_d4, fpu_d5, fpu_d6, fpu_d7, fpu_d8, fpu_d9, fpu_d10, fpu_d11, fpu_d12, fpu_d13, fpu_d14, fpu_d15, fpu_d16, fpu_d17, fpu_d18, fpu_d19, fpu_d20, fpu_d21, fpu_d22, fpu_d23, fpu_d24, fpu_d25, fpu_d26, fpu_d27, fpu_d28, fpu_d29, fpu_d30, fpu_d31, fpu_q0, fpu_q1, fpu_q2, fpu_q3, fpu_q4, fpu_q5, fpu_q6, fpu_q7, fpu_q8, fpu_q9, fpu_q10, fpu_q11, fpu_q12, fpu_q13, fpu_q14, fpu_q15, exc_exception, exc_fsr, exc_far, dbg_bvr0, dbg_bvr1, dbg_bvr2, dbg_bvr3, dbg_bvr4, dbg_bvr5, dbg_bvr6, dbg_bvr7, dbg_bvr8, dbg_bvr9, dbg_bvr10, dbg_bvr11, dbg_bvr12, dbg_bvr13, dbg_bvr14, dbg_bvr15, dbg_bcr0, dbg_bcr1, dbg_bcr2, dbg_bcr3, dbg_bcr4, dbg_bcr5, dbg_bcr6, dbg_bcr7, dbg_bcr8, dbg_bcr9, dbg_bcr10, dbg_bcr11, dbg_bcr12, dbg_bcr13, dbg_bcr14, dbg_bcr15, dbg_wvr0, dbg_wvr1, dbg_wvr2, dbg_wvr3, dbg_wvr4, dbg_wvr5, dbg_wvr6, dbg_wvr7, dbg_wvr8, dbg_wvr9, dbg_wvr10, dbg_wvr11, dbg_wvr12, dbg_wvr13, dbg_wvr14, dbg_wvr15, dbg_wcr0, dbg_wcr1, dbg_wcr2, dbg_wcr3, dbg_wcr4, dbg_wcr5, dbg_wcr6, dbg_wcr7, dbg_wcr8, dbg_wcr9, dbg_wcr10, dbg_wcr11, dbg_wcr12, dbg_wcr13, dbg_wcr14, dbg_wcr15, k_num_registers }; static uint32_t g_s0_invalidates[] = { fpu_d0, fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_s1_invalidates[] = { fpu_d0, fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_s2_invalidates[] = { fpu_d1, fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_s3_invalidates[] = { fpu_d1, fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_s4_invalidates[] = { fpu_d2, fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_s5_invalidates[] = { fpu_d2, fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_s6_invalidates[] = { fpu_d3, fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_s7_invalidates[] = { fpu_d3, fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_s8_invalidates[] = { fpu_d4, fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_s9_invalidates[] = { fpu_d4, fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_s10_invalidates[] = { fpu_d5, fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_s11_invalidates[] = { fpu_d5, fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_s12_invalidates[] = { fpu_d6, fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_s13_invalidates[] = { fpu_d6, fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_s14_invalidates[] = { fpu_d7, fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_s15_invalidates[] = { fpu_d7, fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_s16_invalidates[] = { fpu_d8, fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_s17_invalidates[] = { fpu_d8, fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_s18_invalidates[] = { fpu_d9, fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_s19_invalidates[] = { fpu_d9, fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_s20_invalidates[] = { fpu_d10, fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_s21_invalidates[] = { fpu_d10, fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_s22_invalidates[] = { fpu_d11, fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_s23_invalidates[] = { fpu_d11, fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_s24_invalidates[] = { fpu_d12, fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_s25_invalidates[] = { fpu_d12, fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_s26_invalidates[] = { fpu_d13, fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_s27_invalidates[] = { fpu_d13, fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_s28_invalidates[] = { fpu_d14, fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_s29_invalidates[] = { fpu_d14, fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_s30_invalidates[] = { fpu_d15, fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_s31_invalidates[] = { fpu_d15, fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_d0_contains[] = { fpu_s0, fpu_s1, LLDB_INVALID_REGNUM }; static uint32_t g_d1_contains[] = { fpu_s2, fpu_s3, LLDB_INVALID_REGNUM }; static uint32_t g_d2_contains[] = { fpu_s4, fpu_s5, LLDB_INVALID_REGNUM }; static uint32_t g_d3_contains[] = { fpu_s6, fpu_s7, LLDB_INVALID_REGNUM }; static uint32_t g_d4_contains[] = { fpu_s8, fpu_s9, LLDB_INVALID_REGNUM }; static uint32_t g_d5_contains[] = { fpu_s10, fpu_s11, LLDB_INVALID_REGNUM }; static uint32_t g_d6_contains[] = { fpu_s12, fpu_s13, LLDB_INVALID_REGNUM }; static uint32_t g_d7_contains[] = { fpu_s14, fpu_s15, LLDB_INVALID_REGNUM }; static uint32_t g_d8_contains[] = { fpu_s16, fpu_s17, LLDB_INVALID_REGNUM }; static uint32_t g_d9_contains[] = { fpu_s18, fpu_s19, LLDB_INVALID_REGNUM }; static uint32_t g_d10_contains[] = { fpu_s20, fpu_s21, LLDB_INVALID_REGNUM }; static uint32_t g_d11_contains[] = { fpu_s22, fpu_s23, LLDB_INVALID_REGNUM }; static uint32_t g_d12_contains[] = { fpu_s24, fpu_s25, LLDB_INVALID_REGNUM }; static uint32_t g_d13_contains[] = { fpu_s26, fpu_s27, LLDB_INVALID_REGNUM }; static uint32_t g_d14_contains[] = { fpu_s28, fpu_s29, LLDB_INVALID_REGNUM }; static uint32_t g_d15_contains[] = { fpu_s30, fpu_s31, LLDB_INVALID_REGNUM }; static uint32_t g_d0_invalidates[] = { fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_d1_invalidates[] = { fpu_q0, LLDB_INVALID_REGNUM }; static uint32_t g_d2_invalidates[] = { fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_d3_invalidates[] = { fpu_q1, LLDB_INVALID_REGNUM }; static uint32_t g_d4_invalidates[] = { fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_d5_invalidates[] = { fpu_q2, LLDB_INVALID_REGNUM }; static uint32_t g_d6_invalidates[] = { fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_d7_invalidates[] = { fpu_q3, LLDB_INVALID_REGNUM }; static uint32_t g_d8_invalidates[] = { fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_d9_invalidates[] = { fpu_q4, LLDB_INVALID_REGNUM }; static uint32_t g_d10_invalidates[] = { fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_d11_invalidates[] = { fpu_q5, LLDB_INVALID_REGNUM }; static uint32_t g_d12_invalidates[] = { fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_d13_invalidates[] = { fpu_q6, LLDB_INVALID_REGNUM }; static uint32_t g_d14_invalidates[] = { fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_d15_invalidates[] = { fpu_q7, LLDB_INVALID_REGNUM }; static uint32_t g_d16_invalidates[] = { fpu_q8, LLDB_INVALID_REGNUM }; static uint32_t g_d17_invalidates[] = { fpu_q8, LLDB_INVALID_REGNUM }; static uint32_t g_d18_invalidates[] = { fpu_q9, LLDB_INVALID_REGNUM }; static uint32_t g_d19_invalidates[] = { fpu_q9, LLDB_INVALID_REGNUM }; static uint32_t g_d20_invalidates[] = { fpu_q10, LLDB_INVALID_REGNUM }; static uint32_t g_d21_invalidates[] = { fpu_q10, LLDB_INVALID_REGNUM }; static uint32_t g_d22_invalidates[] = { fpu_q11, LLDB_INVALID_REGNUM }; static uint32_t g_d23_invalidates[] = { fpu_q11, LLDB_INVALID_REGNUM }; static uint32_t g_d24_invalidates[] = { fpu_q12, LLDB_INVALID_REGNUM }; static uint32_t g_d25_invalidates[] = { fpu_q12, LLDB_INVALID_REGNUM }; static uint32_t g_d26_invalidates[] = { fpu_q13, LLDB_INVALID_REGNUM }; static uint32_t g_d27_invalidates[] = { fpu_q13, LLDB_INVALID_REGNUM }; static uint32_t g_d28_invalidates[] = { fpu_q14, LLDB_INVALID_REGNUM }; static uint32_t g_d29_invalidates[] = { fpu_q14, LLDB_INVALID_REGNUM }; static uint32_t g_d30_invalidates[] = { fpu_q15, LLDB_INVALID_REGNUM }; static uint32_t g_d31_invalidates[] = { fpu_q15, LLDB_INVALID_REGNUM }; static uint32_t g_q0_contains[] = { fpu_d0, fpu_d1, fpu_s0, fpu_s1, fpu_s2, fpu_s3, LLDB_INVALID_REGNUM }; static uint32_t g_q1_contains[] = { fpu_d2, fpu_d3, fpu_s4, fpu_s5, fpu_s6, fpu_s7, LLDB_INVALID_REGNUM }; static uint32_t g_q2_contains[] = { fpu_d4, fpu_d5, fpu_s8, fpu_s9, fpu_s10, fpu_s11, LLDB_INVALID_REGNUM }; static uint32_t g_q3_contains[] = { fpu_d6, fpu_d7, fpu_s12, fpu_s13, fpu_s14, fpu_s15, LLDB_INVALID_REGNUM }; static uint32_t g_q4_contains[] = { fpu_d8, fpu_d9, fpu_s16, fpu_s17, fpu_s18, fpu_s19, LLDB_INVALID_REGNUM }; static uint32_t g_q5_contains[] = { fpu_d10, fpu_d11, fpu_s20, fpu_s21, fpu_s22, fpu_s23, LLDB_INVALID_REGNUM }; static uint32_t g_q6_contains[] = { fpu_d12, fpu_d13, fpu_s24, fpu_s25, fpu_s26, fpu_s27, LLDB_INVALID_REGNUM }; static uint32_t g_q7_contains[] = { fpu_d14, fpu_d15, fpu_s28, fpu_s29, fpu_s30, fpu_s31, LLDB_INVALID_REGNUM }; static uint32_t g_q8_contains[] = { fpu_d16, fpu_d17, LLDB_INVALID_REGNUM }; static uint32_t g_q9_contains[] = { fpu_d18, fpu_d19, LLDB_INVALID_REGNUM }; static uint32_t g_q10_contains[] = { fpu_d20, fpu_d21, LLDB_INVALID_REGNUM }; static uint32_t g_q11_contains[] = { fpu_d22, fpu_d23, LLDB_INVALID_REGNUM }; static uint32_t g_q12_contains[] = { fpu_d24, fpu_d25, LLDB_INVALID_REGNUM }; static uint32_t g_q13_contains[] = { fpu_d26, fpu_d27, LLDB_INVALID_REGNUM }; static uint32_t g_q14_contains[] = { fpu_d28, fpu_d29, LLDB_INVALID_REGNUM }; static uint32_t g_q15_contains[] = { fpu_d30, fpu_d31, LLDB_INVALID_REGNUM }; static RegisterInfo g_register_infos_arm[] = { // NAME ALT SZ OFFSET ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE REGS INVALIDATE REGS // =========== ======= == ============== ================ ==================== =================== =================== ========================== =================== ============= ============== ================= -{ "r0", nullptr, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_r0 }, nullptr, nullptr }, -{ "r1", nullptr, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_r1 }, nullptr, nullptr }, -{ "r2", nullptr, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_r2 }, nullptr, nullptr }, -{ "r3", nullptr, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_r3 }, nullptr, nullptr }, -{ "r4", nullptr, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r4 }, nullptr, nullptr }, -{ "r5", nullptr, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r5 }, nullptr, nullptr }, -{ "r6", nullptr, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r6 }, nullptr, nullptr }, -{ "r7", nullptr, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r7 }, nullptr, nullptr }, -{ "r8", nullptr, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r8 }, nullptr, nullptr }, -{ "r9", nullptr, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r9 }, nullptr, nullptr }, -{ "r10", nullptr, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r10 }, nullptr, nullptr }, -{ "r11", nullptr, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_r11 }, nullptr, nullptr }, -{ "r12", nullptr, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r12 }, nullptr, nullptr }, -{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_sp }, nullptr, nullptr }, -{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_lr }, nullptr, nullptr }, -{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc }, nullptr, nullptr }, -{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, gpr_cpsr }, nullptr, nullptr }, +{ "r0", nullptr, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_r0 }, nullptr, nullptr, nullptr, 0}, +{ "r1", nullptr, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_r1 }, nullptr, nullptr, nullptr, 0}, +{ "r2", nullptr, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_r2 }, nullptr, nullptr, nullptr, 0}, +{ "r3", nullptr, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_r3 }, nullptr, nullptr, nullptr, 0}, +{ "r4", nullptr, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r4 }, nullptr, nullptr, nullptr, 0}, +{ "r5", nullptr, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r5 }, nullptr, nullptr, nullptr, 0}, +{ "r6", nullptr, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r6 }, nullptr, nullptr, nullptr, 0}, +{ "r7", nullptr, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r7 }, nullptr, nullptr, nullptr, 0}, +{ "r8", nullptr, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r8 }, nullptr, nullptr, nullptr, 0}, +{ "r9", nullptr, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r9 }, nullptr, nullptr, nullptr, 0}, +{ "r10", nullptr, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r10 }, nullptr, nullptr, nullptr, 0}, +{ "r11", nullptr, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_r11 }, nullptr, nullptr, nullptr, 0}, +{ "r12", nullptr, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_r12 }, nullptr, nullptr, nullptr, 0}, +{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_sp }, nullptr, nullptr, nullptr, 0}, +{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_lr }, nullptr, nullptr, nullptr, 0}, +{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc }, nullptr, nullptr, nullptr, 0}, +{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, gpr_cpsr }, nullptr, nullptr, nullptr, 0}, -{ "s0", nullptr, 4, FPU_OFFSET(0), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s0 }, nullptr, g_s0_invalidates }, -{ "s1", nullptr, 4, FPU_OFFSET(1), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s1 }, nullptr, g_s1_invalidates }, -{ "s2", nullptr, 4, FPU_OFFSET(2), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s2 }, nullptr, g_s2_invalidates }, -{ "s3", nullptr, 4, FPU_OFFSET(3), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s3 }, nullptr, g_s3_invalidates }, -{ "s4", nullptr, 4, FPU_OFFSET(4), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s4 }, nullptr, g_s4_invalidates }, -{ "s5", nullptr, 4, FPU_OFFSET(5), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s5 }, nullptr, g_s5_invalidates }, -{ "s6", nullptr, 4, FPU_OFFSET(6), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s6 }, nullptr, g_s6_invalidates }, -{ "s7", nullptr, 4, FPU_OFFSET(7), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s7 }, nullptr, g_s7_invalidates }, -{ "s8", nullptr, 4, FPU_OFFSET(8), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s8 }, nullptr, g_s8_invalidates }, -{ "s9", nullptr, 4, FPU_OFFSET(9), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s9 }, nullptr, g_s9_invalidates }, -{ "s10", nullptr, 4, FPU_OFFSET(10), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s10 }, nullptr, g_s10_invalidates }, -{ "s11", nullptr, 4, FPU_OFFSET(11), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s11 }, nullptr, g_s11_invalidates }, -{ "s12", nullptr, 4, FPU_OFFSET(12), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s12 }, nullptr, g_s12_invalidates }, -{ "s13", nullptr, 4, FPU_OFFSET(13), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s13 }, nullptr, g_s13_invalidates }, -{ "s14", nullptr, 4, FPU_OFFSET(14), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s14 }, nullptr, g_s14_invalidates }, -{ "s15", nullptr, 4, FPU_OFFSET(15), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s15 }, nullptr, g_s15_invalidates }, -{ "s16", nullptr, 4, FPU_OFFSET(16), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s16 }, nullptr, g_s16_invalidates }, -{ "s17", nullptr, 4, FPU_OFFSET(17), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s17 }, nullptr, g_s17_invalidates }, -{ "s18", nullptr, 4, FPU_OFFSET(18), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s18 }, nullptr, g_s18_invalidates }, -{ "s19", nullptr, 4, FPU_OFFSET(19), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s19 }, nullptr, g_s19_invalidates }, -{ "s20", nullptr, 4, FPU_OFFSET(20), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s20 }, nullptr, g_s20_invalidates }, -{ "s21", nullptr, 4, FPU_OFFSET(21), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s21 }, nullptr, g_s21_invalidates }, -{ "s22", nullptr, 4, FPU_OFFSET(22), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s22 }, nullptr, g_s22_invalidates }, -{ "s23", nullptr, 4, FPU_OFFSET(23), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s23 }, nullptr, g_s23_invalidates }, -{ "s24", nullptr, 4, FPU_OFFSET(24), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s24 }, nullptr, g_s24_invalidates }, -{ "s25", nullptr, 4, FPU_OFFSET(25), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s25 }, nullptr, g_s25_invalidates }, -{ "s26", nullptr, 4, FPU_OFFSET(26), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s26 }, nullptr, g_s26_invalidates }, -{ "s27", nullptr, 4, FPU_OFFSET(27), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s27 }, nullptr, g_s27_invalidates }, -{ "s28", nullptr, 4, FPU_OFFSET(28), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s28 }, nullptr, g_s28_invalidates }, -{ "s29", nullptr, 4, FPU_OFFSET(29), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s29 }, nullptr, g_s29_invalidates }, -{ "s30", nullptr, 4, FPU_OFFSET(30), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s30 }, nullptr, g_s30_invalidates }, -{ "s31", nullptr, 4, FPU_OFFSET(31), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s31 }, nullptr, g_s31_invalidates }, -{ "fpscr", nullptr, 4, FPSCR_OFFSET, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpscr }, nullptr, nullptr }, +{ "s0", nullptr, 4, FPU_OFFSET(0), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s0 }, nullptr, g_s0_invalidates, nullptr, 0}, +{ "s1", nullptr, 4, FPU_OFFSET(1), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s1 }, nullptr, g_s1_invalidates, nullptr, 0}, +{ "s2", nullptr, 4, FPU_OFFSET(2), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s2 }, nullptr, g_s2_invalidates, nullptr, 0}, +{ "s3", nullptr, 4, FPU_OFFSET(3), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s3 }, nullptr, g_s3_invalidates, nullptr, 0}, +{ "s4", nullptr, 4, FPU_OFFSET(4), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s4 }, nullptr, g_s4_invalidates, nullptr, 0}, +{ "s5", nullptr, 4, FPU_OFFSET(5), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s5 }, nullptr, g_s5_invalidates, nullptr, 0}, +{ "s6", nullptr, 4, FPU_OFFSET(6), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s6 }, nullptr, g_s6_invalidates, nullptr, 0}, +{ "s7", nullptr, 4, FPU_OFFSET(7), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s7 }, nullptr, g_s7_invalidates, nullptr, 0}, +{ "s8", nullptr, 4, FPU_OFFSET(8), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s8 }, nullptr, g_s8_invalidates, nullptr, 0}, +{ "s9", nullptr, 4, FPU_OFFSET(9), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s9 }, nullptr, g_s9_invalidates, nullptr, 0}, +{ "s10", nullptr, 4, FPU_OFFSET(10), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s10 }, nullptr, g_s10_invalidates, nullptr, 0}, +{ "s11", nullptr, 4, FPU_OFFSET(11), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s11 }, nullptr, g_s11_invalidates, nullptr, 0}, +{ "s12", nullptr, 4, FPU_OFFSET(12), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s12 }, nullptr, g_s12_invalidates, nullptr, 0}, +{ "s13", nullptr, 4, FPU_OFFSET(13), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s13 }, nullptr, g_s13_invalidates, nullptr, 0}, +{ "s14", nullptr, 4, FPU_OFFSET(14), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s14 }, nullptr, g_s14_invalidates, nullptr, 0}, +{ "s15", nullptr, 4, FPU_OFFSET(15), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s15 }, nullptr, g_s15_invalidates, nullptr, 0}, +{ "s16", nullptr, 4, FPU_OFFSET(16), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s16 }, nullptr, g_s16_invalidates, nullptr, 0}, +{ "s17", nullptr, 4, FPU_OFFSET(17), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s17 }, nullptr, g_s17_invalidates, nullptr, 0}, +{ "s18", nullptr, 4, FPU_OFFSET(18), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s18 }, nullptr, g_s18_invalidates, nullptr, 0}, +{ "s19", nullptr, 4, FPU_OFFSET(19), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s19 }, nullptr, g_s19_invalidates, nullptr, 0}, +{ "s20", nullptr, 4, FPU_OFFSET(20), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s20 }, nullptr, g_s20_invalidates, nullptr, 0}, +{ "s21", nullptr, 4, FPU_OFFSET(21), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s21 }, nullptr, g_s21_invalidates, nullptr, 0}, +{ "s22", nullptr, 4, FPU_OFFSET(22), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s22 }, nullptr, g_s22_invalidates, nullptr, 0}, +{ "s23", nullptr, 4, FPU_OFFSET(23), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s23 }, nullptr, g_s23_invalidates, nullptr, 0}, +{ "s24", nullptr, 4, FPU_OFFSET(24), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s24 }, nullptr, g_s24_invalidates, nullptr, 0}, +{ "s25", nullptr, 4, FPU_OFFSET(25), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s25 }, nullptr, g_s25_invalidates, nullptr, 0}, +{ "s26", nullptr, 4, FPU_OFFSET(26), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s26 }, nullptr, g_s26_invalidates, nullptr, 0}, +{ "s27", nullptr, 4, FPU_OFFSET(27), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s27 }, nullptr, g_s27_invalidates, nullptr, 0}, +{ "s28", nullptr, 4, FPU_OFFSET(28), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s28 }, nullptr, g_s28_invalidates, nullptr, 0}, +{ "s29", nullptr, 4, FPU_OFFSET(29), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s29 }, nullptr, g_s29_invalidates, nullptr, 0}, +{ "s30", nullptr, 4, FPU_OFFSET(30), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s30 }, nullptr, g_s30_invalidates, nullptr, 0}, +{ "s31", nullptr, 4, FPU_OFFSET(31), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_s31 }, nullptr, g_s31_invalidates, nullptr, 0}, +{ "fpscr", nullptr, 4, FPSCR_OFFSET, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpscr }, nullptr, nullptr, nullptr, 0}, -{ "d0", nullptr, 8, FPU_OFFSET(0), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d0 }, g_d0_contains, g_d0_invalidates }, -{ "d1", nullptr, 8, FPU_OFFSET(2), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d1 }, g_d1_contains, g_d1_invalidates }, -{ "d2", nullptr, 8, FPU_OFFSET(4), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d2 }, g_d2_contains, g_d2_invalidates }, -{ "d3", nullptr, 8, FPU_OFFSET(6), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d3 }, g_d3_contains, g_d3_invalidates }, -{ "d4", nullptr, 8, FPU_OFFSET(8), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d4 }, g_d4_contains, g_d4_invalidates }, -{ "d5", nullptr, 8, FPU_OFFSET(10), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d5 }, g_d5_contains, g_d5_invalidates }, -{ "d6", nullptr, 8, FPU_OFFSET(12), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d6 }, g_d6_contains, g_d6_invalidates }, -{ "d7", nullptr, 8, FPU_OFFSET(14), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d7 }, g_d7_contains, g_d7_invalidates }, -{ "d8", nullptr, 8, FPU_OFFSET(16), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d8 }, g_d8_contains, g_d8_invalidates }, -{ "d9", nullptr, 8, FPU_OFFSET(18), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d9 }, g_d9_contains, g_d9_invalidates }, -{ "d10", nullptr, 8, FPU_OFFSET(20), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d10 }, g_d10_contains, g_d10_invalidates }, -{ "d11", nullptr, 8, FPU_OFFSET(22), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d11 }, g_d11_contains, g_d11_invalidates }, -{ "d12", nullptr, 8, FPU_OFFSET(24), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d12 }, g_d12_contains, g_d12_invalidates }, -{ "d13", nullptr, 8, FPU_OFFSET(26), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d13 }, g_d13_contains, g_d13_invalidates }, -{ "d14", nullptr, 8, FPU_OFFSET(28), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d14 }, g_d14_contains, g_d14_invalidates }, -{ "d15", nullptr, 8, FPU_OFFSET(30), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d15 }, g_d15_contains, g_d15_invalidates }, -{ "d16", nullptr, 8, FPU_OFFSET(32), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d16 }, nullptr, g_d16_invalidates }, -{ "d17", nullptr, 8, FPU_OFFSET(34), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d17 }, nullptr, g_d17_invalidates }, -{ "d18", nullptr, 8, FPU_OFFSET(36), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d18 }, nullptr, g_d18_invalidates }, -{ "d19", nullptr, 8, FPU_OFFSET(38), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d19 }, nullptr, g_d19_invalidates }, -{ "d20", nullptr, 8, FPU_OFFSET(40), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d20 }, nullptr, g_d20_invalidates }, -{ "d21", nullptr, 8, FPU_OFFSET(42), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d21 }, nullptr, g_d21_invalidates }, -{ "d22", nullptr, 8, FPU_OFFSET(44), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d22 }, nullptr, g_d22_invalidates }, -{ "d23", nullptr, 8, FPU_OFFSET(46), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d23 }, nullptr, g_d23_invalidates }, -{ "d24", nullptr, 8, FPU_OFFSET(48), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d24 }, nullptr, g_d24_invalidates }, -{ "d25", nullptr, 8, FPU_OFFSET(50), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d25 }, nullptr, g_d25_invalidates }, -{ "d26", nullptr, 8, FPU_OFFSET(52), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d26 }, nullptr, g_d26_invalidates }, -{ "d27", nullptr, 8, FPU_OFFSET(54), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d27 }, nullptr, g_d27_invalidates }, -{ "d28", nullptr, 8, FPU_OFFSET(56), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d28 }, nullptr, g_d28_invalidates }, -{ "d29", nullptr, 8, FPU_OFFSET(58), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d29 }, nullptr, g_d29_invalidates }, -{ "d30", nullptr, 8, FPU_OFFSET(60), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d30 }, nullptr, g_d30_invalidates }, -{ "d31", nullptr, 8, FPU_OFFSET(62), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d31 }, nullptr, g_d31_invalidates }, +{ "d0", nullptr, 8, FPU_OFFSET(0), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d0 }, g_d0_contains, g_d0_invalidates, nullptr, 0}, +{ "d1", nullptr, 8, FPU_OFFSET(2), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d1 }, g_d1_contains, g_d1_invalidates, nullptr, 0}, +{ "d2", nullptr, 8, FPU_OFFSET(4), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d2 }, g_d2_contains, g_d2_invalidates, nullptr, 0}, +{ "d3", nullptr, 8, FPU_OFFSET(6), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d3 }, g_d3_contains, g_d3_invalidates, nullptr, 0}, +{ "d4", nullptr, 8, FPU_OFFSET(8), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d4 }, g_d4_contains, g_d4_invalidates, nullptr, 0}, +{ "d5", nullptr, 8, FPU_OFFSET(10), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d5 }, g_d5_contains, g_d5_invalidates, nullptr, 0}, +{ "d6", nullptr, 8, FPU_OFFSET(12), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d6 }, g_d6_contains, g_d6_invalidates, nullptr, 0}, +{ "d7", nullptr, 8, FPU_OFFSET(14), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d7 }, g_d7_contains, g_d7_invalidates, nullptr, 0}, +{ "d8", nullptr, 8, FPU_OFFSET(16), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d8 }, g_d8_contains, g_d8_invalidates, nullptr, 0}, +{ "d9", nullptr, 8, FPU_OFFSET(18), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d9 }, g_d9_contains, g_d9_invalidates, nullptr, 0}, +{ "d10", nullptr, 8, FPU_OFFSET(20), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d10 }, g_d10_contains, g_d10_invalidates, nullptr, 0}, +{ "d11", nullptr, 8, FPU_OFFSET(22), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d11 }, g_d11_contains, g_d11_invalidates, nullptr, 0}, +{ "d12", nullptr, 8, FPU_OFFSET(24), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d12 }, g_d12_contains, g_d12_invalidates, nullptr, 0}, +{ "d13", nullptr, 8, FPU_OFFSET(26), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d13 }, g_d13_contains, g_d13_invalidates, nullptr, 0}, +{ "d14", nullptr, 8, FPU_OFFSET(28), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d14 }, g_d14_contains, g_d14_invalidates, nullptr, 0}, +{ "d15", nullptr, 8, FPU_OFFSET(30), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d15 }, g_d15_contains, g_d15_invalidates, nullptr, 0}, +{ "d16", nullptr, 8, FPU_OFFSET(32), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d16 }, nullptr, g_d16_invalidates, nullptr, 0 }, +{ "d17", nullptr, 8, FPU_OFFSET(34), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d17 }, nullptr, g_d17_invalidates, nullptr, 0}, +{ "d18", nullptr, 8, FPU_OFFSET(36), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d18 }, nullptr, g_d18_invalidates, nullptr, 0}, +{ "d19", nullptr, 8, FPU_OFFSET(38), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d19 }, nullptr, g_d19_invalidates, nullptr, 0}, +{ "d20", nullptr, 8, FPU_OFFSET(40), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d20 }, nullptr, g_d20_invalidates, nullptr, 0}, +{ "d21", nullptr, 8, FPU_OFFSET(42), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d21 }, nullptr, g_d21_invalidates, nullptr, 0}, +{ "d22", nullptr, 8, FPU_OFFSET(44), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d22 }, nullptr, g_d22_invalidates, nullptr, 0}, +{ "d23", nullptr, 8, FPU_OFFSET(46), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d23 }, nullptr, g_d23_invalidates, nullptr, 0}, +{ "d24", nullptr, 8, FPU_OFFSET(48), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d24 }, nullptr, g_d24_invalidates, nullptr, 0}, +{ "d25", nullptr, 8, FPU_OFFSET(50), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d25 }, nullptr, g_d25_invalidates, nullptr, 0}, +{ "d26", nullptr, 8, FPU_OFFSET(52), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d26 }, nullptr, g_d26_invalidates, nullptr, 0}, +{ "d27", nullptr, 8, FPU_OFFSET(54), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d27 }, nullptr, g_d27_invalidates, nullptr, 0}, +{ "d28", nullptr, 8, FPU_OFFSET(56), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d28 }, nullptr, g_d28_invalidates, nullptr, 0}, +{ "d29", nullptr, 8, FPU_OFFSET(58), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d29 }, nullptr, g_d29_invalidates, nullptr, 0}, +{ "d30", nullptr, 8, FPU_OFFSET(60), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d30 }, nullptr, g_d30_invalidates, nullptr, 0}, +{ "d31", nullptr, 8, FPU_OFFSET(62), eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_d31 }, nullptr, g_d31_invalidates, nullptr, 0}, -{ "q0", nullptr, 16, FPU_OFFSET(0), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q0 }, g_q0_contains, nullptr, }, -{ "q1", nullptr, 16, FPU_OFFSET(4), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q1 }, g_q1_contains, nullptr, }, -{ "q2", nullptr, 16, FPU_OFFSET(8), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q2 }, g_q2_contains, nullptr, }, -{ "q3", nullptr, 16, FPU_OFFSET(12), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q3 }, g_q3_contains, nullptr, }, -{ "q4", nullptr, 16, FPU_OFFSET(16), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q4 }, g_q4_contains, nullptr, }, -{ "q5", nullptr, 16, FPU_OFFSET(20), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q5 }, g_q5_contains, nullptr, }, -{ "q6", nullptr, 16, FPU_OFFSET(24), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q6 }, g_q6_contains, nullptr, }, -{ "q7", nullptr, 16, FPU_OFFSET(28), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q7 }, g_q7_contains, nullptr, }, -{ "q8", nullptr, 16, FPU_OFFSET(32), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q8 }, g_q8_contains, nullptr, }, -{ "q9", nullptr, 16, FPU_OFFSET(36), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q9 }, g_q9_contains, nullptr, }, -{ "q10", nullptr, 16, FPU_OFFSET(40), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q10 }, g_q10_contains, nullptr, }, -{ "q11", nullptr, 16, FPU_OFFSET(44), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q11 }, g_q11_contains, nullptr, }, -{ "q12", nullptr, 16, FPU_OFFSET(48), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q12 }, g_q12_contains, nullptr, }, -{ "q13", nullptr, 16, FPU_OFFSET(52), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q13 }, g_q13_contains, nullptr, }, -{ "q14", nullptr, 16, FPU_OFFSET(56), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q14 }, g_q14_contains, nullptr, }, -{ "q15", nullptr, 16, FPU_OFFSET(60), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q15 }, g_q15_contains, nullptr, }, +{ "q0", nullptr, 16, FPU_OFFSET(0), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q0 }, g_q0_contains, nullptr, nullptr, 0}, +{ "q1", nullptr, 16, FPU_OFFSET(4), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q1 }, g_q1_contains, nullptr, nullptr, 0}, +{ "q2", nullptr, 16, FPU_OFFSET(8), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q2 }, g_q2_contains, nullptr, nullptr, 0}, +{ "q3", nullptr, 16, FPU_OFFSET(12), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q3 }, g_q3_contains, nullptr, nullptr, 0}, +{ "q4", nullptr, 16, FPU_OFFSET(16), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q4 }, g_q4_contains, nullptr, nullptr, 0}, +{ "q5", nullptr, 16, FPU_OFFSET(20), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q5 }, g_q5_contains, nullptr, nullptr, 0}, +{ "q6", nullptr, 16, FPU_OFFSET(24), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q6 }, g_q6_contains, nullptr, nullptr, 0}, +{ "q7", nullptr, 16, FPU_OFFSET(28), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q7 }, g_q7_contains, nullptr, nullptr, 0}, +{ "q8", nullptr, 16, FPU_OFFSET(32), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q8 }, g_q8_contains, nullptr, nullptr, 0}, +{ "q9", nullptr, 16, FPU_OFFSET(36), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q9 }, g_q9_contains, nullptr, nullptr, 0}, +{ "q10", nullptr, 16, FPU_OFFSET(40), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q10 }, g_q10_contains, nullptr, nullptr, 0}, +{ "q11", nullptr, 16, FPU_OFFSET(44), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q11 }, g_q11_contains, nullptr, nullptr, 0}, +{ "q12", nullptr, 16, FPU_OFFSET(48), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q12 }, g_q12_contains, nullptr, nullptr, 0}, +{ "q13", nullptr, 16, FPU_OFFSET(52), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q13 }, g_q13_contains, nullptr, nullptr, 0}, +{ "q14", nullptr, 16, FPU_OFFSET(56), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q14 }, g_q14_contains, nullptr, nullptr, 0}, +{ "q15", nullptr, 16, FPU_OFFSET(60), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_q15 }, g_q15_contains, nullptr, nullptr, 0}, -{ "exception", nullptr, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, nullptr, nullptr }, -{ "fsr", nullptr, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, nullptr, nullptr }, -{ "far", nullptr, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, nullptr, nullptr }, +{ "exception", nullptr, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, nullptr, nullptr, nullptr, 0}, +{ "fsr", nullptr, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, nullptr, nullptr, nullptr, 0}, +{ "far", nullptr, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, nullptr, nullptr, nullptr, 0}, { DEFINE_DBG (bvr, 0) }, { DEFINE_DBG (bvr, 1) }, { DEFINE_DBG (bvr, 2) }, { DEFINE_DBG (bvr, 3) }, { DEFINE_DBG (bvr, 4) }, { DEFINE_DBG (bvr, 5) }, { DEFINE_DBG (bvr, 6) }, { DEFINE_DBG (bvr, 7) }, { DEFINE_DBG (bvr, 8) }, { DEFINE_DBG (bvr, 9) }, { DEFINE_DBG (bvr, 10) }, { DEFINE_DBG (bvr, 11) }, { DEFINE_DBG (bvr, 12) }, { DEFINE_DBG (bvr, 13) }, { DEFINE_DBG (bvr, 14) }, { DEFINE_DBG (bvr, 15) }, { DEFINE_DBG (bcr, 0) }, { DEFINE_DBG (bcr, 1) }, { DEFINE_DBG (bcr, 2) }, { DEFINE_DBG (bcr, 3) }, { DEFINE_DBG (bcr, 4) }, { DEFINE_DBG (bcr, 5) }, { DEFINE_DBG (bcr, 6) }, { DEFINE_DBG (bcr, 7) }, { DEFINE_DBG (bcr, 8) }, { DEFINE_DBG (bcr, 9) }, { DEFINE_DBG (bcr, 10) }, { DEFINE_DBG (bcr, 11) }, { DEFINE_DBG (bcr, 12) }, { DEFINE_DBG (bcr, 13) }, { DEFINE_DBG (bcr, 14) }, { DEFINE_DBG (bcr, 15) }, { DEFINE_DBG (wvr, 0) }, { DEFINE_DBG (wvr, 1) }, { DEFINE_DBG (wvr, 2) }, { DEFINE_DBG (wvr, 3) }, { DEFINE_DBG (wvr, 4) }, { DEFINE_DBG (wvr, 5) }, { DEFINE_DBG (wvr, 6) }, { DEFINE_DBG (wvr, 7) }, { DEFINE_DBG (wvr, 8) }, { DEFINE_DBG (wvr, 9) }, { DEFINE_DBG (wvr, 10) }, { DEFINE_DBG (wvr, 11) }, { DEFINE_DBG (wvr, 12) }, { DEFINE_DBG (wvr, 13) }, { DEFINE_DBG (wvr, 14) }, { DEFINE_DBG (wvr, 15) }, { DEFINE_DBG (wcr, 0) }, { DEFINE_DBG (wcr, 1) }, { DEFINE_DBG (wcr, 2) }, { DEFINE_DBG (wcr, 3) }, { DEFINE_DBG (wcr, 4) }, { DEFINE_DBG (wcr, 5) }, { DEFINE_DBG (wcr, 6) }, { DEFINE_DBG (wcr, 7) }, { DEFINE_DBG (wcr, 8) }, { DEFINE_DBG (wcr, 9) }, { DEFINE_DBG (wcr, 10) }, { DEFINE_DBG (wcr, 11) }, { DEFINE_DBG (wcr, 12) }, { DEFINE_DBG (wcr, 13) }, { DEFINE_DBG (wcr, 14) }, { DEFINE_DBG (wcr, 15) } }; #endif // DECLARE_REGISTER_INFOS_ARM_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm64.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm64.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_arm64.h (revision 304308) @@ -1,351 +1,351 @@ //===-- RegisterInfos_arm64.h -----------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifdef DECLARE_REGISTER_INFOS_ARM64_STRUCT // C Includes #include // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/lldb-private.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "Utility/ARM64_DWARF_Registers.h" #include "Utility/ARM64_ehframe_Registers.h" #ifndef GPR_OFFSET #error GPR_OFFSET must be defined before including this header file #endif #ifndef GPR_OFFSET_NAME #error GPR_OFFSET_NAME must be defined before including this header file #endif #ifndef FPU_OFFSET #error FPU_OFFSET must be defined before including this header file #endif #ifndef FPU_OFFSET_NAME #error FPU_OFFSET_NAME must be defined before including this header file #endif #ifndef EXC_OFFSET_NAME #error EXC_OFFSET_NAME must be defined before including this header file #endif #ifndef DBG_OFFSET_NAME #error DBG_OFFSET_NAME must be defined before including this header file #endif #ifndef DEFINE_DBG #error DEFINE_DBG must be defined before including this header file #endif enum { gpr_x0 = 0, gpr_x1, gpr_x2, gpr_x3, gpr_x4, gpr_x5, gpr_x6, gpr_x7, gpr_x8, gpr_x9, gpr_x10, gpr_x11, gpr_x12, gpr_x13, gpr_x14, gpr_x15, gpr_x16, gpr_x17, gpr_x18, gpr_x19, gpr_x20, gpr_x21, gpr_x22, gpr_x23, gpr_x24, gpr_x25, gpr_x26, gpr_x27, gpr_x28, gpr_x29 = 29, gpr_fp = gpr_x29, gpr_x30 = 30, gpr_lr = gpr_x30, gpr_ra = gpr_x30, gpr_x31 = 31, gpr_sp = gpr_x31, gpr_pc = 32, gpr_cpsr, fpu_v0, fpu_v1, fpu_v2, fpu_v3, fpu_v4, fpu_v5, fpu_v6, fpu_v7, fpu_v8, fpu_v9, fpu_v10, fpu_v11, fpu_v12, fpu_v13, fpu_v14, fpu_v15, fpu_v16, fpu_v17, fpu_v18, fpu_v19, fpu_v20, fpu_v21, fpu_v22, fpu_v23, fpu_v24, fpu_v25, fpu_v26, fpu_v27, fpu_v28, fpu_v29, fpu_v30, fpu_v31, fpu_fpsr, fpu_fpcr, exc_far, exc_esr, exc_exception, dbg_bvr0, dbg_bvr1, dbg_bvr2, dbg_bvr3, dbg_bvr4, dbg_bvr5, dbg_bvr6, dbg_bvr7, dbg_bvr8, dbg_bvr9, dbg_bvr10, dbg_bvr11, dbg_bvr12, dbg_bvr13, dbg_bvr14, dbg_bvr15, dbg_bcr0, dbg_bcr1, dbg_bcr2, dbg_bcr3, dbg_bcr4, dbg_bcr5, dbg_bcr6, dbg_bcr7, dbg_bcr8, dbg_bcr9, dbg_bcr10, dbg_bcr11, dbg_bcr12, dbg_bcr13, dbg_bcr14, dbg_bcr15, dbg_wvr0, dbg_wvr1, dbg_wvr2, dbg_wvr3, dbg_wvr4, dbg_wvr5, dbg_wvr6, dbg_wvr7, dbg_wvr8, dbg_wvr9, dbg_wvr10, dbg_wvr11, dbg_wvr12, dbg_wvr13, dbg_wvr14, dbg_wvr15, dbg_wcr0, dbg_wcr1, dbg_wcr2, dbg_wcr3, dbg_wcr4, dbg_wcr5, dbg_wcr6, dbg_wcr7, dbg_wcr8, dbg_wcr9, dbg_wcr10, dbg_wcr11, dbg_wcr12, dbg_wcr13, dbg_wcr14, dbg_wcr15, k_num_registers }; static lldb_private::RegisterInfo g_register_infos_arm64[] = { // General purpose registers // NAME ALT SZ OFFSET ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE VALUE REGS INVALIDATE REGS // ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== =============== -{ "x0", nullptr, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x0, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_x0 }, nullptr, nullptr}, -{ "x1", nullptr, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x1, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_x1 }, nullptr, nullptr}, -{ "x2", nullptr, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x2, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_x2 }, nullptr, nullptr}, -{ "x3", nullptr, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x3, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_x3 }, nullptr, nullptr}, -{ "x4", nullptr, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x4, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, gpr_x4 }, nullptr, nullptr}, -{ "x5", nullptr, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x5, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, gpr_x5 }, nullptr, nullptr}, -{ "x6", nullptr, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x6, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, gpr_x6 }, nullptr, nullptr}, -{ "x7", nullptr, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x7, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, gpr_x7 }, nullptr, nullptr}, -{ "x8", nullptr, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x8 }, nullptr, nullptr}, -{ "x9", nullptr, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x9 }, nullptr, nullptr}, -{ "x10", nullptr, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x10 }, nullptr, nullptr}, -{ "x11", nullptr, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x11 }, nullptr, nullptr}, -{ "x12", nullptr, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x12 }, nullptr, nullptr}, -{ "x13", nullptr, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x13 }, nullptr, nullptr}, -{ "x14", nullptr, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x14 }, nullptr, nullptr}, -{ "x15", nullptr, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x15 }, nullptr, nullptr}, -{ "x16", nullptr, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x16 }, nullptr, nullptr}, -{ "x17", nullptr, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x17 }, nullptr, nullptr}, -{ "x18", nullptr, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x18 }, nullptr, nullptr}, -{ "x19", nullptr, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x19 }, nullptr, nullptr}, -{ "x20", nullptr, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x20 }, nullptr, nullptr}, -{ "x21", nullptr, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x21 }, nullptr, nullptr}, -{ "x22", nullptr, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x22 }, nullptr, nullptr}, -{ "x23", nullptr, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x23 }, nullptr, nullptr}, -{ "x24", nullptr, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x24 }, nullptr, nullptr}, -{ "x25", nullptr, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x25 }, nullptr, nullptr}, -{ "x26", nullptr, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x26 }, nullptr, nullptr}, -{ "x27", nullptr, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x27 }, nullptr, nullptr}, -{ "x28", nullptr, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x28 }, nullptr, nullptr}, +{ "x0", nullptr, 8, GPR_OFFSET(0), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x0, arm64_dwarf::x0, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM, gpr_x0 }, nullptr, nullptr, nullptr, 0}, +{ "x1", nullptr, 8, GPR_OFFSET(1), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x1, arm64_dwarf::x1, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM, gpr_x1 }, nullptr, nullptr, nullptr, 0}, +{ "x2", nullptr, 8, GPR_OFFSET(2), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x2, arm64_dwarf::x2, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM, gpr_x2 }, nullptr, nullptr, nullptr, 0}, +{ "x3", nullptr, 8, GPR_OFFSET(3), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x3, arm64_dwarf::x3, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM, gpr_x3 }, nullptr, nullptr, nullptr, 0}, +{ "x4", nullptr, 8, GPR_OFFSET(4), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x4, arm64_dwarf::x4, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM, gpr_x4 }, nullptr, nullptr, nullptr, 0}, +{ "x5", nullptr, 8, GPR_OFFSET(5), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x5, arm64_dwarf::x5, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM, gpr_x5 }, nullptr, nullptr, nullptr, 0}, +{ "x6", nullptr, 8, GPR_OFFSET(6), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x6, arm64_dwarf::x6, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM, gpr_x6 }, nullptr, nullptr, nullptr, 0}, +{ "x7", nullptr, 8, GPR_OFFSET(7), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x7, arm64_dwarf::x7, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM, gpr_x7 }, nullptr, nullptr, nullptr, 0}, +{ "x8", nullptr, 8, GPR_OFFSET(8), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x8, arm64_dwarf::x8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x8 }, nullptr, nullptr, nullptr, 0}, +{ "x9", nullptr, 8, GPR_OFFSET(9), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x9, arm64_dwarf::x9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x9 }, nullptr, nullptr, nullptr, 0}, +{ "x10", nullptr, 8, GPR_OFFSET(10), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x10, arm64_dwarf::x10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x10 }, nullptr, nullptr, nullptr, 0}, +{ "x11", nullptr, 8, GPR_OFFSET(11), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x11, arm64_dwarf::x11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x11 }, nullptr, nullptr, nullptr, 0}, +{ "x12", nullptr, 8, GPR_OFFSET(12), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x12, arm64_dwarf::x12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x12 }, nullptr, nullptr, nullptr, 0}, +{ "x13", nullptr, 8, GPR_OFFSET(13), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x13, arm64_dwarf::x13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x13 }, nullptr, nullptr, nullptr, 0}, +{ "x14", nullptr, 8, GPR_OFFSET(14), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x14, arm64_dwarf::x14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x14 }, nullptr, nullptr, nullptr, 0}, +{ "x15", nullptr, 8, GPR_OFFSET(15), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x15, arm64_dwarf::x15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x15 }, nullptr, nullptr, nullptr, 0}, +{ "x16", nullptr, 8, GPR_OFFSET(16), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x16, arm64_dwarf::x16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x16 }, nullptr, nullptr, nullptr, 0}, +{ "x17", nullptr, 8, GPR_OFFSET(17), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x17, arm64_dwarf::x17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x17 }, nullptr, nullptr, nullptr, 0}, +{ "x18", nullptr, 8, GPR_OFFSET(18), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x18, arm64_dwarf::x18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x18 }, nullptr, nullptr, nullptr, 0}, +{ "x19", nullptr, 8, GPR_OFFSET(19), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x19, arm64_dwarf::x19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x19 }, nullptr, nullptr, nullptr, 0}, +{ "x20", nullptr, 8, GPR_OFFSET(20), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x20, arm64_dwarf::x20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x20 }, nullptr, nullptr, nullptr, 0}, +{ "x21", nullptr, 8, GPR_OFFSET(21), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x21, arm64_dwarf::x21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x21 }, nullptr, nullptr, nullptr, 0}, +{ "x22", nullptr, 8, GPR_OFFSET(22), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x22, arm64_dwarf::x22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x22 }, nullptr, nullptr, nullptr, 0}, +{ "x23", nullptr, 8, GPR_OFFSET(23), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x23, arm64_dwarf::x23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x23 }, nullptr, nullptr, nullptr, 0}, +{ "x24", nullptr, 8, GPR_OFFSET(24), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x24, arm64_dwarf::x24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x24 }, nullptr, nullptr, nullptr, 0}, +{ "x25", nullptr, 8, GPR_OFFSET(25), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x25, arm64_dwarf::x25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x25 }, nullptr, nullptr, nullptr, 0}, +{ "x26", nullptr, 8, GPR_OFFSET(26), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x26, arm64_dwarf::x26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x26 }, nullptr, nullptr, nullptr, 0}, +{ "x27", nullptr, 8, GPR_OFFSET(27), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x27, arm64_dwarf::x27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x27 }, nullptr, nullptr, nullptr, 0}, +{ "x28", nullptr, 8, GPR_OFFSET(28), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::x28, arm64_dwarf::x28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gpr_x28 }, nullptr, nullptr, nullptr, 0}, -{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_fp }, nullptr, nullptr}, -{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_lr }, nullptr, nullptr}, -{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_sp }, nullptr, nullptr}, -{ "pc", nullptr, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc }, nullptr, nullptr}, +{ "fp", "x29", 8, GPR_OFFSET(29), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::fp, arm64_dwarf::fp, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM, gpr_fp }, nullptr, nullptr, nullptr, 0}, +{ "lr", "x30", 8, GPR_OFFSET(30), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::lr, arm64_dwarf::lr, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM, gpr_lr }, nullptr, nullptr, nullptr, 0}, +{ "sp", "x31", 8, GPR_OFFSET(31), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::sp, arm64_dwarf::sp, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM, gpr_sp }, nullptr, nullptr, nullptr, 0}, +{ "pc", nullptr, 8, GPR_OFFSET(32), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::pc, arm64_dwarf::pc, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM, gpr_pc }, nullptr, nullptr, nullptr, 0}, -{ "cpsr", nullptr, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, gpr_cpsr }, nullptr, nullptr}, +{ "cpsr", nullptr, 4, GPR_OFFSET_NAME(cpsr), lldb::eEncodingUint, lldb::eFormatHex, { arm64_ehframe::cpsr, arm64_dwarf::cpsr, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM, gpr_cpsr }, nullptr, nullptr, nullptr, 0}, -{ "v0", nullptr, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v0 }, nullptr, nullptr}, -{ "v1", nullptr, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v1 }, nullptr, nullptr}, -{ "v2", nullptr, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v2 }, nullptr, nullptr}, -{ "v3", nullptr, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v3 }, nullptr, nullptr}, -{ "v4", nullptr, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v4 }, nullptr, nullptr}, -{ "v5", nullptr, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v5 }, nullptr, nullptr}, -{ "v6", nullptr, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v6 }, nullptr, nullptr}, -{ "v7", nullptr, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v7 }, nullptr, nullptr}, -{ "v8", nullptr, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v8 }, nullptr, nullptr}, -{ "v9", nullptr, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v9 }, nullptr, nullptr}, -{ "v10", nullptr, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v10 }, nullptr, nullptr}, -{ "v11", nullptr, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v11 }, nullptr, nullptr}, -{ "v12", nullptr, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v12 }, nullptr, nullptr}, -{ "v13", nullptr, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v13 }, nullptr, nullptr}, -{ "v14", nullptr, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v14 }, nullptr, nullptr}, -{ "v15", nullptr, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v15 }, nullptr, nullptr}, -{ "v16", nullptr, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v16 }, nullptr, nullptr}, -{ "v17", nullptr, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v17 }, nullptr, nullptr}, -{ "v18", nullptr, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v18 }, nullptr, nullptr}, -{ "v19", nullptr, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v19 }, nullptr, nullptr}, -{ "v20", nullptr, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v20 }, nullptr, nullptr}, -{ "v21", nullptr, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v21 }, nullptr, nullptr}, -{ "v22", nullptr, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v22 }, nullptr, nullptr}, -{ "v23", nullptr, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v23 }, nullptr, nullptr}, -{ "v24", nullptr, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v24 }, nullptr, nullptr}, -{ "v25", nullptr, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v25 }, nullptr, nullptr}, -{ "v26", nullptr, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v26 }, nullptr, nullptr}, -{ "v27", nullptr, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v27 }, nullptr, nullptr}, -{ "v28", nullptr, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v28 }, nullptr, nullptr}, -{ "v29", nullptr, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v29 }, nullptr, nullptr}, -{ "v30", nullptr, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v30 }, nullptr, nullptr}, -{ "v31", nullptr, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v31 }, nullptr, nullptr}, +{ "v0", nullptr, 16, FPU_OFFSET(0), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v0, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v0 }, nullptr, nullptr, nullptr, 0}, +{ "v1", nullptr, 16, FPU_OFFSET(1), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v1, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v1 }, nullptr, nullptr, nullptr, 0}, +{ "v2", nullptr, 16, FPU_OFFSET(2), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v2, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v2 }, nullptr, nullptr, nullptr, 0}, +{ "v3", nullptr, 16, FPU_OFFSET(3), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v3, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v3 }, nullptr, nullptr, nullptr, 0}, +{ "v4", nullptr, 16, FPU_OFFSET(4), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v4, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v4 }, nullptr, nullptr, nullptr, 0}, +{ "v5", nullptr, 16, FPU_OFFSET(5), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v5, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v5 }, nullptr, nullptr, nullptr, 0}, +{ "v6", nullptr, 16, FPU_OFFSET(6), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v6, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v6 }, nullptr, nullptr, nullptr, 0}, +{ "v7", nullptr, 16, FPU_OFFSET(7), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v7, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v7 }, nullptr, nullptr, nullptr, 0}, +{ "v8", nullptr, 16, FPU_OFFSET(8), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v8, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v8 }, nullptr, nullptr, nullptr, 0}, +{ "v9", nullptr, 16, FPU_OFFSET(9), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v9, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v9 }, nullptr, nullptr, nullptr, 0}, +{ "v10", nullptr, 16, FPU_OFFSET(10), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v10, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v10 }, nullptr, nullptr, nullptr, 0}, +{ "v11", nullptr, 16, FPU_OFFSET(11), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v11, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v11 }, nullptr, nullptr, nullptr, 0}, +{ "v12", nullptr, 16, FPU_OFFSET(12), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v12, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v12 }, nullptr, nullptr, nullptr, 0}, +{ "v13", nullptr, 16, FPU_OFFSET(13), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v13, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v13 }, nullptr, nullptr, nullptr, 0}, +{ "v14", nullptr, 16, FPU_OFFSET(14), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v14, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v14 }, nullptr, nullptr, nullptr, 0}, +{ "v15", nullptr, 16, FPU_OFFSET(15), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v15, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v15 }, nullptr, nullptr, nullptr, 0}, +{ "v16", nullptr, 16, FPU_OFFSET(16), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v16, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v16 }, nullptr, nullptr, nullptr, 0}, +{ "v17", nullptr, 16, FPU_OFFSET(17), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v17, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v17 }, nullptr, nullptr, nullptr, 0}, +{ "v18", nullptr, 16, FPU_OFFSET(18), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v18, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v18 }, nullptr, nullptr, nullptr, 0}, +{ "v19", nullptr, 16, FPU_OFFSET(19), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v19, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v19 }, nullptr, nullptr, nullptr, 0}, +{ "v20", nullptr, 16, FPU_OFFSET(20), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v20, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v20 }, nullptr, nullptr, nullptr, 0}, +{ "v21", nullptr, 16, FPU_OFFSET(21), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v21, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v21 }, nullptr, nullptr, nullptr, 0}, +{ "v22", nullptr, 16, FPU_OFFSET(22), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v22, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v22 }, nullptr, nullptr, nullptr, 0}, +{ "v23", nullptr, 16, FPU_OFFSET(23), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v23, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v23 }, nullptr, nullptr, nullptr, 0}, +{ "v24", nullptr, 16, FPU_OFFSET(24), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v24, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v24 }, nullptr, nullptr, nullptr, 0}, +{ "v25", nullptr, 16, FPU_OFFSET(25), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v25, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v25 }, nullptr, nullptr, nullptr, 0}, +{ "v26", nullptr, 16, FPU_OFFSET(26), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v26, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v26 }, nullptr, nullptr, nullptr, 0}, +{ "v27", nullptr, 16, FPU_OFFSET(27), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v27, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v27 }, nullptr, nullptr, nullptr, 0}, +{ "v28", nullptr, 16, FPU_OFFSET(28), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v28, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v28 }, nullptr, nullptr, nullptr, 0}, +{ "v29", nullptr, 16, FPU_OFFSET(29), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v29, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v29 }, nullptr, nullptr, nullptr, 0}, +{ "v30", nullptr, 16, FPU_OFFSET(30), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v30, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v30 }, nullptr, nullptr, nullptr, 0}, +{ "v31", nullptr, 16, FPU_OFFSET(31), lldb::eEncodingVector, lldb::eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, arm64_dwarf::v31, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_v31 }, nullptr, nullptr, nullptr, 0}, -{ "fpsr", nullptr, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, nullptr, nullptr}, -{ "fpcr", nullptr, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, nullptr, nullptr}, +{ "fpsr", nullptr, 4, FPU_OFFSET_NAME(fpsr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpsr }, nullptr, nullptr, nullptr, 0}, +{ "fpcr", nullptr, 4, FPU_OFFSET_NAME(fpcr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpu_fpcr }, nullptr, nullptr, nullptr, 0}, -{ "far", nullptr, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, nullptr, nullptr}, -{ "esr", nullptr, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, nullptr, nullptr}, -{ "exception",nullptr, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, nullptr, nullptr}, +{ "far", nullptr, 8, EXC_OFFSET_NAME(far), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, nullptr, nullptr, nullptr, 0}, +{ "esr", nullptr, 4, EXC_OFFSET_NAME(esr), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_esr }, nullptr, nullptr, nullptr, 0}, +{ "exception",nullptr, 4, EXC_OFFSET_NAME(exception), lldb::eEncodingUint, lldb::eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, nullptr, nullptr, nullptr, 0}, { DEFINE_DBG (bvr, 0) }, { DEFINE_DBG (bvr, 1) }, { DEFINE_DBG (bvr, 2) }, { DEFINE_DBG (bvr, 3) }, { DEFINE_DBG (bvr, 4) }, { DEFINE_DBG (bvr, 5) }, { DEFINE_DBG (bvr, 6) }, { DEFINE_DBG (bvr, 7) }, { DEFINE_DBG (bvr, 8) }, { DEFINE_DBG (bvr, 9) }, { DEFINE_DBG (bvr, 10) }, { DEFINE_DBG (bvr, 11) }, { DEFINE_DBG (bvr, 12) }, { DEFINE_DBG (bvr, 13) }, { DEFINE_DBG (bvr, 14) }, { DEFINE_DBG (bvr, 15) }, { DEFINE_DBG (bcr, 0) }, { DEFINE_DBG (bcr, 1) }, { DEFINE_DBG (bcr, 2) }, { DEFINE_DBG (bcr, 3) }, { DEFINE_DBG (bcr, 4) }, { DEFINE_DBG (bcr, 5) }, { DEFINE_DBG (bcr, 6) }, { DEFINE_DBG (bcr, 7) }, { DEFINE_DBG (bcr, 8) }, { DEFINE_DBG (bcr, 9) }, { DEFINE_DBG (bcr, 10) }, { DEFINE_DBG (bcr, 11) }, { DEFINE_DBG (bcr, 12) }, { DEFINE_DBG (bcr, 13) }, { DEFINE_DBG (bcr, 14) }, { DEFINE_DBG (bcr, 15) }, { DEFINE_DBG (wvr, 0) }, { DEFINE_DBG (wvr, 1) }, { DEFINE_DBG (wvr, 2) }, { DEFINE_DBG (wvr, 3) }, { DEFINE_DBG (wvr, 4) }, { DEFINE_DBG (wvr, 5) }, { DEFINE_DBG (wvr, 6) }, { DEFINE_DBG (wvr, 7) }, { DEFINE_DBG (wvr, 8) }, { DEFINE_DBG (wvr, 9) }, { DEFINE_DBG (wvr, 10) }, { DEFINE_DBG (wvr, 11) }, { DEFINE_DBG (wvr, 12) }, { DEFINE_DBG (wvr, 13) }, { DEFINE_DBG (wvr, 14) }, { DEFINE_DBG (wvr, 15) }, { DEFINE_DBG (wcr, 0) }, { DEFINE_DBG (wcr, 1) }, { DEFINE_DBG (wcr, 2) }, { DEFINE_DBG (wcr, 3) }, { DEFINE_DBG (wcr, 4) }, { DEFINE_DBG (wcr, 5) }, { DEFINE_DBG (wcr, 6) }, { DEFINE_DBG (wcr, 7) }, { DEFINE_DBG (wcr, 8) }, { DEFINE_DBG (wcr, 9) }, { DEFINE_DBG (wcr, 10) }, { DEFINE_DBG (wcr, 11) }, { DEFINE_DBG (wcr, 12) }, { DEFINE_DBG (wcr, 13) }, { DEFINE_DBG (wcr, 14) }, { DEFINE_DBG (wcr, 15) } }; #endif // DECLARE_REGISTER_INFOS_ARM64_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_i386.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_i386.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_i386.h (revision 304308) @@ -1,222 +1,222 @@ //===-- RegisterInfos_i386.h ------------------------------------*- 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 // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_I386_STRUCT // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR, regname)) // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, i387) + \ LLVM_EXTENSION offsetof(FPR_i386, regname)) // Computes the offset of the YMM register assembled from register halves. // Based on DNBArchImplI386.cpp from debugserver #define YMM_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, i387) + \ LLVM_EXTENSION offsetof(FPR, xstate) + \ LLVM_EXTENSION offsetof(FXSAVE, xmm[7]) + \ sizeof(XMMReg) + (32 * reg_index)) // Number of bytes needed to represent a FPR. #if !defined(FPR_SIZE) #define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) #endif // Number of bytes needed to represent the i'th FP register. #define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) // Number of bytes needed to represent an XMM register. #define XMM_SIZE sizeof(XMMReg) // Number of bytes needed to represent a YMM register. #define YMM_SIZE sizeof(YMMReg) // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_i386 }, NULL, NULL, NULL, 0} #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_i386 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_i386 }, NULL, NULL, NULL, 0} // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB #define DEFINE_FP_ST(reg, i) \ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ { ehframe_st##i##_i386, dwarf_st##i##_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_st##i##_i386 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_FP_MM(reg, i) \ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingUint, eFormatHex, \ { ehframe_mm##i##_i386, dwarf_mm##i##_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_mm##i##_i386 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_XMM(reg, i) \ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ { ehframe_##reg##i##_i386, dwarf_##reg##i##_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg##i##_i386}, \ - NULL, NULL } + NULL, NULL, NULL, 0} // I believe the YMM registers use dwarf_xmm_%_i386 register numbers and then differentiate based on register size. #define DEFINE_YMM(reg, i) \ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \ eEncodingVector, eFormatVectorOfUInt8, \ { LLDB_INVALID_REGNUM, dwarf_xmm##i##_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg##i##_i386 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_DR(reg, i) \ { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL, NULL, 0} #define DEFINE_GPR_PSEUDO_16(reg16, reg32) \ { #reg16, NULL, 2, GPR_OFFSET(reg32), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32, NULL, 0} #define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \ { #reg8, NULL, 1, GPR_OFFSET(reg32)+1, eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32, NULL, 0} #define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \ { #reg8, NULL, 1, GPR_OFFSET(reg32), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_i386 }, RegisterContextPOSIX_x86::g_contained_##reg32, RegisterContextPOSIX_x86::g_invalidate_##reg32, NULL, 0} static RegisterInfo g_register_infos_i386[] = { // General purpose registers. DEFINE_GPR(eax, nullptr, ehframe_eax_i386, dwarf_eax_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ebx, nullptr, ehframe_ebx_i386, dwarf_ebx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ecx, nullptr, ehframe_ecx_i386, dwarf_ecx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(edx, nullptr, ehframe_edx_i386, dwarf_edx_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(edi, nullptr, ehframe_edi_i386, dwarf_edi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(esi, nullptr, ehframe_esi_i386, dwarf_esi_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ebp, "fp", ehframe_ebp_i386, dwarf_ebp_i386, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR(esp, "sp", ehframe_esp_i386, dwarf_esp_i386, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR(eip, "pc", ehframe_eip_i386, dwarf_eip_i386, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(eflags, "flags", ehframe_eflags_i386, dwarf_eflags_i386, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(cs, nullptr, LLDB_INVALID_REGNUM, dwarf_cs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(fs, nullptr, LLDB_INVALID_REGNUM, dwarf_fs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gs, nullptr, LLDB_INVALID_REGNUM, dwarf_gs_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ss, nullptr, LLDB_INVALID_REGNUM, dwarf_ss_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ds, nullptr, LLDB_INVALID_REGNUM, dwarf_ds_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(es, nullptr, LLDB_INVALID_REGNUM, dwarf_es_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR_PSEUDO_16(ax, eax), DEFINE_GPR_PSEUDO_16(bx, ebx), DEFINE_GPR_PSEUDO_16(cx, ecx), DEFINE_GPR_PSEUDO_16(dx, edx), DEFINE_GPR_PSEUDO_16(di, edi), DEFINE_GPR_PSEUDO_16(si, esi), DEFINE_GPR_PSEUDO_16(bp, ebp), DEFINE_GPR_PSEUDO_16(sp, esp), DEFINE_GPR_PSEUDO_8H(ah, eax), DEFINE_GPR_PSEUDO_8H(bh, ebx), DEFINE_GPR_PSEUDO_8H(ch, ecx), DEFINE_GPR_PSEUDO_8H(dh, edx), DEFINE_GPR_PSEUDO_8L(al, eax), DEFINE_GPR_PSEUDO_8L(bl, ebx), DEFINE_GPR_PSEUDO_8L(cl, ecx), DEFINE_GPR_PSEUDO_8L(dl, edx), // i387 Floating point registers. DEFINE_FPR(fctrl, fctrl, LLDB_INVALID_REGNUM, dwarf_fctrl_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fstat, fstat, LLDB_INVALID_REGNUM, dwarf_fstat_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsr, mxcsr, LLDB_INVALID_REGNUM, dwarf_mxcsr_i386, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), DEFINE_FP_MM(mm, 7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5), DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7), // Copy of YMM registers assembled from xmm and ymmh DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2), DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5), DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7), // Debug registers for lldb internal use DEFINE_DR(dr, 0), DEFINE_DR(dr, 1), DEFINE_DR(dr, 2), DEFINE_DR(dr, 3), DEFINE_DR(dr, 4), DEFINE_DR(dr, 5), DEFINE_DR(dr, 6), DEFINE_DR(dr, 7) }; static_assert((sizeof(g_register_infos_i386) / sizeof(g_register_infos_i386[0])) == k_num_registers_i386, "g_register_infos_x86_64 has wrong number of register infos"); #undef GPR_OFFSET #undef FPR_OFFSET #undef YMM_OFFSET #undef FPR_SIZE #undef FP_SIZE #undef XMM_SIZE #undef YMM_SIZE #undef DEFINE_GPR #undef DEFINE_FPR #undef DEFINE_FP #undef DEFINE_XMM #undef DEFINE_YMM #undef DEFINE_DR #undef DEFINE_GPR_PSEUDO_16 #undef DEFINE_GPR_PSEUDO_8H #undef DEFINE_GPR_PSEUDO_8L #endif // DECLARE_REGISTER_INFOS_I386_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips.h (revision 304308) @@ -1,187 +1,194 @@ //===-- RegisterInfos_mips.h -----------------------------------*- 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 // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" +#include "lldb/Core/dwarf.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS_STRUCT // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, gpr) + \ LLVM_EXTENSION offsetof(GPR_linux_mips, regname)) // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR_linux_mips, regname)) // Computes the offset of the given MSA in the extended data area. #define MSA_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, msa) + \ LLVM_EXTENSION offsetof(MSA_linux_mips, regname)) // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR_linux_mips*)NULL)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips }, NULL, NULL, NULL, 0} +const uint8_t dwarf_opcode_mips [] = { + llvm::dwarf::DW_OP_regx, dwarf_sr_mips, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr + }; + #define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL } + eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL, dwarf_opcode_mips, sizeof(dwarf_opcode_mips)} #define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)NULL)->reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips }, NULL, NULL, NULL, 0} #define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \ - eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL } + eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL, NULL, 0} #define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips }, NULL, NULL, NULL, 0} // RegisterKind: EH_Frame, DWARF, Generic, Procss Plugin, LLDB static RegisterInfo g_register_infos_mips[] = { DEFINE_GPR (zero, "zero", dwarf_zero_mips, dwarf_zero_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r1, "at", dwarf_r1_mips, dwarf_r1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r2, nullptr, dwarf_r2_mips, dwarf_r2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r3, nullptr, dwarf_r3_mips, dwarf_r3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r4, nullptr, dwarf_r4_mips, dwarf_r4_mips, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), DEFINE_GPR (r5, nullptr, dwarf_r5_mips, dwarf_r5_mips, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), DEFINE_GPR (r6, nullptr, dwarf_r6_mips, dwarf_r6_mips, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), DEFINE_GPR (r7, nullptr, dwarf_r7_mips, dwarf_r7_mips, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), DEFINE_GPR (r8, nullptr, dwarf_r8_mips, dwarf_r8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r9, nullptr, dwarf_r9_mips, dwarf_r9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r10, nullptr, dwarf_r10_mips, dwarf_r10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r11, nullptr, dwarf_r11_mips, dwarf_r11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r12, nullptr, dwarf_r12_mips, dwarf_r12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r13, nullptr, dwarf_r13_mips, dwarf_r13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r14, nullptr, dwarf_r14_mips, dwarf_r14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r15, nullptr, dwarf_r15_mips, dwarf_r15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r16, nullptr, dwarf_r16_mips, dwarf_r16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r17, nullptr, dwarf_r17_mips, dwarf_r17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r18, nullptr, dwarf_r18_mips, dwarf_r18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r19, nullptr, dwarf_r19_mips, dwarf_r19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r20, nullptr, dwarf_r20_mips, dwarf_r20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r21, nullptr, dwarf_r21_mips, dwarf_r21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r22, nullptr, dwarf_r22_mips, dwarf_r22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r23, nullptr, dwarf_r23_mips, dwarf_r23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r24, nullptr, dwarf_r24_mips, dwarf_r24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r25, nullptr, dwarf_r25_mips, dwarf_r25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r26, nullptr, dwarf_r26_mips, dwarf_r26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (r27, nullptr, dwarf_r27_mips, dwarf_r27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (gp, "gp", dwarf_gp_mips, dwarf_gp_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (sp, "sp", dwarf_sp_mips, dwarf_sp_mips, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR (r30, "fp", dwarf_r30_mips, dwarf_r30_mips, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR (ra, "ra", dwarf_ra_mips, dwarf_ra_mips, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), DEFINE_GPR (sr, "status", dwarf_sr_mips, dwarf_sr_mips, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR (mullo, nullptr, dwarf_lo_mips, dwarf_lo_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (mulhi, nullptr, dwarf_hi_mips, dwarf_hi_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (badvaddr, nullptr, dwarf_bad_mips, dwarf_bad_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (cause, nullptr, dwarf_cause_mips, dwarf_cause_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR (pc, nullptr, dwarf_pc_mips, dwarf_pc_mips, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f0, nullptr, dwarf_f0_mips, dwarf_f0_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f1, nullptr, dwarf_f1_mips, dwarf_f1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f2, nullptr, dwarf_f2_mips, dwarf_f2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f3, nullptr, dwarf_f3_mips, dwarf_f3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f4, nullptr, dwarf_f4_mips, dwarf_f4_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f5, nullptr, dwarf_f5_mips, dwarf_f5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f6, nullptr, dwarf_f6_mips, dwarf_f6_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f7, nullptr, dwarf_f7_mips, dwarf_f7_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f8, nullptr, dwarf_f8_mips, dwarf_f8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f9, nullptr, dwarf_f9_mips, dwarf_f9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f10, nullptr, dwarf_f10_mips, dwarf_f10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f11, nullptr, dwarf_f11_mips, dwarf_f11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f12, nullptr, dwarf_f12_mips, dwarf_f12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f13, nullptr, dwarf_f13_mips, dwarf_f13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f14, nullptr, dwarf_f14_mips, dwarf_f14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f15, nullptr, dwarf_f15_mips, dwarf_f15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f16, nullptr, dwarf_f16_mips, dwarf_f16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f17, nullptr, dwarf_f17_mips, dwarf_f17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f18, nullptr, dwarf_f18_mips, dwarf_f18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f19, nullptr, dwarf_f19_mips, dwarf_f19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f20, nullptr, dwarf_f20_mips, dwarf_f20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f21, nullptr, dwarf_f21_mips, dwarf_f21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f22, nullptr, dwarf_f22_mips, dwarf_f22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f23, nullptr, dwarf_f23_mips, dwarf_f23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f24, nullptr, dwarf_f24_mips, dwarf_f24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f25, nullptr, dwarf_f25_mips, dwarf_f25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f26, nullptr, dwarf_f26_mips, dwarf_f26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f27, nullptr, dwarf_f27_mips, dwarf_f27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f28, nullptr, dwarf_f28_mips, dwarf_f28_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f29, nullptr, dwarf_f29_mips, dwarf_f29_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f30, nullptr, dwarf_f30_mips, dwarf_f30_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f31, nullptr, dwarf_f31_mips, dwarf_f31_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w0, nullptr, dwarf_w0_mips, dwarf_w0_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w1, nullptr, dwarf_w1_mips, dwarf_w1_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w2, nullptr, dwarf_w2_mips, dwarf_w2_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w3, nullptr, dwarf_w3_mips, dwarf_w3_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w4, nullptr, dwarf_w4_mips, dwarf_w4_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w5, nullptr, dwarf_w5_mips, dwarf_w5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w6, nullptr, dwarf_w6_mips, dwarf_w6_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w7, nullptr, dwarf_w7_mips, dwarf_w7_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w8, nullptr, dwarf_w8_mips, dwarf_w8_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w9, nullptr, dwarf_w9_mips, dwarf_w9_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w10, nullptr, dwarf_w10_mips, dwarf_w10_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w11, nullptr, dwarf_w11_mips, dwarf_w11_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w12, nullptr, dwarf_w12_mips, dwarf_w12_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w13, nullptr, dwarf_w13_mips, dwarf_w13_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w14, nullptr, dwarf_w14_mips, dwarf_w14_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w15, nullptr, dwarf_w15_mips, dwarf_w15_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w16, nullptr, dwarf_w16_mips, dwarf_w16_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w17, nullptr, dwarf_w17_mips, dwarf_w17_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w18, nullptr, dwarf_w18_mips, dwarf_w18_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w19, nullptr, dwarf_w19_mips, dwarf_w19_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w20, nullptr, dwarf_w10_mips, dwarf_w20_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w21, nullptr, dwarf_w21_mips, dwarf_w21_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w22, nullptr, dwarf_w22_mips, dwarf_w22_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w23, nullptr, dwarf_w23_mips, dwarf_w23_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w24, nullptr, dwarf_w24_mips, dwarf_w24_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w25, nullptr, dwarf_w25_mips, dwarf_w25_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w26, nullptr, dwarf_w26_mips, dwarf_w26_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w27, nullptr, dwarf_w27_mips, dwarf_w27_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w28, nullptr, dwarf_w28_mips, dwarf_w28_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w29, nullptr, dwarf_w29_mips, dwarf_w29_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w30, nullptr, dwarf_w30_mips, dwarf_w30_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w31, nullptr, dwarf_w31_mips, dwarf_w31_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (mcsr, nullptr, dwarf_mcsr_mips, dwarf_mcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (mir, nullptr, dwarf_mir_mips, dwarf_mir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (fcsr, nullptr, dwarf_fcsr_mips, dwarf_fcsr_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (fir, nullptr, dwarf_fir_mips, dwarf_fir_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (config5, nullptr, dwarf_config5_mips, dwarf_config5_mips, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM) }; static_assert((sizeof(g_register_infos_mips) / sizeof(g_register_infos_mips[0])) == k_num_registers_mips, "g_register_infos_mips has wrong number of register infos"); #undef GPR_OFFSET #undef FPR_OFFSET #undef MSA_OFFSET #undef DEFINE_GPR #undef DEFINE_FPR #undef DEFINE_FPR_INFO #undef DEFINE_MSA #undef DEFINE_MSA_INFO #endif // DECLARE_REGISTER_INFOS_MIPS_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips64.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips64.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_mips64.h (revision 304308) @@ -1,247 +1,255 @@ //===-- RegisterInfos_mips64.h ----------------------------------*- 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 // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" +#include "lldb/Core/dwarf.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_MIPS64_STRUCT // Computes the offset of the given GPR in the user data area. #ifdef LINUX_MIPS64 #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, gpr) + \ LLVM_EXTENSION offsetof(GPR_linux_mips, regname)) #else #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR_freebsd_mips, regname)) #endif // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR_linux_mips, regname)) // Computes the offset of the given MSA in the extended data area. #define MSA_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, msa) + \ LLVM_EXTENSION offsetof(MSA_linux_mips, regname)) // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB // Note that the size and offset will be updated by platform-specific classes. #ifdef LINUX_MIPS64 #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} #else #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR_freebsd_mips*)0)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} #endif #define DEFINE_GPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR_linux_mips*)0)->reg) / 2, GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg##_mips64 }, NULL, NULL, NULL, 0} +const uint8_t dwarf_opcode_mips64 [] = { + llvm::dwarf::DW_OP_regx, dwarf_sr_mips64, llvm::dwarf::DW_OP_lit1, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shl, llvm::dwarf::DW_OP_and, + llvm::dwarf::DW_OP_lit26, llvm::dwarf::DW_OP_shr + }; + + #define DEFINE_FPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL } + eFormatFloat, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL, dwarf_opcode_mips64, sizeof(dwarf_opcode_mips64)} #define DEFINE_FPR_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((FPR_linux_mips*)0)->reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, fpr_##reg##_mips64 }, NULL, NULL, NULL, 0} #define DEFINE_MSA(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingVector, \ - eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL } + eFormatVectorOfUInt8, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL, NULL, 0} #define DEFINE_MSA_INFO(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((MSA_linux_mips*)0)->reg), MSA_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, msa_##reg##_mips64 }, NULL, NULL, NULL, 0} static RegisterInfo g_register_infos_mips64[] = { // General purpose registers. EH_Frame, DWARF, Generic, Process Plugin #ifndef LINUX_MIPS64 DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM), DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM), DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM), DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM), DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), DEFINE_GPR(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(ic, nullptr, dwarf_ic_mips64, dwarf_ic_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(dummy, nullptr, dwarf_dummy_mips64, dwarf_dummy_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), #else DEFINE_GPR(zero, "r0", dwarf_zero_mips64, dwarf_zero_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r1, nullptr, dwarf_r1_mips64, dwarf_r1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r2, nullptr, dwarf_r2_mips64, dwarf_r2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r3, nullptr, dwarf_r3_mips64, dwarf_r3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r4, nullptr, dwarf_r4_mips64, dwarf_r4_mips64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), DEFINE_GPR(r5, nullptr, dwarf_r5_mips64, dwarf_r5_mips64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), DEFINE_GPR(r6, nullptr, dwarf_r6_mips64, dwarf_r6_mips64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), DEFINE_GPR(r7, nullptr, dwarf_r7_mips64, dwarf_r7_mips64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), DEFINE_GPR(r8, nullptr, dwarf_r8_mips64, dwarf_r8_mips64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM), DEFINE_GPR(r9, nullptr, dwarf_r9_mips64, dwarf_r9_mips64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM), DEFINE_GPR(r10, nullptr, dwarf_r10_mips64, dwarf_r10_mips64, LLDB_REGNUM_GENERIC_ARG7, LLDB_INVALID_REGNUM), DEFINE_GPR(r11, nullptr, dwarf_r11_mips64, dwarf_r11_mips64, LLDB_REGNUM_GENERIC_ARG8, LLDB_INVALID_REGNUM), DEFINE_GPR(r12, nullptr, dwarf_r12_mips64, dwarf_r12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r13, nullptr, dwarf_r13_mips64, dwarf_r13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r14, nullptr, dwarf_r14_mips64, dwarf_r14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r15, nullptr, dwarf_r15_mips64, dwarf_r15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r16, nullptr, dwarf_r16_mips64, dwarf_r16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r17, nullptr, dwarf_r17_mips64, dwarf_r17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r18, nullptr, dwarf_r18_mips64, dwarf_r18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r19, nullptr, dwarf_r19_mips64, dwarf_r19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r20, nullptr, dwarf_r20_mips64, dwarf_r20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r21, nullptr, dwarf_r21_mips64, dwarf_r21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r22, nullptr, dwarf_r22_mips64, dwarf_r22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r23, nullptr, dwarf_r23_mips64, dwarf_r23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r24, nullptr, dwarf_r24_mips64, dwarf_r24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r25, nullptr, dwarf_r25_mips64, dwarf_r25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r26, nullptr, dwarf_r26_mips64, dwarf_r26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r27, nullptr, dwarf_r27_mips64, dwarf_r27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gp, "r28", dwarf_gp_mips64, dwarf_gp_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(sp, "r29", dwarf_sp_mips64, dwarf_sp_mips64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR(r30, nullptr, dwarf_r30_mips64, dwarf_r30_mips64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR(ra, "r31", dwarf_ra_mips64, dwarf_ra_mips64, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM), DEFINE_GPR_INFO(sr, nullptr, dwarf_sr_mips64, dwarf_sr_mips64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(mullo, nullptr, dwarf_lo_mips64, dwarf_lo_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(mulhi, nullptr, dwarf_hi_mips64, dwarf_hi_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(badvaddr, nullptr, dwarf_bad_mips64, dwarf_bad_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR_INFO(cause, nullptr, dwarf_cause_mips64, dwarf_cause_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(pc, "pc", dwarf_pc_mips64, dwarf_pc_mips64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR_INFO(config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f0, nullptr, dwarf_f0_mips64, dwarf_f0_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f1, nullptr, dwarf_f1_mips64, dwarf_f1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f2, nullptr, dwarf_f2_mips64, dwarf_f2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f3, nullptr, dwarf_f3_mips64, dwarf_f3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f4, nullptr, dwarf_f4_mips64, dwarf_f4_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f5, nullptr, dwarf_f5_mips64, dwarf_f5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f6, nullptr, dwarf_f6_mips64, dwarf_f6_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f7, nullptr, dwarf_f7_mips64, dwarf_f7_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f8, nullptr, dwarf_f8_mips64, dwarf_f8_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f9, nullptr, dwarf_f9_mips64, dwarf_f9_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f10, nullptr, dwarf_f10_mips64, dwarf_f10_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f11, nullptr, dwarf_f11_mips64, dwarf_f11_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f12, nullptr, dwarf_f12_mips64, dwarf_f12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f13, nullptr, dwarf_f13_mips64, dwarf_f13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f14, nullptr, dwarf_f14_mips64, dwarf_f14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f15, nullptr, dwarf_f15_mips64, dwarf_f15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f16, nullptr, dwarf_f16_mips64, dwarf_f16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f17, nullptr, dwarf_f17_mips64, dwarf_f17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f18, nullptr, dwarf_f18_mips64, dwarf_f18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f19, nullptr, dwarf_f19_mips64, dwarf_f19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f20, nullptr, dwarf_f20_mips64, dwarf_f20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f21, nullptr, dwarf_f21_mips64, dwarf_f21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f22, nullptr, dwarf_f22_mips64, dwarf_f22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f23, nullptr, dwarf_f23_mips64, dwarf_f23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f24, nullptr, dwarf_f24_mips64, dwarf_f24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f25, nullptr, dwarf_f25_mips64, dwarf_f25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f26, nullptr, dwarf_f26_mips64, dwarf_f26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f27, nullptr, dwarf_f27_mips64, dwarf_f27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f28, nullptr, dwarf_f28_mips64, dwarf_f28_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f29, nullptr, dwarf_f29_mips64, dwarf_f29_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f30, nullptr, dwarf_f30_mips64, dwarf_f30_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR (f31, nullptr, dwarf_f31_mips64, dwarf_f31_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR_INFO (config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w0, nullptr, dwarf_w0_mips64, dwarf_w0_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w1, nullptr, dwarf_w1_mips64, dwarf_w1_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w2, nullptr, dwarf_w2_mips64, dwarf_w2_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w3, nullptr, dwarf_w3_mips64, dwarf_w3_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w4, nullptr, dwarf_w4_mips64, dwarf_w4_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w5, nullptr, dwarf_w5_mips64, dwarf_w5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w6, nullptr, dwarf_w6_mips64, dwarf_w6_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w7, nullptr, dwarf_w7_mips64, dwarf_w7_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w8, nullptr, dwarf_w8_mips64, dwarf_w8_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w9, nullptr, dwarf_w9_mips64, dwarf_w9_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w10, nullptr, dwarf_w10_mips64, dwarf_w10_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w11, nullptr, dwarf_w11_mips64, dwarf_w11_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w12, nullptr, dwarf_w12_mips64, dwarf_w12_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w13, nullptr, dwarf_w13_mips64, dwarf_w13_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w14, nullptr, dwarf_w14_mips64, dwarf_w14_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w15, nullptr, dwarf_w15_mips64, dwarf_w15_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w16, nullptr, dwarf_w16_mips64, dwarf_w16_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w17, nullptr, dwarf_w17_mips64, dwarf_w17_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w18, nullptr, dwarf_w18_mips64, dwarf_w18_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w19, nullptr, dwarf_w19_mips64, dwarf_w19_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w20, nullptr, dwarf_w10_mips64, dwarf_w20_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w21, nullptr, dwarf_w21_mips64, dwarf_w21_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w22, nullptr, dwarf_w22_mips64, dwarf_w22_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w23, nullptr, dwarf_w23_mips64, dwarf_w23_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w24, nullptr, dwarf_w24_mips64, dwarf_w24_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w25, nullptr, dwarf_w25_mips64, dwarf_w25_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w26, nullptr, dwarf_w26_mips64, dwarf_w26_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w27, nullptr, dwarf_w27_mips64, dwarf_w27_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w28, nullptr, dwarf_w28_mips64, dwarf_w28_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w29, nullptr, dwarf_w29_mips64, dwarf_w29_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w30, nullptr, dwarf_w30_mips64, dwarf_w30_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA (w31, nullptr, dwarf_w31_mips64, dwarf_w31_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (mcsr, nullptr, dwarf_mcsr_mips64, dwarf_mcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (mir, nullptr, dwarf_mir_mips64, dwarf_mir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (fcsr, nullptr, dwarf_fcsr_mips64, dwarf_fcsr_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (fir, nullptr, dwarf_fir_mips64, dwarf_fir_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_MSA_INFO (config5, nullptr, dwarf_config5_mips64, dwarf_config5_mips64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM) #endif }; static_assert((sizeof(g_register_infos_mips64) / sizeof(g_register_infos_mips64[0])) == k_num_registers_mips64, "g_register_infos_mips64 has wrong number of register infos"); #undef DEFINE_GPR #undef DEFINE_GPR_INFO #undef DEFINE_FPR #undef DEFINE_FPR_INFO #undef DEFINE_MSA #undef DEFINE_MSA_INFO #undef GPR_OFFSET #undef FPR_OFFSET #undef MSA_OFFSET #endif // DECLARE_REGISTER_INFOS_MIPS64_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_powerpc.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_powerpc.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_powerpc.h (revision 304308) @@ -1,184 +1,184 @@ //===-- RegisterInfos_powerpc.h ---------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===---------------------------------------------------------------------===// #include // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (offsetof(GPR, regname)) #define FPR_OFFSET(regname) \ (offsetof(FPR, regname)) #define VMX_OFFSET(regname) \ (offsetof(VMX, regname)) #define GPR_SIZE(regname) \ (sizeof(((GPR*)NULL)->regname)) #ifdef DECLARE_REGISTER_INFOS_POWERPC_STRUCT // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, lldb_kind) \ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, gpr_##reg##_powerpc }, NULL, NULL } + eFormatHex, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, gpr_##reg##_powerpc }, NULL, NULL, NULL, 0} #define DEFINE_FPR(reg, lldb_kind) \ { #reg, NULL, 8, FPR_OFFSET(reg), eEncodingIEEE754, \ - eFormatFloat, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, fpr_##reg##_powerpc }, NULL, NULL } + eFormatFloat, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, fpr_##reg##_powerpc }, NULL, NULL, NULL, 0} #define DEFINE_VMX(reg, lldb_kind) \ { #reg, NULL, 16, VMX_OFFSET(reg), eEncodingVector, \ - eFormatVectorOfUInt32, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, vmx_##reg##_powerpc }, NULL, NULL } + eFormatVectorOfUInt32, { dwarf_##reg##_powerpc, dwarf_##reg##_powerpc, lldb_kind, LLDB_INVALID_REGNUM, vmx_##reg##_powerpc }, NULL, NULL, NULL, 0} // General purpose registers. EH_Frame, DWARF, Generic, Process Plugin #define POWERPC_REGS \ DEFINE_GPR(r0, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r1, "sp", LLDB_REGNUM_GENERIC_SP), \ DEFINE_GPR(r2, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r3, "arg1",LLDB_REGNUM_GENERIC_ARG1), \ DEFINE_GPR(r4, "arg2",LLDB_REGNUM_GENERIC_ARG2), \ DEFINE_GPR(r5, "arg3",LLDB_REGNUM_GENERIC_ARG3), \ DEFINE_GPR(r6, "arg4",LLDB_REGNUM_GENERIC_ARG4), \ DEFINE_GPR(r7, "arg5",LLDB_REGNUM_GENERIC_ARG5), \ DEFINE_GPR(r8, "arg6",LLDB_REGNUM_GENERIC_ARG6), \ DEFINE_GPR(r9, "arg7",LLDB_REGNUM_GENERIC_ARG7), \ DEFINE_GPR(r10, "arg8",LLDB_REGNUM_GENERIC_ARG8), \ DEFINE_GPR(r11, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r12, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r13, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r14, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r15, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r16, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r17, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r18, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r19, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r20, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r21, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r22, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r23, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r24, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r25, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r26, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r27, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r28, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r29, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r30, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(r31, NULL, LLDB_INVALID_REGNUM), \ DEFINE_GPR(lr, "lr", LLDB_REGNUM_GENERIC_RA), \ DEFINE_GPR(cr, "cr", LLDB_REGNUM_GENERIC_FLAGS), \ DEFINE_GPR(xer, "xer", LLDB_INVALID_REGNUM), \ DEFINE_GPR(ctr, "ctr", LLDB_INVALID_REGNUM), \ DEFINE_GPR(pc, "pc", LLDB_REGNUM_GENERIC_PC), \ DEFINE_FPR(f0, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f1, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f2, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f3, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f4, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f5, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f6, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f7, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f8, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f9, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f10, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f11, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f12, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f13, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f14, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f15, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f16, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f17, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f18, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f19, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f20, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f21, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f22, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f23, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f24, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f25, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f26, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f27, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f28, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f29, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f30, LLDB_INVALID_REGNUM), \ DEFINE_FPR(f31, LLDB_INVALID_REGNUM), \ { "fpscr", NULL, 8, FPR_OFFSET(fpscr), eEncodingUint, eFormatHex, { dwarf_fpscr_powerpc, dwarf_fpscr_powerpc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, fpr_fpscr_powerpc }, NULL, NULL }, \ DEFINE_VMX(v0, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v1, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v2, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v3, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v4, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v5, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v6, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v7, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v8, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v9, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v10, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v11, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v12, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v13, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v14, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v15, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v16, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v17, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v18, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v19, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v20, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v21, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v22, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v23, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v24, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v25, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v26, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v27, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v28, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v29, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v30, LLDB_INVALID_REGNUM), \ DEFINE_VMX(v31, LLDB_INVALID_REGNUM), \ - { "vrsave", NULL, 4, VMX_OFFSET(vrsave), eEncodingUint, eFormatHex, { dwarf_vrsave_powerpc, dwarf_vrsave_powerpc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vrsave_powerpc }, NULL, NULL }, \ - { "vscr", NULL, 4, VMX_OFFSET(vscr), eEncodingUint, eFormatHex, { dwarf_vscr_powerpc, dwarf_vscr_powerpc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vscr_powerpc }, NULL, NULL }, + { "vrsave", NULL, 4, VMX_OFFSET(vrsave), eEncodingUint, eFormatHex, { dwarf_vrsave_powerpc, dwarf_vrsave_powerpc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vrsave_powerpc }, NULL, NULL, NULL, 0}, \ + { "vscr", NULL, 4, VMX_OFFSET(vscr), eEncodingUint, eFormatHex, { dwarf_vscr_powerpc, dwarf_vscr_powerpc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, vmx_vscr_powerpc }, NULL, NULL, NULL, 0}, static RegisterInfo g_register_infos_powerpc64[] = { #define GPR GPR64 POWERPC_REGS #undef GPR }; static RegisterInfo g_register_infos_powerpc32[] = { #define GPR GPR32 POWERPC_REGS #undef GPR }; static RegisterInfo g_register_infos_powerpc64_32[] = { #define GPR GPR64 #undef GPR_SIZE #define GPR_SIZE(reg) (sizeof(uint32_t)) #undef GPR_OFFSET #define GPR_OFFSET(regname) \ (offsetof(GPR, regname) + (sizeof(((GPR *)NULL)->regname) - GPR_SIZE(reg))) POWERPC_REGS #undef GPR }; static_assert((sizeof(g_register_infos_powerpc32) / sizeof(g_register_infos_powerpc32[0])) == k_num_registers_powerpc, "g_register_infos_powerpc32 has wrong number of register infos"); static_assert((sizeof(g_register_infos_powerpc64) / sizeof(g_register_infos_powerpc64[0])) == k_num_registers_powerpc, "g_register_infos_powerpc64 has wrong number of register infos"); static_assert(sizeof(g_register_infos_powerpc64_32) == sizeof(g_register_infos_powerpc64), "g_register_infos_powerpc64_32 doesn't match size of g_register_infos_powerpc64"); #undef DEFINE_FPR #undef DEFINE_GPR #endif // DECLARE_REGISTER_INFOS_POWERPC_STRUCT #undef GPR_OFFSET Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_s390x.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_s390x.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_s390x.h (revision 304308) @@ -1,132 +1,132 @@ //===-- RegisterInfos_s390x.h -----------------------------------*- 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 // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" // Project includes #ifdef DECLARE_REGISTER_INFOS_S390X_STRUCT // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(num) (16 + 8 * num) // Computes the offset of the given ACR in the user data area. #define ACR_OFFSET(num) (16 + 8 * 16 + 4 * num) // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(num) (8 + 8 * num) // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB #define DEFINE_GPR(name, size, offset, alt, generic) \ { \ #name, alt, size, offset, eEncodingUint, eFormatHex, \ { dwarf_##name##_s390x, dwarf_##name##_s390x, generic, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ - NULL, NULL, \ + NULL, NULL, NULL, 0 \ } #define DEFINE_GPR_NODWARF(name, size, offset, alt, generic) \ { \ #name, alt, size, offset, eEncodingUint, eFormatHex, \ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, generic, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ - NULL, NULL, \ + NULL, NULL, NULL, 0 \ } #define DEFINE_FPR(name, size, offset) \ { \ #name, NULL, size, offset, eEncodingUint, eFormatHex, \ { dwarf_##name##_s390x, dwarf_##name##_s390x, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ - NULL, NULL, \ + NULL, NULL, NULL, 0 \ } #define DEFINE_FPR_NODWARF(name, size, offset) \ { \ #name, NULL, size, offset, eEncodingUint, eFormatHex, \ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##name##_s390x }, \ - NULL, NULL, \ + NULL, NULL, NULL, 0 \ } static RegisterInfo g_register_infos_s390x[] = { // General purpose registers. DEFINE_GPR(r0, 8, GPR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r1, 8, GPR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r2, 8, GPR_OFFSET(2), "arg1", LLDB_REGNUM_GENERIC_ARG1), DEFINE_GPR(r3, 8, GPR_OFFSET(3), "arg2", LLDB_REGNUM_GENERIC_ARG2), DEFINE_GPR(r4, 8, GPR_OFFSET(4), "arg3", LLDB_REGNUM_GENERIC_ARG3), DEFINE_GPR(r5, 8, GPR_OFFSET(5), "arg4", LLDB_REGNUM_GENERIC_ARG4), DEFINE_GPR(r6, 8, GPR_OFFSET(6), "arg5", LLDB_REGNUM_GENERIC_ARG5), DEFINE_GPR(r7, 8, GPR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r8, 8, GPR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r9, 8, GPR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r10, 8, GPR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r11, 8, GPR_OFFSET(11), "fp", LLDB_REGNUM_GENERIC_FP), DEFINE_GPR(r12, 8, GPR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r13, 8, GPR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r14, 8, GPR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(r15, 8, GPR_OFFSET(15), "sp", LLDB_REGNUM_GENERIC_SP), DEFINE_GPR(acr0, 4, ACR_OFFSET(0), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr1, 4, ACR_OFFSET(1), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr2, 4, ACR_OFFSET(2), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr3, 4, ACR_OFFSET(3), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr4, 4, ACR_OFFSET(4), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr5, 4, ACR_OFFSET(5), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr6, 4, ACR_OFFSET(6), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr7, 4, ACR_OFFSET(7), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr8, 4, ACR_OFFSET(8), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr9, 4, ACR_OFFSET(9), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr10, 4, ACR_OFFSET(10), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr11, 4, ACR_OFFSET(11), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr12, 4, ACR_OFFSET(12), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr13, 4, ACR_OFFSET(13), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr14, 4, ACR_OFFSET(14), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(acr15, 4, ACR_OFFSET(15), nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR(pswm, 8, 0, "flags", LLDB_REGNUM_GENERIC_FLAGS), DEFINE_GPR(pswa, 8, 8, "pc", LLDB_REGNUM_GENERIC_PC), // Floating point registers. DEFINE_FPR(f0, 8, FPR_OFFSET(0)), DEFINE_FPR(f1, 8, FPR_OFFSET(1)), DEFINE_FPR(f2, 8, FPR_OFFSET(2)), DEFINE_FPR(f3, 8, FPR_OFFSET(3)), DEFINE_FPR(f4, 8, FPR_OFFSET(4)), DEFINE_FPR(f5, 8, FPR_OFFSET(5)), DEFINE_FPR(f6, 8, FPR_OFFSET(6)), DEFINE_FPR(f7, 8, FPR_OFFSET(7)), DEFINE_FPR(f8, 8, FPR_OFFSET(8)), DEFINE_FPR(f9, 8, FPR_OFFSET(9)), DEFINE_FPR(f10, 8, FPR_OFFSET(10)), DEFINE_FPR(f11, 8, FPR_OFFSET(11)), DEFINE_FPR(f12, 8, FPR_OFFSET(12)), DEFINE_FPR(f13, 8, FPR_OFFSET(13)), DEFINE_FPR(f14, 8, FPR_OFFSET(14)), DEFINE_FPR(f15, 8, FPR_OFFSET(15)), DEFINE_FPR_NODWARF(fpc, 4, 0), // Linux operating-specific info. DEFINE_GPR_NODWARF(orig_r2, 8, 16 + 16 * 8 + 16 * 4, nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR_NODWARF(last_break, 8, 0, nullptr, LLDB_INVALID_REGNUM), DEFINE_GPR_NODWARF(system_call, 4, 0, nullptr, LLDB_INVALID_REGNUM), }; static_assert((sizeof(g_register_infos_s390x) / sizeof(g_register_infos_s390x[0])) == k_num_registers_s390x, "g_register_infos_s390x has wrong number of register infos"); #undef GPR_OFFSET #undef ACR_OFFSET #undef FPR_OFFSET #undef DEFINE_GPR #undef DEFINE_GPR_NODWARF #undef DEFINE_FPR #undef DEFINE_FPR_NODWARF #endif // DECLARE_REGISTER_INFOS_S390X_STRUCT Index: vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_x86_64.h =================================================================== --- vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_x86_64.h (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/Utility/RegisterInfos_x86_64.h (revision 304308) @@ -1,424 +1,424 @@ //===-- RegisterInfos_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. // //===----------------------------------------------------------------------===// // C Includes #include // C++ Includes // Other libraries and framework includes #include "llvm/Support/Compiler.h" // Project includes // Computes the offset of the given GPR in the user data area. #define GPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(GPR, regname)) // Computes the offset of the given FPR in the extended data area. #define FPR_OFFSET(regname) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xstate) + \ LLVM_EXTENSION offsetof(FXSAVE, regname)) // Computes the offset of the YMM register assembled from register halves. // Based on DNBArchImplX86_64.cpp from debugserver #define YMM_OFFSET(reg_index) \ (LLVM_EXTENSION offsetof(UserArea, fpr) + \ LLVM_EXTENSION offsetof(FPR, xstate) + \ LLVM_EXTENSION offsetof(XSAVE, ymmh[0]) + \ (32 * reg_index)) #ifdef DECLARE_REGISTER_INFOS_X86_64_STRUCT // Number of bytes needed to represent a FPR. #define FPR_SIZE(reg) sizeof(((FXSAVE*)NULL)->reg) // Number of bytes needed to represent the i'th FP register. #define FP_SIZE sizeof(((MMSReg*)NULL)->bytes) // Number of bytes needed to represent an XMM register. #define XMM_SIZE sizeof(XMMReg) // Number of bytes needed to represent a YMM register. #define YMM_SIZE sizeof(YMMReg) #define DR_SIZE sizeof(((DBG*)NULL)->dr[0]) // RegisterKind: EHFrame, DWARF, Generic, Process Plugin, LLDB // Note that the size and offset will be updated by platform-specific classes. #define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \ { #reg, alt, sizeof(((GPR*)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##reg##_x86_64 }, NULL, NULL, NULL, 0} #define DEFINE_FPR(name, reg, kind1, kind2, kind3, kind4) \ { #name, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \ - eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, NULL, NULL } + eFormatHex, { kind1, kind2, kind3, kind4, lldb_##name##_x86_64 }, NULL, NULL, NULL, 0} #define DEFINE_FP_ST(reg, i) \ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ { dwarf_st##i##_x86_64, dwarf_st##i##_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_st##i##_x86_64 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_FP_MM(reg, i) \ { #reg#i, NULL, sizeof(uint64_t), LLVM_EXTENSION FPR_OFFSET(stmm[i]), \ eEncodingUint, eFormatHex, \ { dwarf_mm##i##_x86_64, dwarf_mm##i##_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_mm##i##_x86_64 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_XMM(reg, i) \ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \ eEncodingVector, eFormatVectorOfUInt8, \ { dwarf_##reg##i##_x86_64, dwarf_##reg##i##_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg##i##_x86_64}, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_YMM(reg, i) \ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(i), \ eEncodingVector, eFormatVectorOfUInt8, \ { dwarf_##reg##i##h_x86_64, dwarf_##reg##i##h_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg##i##_x86_64 }, \ - NULL, NULL } + NULL, NULL, NULL, 0} #define DEFINE_DR(reg, i) \ { #reg#i, NULL, DR_SIZE, DR_OFFSET(i), eEncodingUint, eFormatHex, \ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \ - LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL } + LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL, NULL, 0} #define DEFINE_GPR_PSEUDO_32(reg32, reg64) \ { #reg32, NULL, 4, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg32##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64, NULL, 0} #define DEFINE_GPR_PSEUDO_16(reg16, reg64) \ { #reg16, NULL, 2, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg16##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64, NULL, 0} #define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \ { #reg8, NULL, 1, GPR_OFFSET(reg64)+1, eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64, NULL, 0} #define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \ { #reg8, NULL, 1, GPR_OFFSET(reg64), eEncodingUint, \ - eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64 } + eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, lldb_##reg8##_x86_64 }, RegisterContextPOSIX_x86::g_contained_##reg64, RegisterContextPOSIX_x86::g_invalidate_##reg64, NULL, 0} static RegisterInfo g_register_infos_x86_64[] = { // General purpose registers. EH_Frame, DWARF, Generic, Process Plugin DEFINE_GPR(rax, nullptr, dwarf_rax_x86_64, dwarf_rax_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(rbx, nullptr, dwarf_rbx_x86_64, dwarf_rbx_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(rcx, "arg4", dwarf_rcx_x86_64, dwarf_rcx_x86_64, LLDB_REGNUM_GENERIC_ARG4, LLDB_INVALID_REGNUM), DEFINE_GPR(rdx, "arg3", dwarf_rdx_x86_64, dwarf_rdx_x86_64, LLDB_REGNUM_GENERIC_ARG3, LLDB_INVALID_REGNUM), DEFINE_GPR(rdi, "arg1", dwarf_rdi_x86_64, dwarf_rdi_x86_64, LLDB_REGNUM_GENERIC_ARG1, LLDB_INVALID_REGNUM), DEFINE_GPR(rsi, "arg2", dwarf_rsi_x86_64, dwarf_rsi_x86_64, LLDB_REGNUM_GENERIC_ARG2, LLDB_INVALID_REGNUM), DEFINE_GPR(rbp, "fp", dwarf_rbp_x86_64, dwarf_rbp_x86_64, LLDB_REGNUM_GENERIC_FP, LLDB_INVALID_REGNUM), DEFINE_GPR(rsp, "sp", dwarf_rsp_x86_64, dwarf_rsp_x86_64, LLDB_REGNUM_GENERIC_SP, LLDB_INVALID_REGNUM), DEFINE_GPR(r8, "arg5", dwarf_r8_x86_64, dwarf_r8_x86_64, LLDB_REGNUM_GENERIC_ARG5, LLDB_INVALID_REGNUM), DEFINE_GPR(r9, "arg6", dwarf_r9_x86_64, dwarf_r9_x86_64, LLDB_REGNUM_GENERIC_ARG6, LLDB_INVALID_REGNUM), DEFINE_GPR(r10, nullptr, dwarf_r10_x86_64, dwarf_r10_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r11, nullptr, dwarf_r11_x86_64, dwarf_r11_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r12, nullptr, dwarf_r12_x86_64, dwarf_r12_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r13, nullptr, dwarf_r13_x86_64, dwarf_r13_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r14, nullptr, dwarf_r14_x86_64, dwarf_r14_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(r15, nullptr, dwarf_r15_x86_64, dwarf_r15_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(rip, "pc", dwarf_rip_x86_64, dwarf_rip_x86_64, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM), DEFINE_GPR(rflags, "flags", dwarf_rflags_x86_64, dwarf_rflags_x86_64, LLDB_REGNUM_GENERIC_FLAGS, LLDB_INVALID_REGNUM), DEFINE_GPR(cs, nullptr, dwarf_cs_x86_64, dwarf_cs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(fs, nullptr, dwarf_fs_x86_64, dwarf_fs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(gs, nullptr, dwarf_gs_x86_64, dwarf_gs_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ss, nullptr, dwarf_ss_x86_64, dwarf_ss_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(ds, nullptr, dwarf_ds_x86_64, dwarf_ds_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR(es, nullptr, dwarf_es_x86_64, dwarf_es_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_GPR_PSEUDO_32(eax, rax), DEFINE_GPR_PSEUDO_32(ebx, rbx), DEFINE_GPR_PSEUDO_32(ecx, rcx), DEFINE_GPR_PSEUDO_32(edx, rdx), DEFINE_GPR_PSEUDO_32(edi, rdi), DEFINE_GPR_PSEUDO_32(esi, rsi), DEFINE_GPR_PSEUDO_32(ebp, rbp), DEFINE_GPR_PSEUDO_32(esp, rsp), DEFINE_GPR_PSEUDO_32(r8d, r8), DEFINE_GPR_PSEUDO_32(r9d, r9), DEFINE_GPR_PSEUDO_32(r10d, r10), DEFINE_GPR_PSEUDO_32(r11d, r11), DEFINE_GPR_PSEUDO_32(r12d, r12), DEFINE_GPR_PSEUDO_32(r13d, r13), DEFINE_GPR_PSEUDO_32(r14d, r14), DEFINE_GPR_PSEUDO_32(r15d, r15), DEFINE_GPR_PSEUDO_16(ax, rax), DEFINE_GPR_PSEUDO_16(bx, rbx), DEFINE_GPR_PSEUDO_16(cx, rcx), DEFINE_GPR_PSEUDO_16(dx, rdx), DEFINE_GPR_PSEUDO_16(di, rdi), DEFINE_GPR_PSEUDO_16(si, rsi), DEFINE_GPR_PSEUDO_16(bp, rbp), DEFINE_GPR_PSEUDO_16(sp, rsp), DEFINE_GPR_PSEUDO_16(r8w, r8), DEFINE_GPR_PSEUDO_16(r9w, r9), DEFINE_GPR_PSEUDO_16(r10w, r10), DEFINE_GPR_PSEUDO_16(r11w, r11), DEFINE_GPR_PSEUDO_16(r12w, r12), DEFINE_GPR_PSEUDO_16(r13w, r13), DEFINE_GPR_PSEUDO_16(r14w, r14), DEFINE_GPR_PSEUDO_16(r15w, r15), DEFINE_GPR_PSEUDO_8H(ah, rax), DEFINE_GPR_PSEUDO_8H(bh, rbx), DEFINE_GPR_PSEUDO_8H(ch, rcx), DEFINE_GPR_PSEUDO_8H(dh, rdx), DEFINE_GPR_PSEUDO_8L(al, rax), DEFINE_GPR_PSEUDO_8L(bl, rbx), DEFINE_GPR_PSEUDO_8L(cl, rcx), DEFINE_GPR_PSEUDO_8L(dl, rdx), DEFINE_GPR_PSEUDO_8L(dil, rdi), DEFINE_GPR_PSEUDO_8L(sil, rsi), DEFINE_GPR_PSEUDO_8L(bpl, rbp), DEFINE_GPR_PSEUDO_8L(spl, rsp), DEFINE_GPR_PSEUDO_8L(r8l, r8), DEFINE_GPR_PSEUDO_8L(r9l, r9), DEFINE_GPR_PSEUDO_8L(r10l, r10), DEFINE_GPR_PSEUDO_8L(r11l, r11), DEFINE_GPR_PSEUDO_8L(r12l, r12), DEFINE_GPR_PSEUDO_8L(r13l, r13), DEFINE_GPR_PSEUDO_8L(r14l, r14), DEFINE_GPR_PSEUDO_8L(r15l, r15), // i387 Floating point registers. EH_frame, DWARF, Generic, Process Plugin DEFINE_FPR(fctrl, fctrl, dwarf_fctrl_x86_64, dwarf_fctrl_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fstat, fstat, dwarf_fstat_x86_64, dwarf_fstat_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(ftag, ftag, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fop, fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fiseg, ptr.i386_.fiseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fioff, ptr.i386_.fioff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(foseg, ptr.i386_.foseg, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(fooff, ptr.i386_.fooff, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsr, mxcsr, dwarf_mxcsr_x86_64, dwarf_mxcsr_x86_64, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), DEFINE_FPR(mxcsrmask, mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM), // FP registers. DEFINE_FP_ST(st, 0), DEFINE_FP_ST(st, 1), DEFINE_FP_ST(st, 2), DEFINE_FP_ST(st, 3), DEFINE_FP_ST(st, 4), DEFINE_FP_ST(st, 5), DEFINE_FP_ST(st, 6), DEFINE_FP_ST(st, 7), DEFINE_FP_MM(mm, 0), DEFINE_FP_MM(mm, 1), DEFINE_FP_MM(mm, 2), DEFINE_FP_MM(mm, 3), DEFINE_FP_MM(mm, 4), DEFINE_FP_MM(mm, 5), DEFINE_FP_MM(mm, 6), DEFINE_FP_MM(mm, 7), // XMM registers DEFINE_XMM(xmm, 0), DEFINE_XMM(xmm, 1), DEFINE_XMM(xmm, 2), DEFINE_XMM(xmm, 3), DEFINE_XMM(xmm, 4), DEFINE_XMM(xmm, 5), DEFINE_XMM(xmm, 6), DEFINE_XMM(xmm, 7), DEFINE_XMM(xmm, 8), DEFINE_XMM(xmm, 9), DEFINE_XMM(xmm, 10), DEFINE_XMM(xmm, 11), DEFINE_XMM(xmm, 12), DEFINE_XMM(xmm, 13), DEFINE_XMM(xmm, 14), DEFINE_XMM(xmm, 15), // Copy of YMM registers assembled from xmm and ymmh DEFINE_YMM(ymm, 0), DEFINE_YMM(ymm, 1), DEFINE_YMM(ymm, 2), DEFINE_YMM(ymm, 3), DEFINE_YMM(ymm, 4), DEFINE_YMM(ymm, 5), DEFINE_YMM(ymm, 6), DEFINE_YMM(ymm, 7), DEFINE_YMM(ymm, 8), DEFINE_YMM(ymm, 9), DEFINE_YMM(ymm, 10), DEFINE_YMM(ymm, 11), DEFINE_YMM(ymm, 12), DEFINE_YMM(ymm, 13), DEFINE_YMM(ymm, 14), DEFINE_YMM(ymm, 15), // Debug registers for lldb internal use DEFINE_DR(dr, 0), DEFINE_DR(dr, 1), DEFINE_DR(dr, 2), DEFINE_DR(dr, 3), DEFINE_DR(dr, 4), DEFINE_DR(dr, 5), DEFINE_DR(dr, 6), DEFINE_DR(dr, 7) }; static_assert((sizeof(g_register_infos_x86_64) / sizeof(g_register_infos_x86_64[0])) == k_num_registers_x86_64, "g_register_infos_x86_64 has wrong number of register infos"); #undef FPR_SIZE #undef FP_SIZE #undef XMM_SIZE #undef YMM_SIZE #undef DEFINE_GPR #undef DEFINE_FPR #undef DEFINE_FP #undef DEFINE_XMM #undef DEFINE_YMM #undef DEFINE_DR #undef DEFINE_GPR_PSEUDO_32 #undef DEFINE_GPR_PSEUDO_16 #undef DEFINE_GPR_PSEUDO_8H #undef DEFINE_GPR_PSEUDO_8L #endif // DECLARE_REGISTER_INFOS_X86_64_STRUCT #ifdef UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS #define UPDATE_GPR_INFO(reg, reg64) \ do { \ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64); \ } while(false); #define UPDATE_GPR_INFO_8H(reg, reg64) \ do { \ g_register_infos[lldb_##reg##_i386].byte_offset = GPR_OFFSET(reg64) + 1; \ } while(false); #define UPDATE_FPR_INFO(reg, reg64) \ do { \ g_register_infos[lldb_##reg##_i386].byte_offset = FPR_OFFSET(reg64); \ } while(false); #define UPDATE_FP_INFO(reg, i) \ do { \ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(stmm[i]); \ } while(false); #define UPDATE_XMM_INFO(reg, i) \ do { \ g_register_infos[lldb_##reg##i##_i386].byte_offset = FPR_OFFSET(reg[i]); \ } while(false); #define UPDATE_YMM_INFO(reg, i) \ do { \ g_register_infos[lldb_##reg##i##_i386].byte_offset = YMM_OFFSET(i); \ } while(false); #define UPDATE_DR_INFO(reg_index) \ do { \ g_register_infos[lldb_dr##reg_index##_i386].byte_offset = DR_OFFSET(reg_index); \ } while(false); // Update the register offsets UPDATE_GPR_INFO(eax, rax); UPDATE_GPR_INFO(ebx, rbx); UPDATE_GPR_INFO(ecx, rcx); UPDATE_GPR_INFO(edx, rdx); UPDATE_GPR_INFO(edi, rdi); UPDATE_GPR_INFO(esi, rsi); UPDATE_GPR_INFO(ebp, rbp); UPDATE_GPR_INFO(esp, rsp); UPDATE_GPR_INFO(eip, rip); UPDATE_GPR_INFO(eflags, rflags); UPDATE_GPR_INFO(cs, cs); UPDATE_GPR_INFO(fs, fs); UPDATE_GPR_INFO(gs, gs); UPDATE_GPR_INFO(ss, ss); UPDATE_GPR_INFO(ds, ds); UPDATE_GPR_INFO(es, es); UPDATE_GPR_INFO(ax, rax); UPDATE_GPR_INFO(bx, rbx); UPDATE_GPR_INFO(cx, rcx); UPDATE_GPR_INFO(dx, rdx); UPDATE_GPR_INFO(di, rdi); UPDATE_GPR_INFO(si, rsi); UPDATE_GPR_INFO(bp, rbp); UPDATE_GPR_INFO(sp, rsp); UPDATE_GPR_INFO_8H(ah, rax); UPDATE_GPR_INFO_8H(bh, rbx); UPDATE_GPR_INFO_8H(ch, rcx); UPDATE_GPR_INFO_8H(dh, rdx); UPDATE_GPR_INFO(al, rax); UPDATE_GPR_INFO(bl, rbx); UPDATE_GPR_INFO(cl, rcx); UPDATE_GPR_INFO(dl, rdx); UPDATE_FPR_INFO(fctrl, fctrl); UPDATE_FPR_INFO(fstat, fstat); UPDATE_FPR_INFO(ftag, ftag); UPDATE_FPR_INFO(fop, fop); UPDATE_FPR_INFO(fiseg, ptr.i386_.fiseg); UPDATE_FPR_INFO(fioff, ptr.i386_.fioff); UPDATE_FPR_INFO(fooff, ptr.i386_.fooff); UPDATE_FPR_INFO(foseg, ptr.i386_.foseg); UPDATE_FPR_INFO(mxcsr, mxcsr); UPDATE_FPR_INFO(mxcsrmask, mxcsrmask); UPDATE_FP_INFO(st, 0); UPDATE_FP_INFO(st, 1); UPDATE_FP_INFO(st, 2); UPDATE_FP_INFO(st, 3); UPDATE_FP_INFO(st, 4); UPDATE_FP_INFO(st, 5); UPDATE_FP_INFO(st, 6); UPDATE_FP_INFO(st, 7); UPDATE_FP_INFO(mm, 0); UPDATE_FP_INFO(mm, 1); UPDATE_FP_INFO(mm, 2); UPDATE_FP_INFO(mm, 3); UPDATE_FP_INFO(mm, 4); UPDATE_FP_INFO(mm, 5); UPDATE_FP_INFO(mm, 6); UPDATE_FP_INFO(mm, 7); UPDATE_XMM_INFO(xmm, 0); UPDATE_XMM_INFO(xmm, 1); UPDATE_XMM_INFO(xmm, 2); UPDATE_XMM_INFO(xmm, 3); UPDATE_XMM_INFO(xmm, 4); UPDATE_XMM_INFO(xmm, 5); UPDATE_XMM_INFO(xmm, 6); UPDATE_XMM_INFO(xmm, 7); UPDATE_YMM_INFO(ymm, 0); UPDATE_YMM_INFO(ymm, 1); UPDATE_YMM_INFO(ymm, 2); UPDATE_YMM_INFO(ymm, 3); UPDATE_YMM_INFO(ymm, 4); UPDATE_YMM_INFO(ymm, 5); UPDATE_YMM_INFO(ymm, 6); UPDATE_YMM_INFO(ymm, 7); UPDATE_DR_INFO(0); UPDATE_DR_INFO(1); UPDATE_DR_INFO(2); UPDATE_DR_INFO(3); UPDATE_DR_INFO(4); UPDATE_DR_INFO(5); UPDATE_DR_INFO(6); UPDATE_DR_INFO(7); #undef UPDATE_GPR_INFO #undef UPDATE_GPR_INFO_8H #undef UPDATE_FPR_INFO #undef UPDATE_FP_INFO #undef UPDATE_XMM_INFO #undef UPDATE_YMM_INFO #undef UPDATE_DR_INFO #endif // UPDATE_REGISTER_INFOS_I386_STRUCT_WITH_X86_64_OFFSETS #undef GPR_OFFSET #undef FPR_OFFSET #undef YMM_OFFSET Index: vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp (revision 304308) @@ -1,2982 +1,2993 @@ //===-- GDBRemoteCommunicationServerLLGS.cpp --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include #include "lldb/Host/Config.h" #include "GDBRemoteCommunicationServerLLGS.h" #include "lldb/Core/StreamGDBRemote.h" // C Includes // C++ Includes #include #include #include // Other libraries and framework includes #include "llvm/ADT/Triple.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/DataBuffer.h" #include "lldb/Core/Log.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamString.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/Debug.h" #include "lldb/Host/Endian.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostInfo.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/TimeValue.h" #include "lldb/Target/FileAction.h" #include "lldb/Target/MemoryRegionInfo.h" #include "lldb/Host/common/NativeRegisterContext.h" #include "lldb/Host/common/NativeProcessProtocol.h" #include "lldb/Host/common/NativeThreadProtocol.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/LLDBAssert.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" #include "Utility/UriParser.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; using namespace llvm; //---------------------------------------------------------------------- // GDBRemote Errors //---------------------------------------------------------------------- namespace { enum GDBRemoteServerError { // Set to the first unused error number in literal form below eErrorFirst = 29, eErrorNoProcess = eErrorFirst, eErrorResume, eErrorExitStatus }; } //---------------------------------------------------------------------- // GDBRemoteCommunicationServerLLGS constructor //---------------------------------------------------------------------- GDBRemoteCommunicationServerLLGS::GDBRemoteCommunicationServerLLGS(MainLoop &mainloop) : GDBRemoteCommunicationServerCommon("gdb-remote.server", "gdb-remote.server.rx_packet"), m_mainloop(mainloop), m_current_tid(LLDB_INVALID_THREAD_ID), m_continue_tid(LLDB_INVALID_THREAD_ID), m_debugged_process_mutex(), m_debugged_process_sp(), m_stdio_communication("process.stdio"), m_inferior_prev_state(StateType::eStateInvalid), m_active_auxv_buffer_sp(), m_saved_registers_mutex(), m_saved_registers_map(), m_next_saved_registers_id(1), m_handshake_completed(false) { RegisterPacketHandlers(); } void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() { RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_C, &GDBRemoteCommunicationServerLLGS::Handle_C); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_c, &GDBRemoteCommunicationServerLLGS::Handle_c); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_D, &GDBRemoteCommunicationServerLLGS::Handle_D); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_H, &GDBRemoteCommunicationServerLLGS::Handle_H); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_I, &GDBRemoteCommunicationServerLLGS::Handle_I); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_interrupt, &GDBRemoteCommunicationServerLLGS::Handle_interrupt); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_m, &GDBRemoteCommunicationServerLLGS::Handle_memory_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_M, &GDBRemoteCommunicationServerLLGS::Handle_M); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_p, &GDBRemoteCommunicationServerLLGS::Handle_p); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_P, &GDBRemoteCommunicationServerLLGS::Handle_P); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qC, &GDBRemoteCommunicationServerLLGS::Handle_qC); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qfThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qFileLoadAddress, &GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qGetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfo, &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qMemoryRegionInfoSupported, &GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qProcessInfo, &GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qRegisterInfo, &GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QRestoreRegisterState, &GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSaveRegisterState, &GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR, &GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir, &GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qsThreadInfo, &GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qThreadStopInfo, &GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_jThreadsInfo, &GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qWatchpointSupportInfo, &GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qXfer_auxv_read, &GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_s, &GDBRemoteCommunicationServerLLGS::Handle_s); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_stop_reason, &GDBRemoteCommunicationServerLLGS::Handle_stop_reason); // ? RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vAttach, &GDBRemoteCommunicationServerLLGS::Handle_vAttach); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont, &GDBRemoteCommunicationServerLLGS::Handle_vCont); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_vCont_actions, &GDBRemoteCommunicationServerLLGS::Handle_vCont_actions); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_x, &GDBRemoteCommunicationServerLLGS::Handle_memory_read); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_Z, &GDBRemoteCommunicationServerLLGS::Handle_Z); RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z, &GDBRemoteCommunicationServerLLGS::Handle_z); RegisterPacketHandler(StringExtractorGDBRemote::eServerPacketType_k, [this](StringExtractorGDBRemote packet, Error &error, bool &interrupt, bool &quit) { quit = true; return this->Handle_k (packet); }); } Error GDBRemoteCommunicationServerLLGS::SetLaunchArguments (const char *const args[], int argc) { if ((argc < 1) || !args || !args[0] || !args[0][0]) return Error ("%s: no process command line specified to launch", __FUNCTION__); m_process_launch_info.SetArguments (const_cast (args), true); return Error (); } Error GDBRemoteCommunicationServerLLGS::SetLaunchFlags (unsigned int launch_flags) { m_process_launch_info.GetFlags ().Set (launch_flags); return Error (); } Error GDBRemoteCommunicationServerLLGS::LaunchProcess () { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) return Error ("%s: no process command line specified to launch", __FUNCTION__); Error error; { std::lock_guard guard(m_debugged_process_mutex); assert (!m_debugged_process_sp && "lldb-gdbserver creating debugged process but one already exists"); error = NativeProcessProtocol::Launch( m_process_launch_info, *this, m_mainloop, m_debugged_process_sp); } if (!error.Success ()) { fprintf (stderr, "%s: failed to launch executable %s", __FUNCTION__, m_process_launch_info.GetArguments ().GetArgumentAtIndex (0)); return error; } // Handle mirroring of inferior stdout/stderr over the gdb-remote protocol // as needed. // llgs local-process debugging may specify PTY paths, which will make these // file actions non-null // process launch -i/e/o will also make these file actions non-null // nullptr means that the traffic is expected to flow over gdb-remote protocol if ( m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr ) { // nullptr means it's not redirected to file or pty (in case of LLGS local) // at least one of stdio will be transferred pty<->gdb-remote // we need to give the pty master handle to this object to read and/or write if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " setting up stdout/stderr redirection via $O gdb-remote commands", __FUNCTION__, m_debugged_process_sp->GetID ()); // Setup stdout/stderr mapping from inferior to $O auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); if (terminal_fd >= 0) { if (log) log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); error = SetSTDIOFileDescriptor (terminal_fd); if (error.Fail ()) return error; } else { if (log) log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); } } else { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " skipping stdout/stderr redirection via $O: inferior will communicate over client-provided file descriptors", __FUNCTION__, m_debugged_process_sp->GetID ()); } printf ("Launched '%s' as process %" PRIu64 "...\n", m_process_launch_info.GetArguments ().GetArgumentAtIndex (0), m_process_launch_info.GetProcessID ()); return error; } Error GDBRemoteCommunicationServerLLGS::AttachToProcess (lldb::pid_t pid) { Error error; Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64, __FUNCTION__, pid); // Before we try to attach, make sure we aren't already monitoring something else. if (m_debugged_process_sp && m_debugged_process_sp->GetID() != LLDB_INVALID_PROCESS_ID) return Error("cannot attach to a process %" PRIu64 " when another process with pid %" PRIu64 " is being debugged.", pid, m_debugged_process_sp->GetID()); // Try to attach. error = NativeProcessProtocol::Attach(pid, *this, m_mainloop, m_debugged_process_sp); if (!error.Success ()) { fprintf (stderr, "%s: failed to attach to process %" PRIu64 ": %s", __FUNCTION__, pid, error.AsCString ()); return error; } // Setup stdout/stderr mapping from inferior. auto terminal_fd = m_debugged_process_sp->GetTerminalFileDescriptor (); if (terminal_fd >= 0) { if (log) log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s setting inferior STDIO fd to %d", __FUNCTION__, terminal_fd); error = SetSTDIOFileDescriptor (terminal_fd); if (error.Fail ()) return error; } else { if (log) log->Printf ("ProcessGDBRemoteCommunicationServerLLGS::%s ignoring inferior STDIO since terminal fd reported as %d", __FUNCTION__, terminal_fd); } printf ("Attached to process %" PRIu64 "...\n", pid); return error; } void GDBRemoteCommunicationServerLLGS::InitializeDelegate (NativeProcessProtocol *process) { assert (process && "process cannot be NULL"); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", current state: %s", __FUNCTION__, process->GetID (), StateAsCString (process->GetState ())); } } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendWResponse (NativeProcessProtocol *process) { assert (process && "process cannot be NULL"); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // send W notification ExitType exit_type = ExitType::eExitTypeInvalid; int return_code = 0; std::string exit_description; const bool got_exit_info = process->GetExitStatus (&exit_type, &return_code, exit_description); if (!got_exit_info) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", failed to retrieve process exit status", __FUNCTION__, process->GetID ()); StreamGDBRemote response; response.PutChar ('E'); response.PutHex8 (GDBRemoteServerError::eErrorExitStatus); return SendPacketNoLock(response.GetData(), response.GetSize()); } else { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", returning exit type %d, return code %d [%s]", __FUNCTION__, process->GetID (), exit_type, return_code, exit_description.c_str ()); StreamGDBRemote response; char return_type_code; switch (exit_type) { case ExitType::eExitTypeExit: return_type_code = 'W'; break; case ExitType::eExitTypeSignal: return_type_code = 'X'; break; case ExitType::eExitTypeStop: return_type_code = 'S'; break; case ExitType::eExitTypeInvalid: return_type_code = 'E'; break; } response.PutChar (return_type_code); // POSIX exit status limited to unsigned 8 bits. response.PutHex8 (return_code); return SendPacketNoLock(response.GetData(), response.GetSize()); } } static void AppendHexValue (StreamString &response, const uint8_t* buf, uint32_t buf_size, bool swap) { int64_t i; if (swap) { for (i = buf_size-1; i >= 0; i--) response.PutHex8 (buf[i]); } else { for (i = 0; i < buf_size; i++) response.PutHex8 (buf[i]); } } static void WriteRegisterValueInHexFixedWidth (StreamString &response, NativeRegisterContextSP ®_ctx_sp, const RegisterInfo ®_info, const RegisterValue *reg_value_p) { RegisterValue reg_value; if (!reg_value_p) { Error error = reg_ctx_sp->ReadRegister (®_info, reg_value); if (error.Success ()) reg_value_p = ®_value; // else log. } if (reg_value_p) { AppendHexValue (response, (const uint8_t*) reg_value_p->GetBytes (), reg_value_p->GetByteSize (), false); } else { // Zero-out any unreadable values. if (reg_info.byte_size > 0) { std::basic_string zeros(reg_info.byte_size, '\0'); AppendHexValue (response, zeros.data(), zeros.size(), false); } } } static JSONObject::SP GetRegistersAsJSON(NativeThreadProtocol &thread, bool abridged) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); NativeRegisterContextSP reg_ctx_sp = thread.GetRegisterContext (); if (! reg_ctx_sp) return nullptr; JSONObject::SP register_object_sp = std::make_shared(); #ifdef LLDB_JTHREADSINFO_FULL_REGISTER_SET // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. const RegisterSet *reg_set_p = reg_ctx_sp->GetRegisterSet(0); if (! reg_set_p) return nullptr; for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { uint32_t reg_num = *reg_num_p; #else // Expedite only a couple of registers until we figure out why sending registers is // expensive. static const uint32_t k_expedited_registers[] = { LLDB_REGNUM_GENERIC_PC, LLDB_REGNUM_GENERIC_SP, LLDB_REGNUM_GENERIC_FP, LLDB_REGNUM_GENERIC_RA, LLDB_INVALID_REGNUM }; static const uint32_t k_abridged_expedited_registers[] = { LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_REGNUM }; for (const uint32_t *generic_reg_p = abridged ? k_abridged_expedited_registers : k_expedited_registers; *generic_reg_p != LLDB_INVALID_REGNUM; ++generic_reg_p) { uint32_t reg_num = reg_ctx_sp->ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, *generic_reg_p); if (reg_num == LLDB_INVALID_REGNUM) continue; // Target does not support the given register. #endif const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex(reg_num); if (reg_info_p == nullptr) { if (log) log->Printf("%s failed to get register info for register index %" PRIu32, __FUNCTION__, reg_num); continue; } if (reg_info_p->value_regs != nullptr) continue; // Only expedite registers that are not contained in other registers. RegisterValue reg_value; Error error = reg_ctx_sp->ReadRegister(reg_info_p, reg_value); if (error.Fail()) { if (log) log->Printf("%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "", reg_num, error.AsCString ()); continue; } StreamString stream; WriteRegisterValueInHexFixedWidth(stream, reg_ctx_sp, *reg_info_p, ®_value); register_object_sp->SetObject(std::to_string(reg_num), std::make_shared(stream.GetString())); } return register_object_sp; } static const char * GetStopReasonString(StopReason stop_reason) { switch (stop_reason) { case eStopReasonTrace: return "trace"; case eStopReasonBreakpoint: return "breakpoint"; case eStopReasonWatchpoint: return "watchpoint"; case eStopReasonSignal: return "signal"; case eStopReasonException: return "exception"; case eStopReasonExec: return "exec"; case eStopReasonInstrumentation: case eStopReasonInvalid: case eStopReasonPlanComplete: case eStopReasonThreadExiting: case eStopReasonNone: break; // ignored } return nullptr; } static JSONArray::SP GetJSONThreadsInfo(NativeProcessProtocol &process, bool abridged) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); JSONArray::SP threads_array_sp = std::make_shared(); // Ensure we can get info on the given thread. uint32_t thread_idx = 0; for ( NativeThreadProtocolSP thread_sp; (thread_sp = process.GetThreadAtIndex(thread_idx)) != nullptr; ++thread_idx) { lldb::tid_t tid = thread_sp->GetID(); // Grab the reason this thread stopped. struct ThreadStopInfo tid_stop_info; std::string description; if (!thread_sp->GetStopReason (tid_stop_info, description)) return nullptr; const int signum = tid_stop_info.details.signal.signo; if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, __FUNCTION__, process.GetID (), tid, signum, tid_stop_info.reason, tid_stop_info.details.exception.type); } JSONObject::SP thread_obj_sp = std::make_shared(); threads_array_sp->AppendObject(thread_obj_sp); if (JSONObject::SP registers_sp = GetRegistersAsJSON(*thread_sp, abridged)) thread_obj_sp->SetObject("registers", registers_sp); thread_obj_sp->SetObject("tid", std::make_shared(tid)); if (signum != 0) thread_obj_sp->SetObject("signal", std::make_shared(signum)); const std::string thread_name = thread_sp->GetName (); if (! thread_name.empty()) thread_obj_sp->SetObject("name", std::make_shared(thread_name)); if (const char *stop_reason_str = GetStopReasonString(tid_stop_info.reason)) thread_obj_sp->SetObject("reason", std::make_shared(stop_reason_str)); if (! description.empty()) thread_obj_sp->SetObject("description", std::make_shared(description)); if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) { thread_obj_sp->SetObject("metype", std::make_shared(tid_stop_info.details.exception.type)); JSONArray::SP medata_array_sp = std::make_shared(); for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) { medata_array_sp->AppendObject(std::make_shared( tid_stop_info.details.exception.data[i])); } thread_obj_sp->SetObject("medata", medata_array_sp); } // TODO: Expedite interesting regions of inferior memory } return threads_array_sp; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendStopReplyPacketForThread (lldb::tid_t tid) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse (50); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64 " tid %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID (), tid); // Ensure we can get info on the given thread. NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); if (!thread_sp) return SendErrorResponse (51); // Grab the reason this thread stopped. struct ThreadStopInfo tid_stop_info; std::string description; if (!thread_sp->GetStopReason (tid_stop_info, description)) return SendErrorResponse (52); // FIXME implement register handling for exec'd inferiors. // if (tid_stop_info.reason == eStopReasonExec) // { // const bool force = true; // InitializeRegisters(force); // } StreamString response; // Output the T packet with the thread response.PutChar ('T'); int signum = tid_stop_info.details.signal.signo; if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " got signal signo = %d, reason = %d, exc_type = %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID (), tid, signum, tid_stop_info.reason, tid_stop_info.details.exception.type); } // Print the signal number. response.PutHex8 (signum & 0xff); // Include the tid. response.Printf ("thread:%" PRIx64 ";", tid); // Include the thread name if there is one. const std::string thread_name = thread_sp->GetName (); if (!thread_name.empty ()) { size_t thread_name_len = thread_name.length (); if (::strcspn (thread_name.c_str (), "$#+-;:") == thread_name_len) { response.PutCString ("name:"); response.PutCString (thread_name.c_str ()); } else { // The thread name contains special chars, send as hex bytes. response.PutCString ("hexname:"); response.PutCStringAsRawHex8 (thread_name.c_str ()); } response.PutChar (';'); } // If a 'QListThreadsInStopReply' was sent to enable this feature, we // will send all thread IDs back in the "threads" key whose value is // a list of hex thread IDs separated by commas: // "threads:10a,10b,10c;" // This will save the debugger from having to send a pair of qfThreadInfo // and qsThreadInfo packets, but it also might take a lot of room in the // stop reply packet, so it must be enabled only on systems where there // are no limits on packet lengths. if (m_list_threads_in_stop_reply) { response.PutCString ("threads:"); uint32_t thread_index = 0; NativeThreadProtocolSP listed_thread_sp; for (listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); listed_thread_sp; ++thread_index, listed_thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) { if (thread_index > 0) response.PutChar (','); response.Printf ("%" PRIx64, listed_thread_sp->GetID ()); } response.PutChar (';'); // Include JSON info that describes the stop reason for any threads // that actually have stop reasons. We use the new "jstopinfo" key // whose values is hex ascii JSON that contains the thread IDs // thread stop info only for threads that have stop reasons. Only send // this if we have more than one thread otherwise this packet has all // the info it needs. if (thread_index > 0) { const bool threads_with_valid_stop_info_only = true; JSONArray::SP threads_info_sp = GetJSONThreadsInfo(*m_debugged_process_sp, threads_with_valid_stop_info_only); if (threads_info_sp) { response.PutCString("jstopinfo:"); StreamString unescaped_response; threads_info_sp->Write(unescaped_response); response.PutCStringAsRawHex8(unescaped_response.GetData()); response.PutChar(';'); } else if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a jstopinfo field for pid %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID()); } } // // Expedite registers. // // Grab the register context. NativeRegisterContextSP reg_ctx_sp = thread_sp->GetRegisterContext (); if (reg_ctx_sp) { // Expedite all registers in the first register set (i.e. should be GPRs) that are not contained in other registers. const RegisterSet *reg_set_p; if (reg_ctx_sp->GetRegisterSetCount () > 0 && ((reg_set_p = reg_ctx_sp->GetRegisterSet (0)) != nullptr)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s expediting registers from set '%s' (registers set count: %zu)", __FUNCTION__, reg_set_p->name ? reg_set_p->name : "", reg_set_p->num_registers); for (const uint32_t *reg_num_p = reg_set_p->registers; *reg_num_p != LLDB_INVALID_REGNUM; ++reg_num_p) { const RegisterInfo *const reg_info_p = reg_ctx_sp->GetRegisterInfoAtIndex (*reg_num_p); if (reg_info_p == nullptr) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get register info for register set '%s', register index %" PRIu32, __FUNCTION__, reg_set_p->name ? reg_set_p->name : "", *reg_num_p); } else if (reg_info_p->value_regs == nullptr) { // Only expediate registers that are not contained in other registers. RegisterValue reg_value; Error error = reg_ctx_sp->ReadRegister (reg_info_p, reg_value); if (error.Success ()) { response.Printf ("%.02x:", *reg_num_p); WriteRegisterValueInHexFixedWidth(response, reg_ctx_sp, *reg_info_p, ®_value); response.PutChar (';'); } else { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to read register '%s' index %" PRIu32 ": %s", __FUNCTION__, reg_info_p->name ? reg_info_p->name : "", *reg_num_p, error.AsCString ()); } } } } } const char* reason_str = GetStopReasonString(tid_stop_info.reason); if (reason_str != nullptr) { response.Printf ("reason:%s;", reason_str); } if (!description.empty()) { // Description may contains special chars, send as hex bytes. response.PutCString ("description:"); response.PutCStringAsRawHex8 (description.c_str ()); response.PutChar (';'); } else if ((tid_stop_info.reason == eStopReasonException) && tid_stop_info.details.exception.type) { response.PutCString ("metype:"); response.PutHex64 (tid_stop_info.details.exception.type); response.PutCString (";mecount:"); response.PutHex32 (tid_stop_info.details.exception.data_count); response.PutChar (';'); for (uint32_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) { response.PutCString ("medata:"); response.PutHex64 (tid_stop_info.details.exception.data[i]); response.PutChar (';'); } } return SendPacketNoLock (response.GetData(), response.GetSize()); } void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Exited (NativeProcessProtocol *process) { assert (process && "process cannot be NULL"); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); PacketResult result = SendStopReasonForState(StateType::eStateExited); if (result != PacketResult::Success) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); } // Close the pipe to the inferior terminal i/o if we launched it // and set one up. MaybeCloseInferiorTerminalConnection (); // We are ready to exit the debug monitor. m_exit_now = true; } void GDBRemoteCommunicationServerLLGS::HandleInferiorState_Stopped (NativeProcessProtocol *process) { assert (process && "process cannot be NULL"); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Send the stop reason unless this is the stop after the // launch or attach. switch (m_inferior_prev_state) { case eStateLaunching: case eStateAttaching: // Don't send anything per debugserver behavior. break; default: // In all other cases, send the stop reason. PacketResult result = SendStopReasonForState(StateType::eStateStopped); if (result != PacketResult::Success) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send stop notification for PID %" PRIu64 ", state: eStateExited", __FUNCTION__, process->GetID ()); } break; } } void GDBRemoteCommunicationServerLLGS::ProcessStateChanged (NativeProcessProtocol *process, lldb::StateType state) { assert (process && "process cannot be NULL"); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s called with NativeProcessProtocol pid %" PRIu64 ", state: %s", __FUNCTION__, process->GetID (), StateAsCString (state)); } switch (state) { case StateType::eStateRunning: StartSTDIOForwarding(); break; case StateType::eStateStopped: // Make sure we get all of the pending stdout/stderr from the inferior // and send it to the lldb host before we send the state change // notification SendProcessOutput(); // Then stop the forwarding, so that any late output (see llvm.org/pr25652) does not // interfere with our protocol. StopSTDIOForwarding(); HandleInferiorState_Stopped (process); break; case StateType::eStateExited: // Same as above SendProcessOutput(); StopSTDIOForwarding(); HandleInferiorState_Exited (process); break; default: if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s didn't handle state change for pid %" PRIu64 ", new state: %s", __FUNCTION__, process->GetID (), StateAsCString (state)); } break; } // Remember the previous state reported to us. m_inferior_prev_state = state; } void GDBRemoteCommunicationServerLLGS::DidExec (NativeProcessProtocol *process) { ClearProcessSpecificData (); } void GDBRemoteCommunicationServerLLGS::DataAvailableCallback () { Log *log (GetLogIfAnyCategoriesSet(GDBR_LOG_COMM)); if (! m_handshake_completed) { if (! HandshakeWithClient()) { if(log) log->Printf("GDBRemoteCommunicationServerLLGS::%s handshake with client failed, exiting", __FUNCTION__); m_mainloop.RequestTermination(); return; } m_handshake_completed = true; } bool interrupt = false; bool done = false; Error error; while (true) { const PacketResult result = GetPacketAndSendResponse (0, error, interrupt, done); if (result == PacketResult::ErrorReplyTimeout) break; // No more packets in the queue if ((result != PacketResult::Success)) { if(log) log->Printf("GDBRemoteCommunicationServerLLGS::%s processing a packet failed: %s", __FUNCTION__, error.AsCString()); m_mainloop.RequestTermination(); break; } } } Error GDBRemoteCommunicationServerLLGS::InitializeConnection (std::unique_ptr &&connection) { IOObjectSP read_object_sp = connection->GetReadObject(); GDBRemoteCommunicationServer::SetConnection(connection.release()); Error error; m_network_handle_up = m_mainloop.RegisterReadObject(read_object_sp, [this] (MainLoopBase &) { DataAvailableCallback(); }, error); return error; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendONotification (const char *buffer, uint32_t len) { if ((buffer == nullptr) || (len == 0)) { // Nothing to send. return PacketResult::Success; } StreamString response; response.PutChar ('O'); response.PutBytesAsRawHex8 (buffer, len); return SendPacketNoLock (response.GetData (), response.GetSize ()); } Error GDBRemoteCommunicationServerLLGS::SetSTDIOFileDescriptor (int fd) { Error error; // Set up the reading/handling of process I/O std::unique_ptr conn_up (new ConnectionFileDescriptor (fd, true)); if (!conn_up) { error.SetErrorString ("failed to create ConnectionFileDescriptor"); return error; } m_stdio_communication.SetCloseOnEOF (false); m_stdio_communication.SetConnection (conn_up.release()); if (!m_stdio_communication.IsConnected ()) { error.SetErrorString ("failed to set connection for inferior I/O communication"); return error; } return Error(); } void GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() { // Don't forward if not connected (e.g. when attaching). if (! m_stdio_communication.IsConnected()) return; // llgs local-process debugging may specify PTY paths, which will make these // file actions non-null // process launch -e/o will also make these file actions non-null // nullptr means that the traffic is expected to flow over gdb-remote protocol if ( m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) && m_process_launch_info.GetFileActionForFD(STDERR_FILENO)) return; Error error; lldbassert(! m_stdio_handle_up); m_stdio_handle_up = m_mainloop.RegisterReadObject( m_stdio_communication.GetConnection()->GetReadObject(), [this] (MainLoopBase &) { SendProcessOutput(); }, error); if (! m_stdio_handle_up) { // Not much we can do about the failure. Log it and continue without forwarding. if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to set up stdio forwarding: %s", __FUNCTION__, error.AsCString()); } } void GDBRemoteCommunicationServerLLGS::StopSTDIOForwarding() { m_stdio_handle_up.reset(); } void GDBRemoteCommunicationServerLLGS::SendProcessOutput() { char buffer[1024]; ConnectionStatus status; Error error; while (true) { size_t bytes_read = m_stdio_communication.Read(buffer, sizeof buffer, 0, status, &error); switch (status) { case eConnectionStatusSuccess: SendONotification(buffer, bytes_read); break; case eConnectionStatusLostConnection: case eConnectionStatusEndOfFile: case eConnectionStatusError: case eConnectionStatusNoConnection: if (Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)) log->Printf("GDBRemoteCommunicationServerLLGS::%s Stopping stdio forwarding as communication returned status %d (error: %s)", __FUNCTION__, status, error.AsCString()); m_stdio_handle_up.reset(); return; case eConnectionStatusInterrupted: case eConnectionStatusTimedOut: return; } } } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qProcessInfo (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse (68); lldb::pid_t pid = m_debugged_process_sp->GetID (); if (pid == LLDB_INVALID_PROCESS_ID) return SendErrorResponse (1); ProcessInstanceInfo proc_info; if (!Host::GetProcessInfo (pid, proc_info)) return SendErrorResponse (1); StreamString response; CreateProcessInfoResponse_DebugServerStyle(proc_info, response); return SendPacketNoLock (response.GetData (), response.GetSize ()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qC (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse (68); // Make sure we set the current thread so g and p packets return // the data the gdb will expect. lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); SetCurrentThreadID (tid); NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetCurrentThread (); if (!thread_sp) return SendErrorResponse (69); StreamString response; response.Printf ("QC%" PRIx64, thread_sp->GetID ()); return SendPacketNoLock (response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_k (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); StopSTDIOForwarding(); if (! m_debugged_process_sp) { if (log) log->Printf("GDBRemoteCommunicationServerLLGS::%s No debugged process found.", __FUNCTION__); return PacketResult::Success; } Error error = m_debugged_process_sp->Kill(); if (error.Fail() && log) log->Printf("GDBRemoteCommunicationServerLLGS::%s Failed to kill debugged process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID(), error.AsCString()); // No OK response for kill packet. // return SendOKResponse (); return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet) { packet.SetFilePos(::strlen ("QSetDisableASLR:")); if (packet.GetU32(0)) m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR); else m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR); return SendOKResponse (); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet) { packet.SetFilePos (::strlen ("QSetWorkingDir:")); std::string path; packet.GetHexByteString (path); m_process_launch_info.SetWorkingDirectory(FileSpec{path, true}); return SendOKResponse (); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qGetWorkingDir (StringExtractorGDBRemote &packet) { FileSpec working_dir{m_process_launch_info.GetWorkingDirectory()}; if (working_dir) { StreamString response; response.PutCStringAsRawHex8(working_dir.GetCString()); return SendPacketNoLock(response.GetData(), response.GetSize()); } return SendErrorResponse(14); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_C (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); // Ensure we have a native process. if (!m_debugged_process_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); return SendErrorResponse (0x36); } // Pull out the signal number. packet.SetFilePos (::strlen ("C")); if (packet.GetBytesLeft () < 1) { // Shouldn't be using a C without a signal. return SendIllFormedResponse (packet, "C packet specified without signal."); } const uint32_t signo = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (signo == std::numeric_limits::max ()) return SendIllFormedResponse (packet, "failed to parse signal number"); // Handle optional continue address. if (packet.GetBytesLeft () > 0) { // FIXME add continue at address support for $C{signo}[;{continue-address}]. if (*packet.Peek () == ';') return SendUnimplementedResponse (packet.GetStringRef().c_str()); else return SendIllFormedResponse (packet, "unexpected content after $C{signal-number}"); } ResumeActionList resume_actions (StateType::eStateRunning, 0); Error error; // We have two branches: what to do if a continue thread is specified (in which case we target // sending the signal to that thread), or when we don't have a continue thread set (in which // case we send a signal to the process). // TODO discuss with Greg Clayton, make sure this makes sense. lldb::tid_t signal_tid = GetContinueThreadID (); if (signal_tid != LLDB_INVALID_THREAD_ID) { // The resume action for the continue thread (or all threads if a continue thread is not set). ResumeAction action = { GetContinueThreadID (), StateType::eStateRunning, static_cast (signo) }; // Add the action for the continue thread (or all threads when the continue thread isn't present). resume_actions.Append (action); } else { // Send the signal to the process since we weren't targeting a specific continue thread with the signal. error = m_debugged_process_sp->Signal (signo); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to send signal for process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x52); } } // Resume the threads. error = m_debugged_process_sp->Resume (resume_actions); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to resume threads for process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x38); } // Don't send an "OK" packet; response is the stopped/exited message. return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_c (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s called", __FUNCTION__); packet.SetFilePos (packet.GetFilePos() + ::strlen ("c")); // For now just support all continue. const bool has_continue_address = (packet.GetBytesLeft () > 0); if (has_continue_address) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s not implemented for c{address} variant [%s remains]", __FUNCTION__, packet.Peek ()); return SendUnimplementedResponse (packet.GetStringRef().c_str()); } // Ensure we have a native process. if (!m_debugged_process_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); return SendErrorResponse (0x36); } // Build the ResumeActionList ResumeActionList actions (StateType::eStateRunning, 0); Error error = m_debugged_process_sp->Resume (actions); if (error.Fail ()) { if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s c failed for process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); } return SendErrorResponse (GDBRemoteServerError::eErrorResume); } if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); // No response required from continue. return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vCont_actions (StringExtractorGDBRemote &packet) { StreamString response; response.Printf("vCont;c;C;s;S"); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vCont (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s handling vCont packet", __FUNCTION__); packet.SetFilePos (::strlen ("vCont")); if (packet.GetBytesLeft() == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s missing action from vCont package", __FUNCTION__); return SendIllFormedResponse (packet, "Missing action from vCont package"); } // Check if this is all continue (no options or ";c"). if (::strcmp (packet.Peek (), ";c") == 0) { // Move past the ';', then do a simple 'c'. packet.SetFilePos (packet.GetFilePos () + 1); return Handle_c (packet); } else if (::strcmp (packet.Peek (), ";s") == 0) { // Move past the ';', then do a simple 's'. packet.SetFilePos (packet.GetFilePos () + 1); return Handle_s (packet); } // Ensure we have a native process. if (!m_debugged_process_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s no debugged process shared pointer", __FUNCTION__); return SendErrorResponse (0x36); } ResumeActionList thread_actions; while (packet.GetBytesLeft () && *packet.Peek () == ';') { // Skip the semi-colon. packet.GetChar (); // Build up the thread action. ResumeAction thread_action; thread_action.tid = LLDB_INVALID_THREAD_ID; thread_action.state = eStateInvalid; thread_action.signal = 0; const char action = packet.GetChar (); switch (action) { case 'C': thread_action.signal = packet.GetHexMaxU32 (false, 0); if (thread_action.signal == 0) return SendIllFormedResponse (packet, "Could not parse signal in vCont packet C action"); LLVM_FALLTHROUGH; case 'c': // Continue thread_action.state = eStateRunning; break; case 'S': thread_action.signal = packet.GetHexMaxU32 (false, 0); if (thread_action.signal == 0) return SendIllFormedResponse (packet, "Could not parse signal in vCont packet S action"); LLVM_FALLTHROUGH; case 's': // Step thread_action.state = eStateStepping; break; default: return SendIllFormedResponse (packet, "Unsupported vCont action"); break; } // Parse out optional :{thread-id} value. if (packet.GetBytesLeft () && (*packet.Peek () == ':')) { // Consume the separator. packet.GetChar (); thread_action.tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); if (thread_action.tid == LLDB_INVALID_THREAD_ID) return SendIllFormedResponse (packet, "Could not parse thread number in vCont packet"); } thread_actions.Append (thread_action); } Error error = m_debugged_process_sp->Resume (thread_actions); if (error.Fail ()) { if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s vCont failed for process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); } return SendErrorResponse (GDBRemoteServerError::eErrorResume); } if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s continued process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); // No response required from vCont. return PacketResult::Success; } void GDBRemoteCommunicationServerLLGS::SetCurrentThreadID (lldb::tid_t tid) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting current thread id to %" PRIu64, __FUNCTION__, tid); m_current_tid = tid; if (m_debugged_process_sp) m_debugged_process_sp->SetCurrentThreadID (m_current_tid); } void GDBRemoteCommunicationServerLLGS::SetContinueThreadID (lldb::tid_t tid) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_THREAD)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s setting continue thread id to %" PRIu64, __FUNCTION__, tid); m_continue_tid = tid; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_stop_reason (StringExtractorGDBRemote &packet) { // Handle the $? gdbremote command. // If no process, indicate error if (!m_debugged_process_sp) return SendErrorResponse (02); return SendStopReasonForState (m_debugged_process_sp->GetState()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::SendStopReasonForState (lldb::StateType process_state) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); switch (process_state) { case eStateAttaching: case eStateLaunching: case eStateRunning: case eStateStepping: case eStateDetached: // NOTE: gdb protocol doc looks like it should return $OK // when everything is running (i.e. no stopped result). return PacketResult::Success; // Ignore case eStateSuspended: case eStateStopped: case eStateCrashed: { lldb::tid_t tid = m_debugged_process_sp->GetCurrentThreadID (); // Make sure we set the current thread so g and p packets return // the data the gdb will expect. SetCurrentThreadID (tid); return SendStopReplyPacketForThread (tid); } case eStateInvalid: case eStateUnloaded: case eStateExited: return SendWResponse(m_debugged_process_sp.get()); default: if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 ", current state reporting not handled: %s", __FUNCTION__, m_debugged_process_sp->GetID (), StateAsCString (process_state)); } break; } return SendErrorResponse (0); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qRegisterInfo (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse (68); // Ensure we have a thread. NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadAtIndex (0)); if (!thread_sp) return SendErrorResponse (69); // Get the register context for the first thread. NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); if (!reg_context_sp) return SendErrorResponse (69); // Parse out the register number from the request. packet.SetFilePos (strlen("qRegisterInfo")); const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (reg_index == std::numeric_limits::max ()) return SendErrorResponse (69); // Return the end of registers response if we've iterated one past the end of the register set. if (reg_index >= reg_context_sp->GetUserRegisterCount ()) return SendErrorResponse (69); const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); if (!reg_info) return SendErrorResponse (69); // Build the reginfos response. StreamGDBRemote response; response.PutCString ("name:"); response.PutCString (reg_info->name); response.PutChar (';'); if (reg_info->alt_name && reg_info->alt_name[0]) { response.PutCString ("alt-name:"); response.PutCString (reg_info->alt_name); response.PutChar (';'); } response.Printf ("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", reg_info->byte_size * 8, reg_info->byte_offset); switch (reg_info->encoding) { case eEncodingUint: response.PutCString ("encoding:uint;"); break; case eEncodingSint: response.PutCString ("encoding:sint;"); break; case eEncodingIEEE754: response.PutCString ("encoding:ieee754;"); break; case eEncodingVector: response.PutCString ("encoding:vector;"); break; default: break; } switch (reg_info->format) { case eFormatBinary: response.PutCString ("format:binary;"); break; case eFormatDecimal: response.PutCString ("format:decimal;"); break; case eFormatHex: response.PutCString ("format:hex;"); break; case eFormatFloat: response.PutCString ("format:float;"); break; case eFormatVectorOfSInt8: response.PutCString ("format:vector-sint8;"); break; case eFormatVectorOfUInt8: response.PutCString ("format:vector-uint8;"); break; case eFormatVectorOfSInt16: response.PutCString ("format:vector-sint16;"); break; case eFormatVectorOfUInt16: response.PutCString ("format:vector-uint16;"); break; case eFormatVectorOfSInt32: response.PutCString ("format:vector-sint32;"); break; case eFormatVectorOfUInt32: response.PutCString ("format:vector-uint32;"); break; case eFormatVectorOfFloat32: response.PutCString ("format:vector-float32;"); break; case eFormatVectorOfUInt128: response.PutCString ("format:vector-uint128;"); break; default: break; }; const char *const register_set_name = reg_context_sp->GetRegisterSetNameForRegisterAtIndex(reg_index); if (register_set_name) { response.PutCString ("set:"); response.PutCString (register_set_name); response.PutChar (';'); } if (reg_info->kinds[RegisterKind::eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) response.Printf ("ehframe:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindEHFrame]); if (reg_info->kinds[RegisterKind::eRegisterKindDWARF] != LLDB_INVALID_REGNUM) response.Printf ("dwarf:%" PRIu32 ";", reg_info->kinds[RegisterKind::eRegisterKindDWARF]); switch (reg_info->kinds[RegisterKind::eRegisterKindGeneric]) { case LLDB_REGNUM_GENERIC_PC: response.PutCString("generic:pc;"); break; case LLDB_REGNUM_GENERIC_SP: response.PutCString("generic:sp;"); break; case LLDB_REGNUM_GENERIC_FP: response.PutCString("generic:fp;"); break; case LLDB_REGNUM_GENERIC_RA: response.PutCString("generic:ra;"); break; case LLDB_REGNUM_GENERIC_FLAGS: response.PutCString("generic:flags;"); break; case LLDB_REGNUM_GENERIC_ARG1: response.PutCString("generic:arg1;"); break; case LLDB_REGNUM_GENERIC_ARG2: response.PutCString("generic:arg2;"); break; case LLDB_REGNUM_GENERIC_ARG3: response.PutCString("generic:arg3;"); break; case LLDB_REGNUM_GENERIC_ARG4: response.PutCString("generic:arg4;"); break; case LLDB_REGNUM_GENERIC_ARG5: response.PutCString("generic:arg5;"); break; case LLDB_REGNUM_GENERIC_ARG6: response.PutCString("generic:arg6;"); break; case LLDB_REGNUM_GENERIC_ARG7: response.PutCString("generic:arg7;"); break; case LLDB_REGNUM_GENERIC_ARG8: response.PutCString("generic:arg8;"); break; default: break; } if (reg_info->value_regs && reg_info->value_regs[0] != LLDB_INVALID_REGNUM) { response.PutCString ("container-regs:"); int i = 0; for (const uint32_t *reg_num = reg_info->value_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { if (i > 0) response.PutChar (','); response.Printf ("%" PRIx32, *reg_num); } response.PutChar (';'); } if (reg_info->invalidate_regs && reg_info->invalidate_regs[0]) { response.PutCString ("invalidate-regs:"); int i = 0; for (const uint32_t *reg_num = reg_info->invalidate_regs; *reg_num != LLDB_INVALID_REGNUM; ++reg_num, ++i) { if (i > 0) response.PutChar (','); response.Printf ("%" PRIx32, *reg_num); } response.PutChar (';'); } + if (reg_info->dynamic_size_dwarf_expr_bytes) + { + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + response.PutCString("dynamic_size_dwarf_expr_bytes:"); + for(uint32_t i = 0; i < dwarf_opcode_len; ++i) + response.PutHex8 (reg_info->dynamic_size_dwarf_expr_bytes[i]); + response.PutChar(';'); + } return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qfThreadInfo (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s() no process (%s), returning OK", __FUNCTION__, m_debugged_process_sp ? "invalid process id" : "null m_debugged_process_sp"); return SendOKResponse (); } StreamGDBRemote response; response.PutChar ('m'); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s() starting thread iteration", __FUNCTION__); NativeThreadProtocolSP thread_sp; uint32_t thread_index; for (thread_index = 0, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index); thread_sp; ++thread_index, thread_sp = m_debugged_process_sp->GetThreadAtIndex (thread_index)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s() iterated thread %" PRIu32 "(%s, tid=0x%" PRIx64 ")", __FUNCTION__, thread_index, thread_sp ? "is not null" : "null", thread_sp ? thread_sp->GetID () : LLDB_INVALID_THREAD_ID); if (thread_index > 0) response.PutChar(','); response.Printf ("%" PRIx64, thread_sp->GetID ()); } if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s() finished thread iteration", __FUNCTION__); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qsThreadInfo (StringExtractorGDBRemote &packet) { // FIXME for now we return the full thread list in the initial packet and always do nothing here. return SendPacketNoLock ("l", 1); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_p (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Parse out the register number from the request. packet.SetFilePos (strlen("p")); const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (reg_index == std::numeric_limits::max ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); return SendErrorResponse (0x15); } // Get the thread to use. NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); if (!thread_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available", __FUNCTION__); return SendErrorResponse (0x15); } // Get the thread's register context. NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); if (!reg_context_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); return SendErrorResponse (0x15); } // Return the end of registers response if we've iterated one past the end of the register set. if (reg_index >= reg_context_sp->GetUserRegisterCount ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); return SendErrorResponse (0x15); } const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex(reg_index); if (!reg_info) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); return SendErrorResponse (0x15); } // Build the reginfos response. StreamGDBRemote response; // Retrieve the value RegisterValue reg_value; Error error = reg_context_sp->ReadRegister (reg_info, reg_value); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, read of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); return SendErrorResponse (0x15); } const uint8_t *const data = reinterpret_cast (reg_value.GetBytes ()); if (!data) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to get data bytes from requested register %" PRIu32, __FUNCTION__, reg_index); return SendErrorResponse (0x15); } // FIXME flip as needed to get data in big/little endian format for this host. for (uint32_t i = 0; i < reg_value.GetByteSize (); ++i) response.PutHex8 (data[i]); return SendPacketNoLock (response.GetData (), response.GetSize ()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_P (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Ensure there is more content. if (packet.GetBytesLeft () < 1) return SendIllFormedResponse (packet, "Empty P packet"); // Parse out the register number from the request. packet.SetFilePos (strlen("P")); const uint32_t reg_index = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (reg_index == std::numeric_limits::max ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse register number from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); return SendErrorResponse (0x29); } // Note debugserver would send an E30 here. if ((packet.GetBytesLeft () < 1) || (packet.GetChar () != '=')) return SendIllFormedResponse (packet, "P packet missing '=' char after register number"); // Get process architecture. ArchSpec process_arch; if (!m_debugged_process_sp || !m_debugged_process_sp->GetArchitecture (process_arch)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to retrieve inferior architecture", __FUNCTION__); return SendErrorResponse (0x49); } // Parse out the value. uint8_t reg_bytes[32]; // big enough to support up to 256 bit ymmN register size_t reg_size = packet.GetHexBytesAvail (reg_bytes, sizeof(reg_bytes)); // Get the thread to use. NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); if (!thread_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no thread available (thread index 0)", __FUNCTION__); return SendErrorResponse (0x28); } // Get the thread's register context. NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); if (!reg_context_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); return SendErrorResponse (0x15); } const RegisterInfo *reg_info = reg_context_sp->GetRegisterInfoAtIndex (reg_index); if (!reg_info) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " returned NULL", __FUNCTION__, reg_index); return SendErrorResponse (0x48); } // Return the end of registers response if we've iterated one past the end of the register set. if (reg_index >= reg_context_sp->GetUserRegisterCount ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, requested register %" PRIu32 " beyond register count %" PRIu32, __FUNCTION__, reg_index, reg_context_sp->GetUserRegisterCount ()); return SendErrorResponse (0x47); } - if (reg_size != reg_info->byte_size) + // The dwarf expression are evaluate on host site + // which may cause register size to change + // Hence the reg_size may not be same as reg_info->bytes_size + if ((reg_size != reg_info->byte_size) && !(reg_info->dynamic_size_dwarf_expr_bytes)) { return SendIllFormedResponse (packet, "P packet register size is incorrect"); } // Build the reginfos response. StreamGDBRemote response; RegisterValue reg_value (reg_bytes, reg_size, process_arch.GetByteOrder ()); Error error = reg_context_sp->WriteRegister (reg_info, reg_value); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, write of requested register %" PRIu32 " (%s) failed: %s", __FUNCTION__, reg_index, reg_info->name, error.AsCString ()); return SendErrorResponse (0x32); } return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_H (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out which variant of $H is requested. packet.SetFilePos (strlen("H")); if (packet.GetBytesLeft () < 1) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, H command missing {g,c} variant", __FUNCTION__); return SendIllFormedResponse (packet, "H command missing {g,c} variant"); } const char h_variant = packet.GetChar (); switch (h_variant) { case 'g': break; case 'c': break; default: if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, invalid $H variant %c", __FUNCTION__, h_variant); return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); } // Parse out the thread number. // FIXME return a parse success/fail value. All values are valid here. const lldb::tid_t tid = packet.GetHexMaxU64 (false, std::numeric_limits::max ()); // Ensure we have the given thread when not specifying -1 (all threads) or 0 (any thread). if (tid != LLDB_INVALID_THREAD_ID && tid != 0) { NativeThreadProtocolSP thread_sp (m_debugged_process_sp->GetThreadByID (tid)); if (!thread_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, tid %" PRIu64 " not found", __FUNCTION__, tid); return SendErrorResponse (0x15); } } // Now switch the given thread type. switch (h_variant) { case 'g': SetCurrentThreadID (tid); break; case 'c': SetContinueThreadID (tid); break; default: assert (false && "unsupported $H variant - shouldn't get here"); return SendIllFormedResponse (packet, "H variant unsupported, should be c or g"); } return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_I (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } packet.SetFilePos (::strlen("I")); char tmp[4096]; for (;;) { size_t read = packet.GetHexBytesAvail(tmp, sizeof(tmp)); if (read == 0) { break; } // write directly to stdin *this might block if stdin buffer is full* // TODO: enqueue this block in circular buffer and send window size to remote host ConnectionStatus status; Error error; m_stdio_communication.Write(tmp, read, status, &error); if (error.Fail()) { return SendErrorResponse (0x15); } } return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_interrupt (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Interrupt the process. Error error = m_debugged_process_sp->Interrupt (); if (error.Fail ()) { if (log) { log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed for process %" PRIu64 ": %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); } return SendErrorResponse (GDBRemoteServerError::eErrorResume); } if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s stopped process %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID ()); // No response required from stop all. return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_memory_read(StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out the memory address. packet.SetFilePos (strlen("m")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short m packet"); // Read the address. Punting on validation. // FIXME replace with Hex U64 read with no default value that fails on failed read. const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); // Validate comma. if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) return SendIllFormedResponse(packet, "Comma sep missing in m packet"); // Get # bytes to read. if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Length missing in m packet"); const uint64_t byte_count = packet.GetHexMaxU64(false, 0); if (byte_count == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to read: zero-length packet", __FUNCTION__); return SendOKResponse(); } // Allocate the response buffer. std::string buf(byte_count, '\0'); if (buf.empty()) return SendErrorResponse (0x78); // Retrieve the process memory. size_t bytes_read = 0; Error error = m_debugged_process_sp->ReadMemoryWithoutTrap(read_addr, &buf[0], byte_count, bytes_read); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to read. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, error.AsCString ()); return SendErrorResponse (0x08); } if (bytes_read == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": read 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), read_addr, byte_count); return SendErrorResponse (0x08); } StreamGDBRemote response; packet.SetFilePos(0); char kind = packet.GetChar('?'); if (kind == 'x') response.PutEscapedBytes(buf.data(), byte_count); else { assert(kind == 'm'); for (size_t i = 0; i < bytes_read; ++i) response.PutHex8(buf[i]); } return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_M (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out the memory address. packet.SetFilePos (strlen("M")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short M packet"); // Read the address. Punting on validation. // FIXME replace with Hex U64 read with no default value that fails on failed read. const lldb::addr_t write_addr = packet.GetHexMaxU64(false, 0); // Validate comma. if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ',')) return SendIllFormedResponse(packet, "Comma sep missing in M packet"); // Get # bytes to read. if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Length missing in M packet"); const uint64_t byte_count = packet.GetHexMaxU64(false, 0); if (byte_count == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s nothing to write: zero-length packet", __FUNCTION__); return PacketResult::Success; } // Validate colon. if ((packet.GetBytesLeft() < 1) || (packet.GetChar() != ':')) return SendIllFormedResponse(packet, "Comma sep missing in M packet after byte length"); // Allocate the conversion buffer. std::vector buf(byte_count, 0); if (buf.empty()) return SendErrorResponse (0x78); // Convert the hex memory write contents to bytes. StreamGDBRemote response; const uint64_t convert_count = packet.GetHexBytes(&buf[0], byte_count, 0); if (convert_count != byte_count) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": asked to write %" PRIu64 " bytes, but only found %" PRIu64 " to convert.", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count, convert_count); return SendIllFormedResponse (packet, "M content byte length specified did not match hex-encoded content length"); } // Write the process memory. size_t bytes_written = 0; Error error = m_debugged_process_sp->WriteMemory (write_addr, &buf[0], byte_count, bytes_written); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": failed to write. Error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, error.AsCString ()); return SendErrorResponse (0x09); } if (bytes_written == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " mem 0x%" PRIx64 ": wrote 0 of %" PRIu64 " requested bytes", __FUNCTION__, m_debugged_process_sp->GetID (), write_addr, byte_count); return SendErrorResponse (0x09); } return SendOKResponse (); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfoSupported (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Currently only the NativeProcessProtocol knows if it can handle a qMemoryRegionInfoSupported // request, but we're not guaranteed to be attached to a process. For now we'll assume the // client only asks this when a process is being debugged. // Ensure we have a process running; otherwise, we can't figure this out // since we won't have a NativeProcessProtocol. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Test if we can get any region back when asking for the region around NULL. MemoryRegionInfo region_info; const Error error = m_debugged_process_sp->GetMemoryRegionInfo (0, region_info); if (error.Fail ()) { // We don't support memory region info collection for this NativeProcessProtocol. return SendUnimplementedResponse (""); } return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qMemoryRegionInfo (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Ensure we have a process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out the memory address. packet.SetFilePos (strlen("qMemoryRegionInfo:")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short qMemoryRegionInfo: packet"); // Read the address. Punting on validation. const lldb::addr_t read_addr = packet.GetHexMaxU64(false, 0); StreamGDBRemote response; // Get the memory region info for the target address. MemoryRegionInfo region_info; const Error error = m_debugged_process_sp->GetMemoryRegionInfo (read_addr, region_info); if (error.Fail ()) { // Return the error message. response.PutCString ("error:"); response.PutCStringAsRawHex8 (error.AsCString ()); response.PutChar (';'); } else { // Range start and size. response.Printf ("start:%" PRIx64 ";size:%" PRIx64 ";", region_info.GetRange ().GetRangeBase (), region_info.GetRange ().GetByteSize ()); // Permissions. if (region_info.GetReadable () || region_info.GetWritable () || region_info.GetExecutable ()) { // Write permissions info. response.PutCString ("permissions:"); if (region_info.GetReadable ()) response.PutChar ('r'); if (region_info.GetWritable ()) response.PutChar('w'); if (region_info.GetExecutable()) response.PutChar ('x'); response.PutChar (';'); } } return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_Z (StringExtractorGDBRemote &packet) { // Ensure we have a process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out software or hardware breakpoint or watchpoint requested. packet.SetFilePos (strlen("Z")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short Z packet, missing software/hardware specifier"); bool want_breakpoint = true; bool want_hardware = false; uint32_t watch_flags = 0; const GDBStoppointType stoppoint_type = GDBStoppointType(packet.GetS32 (eStoppointInvalid)); switch (stoppoint_type) { case eBreakpointSoftware: want_hardware = false; want_breakpoint = true; break; case eBreakpointHardware: want_hardware = true; want_breakpoint = true; break; case eWatchpointWrite: watch_flags = 1; want_hardware = true; want_breakpoint = false; break; case eWatchpointRead: watch_flags = 2; want_hardware = true; want_breakpoint = false; break; case eWatchpointReadWrite: watch_flags = 3; want_hardware = true; want_breakpoint = false; break; case eStoppointInvalid: return SendIllFormedResponse(packet, "Z packet had invalid software/hardware specifier"); } if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after stoppoint type"); // Parse out the stoppoint address. if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short Z packet, missing address"); const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') return SendIllFormedResponse(packet, "Malformed Z packet, expecting comma after address"); // Parse out the stoppoint size (i.e. size hint for opcode size). const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (size == std::numeric_limits::max ()) return SendIllFormedResponse(packet, "Malformed Z packet, failed to parse size argument"); if (want_breakpoint) { // Try to set the breakpoint. const Error error = m_debugged_process_sp->SetBreakpoint (addr, size, want_hardware); if (error.Success ()) return SendOKResponse (); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to set breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x09); } else { // Try to set the watchpoint. const Error error = m_debugged_process_sp->SetWatchpoint ( addr, size, watch_flags, want_hardware); if (error.Success ()) return SendOKResponse (); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to set watchpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x09); } } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_z (StringExtractorGDBRemote &packet) { // Ensure we have a process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } // Parse out software or hardware breakpoint or watchpoint requested. packet.SetFilePos (strlen("z")); if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short z packet, missing software/hardware specifier"); bool want_breakpoint = true; const GDBStoppointType stoppoint_type = GDBStoppointType(packet.GetS32 (eStoppointInvalid)); switch (stoppoint_type) { case eBreakpointHardware: want_breakpoint = true; break; case eBreakpointSoftware: want_breakpoint = true; break; case eWatchpointWrite: want_breakpoint = false; break; case eWatchpointRead: want_breakpoint = false; break; case eWatchpointReadWrite: want_breakpoint = false; break; default: return SendIllFormedResponse(packet, "z packet had invalid software/hardware specifier"); } if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after stoppoint type"); // Parse out the stoppoint address. if (packet.GetBytesLeft() < 1) return SendIllFormedResponse(packet, "Too short z packet, missing address"); const lldb::addr_t addr = packet.GetHexMaxU64(false, 0); if ((packet.GetBytesLeft() < 1) || packet.GetChar () != ',') return SendIllFormedResponse(packet, "Malformed z packet, expecting comma after address"); /* // Parse out the stoppoint size (i.e. size hint for opcode size). const uint32_t size = packet.GetHexMaxU32 (false, std::numeric_limits::max ()); if (size == std::numeric_limits::max ()) return SendIllFormedResponse(packet, "Malformed z packet, failed to parse size argument"); */ if (want_breakpoint) { // Try to clear the breakpoint. const Error error = m_debugged_process_sp->RemoveBreakpoint (addr); if (error.Success ()) return SendOKResponse (); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to remove breakpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x09); } else { // Try to clear the watchpoint. const Error error = m_debugged_process_sp->RemoveWatchpoint (addr); if (error.Success ()) return SendOKResponse (); Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to remove watchpoint: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x09); } } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_s (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_THREAD)); // Ensure we have a process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x32); } // We first try to use a continue thread id. If any one or any all set, use the current thread. // Bail out if we don't have a thread id. lldb::tid_t tid = GetContinueThreadID (); if (tid == 0 || tid == LLDB_INVALID_THREAD_ID) tid = GetCurrentThreadID (); if (tid == LLDB_INVALID_THREAD_ID) return SendErrorResponse (0x33); // Double check that we have such a thread. // TODO investigate: on MacOSX we might need to do an UpdateThreads () here. NativeThreadProtocolSP thread_sp = m_debugged_process_sp->GetThreadByID (tid); if (!thread_sp || thread_sp->GetID () != tid) return SendErrorResponse (0x33); // Create the step action for the given thread. ResumeAction action = { tid, eStateStepping, 0 }; // Setup the actions list. ResumeActionList actions; actions.Append (action); // All other threads stop while we're single stepping a thread. actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); Error error = m_debugged_process_sp->Resume (actions); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " Resume() failed with error: %s", __FUNCTION__, m_debugged_process_sp->GetID (), tid, error.AsCString ()); return SendErrorResponse(0x49); } // No response here - the stop or exit will come from the resulting action. return PacketResult::Success; } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qXfer_auxv_read (StringExtractorGDBRemote &packet) { // *BSD impls should be able to do this too. #if defined(__linux__) Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Parse out the offset. packet.SetFilePos (strlen("qXfer:auxv:read::")); if (packet.GetBytesLeft () < 1) return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); const uint64_t auxv_offset = packet.GetHexMaxU64 (false, std::numeric_limits::max ()); if (auxv_offset == std::numeric_limits::max ()) return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing offset"); // Parse out comma. if (packet.GetBytesLeft () < 1 || packet.GetChar () != ',') return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing comma after offset"); // Parse out the length. const uint64_t auxv_length = packet.GetHexMaxU64 (false, std::numeric_limits::max ()); if (auxv_length == std::numeric_limits::max ()) return SendIllFormedResponse (packet, "qXfer:auxv:read:: packet missing length"); // Grab the auxv data if we need it. if (!m_active_auxv_buffer_sp) { // Make sure we have a valid process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x10); } // Grab the auxv data. m_active_auxv_buffer_sp = Host::GetAuxvData (m_debugged_process_sp->GetID ()); if (!m_active_auxv_buffer_sp || m_active_auxv_buffer_sp->GetByteSize () == 0) { // Hmm, no auxv data, call that an error. if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no auxv data retrieved", __FUNCTION__); m_active_auxv_buffer_sp.reset (); return SendErrorResponse (0x11); } } // FIXME find out if/how I lock the stream here. StreamGDBRemote response; bool done_with_buffer = false; if (auxv_offset >= m_active_auxv_buffer_sp->GetByteSize ()) { // We have nothing left to send. Mark the buffer as complete. response.PutChar ('l'); done_with_buffer = true; } else { // Figure out how many bytes are available starting at the given offset. const uint64_t bytes_remaining = m_active_auxv_buffer_sp->GetByteSize () - auxv_offset; // Figure out how many bytes we're going to read. const uint64_t bytes_to_read = (auxv_length > bytes_remaining) ? bytes_remaining : auxv_length; // Mark the response type according to whether we're reading the remainder of the auxv data. if (bytes_to_read >= bytes_remaining) { // There will be nothing left to read after this response.PutChar ('l'); done_with_buffer = true; } else { // There will still be bytes to read after this request. response.PutChar ('m'); } // Now write the data in encoded binary form. response.PutEscapedBytes (m_active_auxv_buffer_sp->GetBytes () + auxv_offset, bytes_to_read); } if (done_with_buffer) m_active_auxv_buffer_sp.reset (); return SendPacketNoLock(response.GetData(), response.GetSize()); #else return SendUnimplementedResponse ("not implemented on this platform"); #endif } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QSaveRegisterState (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Move past packet name. packet.SetFilePos (strlen ("QSaveRegisterState")); // Get the thread to use. NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); if (!thread_sp) { if (m_thread_suffix_supported) return SendIllFormedResponse (packet, "No thread specified in QSaveRegisterState packet"); else return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); } // Grab the register context for the thread. NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); if (!reg_context_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); return SendErrorResponse (0x15); } // Save registers to a buffer. DataBufferSP register_data_sp; Error error = reg_context_sp->ReadAllRegisterValues (register_data_sp); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to save all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x75); } // Allocate a new save id. const uint32_t save_id = GetNextSavedRegistersID (); assert ((m_saved_registers_map.find (save_id) == m_saved_registers_map.end ()) && "GetNextRegisterSaveID() returned an existing register save id"); // Save the register data buffer under the save id. { std::lock_guard guard(m_saved_registers_mutex); m_saved_registers_map[save_id] = register_data_sp; } // Write the response. StreamGDBRemote response; response.Printf ("%" PRIu32, save_id); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_QRestoreRegisterState (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Parse out save id. packet.SetFilePos (strlen ("QRestoreRegisterState:")); if (packet.GetBytesLeft () < 1) return SendIllFormedResponse (packet, "QRestoreRegisterState packet missing register save id"); const uint32_t save_id = packet.GetU32 (0); if (save_id == 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s QRestoreRegisterState packet has malformed save id, expecting decimal uint32_t", __FUNCTION__); return SendErrorResponse (0x76); } // Get the thread to use. NativeThreadProtocolSP thread_sp = GetThreadFromSuffix (packet); if (!thread_sp) { if (m_thread_suffix_supported) return SendIllFormedResponse (packet, "No thread specified in QRestoreRegisterState packet"); else return SendIllFormedResponse (packet, "No thread was is set with the Hg packet"); } // Grab the register context for the thread. NativeRegisterContextSP reg_context_sp (thread_sp->GetRegisterContext ()); if (!reg_context_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " tid %" PRIu64 " failed, no register context available for the thread", __FUNCTION__, m_debugged_process_sp->GetID (), thread_sp->GetID ()); return SendErrorResponse (0x15); } // Retrieve register state buffer, then remove from the list. DataBufferSP register_data_sp; { std::lock_guard guard(m_saved_registers_mutex); // Find the register set buffer for the given save id. auto it = m_saved_registers_map.find (save_id); if (it == m_saved_registers_map.end ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " does not have a register set save buffer for id %" PRIu32, __FUNCTION__, m_debugged_process_sp->GetID (), save_id); return SendErrorResponse (0x77); } register_data_sp = it->second; // Remove it from the map. m_saved_registers_map.erase (it); } Error error = reg_context_sp->WriteAllRegisterValues (register_data_sp); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s pid %" PRIu64 " failed to restore all register values: %s", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x77); } return SendOKResponse(); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_vAttach (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Consume the ';' after vAttach. packet.SetFilePos (strlen ("vAttach")); if (!packet.GetBytesLeft () || packet.GetChar () != ';') return SendIllFormedResponse (packet, "vAttach missing expected ';'"); // Grab the PID to which we will attach (assume hex encoding). lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); if (pid == LLDB_INVALID_PROCESS_ID) return SendIllFormedResponse (packet, "vAttach failed to parse the process id"); // Attempt to attach. if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s attempting to attach to pid %" PRIu64, __FUNCTION__, pid); Error error = AttachToProcess (pid); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to attach to pid %" PRIu64 ": %s\n", __FUNCTION__, pid, error.AsCString()); return SendErrorResponse (0x01); } // Notify we attached by sending a stop packet. return SendStopReasonForState (m_debugged_process_sp->GetState ()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_D (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); StopSTDIOForwarding(); // Fail if we don't have a current process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, no process available", __FUNCTION__); return SendErrorResponse (0x15); } lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; // Consume the ';' after D. packet.SetFilePos (1); if (packet.GetBytesLeft ()) { if (packet.GetChar () != ';') return SendIllFormedResponse (packet, "D missing expected ';'"); // Grab the PID from which we will detach (assume hex encoding). pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID, 16); if (pid == LLDB_INVALID_PROCESS_ID) return SendIllFormedResponse (packet, "D failed to parse the process id"); } if (pid != LLDB_INVALID_PROCESS_ID && m_debugged_process_sp->GetID () != pid) { return SendIllFormedResponse (packet, "Invalid pid"); } const Error error = m_debugged_process_sp->Detach (); if (error.Fail ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to detach from pid %" PRIu64 ": %s\n", __FUNCTION__, m_debugged_process_sp->GetID (), error.AsCString ()); return SendErrorResponse (0x01); } return SendOKResponse (); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qThreadStopInfo (StringExtractorGDBRemote &packet) { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); packet.SetFilePos (strlen("qThreadStopInfo")); const lldb::tid_t tid = packet.GetHexMaxU32 (false, LLDB_INVALID_THREAD_ID); if (tid == LLDB_INVALID_THREAD_ID) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed, could not parse thread id from request \"%s\"", __FUNCTION__, packet.GetStringRef ().c_str ()); return SendErrorResponse (0x15); } return SendStopReplyPacketForThread (tid); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_jThreadsInfo (StringExtractorGDBRemote &) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_THREAD)); // Ensure we have a debugged process. if (!m_debugged_process_sp || (m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID)) return SendErrorResponse (50); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s preparing packet for pid %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID()); StreamString response; const bool threads_with_valid_stop_info_only = false; JSONArray::SP threads_array_sp = GetJSONThreadsInfo(*m_debugged_process_sp, threads_with_valid_stop_info_only); if (! threads_array_sp) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s failed to prepare a packet for pid %" PRIu64, __FUNCTION__, m_debugged_process_sp->GetID()); return SendErrorResponse(52); } threads_array_sp->Write(response); StreamGDBRemote escaped_response; escaped_response.PutEscapedBytes(response.GetData(), response.GetSize()); return SendPacketNoLock (escaped_response.GetData(), escaped_response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qWatchpointSupportInfo (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) return SendErrorResponse (68); packet.SetFilePos(strlen("qWatchpointSupportInfo")); if (packet.GetBytesLeft() == 0) return SendOKResponse(); if (packet.GetChar() != ':') return SendErrorResponse(67); uint32_t num = m_debugged_process_sp->GetMaxWatchpoints(); StreamGDBRemote response; response.Printf ("num:%d;", num); return SendPacketNoLock(response.GetData(), response.GetSize()); } GDBRemoteCommunication::PacketResult GDBRemoteCommunicationServerLLGS::Handle_qFileLoadAddress (StringExtractorGDBRemote &packet) { // Fail if we don't have a current process. if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) return SendErrorResponse(67); packet.SetFilePos(strlen("qFileLoadAddress:")); if (packet.GetBytesLeft() == 0) return SendErrorResponse(68); std::string file_name; packet.GetHexByteString(file_name); lldb::addr_t file_load_address = LLDB_INVALID_ADDRESS; Error error = m_debugged_process_sp->GetFileLoadAddress(file_name, file_load_address); if (error.Fail()) return SendErrorResponse(69); if (file_load_address == LLDB_INVALID_ADDRESS) return SendErrorResponse(1); // File not loaded StreamGDBRemote response; response.PutHex64(file_load_address); return SendPacketNoLock(response.GetData(), response.GetSize()); } void GDBRemoteCommunicationServerLLGS::MaybeCloseInferiorTerminalConnection () { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); // Tell the stdio connection to shut down. if (m_stdio_communication.IsConnected()) { auto connection = m_stdio_communication.GetConnection(); if (connection) { Error error; connection->Disconnect (&error); if (error.Success ()) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - SUCCESS", __FUNCTION__); } else { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s disconnect process terminal stdio - FAIL: %s", __FUNCTION__, error.AsCString ()); } } } } NativeThreadProtocolSP GDBRemoteCommunicationServerLLGS::GetThreadFromSuffix (StringExtractorGDBRemote &packet) { NativeThreadProtocolSP thread_sp; // We have no thread if we don't have a process. if (!m_debugged_process_sp || m_debugged_process_sp->GetID () == LLDB_INVALID_PROCESS_ID) return thread_sp; // If the client hasn't asked for thread suffix support, there will not be a thread suffix. // Use the current thread in that case. if (!m_thread_suffix_supported) { const lldb::tid_t current_tid = GetCurrentThreadID (); if (current_tid == LLDB_INVALID_THREAD_ID) return thread_sp; else if (current_tid == 0) { // Pick a thread. return m_debugged_process_sp->GetThreadAtIndex (0); } else return m_debugged_process_sp->GetThreadByID (current_tid); } Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_THREAD)); // Parse out the ';'. if (packet.GetBytesLeft () < 1 || packet.GetChar () != ';') { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected ';' prior to start of thread suffix: packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); return thread_sp; } if (!packet.GetBytesLeft ()) return thread_sp; // Parse out thread: portion. if (strncmp (packet.Peek (), "thread:", strlen("thread:")) != 0) { if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s gdb-remote parse error: expected 'thread:' but not found, packet contents = '%s'", __FUNCTION__, packet.GetStringRef ().c_str ()); return thread_sp; } packet.SetFilePos (packet.GetFilePos () + strlen("thread:")); const lldb::tid_t tid = packet.GetHexMaxU64(false, 0); if (tid != 0) return m_debugged_process_sp->GetThreadByID (tid); return thread_sp; } lldb::tid_t GDBRemoteCommunicationServerLLGS::GetCurrentThreadID () const { if (m_current_tid == 0 || m_current_tid == LLDB_INVALID_THREAD_ID) { // Use whatever the debug process says is the current thread id // since the protocol either didn't specify or specified we want // any/all threads marked as the current thread. if (!m_debugged_process_sp) return LLDB_INVALID_THREAD_ID; return m_debugged_process_sp->GetCurrentThreadID (); } // Use the specific current thread id set by the gdb remote protocol. return m_current_tid; } uint32_t GDBRemoteCommunicationServerLLGS::GetNextSavedRegistersID () { std::lock_guard guard(m_saved_registers_mutex); return m_next_saved_registers_id++; } void GDBRemoteCommunicationServerLLGS::ClearProcessSpecificData () { Log *log (GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS|GDBR_LOG_PROCESS)); if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s()", __FUNCTION__); // Clear any auxv cached data. // *BSD impls should be able to do this too. #if defined(__linux__) if (log) log->Printf ("GDBRemoteCommunicationServerLLGS::%s clearing auxv buffer (previously %s)", __FUNCTION__, m_active_auxv_buffer_sp ? "was set" : "was not set"); m_active_auxv_buffer_sp.reset (); #endif } FileSpec GDBRemoteCommunicationServerLLGS::FindModuleFile(const std::string& module_path, const ArchSpec& arch) { if (m_debugged_process_sp) { FileSpec file_spec; if (m_debugged_process_sp->GetLoadedModuleFileSpec(module_path.c_str(), file_spec).Success()) { if (file_spec.Exists()) return file_spec; } } return GDBRemoteCommunicationServerCommon::FindModuleFile(module_path, arch); } Index: vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp (revision 304308) @@ -1,1215 +1,1223 @@ //===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "GDBRemoteRegisterContext.h" // C Includes // C++ Includes // Other libraries and framework includes #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Core/StreamString.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Target.h" #include "lldb/Utility/Utils.h" // Project includes #include "Utility/StringExtractorGDBRemote.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" #include "Utility/ARM_DWARF_Registers.h" #include "Utility/ARM_ehframe_Registers.h" using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; //---------------------------------------------------------------------- // GDBRemoteRegisterContext constructor //---------------------------------------------------------------------- GDBRemoteRegisterContext::GDBRemoteRegisterContext ( ThreadGDBRemote &thread, uint32_t concrete_frame_idx, GDBRemoteDynamicRegisterInfo ®_info, bool read_all_at_once ) : RegisterContext (thread, concrete_frame_idx), m_reg_info (reg_info), m_reg_valid (), m_reg_data (), m_read_all_at_once (read_all_at_once) { // Resize our vector of bools to contain one bool for every register. // We will use these boolean values to know when a register value // is valid in m_reg_data. m_reg_valid.resize (reg_info.GetNumRegisters()); // Make a heap based buffer that is big enough to store all registers DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0)); m_reg_data.SetData (reg_data_sp); m_reg_data.SetByteOrder(thread.GetProcess()->GetByteOrder()); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- GDBRemoteRegisterContext::~GDBRemoteRegisterContext() { } void GDBRemoteRegisterContext::InvalidateAllRegisters () { SetAllRegisterValid (false); } void GDBRemoteRegisterContext::SetAllRegisterValid (bool b) { std::vector::iterator pos, end = m_reg_valid.end(); for (pos = m_reg_valid.begin(); pos != end; ++pos) *pos = b; } size_t GDBRemoteRegisterContext::GetRegisterCount () { return m_reg_info.GetNumRegisters (); } const RegisterInfo * GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg) { - return m_reg_info.GetRegisterInfoAtIndex (reg); + RegisterInfo* reg_info = m_reg_info.GetRegisterInfoAtIndex (reg); + + if (reg_info && reg_info->dynamic_size_dwarf_expr_bytes) + { + const ArchSpec &arch = m_thread.GetProcess ()->GetTarget ().GetArchitecture (); + uint8_t reg_size = UpdateDynamicRegisterSize (arch, reg_info); + reg_info->byte_size = reg_size; + } + return reg_info; } size_t GDBRemoteRegisterContext::GetRegisterSetCount () { return m_reg_info.GetNumRegisterSets (); } const RegisterSet * GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set) { return m_reg_info.GetRegisterSet (reg_set); } bool GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value) { // Read the register if (ReadRegisterBytes (reg_info, m_reg_data)) { const bool partial_data_ok = false; Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok)); return error.Success(); } return false; } bool GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); if (reg_info == NULL) return false; // Invalidate if needed InvalidateIfNeeded(false); const uint32_t reg_byte_size = reg_info->byte_size; const size_t bytes_copied = response.GetHexBytes (const_cast(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc'); bool success = bytes_copied == reg_byte_size; if (success) { SetRegisterIsValid(reg, true); } else if (bytes_copied > 0) { // Only set register is valid to false if we copied some bytes, else // leave it as it was. SetRegisterIsValid(reg, false); } return success; } bool GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, uint64_t new_reg_val) { const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); if (reg_info == NULL) return false; // Early in process startup, we can get a thread that has an invalid byte order // because the process hasn't been completely set up yet (see the ctor where the // byte order is setfrom the process). If that's the case, we can't set the // value here. if (m_reg_data.GetByteOrder() == eByteOrderInvalid) { return false; } // Invalidate if needed InvalidateIfNeeded (false); DataBufferSP buffer_sp (new DataBufferHeap (&new_reg_val, sizeof (new_reg_val))); DataExtractor data (buffer_sp, endian::InlHostByteOrder(), sizeof (void*)); // If our register context and our register info disagree, which should never happen, don't // overwrite past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; // Grab a pointer to where we are going to put this register uint8_t *dst = const_cast(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); if (dst == NULL) return false; if (data.CopyByteOrderedData (0, // src offset reg_info->byte_size, // src length dst, // dst reg_info->byte_size, // dst length m_reg_data.GetByteOrder())) // dst byte order { SetRegisterIsValid (reg, true); return true; } return false; } // Helper function for GDBRemoteRegisterContext::ReadRegisterBytes(). bool GDBRemoteRegisterContext::GetPrimordialRegister(const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { const uint32_t lldb_reg = reg_info->kinds[eRegisterKindLLDB]; const uint32_t remote_reg = reg_info->kinds[eRegisterKindProcessPlugin]; StringExtractorGDBRemote response; if (gdb_comm.ReadRegister(m_thread.GetProtocolID(), remote_reg, response)) return PrivateSetRegisterValue (lldb_reg, response); return false; } bool GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data) { ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); InvalidateIfNeeded(false); const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; if (!GetRegisterIsValid(reg)) { if (m_read_all_at_once) { StringExtractorGDBRemote response; if (!gdb_comm.ReadAllRegisters(m_thread.GetProtocolID(), response)) return false; if (response.IsNormalResponse()) if (response.GetHexBytes(const_cast(reinterpret_cast(m_reg_data.GetDataStart())), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize()) SetAllRegisterValid (true); } else if (reg_info->value_regs) { // Process this composite register request by delegating to the constituent // primordial registers. // Index of the primordial register. bool success = true; for (uint32_t idx = 0; success; ++idx) { const uint32_t prim_reg = reg_info->value_regs[idx]; if (prim_reg == LLDB_INVALID_REGNUM) break; // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg); if (prim_reg_info == NULL) success = false; else { // Read the containing register if it hasn't already been read if (!GetRegisterIsValid(prim_reg)) success = GetPrimordialRegister(prim_reg_info, gdb_comm); } } if (success) { // If we reach this point, all primordial register requests have succeeded. // Validate this composite register. SetRegisterIsValid (reg_info, true); } } else { // Get each register individually GetPrimordialRegister(reg_info, gdb_comm); } // Make sure we got a valid register value after reading it if (!GetRegisterIsValid(reg)) return false; } if (&data != &m_reg_data) { #if defined (LLDB_CONFIGURATION_DEBUG) assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); #endif // If our register context and our register info disagree, which should never happen, don't // read past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; // If we aren't extracting into our own buffer (which // only happens when this function is called from // ReadRegisterValue(uint32_t, Scalar&)) then // we transfer bytes from our buffer into the data // buffer that was passed in data.SetByteOrder (m_reg_data.GetByteOrder()); data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size); } return true; } bool GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value) { DataExtractor data; if (value.GetData (data)) return WriteRegisterBytes (reg_info, data, 0); return false; } // Helper function for GDBRemoteRegisterContext::WriteRegisterBytes(). bool GDBRemoteRegisterContext::SetPrimordialRegister(const RegisterInfo *reg_info, GDBRemoteCommunicationClient &gdb_comm) { StreamString packet; StringExtractorGDBRemote response; const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size), reg_info->byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); if (gdb_comm.GetThreadSuffixSupported()) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); // Invalidate just this register SetRegisterIsValid(reg, false); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; } return false; } void GDBRemoteRegisterContext::SyncThreadState(Process *process) { // NB. We assume our caller has locked the sequence mutex. GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote()); if (!gdb_comm.GetSyncThreadStateSupported()) return; StreamString packet; StringExtractorGDBRemote response; packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID()); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) InvalidateAllRegisters(); } } bool GDBRemoteRegisterContext::WriteRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset) { ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); // FIXME: This check isn't right because IsRunning checks the Public state, but this // is work you need to do - for instance in ShouldStop & friends - before the public // state has been changed. // if (gdb_comm.IsRunning()) // return false; #if defined (LLDB_CONFIGURATION_DEBUG) assert (m_reg_data.GetByteSize() >= reg_info->byte_offset + reg_info->byte_size); #endif // If our register context and our register info disagree, which should never happen, don't // overwrite past the end of the buffer. if (m_reg_data.GetByteSize() < reg_info->byte_offset + reg_info->byte_size) return false; // Grab a pointer to where we are going to put this register uint8_t *dst = const_cast(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size)); if (dst == NULL) return false; if (data.CopyByteOrderedData (data_offset, // src offset reg_info->byte_size, // src length dst, // dst reg_info->byte_size, // dst length m_reg_data.GetByteOrder())) // dst byte order { Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register.")) { const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); ProcessSP process_sp (m_thread.GetProcess()); if (thread_suffix_supported || static_cast(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) { StreamString packet; StringExtractorGDBRemote response; if (m_read_all_at_once) { // Set all registers in one packet packet.PutChar ('G'); packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), endian::InlHostByteOrder(), endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); // Invalidate all register values InvalidateIfNeeded (true); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { SetAllRegisterValid (false); if (response.IsOKResponse()) { return true; } } } else { bool success = true; if (reg_info->value_regs) { // This register is part of another register. In this case we read the actual // register data for any "value_regs", and once all that data is read, we will // have enough data in our register context bytes for the value of this register // Invalidate this composite register first. for (uint32_t idx = 0; success; ++idx) { const uint32_t reg = reg_info->value_regs[idx]; if (reg == LLDB_INVALID_REGNUM) break; // We have a valid primordial register as our constituent. // Grab the corresponding register info. const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg); if (value_reg_info == NULL) success = false; else success = SetPrimordialRegister(value_reg_info, gdb_comm); } } else { // This is an actual register, write it success = SetPrimordialRegister(reg_info, gdb_comm); } // Check if writing this register will invalidate any other register values? // If so, invalidate them if (reg_info->invalidate_regs) { for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0]; reg != LLDB_INVALID_REGNUM; reg = reg_info->invalidate_regs[++idx]) { SetRegisterIsValid(reg, false); } } return success; } } } else { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { if (log->GetVerbose()) { StreamString strm; gdb_comm.DumpHistory(strm); log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData()); } else log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name); } } } return false; } bool GDBRemoteRegisterContext::ReadAllRegisterValues (RegisterCheckpoint ®_checkpoint) { ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); uint32_t save_id = 0; if (gdb_comm.SaveRegisterState(thread->GetProtocolID(), save_id)) { reg_checkpoint.SetID(save_id); reg_checkpoint.GetData().reset(); return true; } else { reg_checkpoint.SetID(0); // Invalid save ID is zero return ReadAllRegisterValues(reg_checkpoint.GetData()); } } bool GDBRemoteRegisterContext::WriteAllRegisterValues (const RegisterCheckpoint ®_checkpoint) { uint32_t save_id = reg_checkpoint.GetID(); if (save_id != 0) { ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); return gdb_comm.RestoreRegisterState(m_thread.GetProtocolID(), save_id); } else { return WriteAllRegisterValues(reg_checkpoint.GetData()); } } bool GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); StringExtractorGDBRemote response; const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers.")) { SyncThreadState(process); char packet[32]; const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); ProcessSP process_sp (m_thread.GetProcess()); if (thread_suffix_supported || static_cast(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) { int packet_len = 0; if (thread_suffix_supported) packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); else packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { int packet_len = 0; if (thread_suffix_supported) packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID()); else packet_len = ::snprintf (packet, sizeof(packet), "g"); assert (packet_len < ((int)sizeof(packet) - 1)); if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsErrorResponse()) return false; std::string &response_str = response.GetStringRef(); if (isxdigit(response_str[0])) { response_str.insert(0, 1, 'G'); if (thread_suffix_supported) { char thread_id_cstr[64]; ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); response_str.append (thread_id_cstr); } data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size())); return true; } } } else { // For the use_g_packet == false case, we're going to read each register // individually and store them as binary data in a buffer instead of as ascii // characters. const RegisterInfo *reg_info; // data_sp will take ownership of this DataBufferHeap pointer soon. DataBufferSP reg_ctx(new DataBufferHeap(m_reg_info.GetRegisterDataByteSize(), 0)); for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) { if (reg_info->value_regs) // skip registers that are slices of real registers continue; ReadRegisterBytes (reg_info, m_reg_data); // ReadRegisterBytes saves the contents of the register in to the m_reg_data buffer } memcpy (reg_ctx->GetBytes(), m_reg_data.GetDataStart(), m_reg_info.GetRegisterDataByteSize()); data_sp = reg_ctx; return true; } } } else { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { if (log->GetVerbose()) { StreamString strm; gdb_comm.DumpHistory(strm); log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData()); } else log->Printf("error: failed to get packet sequence mutex, not sending read all registers"); } } data_sp.reset(); return false; } bool GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0) return false; ExecutionContext exe_ctx (CalculateThread()); Process *process = exe_ctx.GetProcessPtr(); Thread *thread = exe_ctx.GetThreadPtr(); if (process == NULL || thread == NULL) return false; GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote()); const bool use_g_packet = gdb_comm.AvoidGPackets ((ProcessGDBRemote *)process) == false; StringExtractorGDBRemote response; Mutex::Locker locker; if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers.")) { const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported(); ProcessSP process_sp (m_thread.GetProcess()); if (thread_suffix_supported || static_cast(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID())) { // The data_sp contains the entire G response packet including the // G, and if the thread suffix is supported, it has the thread suffix // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); if (use_g_packet && gdb_comm.SendPacketAndWaitForResponse (G_packet, G_packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { // The data_sp contains the entire G response packet including the // G, and if the thread suffix is supported, it has the thread suffix // as well. const char *G_packet = (const char *)data_sp->GetBytes(); size_t G_packet_len = data_sp->GetByteSize(); if (gdb_comm.SendPacketAndWaitForResponse (G_packet, G_packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) return true; else if (response.IsErrorResponse()) { uint32_t num_restored = 0; // We need to manually go through all of the registers and // restore them manually response.GetStringRef().assign (G_packet, G_packet_len); response.SetFilePos(1); // Skip the leading 'G' // G_packet_len is hex-ascii characters plus prefix 'G' plus suffix thread specifier. // This means buffer will be a little more than 2x larger than necessary but we resize // it down once we've extracted all hex ascii chars from the packet. DataBufferHeap buffer (G_packet_len, 0); const uint32_t bytes_extracted = response.GetHexBytes (buffer.GetBytes(), buffer.GetByteSize(), '\xcc'); DataExtractor restore_data (buffer.GetBytes(), buffer.GetByteSize(), m_reg_data.GetByteOrder(), m_reg_data.GetAddressByteSize()); if (bytes_extracted < restore_data.GetByteSize()) restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder()); const RegisterInfo *reg_info; // The g packet contents may either include the slice registers (registers defined in // terms of other registers, e.g. eax is a subset of rax) or not. The slice registers // should NOT be in the g packet, but some implementations may incorrectly include them. // // If the slice registers are included in the packet, we must step over the slice registers // when parsing the packet -- relying on the RegisterInfo byte_offset field would be incorrect. // If the slice registers are not included, then using the byte_offset values into the // data buffer is the best way to find individual register values. uint64_t size_including_slice_registers = 0; uint64_t size_not_including_slice_registers = 0; uint64_t size_by_highest_offset = 0; for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx) { size_including_slice_registers += reg_info->byte_size; if (reg_info->value_regs == NULL) size_not_including_slice_registers += reg_info->byte_size; if (reg_info->byte_offset >= size_by_highest_offset) size_by_highest_offset = reg_info->byte_offset + reg_info->byte_size; } bool use_byte_offset_into_buffer; if (size_by_highest_offset == restore_data.GetByteSize()) { // The size of the packet agrees with the highest offset: + size in the register file use_byte_offset_into_buffer = true; } else if (size_not_including_slice_registers == restore_data.GetByteSize()) { // The size of the packet is the same as concatenating all of the registers sequentially, // skipping the slice registers use_byte_offset_into_buffer = true; } else if (size_including_slice_registers == restore_data.GetByteSize()) { // The slice registers are present in the packet (when they shouldn't be). // Don't try to use the RegisterInfo byte_offset into the restore_data, it will // point to the wrong place. use_byte_offset_into_buffer = false; } else { // None of our expected sizes match the actual g packet data we're looking at. // The most conservative approach here is to use the running total byte offset. use_byte_offset_into_buffer = false; } // In case our register definitions don't include the correct offsets, // keep track of the size of each reg & compute offset based on that. uint32_t running_byte_offset = 0; for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, running_byte_offset += reg_info->byte_size) { // Skip composite aka slice registers (e.g. eax is a slice of rax). if (reg_info->value_regs) continue; const uint32_t reg = reg_info->kinds[eRegisterKindLLDB]; uint32_t register_offset; if (use_byte_offset_into_buffer) { register_offset = reg_info->byte_offset; } else { register_offset = running_byte_offset; } // Only write down the registers that need to be written // if we are going to be doing registers individually. bool write_reg = true; const uint32_t reg_byte_size = reg_info->byte_size; const char *restore_src = (const char *)restore_data.PeekData(register_offset, reg_byte_size); if (restore_src) { StreamString packet; packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); packet.PutBytesAsRawHex8 (restore_src, reg_byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); SetRegisterIsValid(reg, false); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { const char *current_src = (const char *)m_reg_data.PeekData(register_offset, reg_byte_size); if (current_src) write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0; } if (write_reg) { StreamString packet; packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); packet.PutBytesAsRawHex8 (restore_src, reg_byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); SetRegisterIsValid(reg, false); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) ++num_restored; } } } } return num_restored > 0; } } } else { // For the use_g_packet == false case, we're going to write each register // individually. The data buffer is binary data in this case, instead of // ascii characters. bool arm64_debugserver = false; if (m_thread.GetProcess().get()) { const ArchSpec &arch = m_thread.GetProcess()->GetTarget().GetArchitecture(); if (arch.IsValid() && arch.GetMachine() == llvm::Triple::aarch64 && arch.GetTriple().getVendor() == llvm::Triple::Apple && arch.GetTriple().getOS() == llvm::Triple::IOS) { arm64_debugserver = true; } } uint32_t num_restored = 0; const RegisterInfo *reg_info; for (uint32_t i = 0; (reg_info = GetRegisterInfoAtIndex (i)) != NULL; i++) { if (reg_info->value_regs) // skip registers that are slices of real registers continue; // Skip the fpsr and fpcr floating point status/control register writing to // work around a bug in an older version of debugserver that would lead to // register context corruption when writing fpsr/fpcr. if (arm64_debugserver && (strcmp (reg_info->name, "fpsr") == 0 || strcmp (reg_info->name, "fpcr") == 0)) { continue; } StreamString packet; packet.Printf ("P%x=", reg_info->kinds[eRegisterKindProcessPlugin]); packet.PutBytesAsRawHex8 (data_sp->GetBytes() + reg_info->byte_offset, reg_info->byte_size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); if (thread_suffix_supported) packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID()); SetRegisterIsValid(reg_info, false); if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), packet.GetString().size(), response, false) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) ++num_restored; } } return num_restored > 0; } } } else { Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS)); if (log) { if (log->GetVerbose()) { StreamString strm; gdb_comm.DumpHistory(strm); log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData()); } else log->Printf("error: failed to get packet sequence mutex, not sending write all registers"); } } return false; } uint32_t GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (lldb::RegisterKind kind, uint32_t num) { return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num); } void GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch) { // For Advanced SIMD and VFP register mapping. static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1) static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3) static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5) static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7) static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9) static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11) static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13) static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15) static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17) static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19) static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21) static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23) static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25) static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27) static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29) static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31) static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3) static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7) static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11) static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15) static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19) static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23) static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27) static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31) static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17) static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19) static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21) static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23) static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25) static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27) static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29) static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31) // This is our array of composite registers, with each element coming from the above register mappings. static uint32_t *g_composites[] = { g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs, g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs, g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs, g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs }; static RegisterInfo g_register_infos[] = { // NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB VALUE REGS INVALIDATE REGS // ====== ====== === === ============= ============ =================== =================== ====================== ============= ==== ========== =============== { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { ehframe_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL}, { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { ehframe_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL}, { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { ehframe_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL}, { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { ehframe_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL}, { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL}, { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL}, { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL}, { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { ehframe_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL}, { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL}, { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL}, { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL}, { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL}, { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { ehframe_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL}, { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { ehframe_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL}, { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { ehframe_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL}, { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { ehframe_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL}, { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL}, { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL}, { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL}, { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL}, { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL}, { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL}, { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL}, { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL}, { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL}, { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { ehframe_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL}, { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL}, { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL}, { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL}, { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL}, { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL}, { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL}, { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL}, { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL}, { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL}, { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL}, { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL}, { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL}, { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL}, { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL}, { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL}, { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL}, { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL}, { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL}, { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL}, { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL}, { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL}, { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL}, { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL}, { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL}, { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL}, { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL}, { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL}, { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL}, { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL}, { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL}, { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL}, { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL}, { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL}, { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL}, { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL}, { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL}, { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL}, { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL}, { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL}, { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL}, { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL}, { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL}, { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL}, { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL}, { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL}, { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL}, { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL}, { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL}, { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL}, { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL}, { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL}, { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL}, { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL}, { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL}, { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL}, { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL}, { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL}, { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL}, { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL}, { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL}, { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL}, { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL}, { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL}, { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL}, { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL}, { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL}, { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL}, { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL}, { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL}, { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL}, { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL}, { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL}, { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL}, { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL}, { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL}, { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL}, { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL}, { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL}, { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL}, { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL}, { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL} }; static const uint32_t num_registers = llvm::array_lengthof(g_register_infos); static ConstString gpr_reg_set ("General Purpose Registers"); static ConstString sfp_reg_set ("Software Floating Point Registers"); static ConstString vfp_reg_set ("Floating Point Registers"); size_t i; if (from_scratch) { // Calculate the offsets of the registers // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the // "primordial" registers is important. This enables us to calculate the offset of the composite // register by using the offset of its first primordial register. For example, to calculate the // offset of q0, use s0's offset. if (g_register_infos[2].byte_offset == 0) { uint32_t byte_offset = 0; for (i=0; iname && ::strcasecmp(reg_info->name, reg_name) == 0) { // The name matches the existing primordial entry. // Find and assign the offset, and then add this composite register entry. g_comp_register_infos[i].byte_offset = reg_info->byte_offset; name.SetCString(g_comp_register_infos[i].name); AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set); } } } } } } } Index: vendor/lldb/dist/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- vendor/lldb/dist/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (revision 304307) +++ vendor/lldb/dist/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (revision 304308) @@ -1,5287 +1,5326 @@ //===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Host/Config.h" // C Includes #include #include #ifndef LLDB_DISABLE_POSIX #include #include // for mmap #endif #include #include #include // C++ Includes #include #include #include #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Interpreter/Args.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/Debugger.h" #include "lldb/Host/ConnectionFileDescriptor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/State.h" #include "lldb/Core/StreamFile.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Core/Value.h" #include "lldb/DataFormatters/FormatManager.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/TimeValue.h" #include "lldb/Host/XML.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/CommandObject.h" #include "lldb/Interpreter/CommandObjectMultiword.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Options.h" #include "lldb/Interpreter/OptionGroupBoolean.h" #include "lldb/Interpreter/OptionGroupUInt64.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/ABI.h" #include "lldb/Target/DynamicLoader.h" #include "lldb/Target/Target.h" #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Utility/PseudoTerminal.h" // Project includes #include "lldb/Host/Host.h" #include "Plugins/Process/Utility/GDBRemoteSignals.h" #include "Plugins/Process/Utility/InferiorCallPOSIX.h" #include "Plugins/Process/Utility/StopInfoMachException.h" #include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h" #include "Utility/StringExtractorGDBRemote.h" #include "GDBRemoteRegisterContext.h" #include "ProcessGDBRemote.h" #include "ProcessGDBRemoteLog.h" #include "ThreadGDBRemote.h" #define DEBUGSERVER_BASENAME "debugserver" using namespace lldb; using namespace lldb_private; using namespace lldb_private::process_gdb_remote; namespace lldb { // Provide a function that can easily dump the packet history if we know a // ProcessGDBRemote * value (which we can get from logs or from debugging). // We need the function in the lldb namespace so it makes it into the final // executable since the LLDB shared library only exports stuff in the lldb // namespace. This allows you to attach with a debugger and call this // function and get the packet history dumped to a file. void DumpProcessGDBRemotePacketHistory (void *p, const char *path) { StreamFile strm; Error error (strm.GetFile().Open(path, File::eOpenOptionWrite | File::eOpenOptionCanCreate)); if (error.Success()) ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm); } } namespace { static PropertyDefinition g_properties[] = { { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." }, { "target-definition-file" , OptionValue::eTypeFileSpec , true, 0 , NULL, NULL, "The file that provides the description for remote target registers." }, { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL } }; enum { ePropertyPacketTimeout, ePropertyTargetDefinitionFile }; class PluginProperties : public Properties { public: static ConstString GetSettingName () { return ProcessGDBRemote::GetPluginNameStatic(); } PluginProperties() : Properties () { m_collection_sp.reset (new OptionValueProperties(GetSettingName())); m_collection_sp->Initialize(g_properties); } virtual ~PluginProperties() { } uint64_t GetPacketTimeout() { const uint32_t idx = ePropertyPacketTimeout; return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value); } bool SetPacketTimeout(uint64_t timeout) { const uint32_t idx = ePropertyPacketTimeout; return m_collection_sp->SetPropertyAtIndexAsUInt64(NULL, idx, timeout); } FileSpec GetTargetDefinitionFile () const { const uint32_t idx = ePropertyTargetDefinitionFile; return m_collection_sp->GetPropertyAtIndexAsFileSpec (NULL, idx); } }; typedef std::shared_ptr ProcessKDPPropertiesSP; static const ProcessKDPPropertiesSP & GetGlobalPluginProperties() { static ProcessKDPPropertiesSP g_settings_sp; if (!g_settings_sp) g_settings_sp.reset (new PluginProperties ()); return g_settings_sp; } } // anonymous namespace end // TODO Randomly assigning a port is unsafe. We should get an unused // ephemeral port from the kernel and make sure we reserve it before passing // it to debugserver. #if defined (__APPLE__) #define LOW_PORT (IPPORT_RESERVED) #define HIGH_PORT (IPPORT_HIFIRSTAUTO) #else #define LOW_PORT (1024u) #define HIGH_PORT (49151u) #endif #if defined(__APPLE__) && (defined(__arm__) || defined(__arm64__) || defined(__aarch64__)) static bool rand_initialized = false; static inline uint16_t get_random_port () { if (!rand_initialized) { time_t seed = time(NULL); rand_initialized = true; srand(seed); } return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT; } #endif ConstString ProcessGDBRemote::GetPluginNameStatic() { static ConstString g_name("gdb-remote"); return g_name; } const char * ProcessGDBRemote::GetPluginDescriptionStatic() { return "GDB Remote protocol based debugging plug-in."; } void ProcessGDBRemote::Terminate() { PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance); } lldb::ProcessSP ProcessGDBRemote::CreateInstance (lldb::TargetSP target_sp, ListenerSP listener_sp, const FileSpec *crash_file_path) { lldb::ProcessSP process_sp; if (crash_file_path == NULL) process_sp.reset (new ProcessGDBRemote (target_sp, listener_sp)); return process_sp; } bool ProcessGDBRemote::CanDebug (lldb::TargetSP target_sp, 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_sp->GetExecutableModulePointer(); if (exe_module) { ObjectFile *exe_objfile = exe_module->GetObjectFile(); // We can't debug core files... switch (exe_objfile->GetType()) { case ObjectFile::eTypeInvalid: case ObjectFile::eTypeCoreFile: case ObjectFile::eTypeDebugInfo: case ObjectFile::eTypeObjectFile: case ObjectFile::eTypeSharedLibrary: case ObjectFile::eTypeStubLibrary: case ObjectFile::eTypeJIT: return false; case ObjectFile::eTypeExecutable: case ObjectFile::eTypeDynamicLinker: case ObjectFile::eTypeUnknown: break; } return exe_module->GetFileSpec().Exists(); } // However, if there is no executable module, we return true since we might be preparing to attach. return true; } //---------------------------------------------------------------------- // ProcessGDBRemote constructor //---------------------------------------------------------------------- ProcessGDBRemote::ProcessGDBRemote(lldb::TargetSP target_sp, ListenerSP listener_sp) : Process(target_sp, listener_sp), m_flags(0), m_gdb_comm(), m_debugserver_pid(LLDB_INVALID_PROCESS_ID), m_last_stop_packet_mutex(), m_register_info(), m_async_broadcaster(NULL, "lldb.process.gdb-remote.async-broadcaster"), m_async_listener_sp(Listener::MakeListener("lldb.process.gdb-remote.async-listener")), m_async_thread_state_mutex(), m_thread_ids(), m_thread_pcs(), m_jstopinfo_sp(), m_jthreadsinfo_sp(), m_continue_c_tids(), m_continue_C_tids(), m_continue_s_tids(), m_continue_S_tids(), m_max_memory_size(0), m_remote_stub_max_memory_size(0), m_addr_to_mmap_size(), m_thread_create_bp_sp(), m_waiting_for_attach(false), m_destroy_tried_resuming(false), m_command_sp(), m_breakpoint_pc_offset(0), m_initial_tid(LLDB_INVALID_THREAD_ID) { m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadShouldExit, "async thread should exit"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncContinue, "async thread continue"); m_async_broadcaster.SetEventName(eBroadcastBitAsyncThreadDidExit, "async thread did exit"); Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_ASYNC)); const uint32_t async_event_mask = eBroadcastBitAsyncContinue | eBroadcastBitAsyncThreadShouldExit; if (m_async_listener_sp->StartListeningForEvents(&m_async_broadcaster, async_event_mask) != async_event_mask) { if (log) log->Printf("ProcessGDBRemote::%s failed to listen for m_async_broadcaster events", __FUNCTION__); } const uint32_t gdb_event_mask = Communication::eBroadcastBitReadThreadDidExit | GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify; if (m_async_listener_sp->StartListeningForEvents(&m_gdb_comm, gdb_event_mask) != gdb_event_mask) { if (log) log->Printf("ProcessGDBRemote::%s failed to listen for m_gdb_comm events", __FUNCTION__); } const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout(); if (timeout_seconds > 0) m_gdb_comm.SetPacketTimeout(timeout_seconds); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- ProcessGDBRemote::~ProcessGDBRemote() { // m_mach_process.UnregisterNotificationCallbacks (this); 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(); // The general Finalize is going to try to destroy the process and that SHOULD // shut down the async thread. However, if we don't kill it it will get stranded and // its connection will go away so when it wakes up it will crash. So kill it for sure here. StopAsyncThread(); KillDebugserverProcess(); } //---------------------------------------------------------------------- // PluginInterface //---------------------------------------------------------------------- ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); } uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; } bool ProcessGDBRemote::ParsePythonTargetDefinition(const FileSpec &target_definition_fspec) { ScriptInterpreter *interpreter = GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); Error error; StructuredData::ObjectSP module_object_sp(interpreter->LoadPluginModule(target_definition_fspec, error)); if (module_object_sp) { StructuredData::DictionarySP target_definition_sp( interpreter->GetDynamicSettings(module_object_sp, &GetTarget(), "gdb-server-target-definition", error)); if (target_definition_sp) { StructuredData::ObjectSP target_object(target_definition_sp->GetValueForKey("host-info")); if (target_object) { if (auto host_info_dict = target_object->GetAsDictionary()) { StructuredData::ObjectSP triple_value = host_info_dict->GetValueForKey("triple"); if (auto triple_string_value = triple_value->GetAsString()) { std::string triple_string = triple_string_value->GetValue(); ArchSpec host_arch(triple_string.c_str()); if (!host_arch.IsCompatibleMatch(GetTarget().GetArchitecture())) { GetTarget().SetArchitecture(host_arch); } } } } m_breakpoint_pc_offset = 0; StructuredData::ObjectSP breakpoint_pc_offset_value = target_definition_sp->GetValueForKey("breakpoint-pc-offset"); if (breakpoint_pc_offset_value) { if (auto breakpoint_pc_int_value = breakpoint_pc_offset_value->GetAsInteger()) m_breakpoint_pc_offset = breakpoint_pc_int_value->GetValue(); } if (m_register_info.SetRegisterInfo(*target_definition_sp, GetTarget().GetArchitecture()) > 0) { return true; } } } return false; } // If the remote stub didn't give us eh_frame or DWARF register numbers for a register, // see if the ABI can provide them. // DWARF and eh_frame register numbers are defined as a part of the ABI. static void AugmentRegisterInfoViaABI (RegisterInfo ®_info, ConstString reg_name, ABISP abi_sp) { if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM || reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM) { if (abi_sp) { RegisterInfo abi_reg_info; if (abi_sp->GetRegisterInfoByName (reg_name, abi_reg_info)) { if (reg_info.kinds[eRegisterKindEHFrame] == LLDB_INVALID_REGNUM && abi_reg_info.kinds[eRegisterKindEHFrame] != LLDB_INVALID_REGNUM) { reg_info.kinds[eRegisterKindEHFrame] = abi_reg_info.kinds[eRegisterKindEHFrame]; } if (reg_info.kinds[eRegisterKindDWARF] == LLDB_INVALID_REGNUM && abi_reg_info.kinds[eRegisterKindDWARF] != LLDB_INVALID_REGNUM) { reg_info.kinds[eRegisterKindDWARF] = abi_reg_info.kinds[eRegisterKindDWARF]; } if (reg_info.kinds[eRegisterKindGeneric] == LLDB_INVALID_REGNUM && abi_reg_info.kinds[eRegisterKindGeneric] != LLDB_INVALID_REGNUM) { reg_info.kinds[eRegisterKindGeneric] = abi_reg_info.kinds[eRegisterKindGeneric]; } } } } } static size_t SplitCommaSeparatedRegisterNumberString(const llvm::StringRef &comma_separated_regiter_numbers, std::vector ®nums, int base) { regnums.clear(); std::pair value_pair; value_pair.second = comma_separated_regiter_numbers; do { value_pair = value_pair.second.split(','); if (!value_pair.first.empty()) { uint32_t reg = StringConvert::ToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, base); if (reg != LLDB_INVALID_REGNUM) regnums.push_back (reg); } } while (!value_pair.second.empty()); return regnums.size(); } void ProcessGDBRemote::BuildDynamicRegisterInfo (bool force) { if (!force && m_register_info.GetNumRegisters() > 0) return; m_register_info.Clear(); // Check if qHostInfo specified a specific packet timeout for this connection. // If so then lets update our setting so the user knows what the timeout is // and can see it. const uint32_t host_packet_timeout = m_gdb_comm.GetHostDefaultPacketTimeout(); if (host_packet_timeout) { GetGlobalPluginProperties()->SetPacketTimeout(host_packet_timeout); } // Register info search order: // 1 - Use the target definition python file if one is specified. // 2 - If the target definition doesn't have any of the info from the target.xml (registers) then proceed to read the target.xml. // 3 - Fall back on the qRegisterInfo packets. FileSpec target_definition_fspec = GetGlobalPluginProperties()->GetTargetDefinitionFile (); if (!target_definition_fspec.Exists()) { // If the filename doesn't exist, it may be a ~ not having been expanded - try to resolve it. target_definition_fspec.ResolvePath(); } if (target_definition_fspec) { // See if we can get register definitions from a python file if (ParsePythonTargetDefinition (target_definition_fspec)) { return; } else { StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); stream_sp->Printf ("ERROR: target description file %s failed to parse.\n", target_definition_fspec.GetPath().c_str()); } } const ArchSpec &target_arch = GetTarget().GetArchitecture(); const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture(); const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); // Use the process' architecture instead of the host arch, if available ArchSpec arch_to_use; if (remote_process_arch.IsValid ()) arch_to_use = remote_process_arch; else arch_to_use = remote_host_arch; if (!arch_to_use.IsValid()) arch_to_use = target_arch; if (GetGDBServerRegisterInfo (arch_to_use)) return; char packet[128]; uint32_t reg_offset = 0; uint32_t reg_num = 0; for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; response_type == StringExtractorGDBRemote::eResponse; ++reg_num) { const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num); assert (packet_len < (int)sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false) == GDBRemoteCommunication::PacketResult::Success) { response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { std::string name; std::string value; ConstString reg_name; ConstString alt_name; ConstString set_name; std::vector value_regs; std::vector invalidate_regs; + std::vector dwarf_opcode_bytes; RegisterInfo reg_info = { NULL, // Name NULL, // Alt name 0, // byte size reg_offset, // offset eEncodingUint, // encoding eFormatHex, // format { LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num reg_num, // process plugin reg num reg_num // native register number }, NULL, - NULL + NULL, + NULL, // Dwarf expression opcode bytes pointer + 0 // Dwarf expression opcode bytes length }; while (response.GetNameColonValue(name, value)) { if (name.compare("name") == 0) { reg_name.SetCString(value.c_str()); } else if (name.compare("alt-name") == 0) { alt_name.SetCString(value.c_str()); } else if (name.compare("bitsize") == 0) { reg_info.byte_size = StringConvert::ToUInt32(value.c_str(), 0, 0) / CHAR_BIT; } else if (name.compare("offset") == 0) { uint32_t offset = StringConvert::ToUInt32(value.c_str(), UINT32_MAX, 0); if (reg_offset != offset) { reg_offset = offset; } } else if (name.compare("encoding") == 0) { const Encoding encoding = Args::StringToEncoding (value.c_str()); if (encoding != eEncodingInvalid) reg_info.encoding = encoding; } else if (name.compare("format") == 0) { Format format = eFormatInvalid; if (Args::StringToFormat (value.c_str(), format, NULL).Success()) reg_info.format = format; else if (value.compare("binary") == 0) reg_info.format = eFormatBinary; else if (value.compare("decimal") == 0) reg_info.format = eFormatDecimal; else if (value.compare("hex") == 0) reg_info.format = eFormatHex; else if (value.compare("float") == 0) reg_info.format = eFormatFloat; else if (value.compare("vector-sint8") == 0) reg_info.format = eFormatVectorOfSInt8; else if (value.compare("vector-uint8") == 0) reg_info.format = eFormatVectorOfUInt8; else if (value.compare("vector-sint16") == 0) reg_info.format = eFormatVectorOfSInt16; else if (value.compare("vector-uint16") == 0) reg_info.format = eFormatVectorOfUInt16; else if (value.compare("vector-sint32") == 0) reg_info.format = eFormatVectorOfSInt32; else if (value.compare("vector-uint32") == 0) reg_info.format = eFormatVectorOfUInt32; else if (value.compare("vector-float32") == 0) reg_info.format = eFormatVectorOfFloat32; else if (value.compare("vector-uint128") == 0) reg_info.format = eFormatVectorOfUInt128; } else if (name.compare("set") == 0) { set_name.SetCString(value.c_str()); } else if (name.compare("gcc") == 0 || name.compare("ehframe") == 0) { reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); } else if (name.compare("dwarf") == 0) { reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0); } else if (name.compare("generic") == 0) { reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str()); } else if (name.compare("container-regs") == 0) { SplitCommaSeparatedRegisterNumberString(value, value_regs, 16); } else if (name.compare("invalidate-regs") == 0) { SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 16); } + else if (name.compare("dynamic_size_dwarf_expr_bytes") == 0) + { + size_t dwarf_opcode_len = value.length () / 2; + assert (dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize (dwarf_opcode_len); + StringExtractor opcode_extractor; + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + + // Swap "value" over into "opcode_extractor" + opcode_extractor.GetStringRef ().swap (value); + uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), + dwarf_opcode_len); + assert (dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); + } } reg_info.byte_offset = reg_offset; assert (reg_info.byte_size != 0); reg_offset += reg_info.byte_size; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); } if (!invalidate_regs.empty()) { invalidate_regs.push_back(LLDB_INVALID_REGNUM); reg_info.invalidate_regs = invalidate_regs.data(); } // We have to make a temporary ABI here, and not use the GetABI because this code // gets called in DidAttach, when the target architecture (and consequently the ABI we'll get from // the process) may be wrong. ABISP abi_to_use = ABI::FindPlugin(arch_to_use); AugmentRegisterInfoViaABI (reg_info, reg_name, abi_to_use); m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name); } else { break; // ensure exit before reg_num is incremented } } else { break; } } if (m_register_info.GetNumRegisters() > 0) { m_register_info.Finalize(GetTarget().GetArchitecture()); return; } // We didn't get anything if the accumulated reg_num is zero. See if we are // debugging ARM and fill with a hard coded register set until we can get an // updated debugserver down on the devices. // On the other hand, if the accumulated reg_num is positive, see if we can // add composite registers to the existing primordial ones. bool from_scratch = (m_register_info.GetNumRegisters() == 0); if (!target_arch.IsValid()) { if (arch_to_use.IsValid() && (arch_to_use.GetMachine() == llvm::Triple::arm || arch_to_use.GetMachine() == llvm::Triple::thumb) && arch_to_use.GetTriple().getVendor() == llvm::Triple::Apple) m_register_info.HardcodeARMRegisters(from_scratch); } else if (target_arch.GetMachine() == llvm::Triple::arm || target_arch.GetMachine() == llvm::Triple::thumb) { m_register_info.HardcodeARMRegisters(from_scratch); } // At this point, we can finalize our register info. m_register_info.Finalize (GetTarget().GetArchitecture()); } Error ProcessGDBRemote::WillLaunch (Module* module) { return WillLaunchOrAttach (); } Error ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid) { return WillLaunchOrAttach (); } Error ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch) { return WillLaunchOrAttach (); } Error ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error (WillLaunchOrAttach ()); if (error.Fail()) return error; error = ConnectToDebugserver (remote_url); if (error.Fail()) return error; StartAsyncThread (); lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); if (pid == LLDB_INVALID_PROCESS_ID) { // We don't have a valid process ID, so note that we are connected // and could now request to launch or attach, or get remote process // listings... SetPrivateState (eStateConnected); } else { // We have a valid process SetID (pid); GetThreadList(); StringExtractorGDBRemote response; if (m_gdb_comm.GetStopReply(response)) { SetLastStopPacket(response); // '?' Packets must be handled differently in non-stop mode if (GetTarget().GetNonStopModeEnabled()) HandleStopReplySequence(); Target &target = GetTarget(); if (!target.GetArchitecture().IsValid()) { if (m_gdb_comm.GetProcessArchitecture().IsValid()) { target.SetArchitecture(m_gdb_comm.GetProcessArchitecture()); } else { target.SetArchitecture(m_gdb_comm.GetHostArchitecture()); } } const StateType state = SetThreadStopInfo (response); if (state != eStateInvalid) { SetPrivateState (state); } else error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state)); } else error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url); } if (log) log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalizing target architecture initial triple: %s (GetTarget().GetArchitecture().IsValid() %s, m_gdb_comm.GetHostArchitecture().IsValid(): %s)", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str (), GetTarget ().GetArchitecture ().IsValid () ? "true" : "false", m_gdb_comm.GetHostArchitecture ().IsValid () ? "true" : "false"); if (error.Success() && !GetTarget().GetArchitecture().IsValid() && m_gdb_comm.GetHostArchitecture().IsValid()) { // Prefer the *process'* architecture over that of the *host*, if available. if (m_gdb_comm.GetProcessArchitecture().IsValid()) GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture()); else GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture()); } if (log) log->Printf ("ProcessGDBRemote::%s pid %" PRIu64 ": normalized target architecture triple: %s", __FUNCTION__, GetID (), GetTarget ().GetArchitecture ().GetTriple ().getTriple ().c_str ()); if (error.Success()) { PlatformSP platform_sp = GetTarget().GetPlatform(); if (platform_sp && platform_sp->IsConnected()) SetUnixSignals(platform_sp->GetUnixSignals()); else SetUnixSignals(UnixSignals::Create(GetTarget().GetArchitecture())); } return error; } Error ProcessGDBRemote::WillLaunchOrAttach () { Error error; m_stdio_communication.Clear (); return error; } //---------------------------------------------------------------------- // Process Control //---------------------------------------------------------------------- Error ProcessGDBRemote::DoLaunch (Module *exe_module, ProcessLaunchInfo &launch_info) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error; if (log) log->Printf ("ProcessGDBRemote::%s() entered", __FUNCTION__); uint32_t launch_flags = launch_info.GetFlags().Get(); FileSpec stdin_file_spec{}; FileSpec stdout_file_spec{}; FileSpec stderr_file_spec{}; FileSpec working_dir = launch_info.GetWorkingDirectory(); const FileAction *file_action; file_action = launch_info.GetFileActionForFD (STDIN_FILENO); if (file_action) { if (file_action->GetAction() == FileAction::eFileActionOpen) stdin_file_spec = file_action->GetFileSpec(); } file_action = launch_info.GetFileActionForFD (STDOUT_FILENO); if (file_action) { if (file_action->GetAction() == FileAction::eFileActionOpen) stdout_file_spec = file_action->GetFileSpec(); } file_action = launch_info.GetFileActionForFD (STDERR_FILENO); if (file_action) { if (file_action->GetAction() == FileAction::eFileActionOpen) stderr_file_spec = file_action->GetFileSpec(); } if (log) { if (stdin_file_spec || stdout_file_spec || stderr_file_spec) log->Printf ("ProcessGDBRemote::%s provided with STDIO paths via launch_info: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_file_spec ? stdin_file_spec.GetCString() : "", stdout_file_spec ? stdout_file_spec.GetCString() : "", stderr_file_spec ? stderr_file_spec.GetCString() : ""); else log->Printf ("ProcessGDBRemote::%s no STDIO paths given via launch_info", __FUNCTION__); } const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; if (stdin_file_spec || disable_stdio) { // the inferior will be reading stdin from the specified file // or stdio is completely disabled m_stdin_forward = false; } else { m_stdin_forward = true; } // ::LogSetBitMask (GDBR_LOG_DEFAULT); // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD); // ::LogSetLogFile ("/dev/stdout"); ObjectFile * object_file = exe_module->GetObjectFile(); if (object_file) { error = EstablishConnectionIfNeeded (launch_info); if (error.Success()) { lldb_utility::PseudoTerminal pty; const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0; PlatformSP platform_sp (GetTarget().GetPlatform()); if (disable_stdio) { // set to /dev/null unless redirected to a file above if (!stdin_file_spec) stdin_file_spec.SetFile(FileSystem::DEV_NULL, false); if (!stdout_file_spec) stdout_file_spec.SetFile(FileSystem::DEV_NULL, false); if (!stderr_file_spec) stderr_file_spec.SetFile(FileSystem::DEV_NULL, false); } else if (platform_sp && platform_sp->IsHost()) { // If the debugserver is local and we aren't disabling STDIO, lets use // a pseudo terminal to instead of relying on the 'O' packets for stdio // since 'O' packets can really slow down debugging if the inferior // does a lot of output. if ((!stdin_file_spec || !stdout_file_spec || !stderr_file_spec) && pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0)) { FileSpec slave_name{pty.GetSlaveName(NULL, 0), false}; if (!stdin_file_spec) stdin_file_spec = slave_name; if (!stdout_file_spec) stdout_file_spec = slave_name; if (!stderr_file_spec) stderr_file_spec = slave_name; } if (log) log->Printf ("ProcessGDBRemote::%s adjusted STDIO paths for local platform (IsHost() is true) using slave: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_file_spec ? stdin_file_spec.GetCString() : "", stdout_file_spec ? stdout_file_spec.GetCString() : "", stderr_file_spec ? stderr_file_spec.GetCString() : ""); } if (log) log->Printf ("ProcessGDBRemote::%s final STDIO paths after all adjustments: stdin=%s, stdout=%s, stderr=%s", __FUNCTION__, stdin_file_spec ? stdin_file_spec.GetCString() : "", stdout_file_spec ? stdout_file_spec.GetCString() : "", stderr_file_spec ? stderr_file_spec.GetCString() : ""); if (stdin_file_spec) m_gdb_comm.SetSTDIN(stdin_file_spec); if (stdout_file_spec) m_gdb_comm.SetSTDOUT(stdout_file_spec); if (stderr_file_spec) m_gdb_comm.SetSTDERR(stderr_file_spec); m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR); m_gdb_comm.SetDetachOnError (launch_flags & eLaunchFlagDetachOnError); m_gdb_comm.SendLaunchArchPacket (GetTarget().GetArchitecture().GetArchitectureName()); const char * launch_event_data = launch_info.GetLaunchEventData(); if (launch_event_data != NULL && *launch_event_data != '\0') m_gdb_comm.SendLaunchEventDataPacket (launch_event_data); if (working_dir) { m_gdb_comm.SetWorkingDir (working_dir); } // Send the environment and the program + arguments after we connect const Args &environment = launch_info.GetEnvironmentEntries(); if (environment.GetArgumentCount()) { size_t num_environment_entries = environment.GetArgumentCount(); for (size_t i=0; iPrintf("failed to connect to debugserver: %s", error.AsCString()); KillDebugserverProcess (); return error; } StringExtractorGDBRemote response; if (m_gdb_comm.GetStopReply(response)) { SetLastStopPacket(response); // '?' Packets must be handled differently in non-stop mode if (GetTarget().GetNonStopModeEnabled()) HandleStopReplySequence(); const ArchSpec &process_arch = m_gdb_comm.GetProcessArchitecture(); if (process_arch.IsValid()) { GetTarget().MergeArchitecture(process_arch); } else { const ArchSpec &host_arch = m_gdb_comm.GetHostArchitecture(); if (host_arch.IsValid()) GetTarget().MergeArchitecture(host_arch); } SetPrivateState (SetThreadStopInfo (response)); if (!disable_stdio) { if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd) SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor()); } } } else { if (log) log->Printf("failed to connect to debugserver: %s", error.AsCString()); } } else { // Set our user ID to an invalid process ID. SetID(LLDB_INVALID_PROCESS_ID); error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s", exe_module->GetFileSpec().GetFilename().AsCString(), exe_module->GetArchitecture().GetArchitectureName()); } return error; } Error ProcessGDBRemote::ConnectToDebugserver (const char *connect_url) { Error error; // Only connect if we have a valid connect URL Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (connect_url && connect_url[0]) { if (log) log->Printf("ProcessGDBRemote::%s Connecting to %s", __FUNCTION__, connect_url); std::unique_ptr conn_ap(new ConnectionFileDescriptor()); if (conn_ap.get()) { const uint32_t max_retry_count = 50; uint32_t retry_count = 0; while (!m_gdb_comm.IsConnected()) { if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess) { m_gdb_comm.SetConnection (conn_ap.release()); break; } else if (error.WasInterrupted()) { // If we were interrupted, don't keep retrying. break; } retry_count++; if (retry_count >= max_retry_count) break; usleep (100000); } } } if (!m_gdb_comm.IsConnected()) { if (error.Success()) error.SetErrorString("not connected to remote gdb server"); return error; } // Start the communications read thread so all incoming data can be // parsed into packets and queued as they arrive. if (GetTarget().GetNonStopModeEnabled()) m_gdb_comm.StartReadThread(); // We always seem to be able to open a connection to a local port // so we need to make sure we can then send data to it. If we can't // then we aren't actually connected to anything, so try and do the // handshake with the remote GDB server and make sure that goes // alright. if (!m_gdb_comm.HandshakeWithServer (&error)) { m_gdb_comm.Disconnect(); if (error.Success()) error.SetErrorString("not connected to remote gdb server"); return error; } // Send $QNonStop:1 packet on startup if required if (GetTarget().GetNonStopModeEnabled()) GetTarget().SetNonStopModeEnabled (m_gdb_comm.SetNonStopMode(true)); m_gdb_comm.GetEchoSupported (); m_gdb_comm.GetThreadSuffixSupported (); m_gdb_comm.GetListThreadsInStopReplySupported (); m_gdb_comm.GetHostInfo (); m_gdb_comm.GetVContSupported ('c'); m_gdb_comm.GetVAttachOrWaitSupported(); // Ask the remote server for the default thread id if (GetTarget().GetNonStopModeEnabled()) m_gdb_comm.GetDefaultThreadId(m_initial_tid); size_t num_cmds = GetExtraStartupCommands().GetArgumentCount(); for (size_t idx = 0; idx < num_cmds; idx++) { StringExtractorGDBRemote response; m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false); } return error; } void ProcessGDBRemote::DidLaunchOrAttach (ArchSpec& process_arch) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::DidLaunch()"); if (GetID() != LLDB_INVALID_PROCESS_ID) { BuildDynamicRegisterInfo (false); // See if the GDB server supports the qHostInfo information // See if the GDB server supports the qProcessInfo packet, if so // prefer that over the Host information as it will be more specific // to our process. const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture(); if (remote_process_arch.IsValid()) { process_arch = remote_process_arch; if (log) log->Printf ("ProcessGDBRemote::%s gdb-remote had process architecture, using %s %s", __FUNCTION__, process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "", process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : ""); } else { process_arch = m_gdb_comm.GetHostArchitecture(); if (log) log->Printf ("ProcessGDBRemote::%s gdb-remote did not have process architecture, using gdb-remote host architecture %s %s", __FUNCTION__, process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "", process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : ""); } if (process_arch.IsValid()) { const ArchSpec &target_arch = GetTarget().GetArchitecture(); if (target_arch.IsValid()) { if (log) log->Printf ("ProcessGDBRemote::%s analyzing target arch, currently %s %s", __FUNCTION__, target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "", target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : ""); // If the remote host is ARM and we have apple as the vendor, then // ARM executables and shared libraries can have mixed ARM architectures. // You can have an armv6 executable, and if the host is armv7, then the // system will load the best possible architecture for all shared libraries // it has, so we really need to take the remote host architecture as our // defacto architecture in this case. if ((process_arch.GetMachine() == llvm::Triple::arm || process_arch.GetMachine() == llvm::Triple::thumb) && process_arch.GetTriple().getVendor() == llvm::Triple::Apple) { GetTarget().SetArchitecture (process_arch); if (log) log->Printf ("ProcessGDBRemote::%s remote process is ARM/Apple, setting target arch to %s %s", __FUNCTION__, process_arch.GetArchitectureName () ? process_arch.GetArchitectureName () : "", process_arch.GetTriple().getTriple ().c_str() ? process_arch.GetTriple().getTriple ().c_str() : ""); } else { // Fill in what is missing in the triple const llvm::Triple &remote_triple = process_arch.GetTriple(); llvm::Triple new_target_triple = target_arch.GetTriple(); if (new_target_triple.getVendorName().size() == 0) { new_target_triple.setVendor (remote_triple.getVendor()); if (new_target_triple.getOSName().size() == 0) { new_target_triple.setOS (remote_triple.getOS()); if (new_target_triple.getEnvironmentName().size() == 0) new_target_triple.setEnvironment (remote_triple.getEnvironment()); } ArchSpec new_target_arch = target_arch; new_target_arch.SetTriple(new_target_triple); GetTarget().SetArchitecture(new_target_arch); } } if (log) log->Printf ("ProcessGDBRemote::%s final target arch after adjustments for remote architecture: %s %s", __FUNCTION__, target_arch.GetArchitectureName () ? target_arch.GetArchitectureName () : "", target_arch.GetTriple().getTriple ().c_str() ? target_arch.GetTriple().getTriple ().c_str() : ""); } else { // The target doesn't have a valid architecture yet, set it from // the architecture we got from the remote GDB server GetTarget().SetArchitecture (process_arch); } } } } void ProcessGDBRemote::DidLaunch () { ArchSpec process_arch; DidLaunchOrAttach (process_arch); } Error ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); Error error; if (log) log->Printf ("ProcessGDBRemote::%s()", __FUNCTION__); // Clear out and clean up from any current state Clear(); if (attach_pid != LLDB_INVALID_PROCESS_ID) { error = EstablishConnectionIfNeeded (attach_info); if (error.Success()) { m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); char packet[64]; const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid); SetID (attach_pid); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len)); } else SetExitStatus (-1, error.AsCString()); } return error; } Error ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, const ProcessAttachInfo &attach_info) { Error error; // Clear out and clean up from any current state Clear(); if (process_name && process_name[0]) { error = EstablishConnectionIfNeeded (attach_info); if (error.Success()) { StreamString packet; m_gdb_comm.SetDetachOnError(attach_info.GetDetachOnError()); if (attach_info.GetWaitForLaunch()) { if (!m_gdb_comm.GetVAttachOrWaitSupported()) { packet.PutCString ("vAttachWait"); } else { if (attach_info.GetIgnoreExisting()) packet.PutCString("vAttachWait"); else packet.PutCString ("vAttachOrWait"); } } else packet.PutCString("vAttachName"); packet.PutChar(';'); packet.PutBytesAsRawHex8(process_name, strlen(process_name), endian::InlHostByteOrder(), endian::InlHostByteOrder()); m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize())); } else SetExitStatus (-1, error.AsCString()); } return error; } void ProcessGDBRemote::DidExit () { // When we exit, disconnect from the GDB server communications m_gdb_comm.Disconnect(); } void ProcessGDBRemote::DidAttach (ArchSpec &process_arch) { // If you can figure out what the architecture is, fill it in here. process_arch.Clear(); DidLaunchOrAttach (process_arch); } Error ProcessGDBRemote::WillResume () { m_continue_c_tids.clear(); m_continue_C_tids.clear(); m_continue_s_tids.clear(); m_continue_S_tids.clear(); m_jstopinfo_sp.reset(); m_jthreadsinfo_sp.reset(); return Error(); } Error ProcessGDBRemote::DoResume () { Error error; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::Resume()"); ListenerSP listener_sp (Listener::MakeListener("gdb-remote.resume-packet-sent")); if (listener_sp->StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent)) { listener_sp->StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit); const size_t num_threads = GetThreadList().GetSize(); StreamString continue_packet; bool continue_packet_error = false; if (m_gdb_comm.HasAnyVContSupport ()) { if (!GetTarget().GetNonStopModeEnabled() && (m_continue_c_tids.size() == num_threads || (m_continue_c_tids.empty() && m_continue_C_tids.empty() && m_continue_s_tids.empty() && m_continue_S_tids.empty()))) { // All threads are continuing, just send a "c" packet continue_packet.PutCString ("c"); } else { continue_packet.PutCString ("vCont"); if (!m_continue_c_tids.empty()) { if (m_gdb_comm.GetVContSupported ('c')) { for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos) continue_packet.Printf(";c:%4.4" PRIx64, *t_pos); } else continue_packet_error = true; } if (!continue_packet_error && !m_continue_C_tids.empty()) { if (m_gdb_comm.GetVContSupported ('C')) { for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos) continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); } else continue_packet_error = true; } if (!continue_packet_error && !m_continue_s_tids.empty()) { if (m_gdb_comm.GetVContSupported ('s')) { for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos) continue_packet.Printf(";s:%4.4" PRIx64, *t_pos); } else continue_packet_error = true; } if (!continue_packet_error && !m_continue_S_tids.empty()) { if (m_gdb_comm.GetVContSupported ('S')) { for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos) continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first); } else continue_packet_error = true; } if (continue_packet_error) continue_packet.GetString().clear(); } } else continue_packet_error = true; if (continue_packet_error) { // Either no vCont support, or we tried to use part of the vCont // packet that wasn't supported by the remote GDB server. // We need to try and make a simple packet that can do our continue const size_t num_continue_c_tids = m_continue_c_tids.size(); const size_t num_continue_C_tids = m_continue_C_tids.size(); const size_t num_continue_s_tids = m_continue_s_tids.size(); const size_t num_continue_S_tids = m_continue_S_tids.size(); if (num_continue_c_tids > 0) { if (num_continue_c_tids == num_threads) { // All threads are resuming... m_gdb_comm.SetCurrentThreadForRun (-1); continue_packet.PutChar ('c'); continue_packet_error = false; } else if (num_continue_c_tids == 1 && num_continue_C_tids == 0 && num_continue_s_tids == 0 && num_continue_S_tids == 0 ) { // Only one thread is continuing m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front()); continue_packet.PutChar ('c'); continue_packet_error = false; } } if (continue_packet_error && num_continue_C_tids > 0) { if ((num_continue_C_tids + num_continue_c_tids) == num_threads && num_continue_C_tids > 0 && num_continue_s_tids == 0 && num_continue_S_tids == 0 ) { const int continue_signo = m_continue_C_tids.front().second; // Only one thread is continuing if (num_continue_C_tids > 1) { // More that one thread with a signal, yet we don't have // vCont support and we are being asked to resume each // thread with a signal, we need to make sure they are // all the same signal, or we can't issue the continue // accurately with the current support... if (num_continue_C_tids > 1) { continue_packet_error = false; for (size_t i=1; i 0) { if (num_continue_s_tids == num_threads) { // All threads are resuming... m_gdb_comm.SetCurrentThreadForRun (-1); // If in Non-Stop-Mode use vCont when stepping if (GetTarget().GetNonStopModeEnabled()) { if (m_gdb_comm.GetVContSupported('s')) continue_packet.PutCString("vCont;s"); else continue_packet.PutChar('s'); } else continue_packet.PutChar('s'); continue_packet_error = false; } else if (num_continue_c_tids == 0 && num_continue_C_tids == 0 && num_continue_s_tids == 1 && num_continue_S_tids == 0 ) { // Only one thread is stepping m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front()); continue_packet.PutChar ('s'); continue_packet_error = false; } } if (!continue_packet_error && num_continue_S_tids > 0) { if (num_continue_S_tids == num_threads) { const int step_signo = m_continue_S_tids.front().second; // Are all threads trying to step with the same signal? continue_packet_error = false; if (num_continue_S_tids > 1) { for (size_t i=1; iPrintf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead."); return error; } m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize())); if (listener_sp->WaitForEvent (&timeout, event_sp) == false) { error.SetErrorString("Resume timed out."); if (log) log->Printf ("ProcessGDBRemote::DoResume: Resume timed out."); } else if (event_sp->BroadcasterIs (&m_async_broadcaster)) { error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back."); if (log) log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back."); return error; } } } return error; } void ProcessGDBRemote::HandleStopReplySequence () { while(true) { // Send vStopped StringExtractorGDBRemote response; m_gdb_comm.SendPacketAndWaitForResponse("vStopped", response, false); // OK represents end of signal list if (response.IsOKResponse()) break; // If not OK or a normal packet we have a problem if (!response.IsNormalResponse()) break; SetLastStopPacket(response); } } void ProcessGDBRemote::ClearThreadIDList () { std::lock_guard guard(m_thread_list_real.GetMutex()); m_thread_ids.clear(); m_thread_pcs.clear(); } size_t ProcessGDBRemote::UpdateThreadIDsFromStopReplyThreadsValue (std::string &value) { m_thread_ids.clear(); m_thread_pcs.clear(); size_t comma_pos; lldb::tid_t tid; while ((comma_pos = value.find(',')) != std::string::npos) { value[comma_pos] = '\0'; // thread in big endian hex tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); value.erase(0, comma_pos + 1); } tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); return m_thread_ids.size(); } size_t ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue (std::string &value) { m_thread_pcs.clear(); size_t comma_pos; lldb::addr_t pc; while ((comma_pos = value.find(',')) != std::string::npos) { value[comma_pos] = '\0'; pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); if (pc != LLDB_INVALID_ADDRESS) m_thread_pcs.push_back (pc); value.erase(0, comma_pos + 1); } pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); if (pc != LLDB_INVALID_THREAD_ID) m_thread_pcs.push_back (pc); return m_thread_pcs.size(); } bool ProcessGDBRemote::UpdateThreadIDList () { std::lock_guard guard(m_thread_list_real.GetMutex()); if (m_jthreadsinfo_sp) { // If we have the JSON threads info, we can get the thread list from that StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); if (thread_infos && thread_infos->GetSize() > 0) { m_thread_ids.clear(); m_thread_pcs.clear(); thread_infos->ForEach([this](StructuredData::Object* object) -> bool { StructuredData::Dictionary *thread_dict = object->GetAsDictionary(); if (thread_dict) { // Set the thread stop info from the JSON dictionary SetThreadStopInfo (thread_dict); lldb::tid_t tid = LLDB_INVALID_THREAD_ID; if (thread_dict->GetValueForKeyAsInteger("tid", tid)) m_thread_ids.push_back(tid); } return true; // Keep iterating through all thread_info objects }); } if (!m_thread_ids.empty()) return true; } else { // See if we can get the thread IDs from the current stop reply packets // that might contain a "threads" key/value pair // Lock the thread stack while we access it //Mutex::Locker stop_stack_lock(m_last_stop_packet_mutex); std::unique_lock stop_stack_lock(m_last_stop_packet_mutex, std::defer_lock); if (stop_stack_lock.try_lock()) { // Get the number of stop packets on the stack int nItems = m_stop_packet_stack.size(); // Iterate over them for (int i = 0; i < nItems; i++) { // Get the thread stop info StringExtractorGDBRemote &stop_info = m_stop_packet_stack[i]; const std::string &stop_info_str = stop_info.GetStringRef(); m_thread_pcs.clear(); const size_t thread_pcs_pos = stop_info_str.find(";thread-pcs:"); if (thread_pcs_pos != std::string::npos) { const size_t start = thread_pcs_pos + strlen(";thread-pcs:"); const size_t end = stop_info_str.find(';', start); if (end != std::string::npos) { std::string value = stop_info_str.substr(start, end - start); UpdateThreadPCsFromStopReplyThreadsValue(value); } } const size_t threads_pos = stop_info_str.find(";threads:"); if (threads_pos != std::string::npos) { const size_t start = threads_pos + strlen(";threads:"); const size_t end = stop_info_str.find(';', start); if (end != std::string::npos) { std::string value = stop_info_str.substr(start, end - start); if (UpdateThreadIDsFromStopReplyThreadsValue(value)) return true; } } } } } bool sequence_mutex_unavailable = false; m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable); if (sequence_mutex_unavailable) { return false; // We just didn't get the list } return true; } bool ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list) { // locker will keep a mutex locked until it goes out of scope Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD)); if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID()); size_t num_thread_ids = m_thread_ids.size(); // The "m_thread_ids" thread ID list should always be updated after each stop // reply packet, but in case it isn't, update it here. if (num_thread_ids == 0) { if (!UpdateThreadIDList ()) return false; num_thread_ids = m_thread_ids.size(); } ThreadList old_thread_list_copy(old_thread_list); if (num_thread_ids > 0) { for (size_t i=0; iGetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n", __FUNCTION__, static_cast(thread_sp.get()), thread_sp->GetID()); } else { if (log && log->GetMask().Test(GDBR_LOG_VERBOSE)) log->Printf( "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n", __FUNCTION__, static_cast(thread_sp.get()), thread_sp->GetID()); } // The m_thread_pcs vector has pc values in big-endian order, not target-endian, unlike most // of the register read/write packets in gdb-remote protocol. // Early in the process startup, we may not yet have set the process ByteOrder so we ignore these; // they are a performance improvement over fetching thread register values individually, the // method we will fall back to if needed. if (m_thread_ids.size() == m_thread_pcs.size() && thread_sp.get() && GetByteOrder() != eByteOrderInvalid) { ThreadGDBRemote *gdb_thread = static_cast (thread_sp.get()); RegisterContextSP reg_ctx_sp (thread_sp->GetRegisterContext()); if (reg_ctx_sp) { uint32_t pc_regnum = reg_ctx_sp->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); if (pc_regnum != LLDB_INVALID_REGNUM) { gdb_thread->PrivateSetRegisterValue (pc_regnum, m_thread_pcs[i]); } } } new_thread_list.AddThreadSortedByIndexID (thread_sp); } } // Whatever that is left in old_thread_list_copy are not // present in new_thread_list. Remove non-existent threads from internal id table. size_t old_num_thread_ids = old_thread_list_copy.GetSize(false); for (size_t i=0; iGetProtocolID(); m_thread_id_to_index_id_map.erase(old_thread_id); } } return true; } bool ProcessGDBRemote::GetThreadStopInfoFromJSON (ThreadGDBRemote *thread, const StructuredData::ObjectSP &thread_infos_sp) { // See if we got thread stop infos for all threads via the "jThreadsInfo" packet if (thread_infos_sp) { StructuredData::Array *thread_infos = thread_infos_sp->GetAsArray(); if (thread_infos) { lldb::tid_t tid; const size_t n = thread_infos->GetSize(); for (size_t i=0; iGetItemAtIndex(i)->GetAsDictionary(); if (thread_dict) { if (thread_dict->GetValueForKeyAsInteger("tid", tid, LLDB_INVALID_THREAD_ID)) { if (tid == thread->GetID()) return (bool)SetThreadStopInfo(thread_dict); } } } } } return false; } bool ProcessGDBRemote::CalculateThreadStopInfo (ThreadGDBRemote *thread) { // See if we got thread stop infos for all threads via the "jThreadsInfo" packet if (GetThreadStopInfoFromJSON (thread, m_jthreadsinfo_sp)) return true; // See if we got thread stop info for any threads valid stop info reasons threads // via the "jstopinfo" packet stop reply packet key/value pair? if (m_jstopinfo_sp) { // If we have "jstopinfo" then we have stop descriptions for all threads // that have stop reasons, and if there is no entry for a thread, then // it has no stop reason. thread->GetRegisterContext()->InvalidateIfNeeded(true); if (!GetThreadStopInfoFromJSON (thread, m_jstopinfo_sp)) { thread->SetStopInfo (StopInfoSP()); } return true; } // Fall back to using the qThreadStopInfo packet StringExtractorGDBRemote stop_packet; if (GetGDBRemote().GetThreadStopInfo(thread->GetProtocolID(), stop_packet)) return SetThreadStopInfo (stop_packet) == eStateStopped; return false; } ThreadSP ProcessGDBRemote::SetThreadStopInfo (lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map, uint8_t signo, const std::string &thread_name, const std::string &reason, const std::string &description, uint32_t exc_type, const std::vector &exc_data, addr_t thread_dispatch_qaddr, bool queue_vars_valid, // Set to true if queue_name, queue_kind and queue_serial are valid LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t, std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) { ThreadSP thread_sp; if (tid != LLDB_INVALID_THREAD_ID) { // Scope for "locker" below { // m_thread_list_real does have its own mutex, but we need to // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...) // and the m_thread_list_real.AddThread(...) so it doesn't change on us std::lock_guard guard(m_thread_list_real.GetMutex()); thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false); if (!thread_sp) { // Create the thread if we need to thread_sp.reset (new ThreadGDBRemote (*this, tid)); m_thread_list_real.AddThread(thread_sp); } } if (thread_sp) { ThreadGDBRemote *gdb_thread = static_cast (thread_sp.get()); gdb_thread->GetRegisterContext()->InvalidateIfNeeded(true); for (const auto &pair : expedited_register_map) { StringExtractor reg_value_extractor; reg_value_extractor.GetStringRef() = pair.second; gdb_thread->PrivateSetRegisterValue (pair.first, reg_value_extractor); } thread_sp->SetName (thread_name.empty() ? NULL : thread_name.c_str()); gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr); // Check if the GDB server was able to provide the queue name, kind and serial number if (queue_vars_valid) gdb_thread->SetQueueInfo(std::move(queue_name), queue_kind, queue_serial, dispatch_queue_t, associated_with_dispatch_queue); else gdb_thread->ClearQueueInfo(); gdb_thread->SetAssociatedWithLibdispatchQueue (associated_with_dispatch_queue); if (dispatch_queue_t != LLDB_INVALID_ADDRESS) gdb_thread->SetQueueLibdispatchQueueAddress (dispatch_queue_t); // Make sure we update our thread stop reason just once if (!thread_sp->StopInfoIsUpToDate()) { thread_sp->SetStopInfo (StopInfoSP()); // If there's a memory thread backed by this thread, we need to use it to calcualte StopInfo. ThreadSP memory_thread_sp = m_thread_list.FindThreadByProtocolID(thread_sp->GetProtocolID()); if (memory_thread_sp) thread_sp = memory_thread_sp; if (exc_type != 0) { const size_t exc_data_size = exc_data.size(); thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp, exc_type, exc_data_size, exc_data_size >= 1 ? exc_data[0] : 0, exc_data_size >= 2 ? exc_data[1] : 0, exc_data_size >= 3 ? exc_data[2] : 0)); } else { bool handled = false; bool did_exec = false; if (!reason.empty()) { if (reason.compare("trace") == 0) { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint // Otherwise, it will be set to Trace. if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); } else thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); handled = true; } else if (reason.compare("breakpoint") == 0) { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. handled = true; if (bp_site_sp->ValidForThisThread (thread_sp.get())) { thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); } else { StopInfoSP invalid_stop_info_sp; thread_sp->SetStopInfo (invalid_stop_info_sp); } } } else if (reason.compare("trap") == 0) { // Let the trap just use the standard signal stop reason below... } else if (reason.compare("watchpoint") == 0) { StringExtractor desc_extractor(description.c_str()); addr_t wp_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); uint32_t wp_index = desc_extractor.GetU32(LLDB_INVALID_INDEX32); addr_t wp_hit_addr = desc_extractor.GetU64(LLDB_INVALID_ADDRESS); watch_id_t watch_id = LLDB_INVALID_WATCH_ID; if (wp_addr != LLDB_INVALID_ADDRESS) { WatchpointSP wp_sp; ArchSpec::Core core = GetTarget().GetArchitecture().GetCore(); if ((core >= ArchSpec::kCore_mips_first && core <= ArchSpec::kCore_mips_last) || (core >= ArchSpec::eCore_arm_generic && core <= ArchSpec::eCore_arm_aarch64)) wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_hit_addr); if (!wp_sp) wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); if (wp_sp) { wp_sp->SetHardwareIndex(wp_index); watch_id = wp_sp->GetID(); } } if (watch_id == LLDB_INVALID_WATCH_ID) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_WATCHPOINTS)); if (log) log->Printf ("failed to find watchpoint"); } thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id, wp_hit_addr)); handled = true; } else if (reason.compare("exception") == 0) { thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str())); handled = true; } else if (reason.compare("exec") == 0) { did_exec = true; thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp)); handled = true; } } else if (!signo) { addr_t pc = thread_sp->GetRegisterContext()->GetPC(); lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); // If the current pc is a breakpoint site then the StopInfo should be set to Breakpoint // even though the remote stub did not set it as such. This can happen when // the thread is involuntarily interrupted (e.g. due to stops on other // threads) just as it is about to execute the breakpoint instruction. if (bp_site_sp && bp_site_sp->ValidForThisThread(thread_sp.get())) { thread_sp->SetStopInfo( StopInfo::CreateStopReasonWithBreakpointSiteID(*thread_sp, bp_site_sp->GetID())); handled = true; } } if (!handled && signo && did_exec == false) { if (signo == SIGTRAP) { // Currently we are going to assume SIGTRAP means we are either // hitting a breakpoint or hardware single stepping. handled = true; addr_t pc = thread_sp->GetRegisterContext()->GetPC() + m_breakpoint_pc_offset; lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc); if (bp_site_sp) { // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread, // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc. if (bp_site_sp->ValidForThisThread (thread_sp.get())) { if(m_breakpoint_pc_offset != 0) thread_sp->GetRegisterContext()->SetPC(pc); thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID())); } else { StopInfoSP invalid_stop_info_sp; thread_sp->SetStopInfo (invalid_stop_info_sp); } } else { // If we were stepping then assume the stop was the result of the trace. If we were // not stepping then report the SIGTRAP. // FIXME: We are still missing the case where we single step over a trap instruction. if (thread_sp->GetTemporaryResumeState() == eStateStepping) thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp)); else thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo, description.c_str())); } } if (!handled) thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo, description.c_str())); } if (!description.empty()) { lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); if (stop_info_sp) { const char *stop_info_desc = stop_info_sp->GetDescription(); if (!stop_info_desc || !stop_info_desc[0]) stop_info_sp->SetDescription (description.c_str()); } else { thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str())); } } } } } } return thread_sp; } lldb::ThreadSP ProcessGDBRemote::SetThreadStopInfo (StructuredData::Dictionary *thread_dict) { static ConstString g_key_tid("tid"); static ConstString g_key_name("name"); static ConstString g_key_reason("reason"); static ConstString g_key_metype("metype"); static ConstString g_key_medata("medata"); static ConstString g_key_qaddr("qaddr"); static ConstString g_key_dispatch_queue_t("dispatch_queue_t"); static ConstString g_key_associated_with_dispatch_queue("associated_with_dispatch_queue"); static ConstString g_key_queue_name("qname"); static ConstString g_key_queue_kind("qkind"); static ConstString g_key_queue_serial_number("qserialnum"); static ConstString g_key_registers("registers"); static ConstString g_key_memory("memory"); static ConstString g_key_address("address"); static ConstString g_key_bytes("bytes"); static ConstString g_key_description("description"); static ConstString g_key_signal("signal"); // Stop with signal and thread info lldb::tid_t tid = LLDB_INVALID_THREAD_ID; uint8_t signo = 0; std::string value; std::string thread_name; std::string reason; std::string description; uint32_t exc_type = 0; std::vector exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; ExpeditedRegisterMap expedited_register_map; bool queue_vars_valid = false; addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; uint64_t queue_serial_number = 0; // Iterate through all of the thread dictionary key/value pairs from the structured data dictionary thread_dict->ForEach([this, &tid, &expedited_register_map, &thread_name, &signo, &reason, &description, &exc_type, &exc_data, &thread_dispatch_qaddr, &queue_vars_valid, &associated_with_dispatch_queue, &dispatch_queue_t, &queue_name, &queue_kind, &queue_serial_number] (ConstString key, StructuredData::Object* object) -> bool { if (key == g_key_tid) { // thread in big endian hex tid = object->GetIntegerValue(LLDB_INVALID_THREAD_ID); } else if (key == g_key_metype) { // exception type in big endian hex exc_type = object->GetIntegerValue(0); } else if (key == g_key_medata) { // exception data in big endian hex StructuredData::Array *array = object->GetAsArray(); if (array) { array->ForEach([&exc_data](StructuredData::Object* object) -> bool { exc_data.push_back(object->GetIntegerValue()); return true; // Keep iterating through all array items }); } } else if (key == g_key_name) { thread_name = object->GetStringValue(); } else if (key == g_key_qaddr) { thread_dispatch_qaddr = object->GetIntegerValue(LLDB_INVALID_ADDRESS); } else if (key == g_key_queue_name) { queue_vars_valid = true; queue_name = object->GetStringValue(); } else if (key == g_key_queue_kind) { std::string queue_kind_str = object->GetStringValue(); if (queue_kind_str == "serial") { queue_vars_valid = true; queue_kind = eQueueKindSerial; } else if (queue_kind_str == "concurrent") { queue_vars_valid = true; queue_kind = eQueueKindConcurrent; } } else if (key == g_key_queue_serial_number) { queue_serial_number = object->GetIntegerValue(0); if (queue_serial_number != 0) queue_vars_valid = true; } else if (key == g_key_dispatch_queue_t) { dispatch_queue_t = object->GetIntegerValue(0); if (dispatch_queue_t != 0 && dispatch_queue_t != LLDB_INVALID_ADDRESS) queue_vars_valid = true; } else if (key == g_key_associated_with_dispatch_queue) { queue_vars_valid = true; bool associated = object->GetBooleanValue (); if (associated) associated_with_dispatch_queue = eLazyBoolYes; else associated_with_dispatch_queue = eLazyBoolNo; } else if (key == g_key_reason) { reason = object->GetStringValue(); } else if (key == g_key_description) { description = object->GetStringValue(); } else if (key == g_key_registers) { StructuredData::Dictionary *registers_dict = object->GetAsDictionary(); if (registers_dict) { registers_dict->ForEach([&expedited_register_map](ConstString key, StructuredData::Object* object) -> bool { const uint32_t reg = StringConvert::ToUInt32 (key.GetCString(), UINT32_MAX, 10); if (reg != UINT32_MAX) expedited_register_map[reg] = object->GetStringValue(); return true; // Keep iterating through all array items }); } } else if (key == g_key_memory) { StructuredData::Array *array = object->GetAsArray(); if (array) { array->ForEach([this](StructuredData::Object* object) -> bool { StructuredData::Dictionary *mem_cache_dict = object->GetAsDictionary(); if (mem_cache_dict) { lldb::addr_t mem_cache_addr = LLDB_INVALID_ADDRESS; if (mem_cache_dict->GetValueForKeyAsInteger("address", mem_cache_addr)) { if (mem_cache_addr != LLDB_INVALID_ADDRESS) { StringExtractor bytes; if (mem_cache_dict->GetValueForKeyAsString("bytes", bytes.GetStringRef())) { bytes.SetFilePos(0); const size_t byte_size = bytes.GetStringRef().size()/2; DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); if (bytes_copied == byte_size) m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); } } } } return true; // Keep iterating through all array items }); } } else if (key == g_key_signal) signo = object->GetIntegerValue(LLDB_INVALID_SIGNAL_NUMBER); return true; // Keep iterating through all dictionary key/value pairs }); return SetThreadStopInfo (tid, expedited_register_map, signo, thread_name, reason, description, exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid, associated_with_dispatch_queue, dispatch_queue_t, queue_name, queue_kind, queue_serial_number); } StateType ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet) { stop_packet.SetFilePos (0); const char stop_type = stop_packet.GetChar(); switch (stop_type) { case 'T': case 'S': { // This is a bit of a hack, but is is required. If we did exec, we // need to clear our thread lists and also know to rebuild our dynamic // register info before we lookup and threads and populate the expedited // register values so we need to know this right away so we can cleanup // and update our registers. const uint32_t stop_id = GetStopID(); if (stop_id == 0) { // Our first stop, make sure we have a process ID, and also make // sure we know about our registers if (GetID() == LLDB_INVALID_PROCESS_ID) { lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID (); if (pid != LLDB_INVALID_PROCESS_ID) SetID (pid); } BuildDynamicRegisterInfo (true); } // Stop with signal and thread info lldb::tid_t tid = LLDB_INVALID_THREAD_ID; const uint8_t signo = stop_packet.GetHexU8(); std::string key; std::string value; std::string thread_name; std::string reason; std::string description; uint32_t exc_type = 0; std::vector exc_data; addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS; bool queue_vars_valid = false; // says if locals below that start with "queue_" are valid addr_t dispatch_queue_t = LLDB_INVALID_ADDRESS; LazyBool associated_with_dispatch_queue = eLazyBoolCalculate; std::string queue_name; QueueKind queue_kind = eQueueKindUnknown; uint64_t queue_serial_number = 0; ExpeditedRegisterMap expedited_register_map; while (stop_packet.GetNameColonValue(key, value)) { if (key.compare("metype") == 0) { // exception type in big endian hex exc_type = StringConvert::ToUInt32 (value.c_str(), 0, 16); } else if (key.compare("medata") == 0) { // exception data in big endian hex exc_data.push_back(StringConvert::ToUInt64 (value.c_str(), 0, 16)); } else if (key.compare("thread") == 0) { // thread in big endian hex tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); } else if (key.compare("threads") == 0) { std::lock_guard guard(m_thread_list_real.GetMutex()); m_thread_ids.clear(); // A comma separated list of all threads in the current // process that includes the thread for this stop reply // packet size_t comma_pos; lldb::tid_t tid; while ((comma_pos = value.find(',')) != std::string::npos) { value[comma_pos] = '\0'; // thread in big endian hex tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); value.erase(0, comma_pos + 1); } tid = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16); if (tid != LLDB_INVALID_THREAD_ID) m_thread_ids.push_back (tid); } else if (key.compare("thread-pcs") == 0) { m_thread_pcs.clear(); // A comma separated list of all threads in the current // process that includes the thread for this stop reply // packet size_t comma_pos; lldb::addr_t pc; while ((comma_pos = value.find(',')) != std::string::npos) { value[comma_pos] = '\0'; // thread in big endian hex pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); if (pc != LLDB_INVALID_ADDRESS) m_thread_pcs.push_back (pc); value.erase(0, comma_pos + 1); } pc = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); if (pc != LLDB_INVALID_ADDRESS) m_thread_pcs.push_back (pc); } else if (key.compare("jstopinfo") == 0) { StringExtractor json_extractor; // Swap "value" over into "name_extractor" json_extractor.GetStringRef().swap(value); // Now convert the HEX bytes into a string value json_extractor.GetHexByteString (value); // This JSON contains thread IDs and thread stop info for all threads. // It doesn't contain expedited registers, memory or queue info. m_jstopinfo_sp = StructuredData::ParseJSON (value); } else if (key.compare("hexname") == 0) { StringExtractor name_extractor; // Swap "value" over into "name_extractor" name_extractor.GetStringRef().swap(value); // Now convert the HEX bytes into a string value name_extractor.GetHexByteString (value); thread_name.swap (value); } else if (key.compare("name") == 0) { thread_name.swap (value); } else if (key.compare("qaddr") == 0) { thread_dispatch_qaddr = StringConvert::ToUInt64 (value.c_str(), 0, 16); } else if (key.compare("dispatch_queue_t") == 0) { queue_vars_valid = true; dispatch_queue_t = StringConvert::ToUInt64 (value.c_str(), 0, 16); } else if (key.compare("qname") == 0) { queue_vars_valid = true; StringExtractor name_extractor; // Swap "value" over into "name_extractor" name_extractor.GetStringRef().swap(value); // Now convert the HEX bytes into a string value name_extractor.GetHexByteString (value); queue_name.swap (value); } else if (key.compare("qkind") == 0) { if (value == "serial") { queue_vars_valid = true; queue_kind = eQueueKindSerial; } else if (value == "concurrent") { queue_vars_valid = true; queue_kind = eQueueKindConcurrent; } } else if (key.compare("qserialnum") == 0) { queue_serial_number = StringConvert::ToUInt64 (value.c_str(), 0, 0); if (queue_serial_number != 0) queue_vars_valid = true; } else if (key.compare("reason") == 0) { reason.swap(value); } else if (key.compare("description") == 0) { StringExtractor desc_extractor; // Swap "value" over into "name_extractor" desc_extractor.GetStringRef().swap(value); // Now convert the HEX bytes into a string value desc_extractor.GetHexByteString (value); description.swap(value); } else if (key.compare("memory") == 0) { // Expedited memory. GDB servers can choose to send back expedited memory // that can populate the L1 memory cache in the process so that things like // the frame pointer backchain can be expedited. This will help stack // backtracing be more efficient by not having to send as many memory read // requests down the remote GDB server. // Key/value pair format: memory:=; // is a number whose base will be interpreted by the prefix: // "0x[0-9a-fA-F]+" for hex // "0[0-7]+" for octal // "[1-9]+" for decimal // is native endian ASCII hex bytes just like the register values llvm::StringRef value_ref(value); std::pair pair; pair = value_ref.split('='); if (!pair.first.empty() && !pair.second.empty()) { std::string addr_str(pair.first.str()); const lldb::addr_t mem_cache_addr = StringConvert::ToUInt64(addr_str.c_str(), LLDB_INVALID_ADDRESS, 0); if (mem_cache_addr != LLDB_INVALID_ADDRESS) { StringExtractor bytes; bytes.GetStringRef() = pair.second.str(); const size_t byte_size = bytes.GetStringRef().size()/2; DataBufferSP data_buffer_sp(new DataBufferHeap(byte_size, 0)); const size_t bytes_copied = bytes.GetHexBytes (data_buffer_sp->GetBytes(), byte_size, 0); if (bytes_copied == byte_size) m_memory_cache.AddL1CacheData(mem_cache_addr, data_buffer_sp); } } } else if (key.compare("watch") == 0 || key.compare("rwatch") == 0 || key.compare("awatch") == 0) { // Support standard GDB remote stop reply packet 'TAAwatch:addr' lldb::addr_t wp_addr = StringConvert::ToUInt64 (value.c_str(), LLDB_INVALID_ADDRESS, 16); WatchpointSP wp_sp = GetTarget().GetWatchpointList().FindByAddress(wp_addr); uint32_t wp_index = LLDB_INVALID_INDEX32; if (wp_sp) wp_index = wp_sp->GetHardwareIndex(); reason = "watchpoint"; StreamString ostr; ostr.Printf("%" PRIu64 " %" PRIu32, wp_addr, wp_index); description = ostr.GetString().c_str(); } else if (key.compare("library") == 0) { LoadModules(); } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) { uint32_t reg = StringConvert::ToUInt32 (key.c_str(), UINT32_MAX, 16); if (reg != UINT32_MAX) expedited_register_map[reg] = std::move(value); } } if (tid == LLDB_INVALID_THREAD_ID) { // A thread id may be invalid if the response is old style 'S' packet which does not provide the // thread information. So update the thread list and choose the first one. UpdateThreadIDList (); if (!m_thread_ids.empty ()) { tid = m_thread_ids.front (); } } ThreadSP thread_sp = SetThreadStopInfo (tid, expedited_register_map, signo, thread_name, reason, description, exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid, associated_with_dispatch_queue, dispatch_queue_t, queue_name, queue_kind, queue_serial_number); return eStateStopped; } break; case 'W': case 'X': // process exited return eStateExited; default: break; } return eStateInvalid; } void ProcessGDBRemote::RefreshStateAfterStop () { std::lock_guard guard(m_thread_list_real.GetMutex()); m_thread_ids.clear(); m_thread_pcs.clear(); // Set the thread stop info. It might have a "threads" key whose value is // a list of all thread IDs in the current process, so m_thread_ids might // get set. // Scope for the lock { // Lock the thread stack while we access it std::lock_guard guard(m_last_stop_packet_mutex); // Get the number of stop packets on the stack int nItems = m_stop_packet_stack.size(); // Iterate over them for (int i = 0; i < nItems; i++) { // Get the thread stop info StringExtractorGDBRemote stop_info = m_stop_packet_stack[i]; // Process thread stop info SetThreadStopInfo(stop_info); } // Clear the thread stop stack m_stop_packet_stack.clear(); } // Check to see if SetThreadStopInfo() filled in m_thread_ids? if (m_thread_ids.empty()) { // No, we need to fetch the thread list manually UpdateThreadIDList(); } // If we have queried for a default thread id if (m_initial_tid != LLDB_INVALID_THREAD_ID) { m_thread_list.SetSelectedThreadByID(m_initial_tid); m_initial_tid = LLDB_INVALID_THREAD_ID; } // Let all threads recover from stopping and do any clean up based // on the previous thread state (if any). m_thread_list_real.RefreshStateAfterStop(); } Error ProcessGDBRemote::DoHalt (bool &caused_stop) { Error error; bool timed_out = false; Mutex::Locker locker; if (m_public_state.GetValue() == eStateAttaching) { // We are being asked to halt during an attach. We need to just close // our file handle and debugserver will go away, and we can be done... m_gdb_comm.Disconnect(); } else { if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out)) { if (timed_out) error.SetErrorString("timed out sending interrupt packet"); else error.SetErrorString("unknown error sending interrupt packet"); } caused_stop = m_gdb_comm.GetInterruptWasSent (); } return error; } Error ProcessGDBRemote::DoDetach(bool keep_stopped) { Error error; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped); error = m_gdb_comm.Detach (keep_stopped); if (log) { if (error.Success()) log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully"); else log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : ""); } if (!error.Success()) return error; // Sleep for one second to let the process get all detached... StopAsyncThread (); SetPrivateState (eStateDetached); ResumePrivateStateThread(); //KillDebugserverProcess (); return error; } Error ProcessGDBRemote::DoDestroy () { Error error; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::DoDestroy()"); // There is a bug in older iOS debugservers where they don't shut down the process // they are debugging properly. If the process is sitting at a breakpoint or an exception, // this can cause problems with restarting. So we check to see if any of our threads are stopped // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN // destroy it again. // // Note, we don't have a good way to test the version of debugserver, but I happen to know that // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of // the debugservers with this bug are equal. There really should be a better way to test this! // // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and // get called here to destroy again and we're still at a breakpoint or exception, then we should // just do the straight-forward kill. // // And of course, if we weren't able to stop the process by the time we get here, it isn't // necessary (or helpful) to do any of this. if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning) { PlatformSP platform_sp = GetTarget().GetPlatform(); // FIXME: These should be ConstStrings so we aren't doing strcmp'ing. if (platform_sp && platform_sp->GetName() && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic()) { if (m_destroy_tried_resuming) { if (log) log->PutCString ("ProcessGDBRemote::DoDestroy() - Tried resuming to destroy once already, not doing it again."); } else { // At present, the plans are discarded and the breakpoints disabled Process::Destroy, // but we really need it to happen here and it doesn't matter if we do it twice. m_thread_list.DiscardThreadPlans(); DisableAllBreakpointSites(); bool stop_looks_like_crash = false; ThreadList &threads = GetThreadList(); { std::lock_guard guard(threads.GetMutex()); size_t num_threads = threads.GetSize(); for (size_t i = 0; i < num_threads; i++) { ThreadSP thread_sp = threads.GetThreadAtIndex(i); StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); StopReason reason = eStopReasonInvalid; if (stop_info_sp) reason = stop_info_sp->GetStopReason(); if (reason == eStopReasonBreakpoint || reason == eStopReasonException) { if (log) log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.", thread_sp->GetProtocolID(), stop_info_sp->GetDescription()); stop_looks_like_crash = true; break; } } } if (stop_looks_like_crash) { if (log) log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill."); m_destroy_tried_resuming = true; // If we are going to run again before killing, it would be good to suspend all the threads // before resuming so they won't get into more trouble. Sadly, for the threads stopped with // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do // have to run the risk of letting those threads proceed a bit. { std::lock_guard guard(threads.GetMutex()); size_t num_threads = threads.GetSize(); for (size_t i = 0; i < num_threads; i++) { ThreadSP thread_sp = threads.GetThreadAtIndex(i); StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo(); StopReason reason = eStopReasonInvalid; if (stop_info_sp) reason = stop_info_sp->GetStopReason(); if (reason != eStopReasonBreakpoint && reason != eStopReasonException) { if (log) log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.", thread_sp->GetProtocolID()); thread_sp->SetResumeState(eStateSuspended); } } } Resume (); return Destroy(false); } } } } // Interrupt if our inferior is running... int exit_status = SIGABRT; std::string exit_string; if (m_gdb_comm.IsConnected()) { if (m_public_state.GetValue() != eStateAttaching) { StringExtractorGDBRemote response; bool send_async = true; GDBRemoteCommunication::ScopedTimeout (m_gdb_comm, 3); if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async) == GDBRemoteCommunication::PacketResult::Success) { char packet_cmd = response.GetChar(0); if (packet_cmd == 'W' || packet_cmd == 'X') { #if defined(__APPLE__) // For Native processes on Mac OS X, we launch through the Host Platform, then hand the process off // to debugserver, which becomes the parent process through "PT_ATTACH". Then when we go to kill // the process on Mac OS X we call ptrace(PT_KILL) to kill it, then we call waitpid which returns // with no error and the correct status. But amusingly enough that doesn't seem to actually reap // the process, but instead it is left around as a Zombie. Probably the kernel is in the process of // switching ownership back to lldb which was the original parent, and gets confused in the handoff. // Anyway, so call waitpid here to finally reap it. PlatformSP platform_sp(GetTarget().GetPlatform()); if (platform_sp && platform_sp->IsHost()) { int status; ::pid_t reap_pid; reap_pid = waitpid (GetID(), &status, WNOHANG); if (log) log->Printf ("Reaped pid: %d, status: %d.\n", reap_pid, status); } #endif SetLastStopPacket (response); ClearThreadIDList (); exit_status = response.GetHexU8(); } else { if (log) log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str()); exit_string.assign("got unexpected response to k packet: "); exit_string.append(response.GetStringRef()); } } else { if (log) log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet"); exit_string.assign("failed to send the k packet"); } } else { if (log) log->Printf ("ProcessGDBRemote::DoDestroy - killed or interrupted while attaching"); exit_string.assign ("killed or interrupted while attaching."); } } else { // If we missed setting the exit status on the way out, do it here. // NB set exit status can be called multiple times, the first one sets the status. exit_string.assign("destroying when not connected to debugserver"); } SetExitStatus(exit_status, exit_string.c_str()); StopAsyncThread (); KillDebugserverProcess (); return error; } void ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response) { const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos; if (did_exec) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec"); m_thread_list_real.Clear(); m_thread_list.Clear(); BuildDynamicRegisterInfo (true); m_gdb_comm.ResetDiscoverableSettings (did_exec); } // Scope the lock { // Lock the thread stack while we access it std::lock_guard guard(m_last_stop_packet_mutex); // We are are not using non-stop mode, there can only be one last stop // reply packet, so clear the list. if (GetTarget().GetNonStopModeEnabled() == false) m_stop_packet_stack.clear(); // Add this stop packet to the stop packet stack // This stack will get popped and examined when we switch to the // Stopped state m_stop_packet_stack.push_back(response); } } void ProcessGDBRemote::SetUnixSignals(const UnixSignalsSP &signals_sp) { Process::SetUnixSignals(std::make_shared(signals_sp)); } //------------------------------------------------------------------ // Process Queries //------------------------------------------------------------------ bool ProcessGDBRemote::IsAlive () { return m_gdb_comm.IsConnected() && Process::IsAlive(); } addr_t ProcessGDBRemote::GetImageInfoAddress() { // request the link map address via the $qShlibInfoAddr packet lldb::addr_t addr = m_gdb_comm.GetShlibInfoAddr(); // the loaded module list can also provides a link map address if (addr == LLDB_INVALID_ADDRESS) { LoadedModuleInfoList list; if (GetLoadedModuleList (list).Success()) addr = list.m_link_map; } return addr; } void ProcessGDBRemote::WillPublicStop () { // See if the GDB remote client supports the JSON threads info. // If so, we gather stop info for all threads, expedited registers, // expedited memory, runtime queue information (iOS and MacOSX only), // and more. Expediting memory will help stack backtracing be much // faster. Expediting registers will make sure we don't have to read // the thread registers for GPRs. m_jthreadsinfo_sp = m_gdb_comm.GetThreadsInfo(); if (m_jthreadsinfo_sp) { // Now set the stop info for each thread and also expedite any registers // and memory that was in the jThreadsInfo response. StructuredData::Array *thread_infos = m_jthreadsinfo_sp->GetAsArray(); if (thread_infos) { const size_t n = thread_infos->GetSize(); for (size_t i=0; iGetItemAtIndex(i)->GetAsDictionary(); if (thread_dict) SetThreadStopInfo(thread_dict); } } } } //------------------------------------------------------------------ // Process Memory //------------------------------------------------------------------ size_t ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error) { GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be // called multiple times in order to complete the task by // lldb_private::Process so it is ok to do this. size = m_max_memory_size; } char packet[64]; int packet_len; bool binary_memory_read = m_gdb_comm.GetxPacketSupported(); packet_len = ::snprintf(packet, sizeof(packet), "%c%" PRIx64 ",%" PRIx64, binary_memory_read ? 'x' : 'm', (uint64_t)addr, (uint64_t)size); assert (packet_len + 1 < (int)sizeof(packet)); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsNormalResponse()) { error.Clear(); if (binary_memory_read) { // The lower level GDBRemoteCommunication packet receive layer has already de-quoted any // 0x7d character escaping that was present in the packet size_t data_received_size = response.GetBytesLeft(); if (data_received_size > size) { // Don't write past the end of BUF if the remote debug server gave us too // much data for some reason. data_received_size = size; } memcpy (buf, response.GetStringRef().data(), data_received_size); return data_received_size; } else { return response.GetHexBytes(buf, size, '\xdd'); } } else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr); else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("GDB server does not support reading memory"); else error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str()); } else { error.SetErrorStringWithFormat("failed to send packet: '%s'", packet); } return 0; } size_t ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error) { GetMaxMemorySize (); if (size > m_max_memory_size) { // Keep memory read sizes down to a sane limit. This function will be // called multiple times in order to complete the task by // lldb_private::Process so it is ok to do this. size = m_max_memory_size; } StreamString packet; packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size); packet.PutBytesAsRawHex8(buf, size, endian::InlHostByteOrder(), endian::InlHostByteOrder()); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true) == GDBRemoteCommunication::PacketResult::Success) { if (response.IsOKResponse()) { error.Clear(); return size; } else if (response.IsErrorResponse()) error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr); else if (response.IsUnsupportedResponse()) error.SetErrorStringWithFormat("GDB server does not support writing memory"); else error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str()); } else { error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str()); } return 0; } lldb::addr_t ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error) { Log *log (GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_EXPRESSIONS)); addr_t allocated_addr = LLDB_INVALID_ADDRESS; if (m_gdb_comm.SupportsAllocDeallocMemory() != eLazyBoolNo) { allocated_addr = m_gdb_comm.AllocateMemory (size, permissions); if (allocated_addr != LLDB_INVALID_ADDRESS || m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolYes) return allocated_addr; } if (m_gdb_comm.SupportsAllocDeallocMemory() == eLazyBoolNo) { // Call mmap() to create memory in the inferior.. unsigned prot = 0; if (permissions & lldb::ePermissionsReadable) prot |= eMmapProtRead; if (permissions & lldb::ePermissionsWritable) prot |= eMmapProtWrite; if (permissions & lldb::ePermissionsExecutable) prot |= eMmapProtExec; if (InferiorCallMmap(this, allocated_addr, 0, size, prot, eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) m_addr_to_mmap_size[allocated_addr] = size; else { allocated_addr = LLDB_INVALID_ADDRESS; if (log) log->Printf ("ProcessGDBRemote::%s no direct stub support for memory allocation, and InferiorCallMmap also failed - is stub missing register context save/restore capability?", __FUNCTION__); } } if (allocated_addr == LLDB_INVALID_ADDRESS) error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions)); else error.Clear(); return allocated_addr; } Error ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr, MemoryRegionInfo ®ion_info) { Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info)); return error; } Error ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num) { Error error (m_gdb_comm.GetWatchpointSupportInfo (num)); return error; } Error ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after) { Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after, GetTarget().GetArchitecture())); return error; } Error ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr) { Error error; LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory(); switch (supported) { case eLazyBoolCalculate: // We should never be deallocating memory without allocating memory // first so we should never get eLazyBoolCalculate error.SetErrorString ("tried to deallocate memory without ever allocating memory"); break; case eLazyBoolYes: if (!m_gdb_comm.DeallocateMemory (addr)) error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); break; case eLazyBoolNo: // Call munmap() to deallocate memory in the inferior.. { MMapMap::iterator pos = m_addr_to_mmap_size.find(addr); if (pos != m_addr_to_mmap_size.end() && InferiorCallMunmap(this, addr, pos->second)) m_addr_to_mmap_size.erase (pos); else error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr); } break; } return error; } //------------------------------------------------------------------ // Process STDIO //------------------------------------------------------------------ size_t ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error) { if (m_stdio_communication.IsConnected()) { ConnectionStatus status; m_stdio_communication.Write(src, src_len, status, NULL); } else if (m_stdin_forward) { m_gdb_comm.SendStdinNotification(src, src_len); } return 0; } Error ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site) { Error error; assert(bp_site != NULL); // Get logging info Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); user_id_t site_id = bp_site->GetID(); // Get the breakpoint address const addr_t addr = bp_site->GetLoadAddress(); // Log that a breakpoint was requested if (log) log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr); // Breakpoint already exists and is enabled if (bp_site->IsEnabled()) { if (log) log->Printf("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr); return error; } // Get the software breakpoint trap opcode size const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode(bp_site); // SupportsGDBStoppointPacket() simply checks a boolean, indicating if this breakpoint type // is supported by the remote stub. These are set to true by default, and later set to false // only after we receive an unimplemented response when sending a breakpoint packet. This means // initially that unless we were specifically instructed to use a hardware breakpoint, LLDB will // attempt to set a software breakpoint. HardwareRequired() also queries a boolean variable which // indicates if the user specifically asked for hardware breakpoints. If true then we will // skip over software breakpoints. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware) && (!bp_site->HardwareRequired())) { // Try to send off a software breakpoint packet ($Z0) uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size); if (error_no == 0) { // The breakpoint was placed successfully bp_site->SetEnabled(true); bp_site->SetType(BreakpointSite::eExternal); return error; } // SendGDBStoppointTypePacket() will return an error if it was unable to set this // breakpoint. We need to differentiate between a error specific to placing this breakpoint // or if we have learned that this breakpoint type is unsupported. To do this, we // must test the support boolean for this breakpoint type to see if it now indicates that // this breakpoint type is unsupported. If they are still supported then we should return // with the error code. If they are now unsupported, then we would like to fall through // and try another form of breakpoint. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointSoftware)) { if (error_no != UINT8_MAX) error.SetErrorStringWithFormat("error: %d sending the breakpoint request", errno); else error.SetErrorString("error sending the breakpoint request"); return error; } // We reach here when software breakpoints have been found to be unsupported. For future // calls to set a breakpoint, we will not attempt to set a breakpoint with a type that is // known not to be supported. if (log) log->Printf("Software breakpoints are unsupported"); // So we will fall through and try a hardware breakpoint } // The process of setting a hardware breakpoint is much the same as above. We check the // supported boolean for this breakpoint type, and if it is thought to be supported then we // will try to set this breakpoint with a hardware breakpoint. if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { // Try to send off a hardware breakpoint packet ($Z1) uint8_t error_no = m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size); if (error_no == 0) { // The breakpoint was placed successfully bp_site->SetEnabled(true); bp_site->SetType(BreakpointSite::eHardware); return error; } // Check if the error was something other then an unsupported breakpoint type if (m_gdb_comm.SupportsGDBStoppointPacket(eBreakpointHardware)) { // Unable to set this hardware breakpoint if (error_no != UINT8_MAX) error.SetErrorStringWithFormat("error: %d sending the hardware breakpoint request " "(hardware breakpoint resources might be exhausted or unavailable)", error_no); else error.SetErrorString("error sending the hardware breakpoint request (hardware breakpoint resources " "might be exhausted or unavailable)"); return error; } // We will reach here when the stub gives an unsupported response to a hardware breakpoint if (log) log->Printf("Hardware breakpoints are unsupported"); // Finally we will falling through to a #trap style breakpoint } // Don't fall through when hardware breakpoints were specifically requested if (bp_site->HardwareRequired()) { error.SetErrorString("hardware breakpoints are not supported"); return error; } // As a last resort we want to place a manual breakpoint. An instruction // is placed into the process memory using memory write packets. return EnableSoftwareBreakpoint(bp_site); } Error ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site) { Error error; assert (bp_site != NULL); addr_t addr = bp_site->GetLoadAddress(); user_id_t site_id = bp_site->GetID(); Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS)); if (log) log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr); if (bp_site->IsEnabled()) { const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site); BreakpointSite::Type bp_type = bp_site->GetType(); switch (bp_type) { case BreakpointSite::eSoftware: error = DisableSoftwareBreakpoint (bp_site); break; case BreakpointSite::eHardware: if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, false, addr, bp_op_size)) error.SetErrorToGenericError(); break; case BreakpointSite::eExternal: { GDBStoppointType stoppoint_type; if (bp_site->IsHardware()) stoppoint_type = eBreakpointHardware; else stoppoint_type = eBreakpointSoftware; if (m_gdb_comm.SendGDBStoppointTypePacket(stoppoint_type, false, addr, bp_op_size)) error.SetErrorToGenericError(); } break; } if (error.Success()) bp_site->SetEnabled(false); } else { if (log) log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr); return error; } if (error.Success()) error.SetErrorToGenericError(); return error; } // Pre-requisite: wp != NULL. static GDBStoppointType GetGDBStoppointType (Watchpoint *wp) { assert(wp); bool watch_read = wp->WatchpointRead(); bool watch_write = wp->WatchpointWrite(); // watch_read and watch_write cannot both be false. assert(watch_read || watch_write); if (watch_read && watch_write) return eWatchpointReadWrite; else if (watch_read) return eWatchpointRead; else // Must be watch_write, then. return eWatchpointWrite; } Error ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify) { Error error; if (wp) { user_id_t watchID = wp->GetID(); addr_t addr = wp->GetLoadAddress(); Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); if (log) log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID); if (wp->IsEnabled()) { if (log) log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr); return error; } GDBStoppointType type = GetGDBStoppointType(wp); // Pass down an appropriate z/Z packet... if (m_gdb_comm.SupportsGDBStoppointPacket (type)) { if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0) { wp->SetEnabled(true, notify); return error; } else error.SetErrorString("sending gdb watchpoint packet failed"); } else error.SetErrorString("watchpoints not supported"); } else { error.SetErrorString("Watchpoint argument was NULL."); } if (error.Success()) error.SetErrorToGenericError(); return error; } Error ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify) { Error error; if (wp) { user_id_t watchID = wp->GetID(); Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS)); addr_t addr = wp->GetLoadAddress(); if (log) log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr); if (!wp->IsEnabled()) { if (log) log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr); // See also 'class WatchpointSentry' within StopInfo.cpp. // This disabling attempt might come from the user-supplied actions, we'll route it in order for // the watchpoint object to intelligently process this action. wp->SetEnabled(false, notify); return error; } if (wp->IsHardware()) { GDBStoppointType type = GetGDBStoppointType(wp); // Pass down an appropriate z/Z packet... if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0) { wp->SetEnabled(false, notify); return error; } else error.SetErrorString("sending gdb watchpoint packet failed"); } // TODO: clear software watchpoints if we implement them } else { error.SetErrorString("Watchpoint argument was NULL."); } if (error.Success()) error.SetErrorToGenericError(); return error; } void ProcessGDBRemote::Clear() { m_flags = 0; m_thread_list_real.Clear(); m_thread_list.Clear(); } Error ProcessGDBRemote::DoSignal (int signo) { Error error; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo); if (!m_gdb_comm.SendAsyncSignal (signo)) error.SetErrorStringWithFormat("failed to send signal %i", signo); return error; } Error ProcessGDBRemote::EstablishConnectionIfNeeded (const ProcessInfo &process_info) { // Make sure we aren't already connected? if (m_gdb_comm.IsConnected()) return Error(); PlatformSP platform_sp (GetTarget ().GetPlatform ()); if (platform_sp && !platform_sp->IsHost ()) return Error("Lost debug server connection"); auto error = LaunchAndConnectToDebugserver (process_info); if (error.Fail()) { const char *error_string = error.AsCString(); if (error_string == nullptr) error_string = "unable to launch " DEBUGSERVER_BASENAME; } return error; } Error ProcessGDBRemote::LaunchAndConnectToDebugserver (const ProcessInfo &process_info) { using namespace std::placeholders; // For _1, _2, etc. Error error; if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID) { // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; ProcessLaunchInfo debugserver_launch_info; // Make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver. debugserver_launch_info.SetLaunchInSeparateProcessGroup(true); const std::weak_ptr this_wp = std::static_pointer_cast(shared_from_this()); debugserver_launch_info.SetMonitorProcessCallback(std::bind(MonitorDebugserverProcess, this_wp, _1, _2, _3, _4), false); debugserver_launch_info.SetUserID(process_info.GetUserID()); #if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__)) // On iOS, still do a local connection using a random port const char *hostname = "127.0.0.1"; uint16_t port = get_random_port (); #else // Set hostname being NULL to do the reverse connect where debugserver // will bind to port zero and it will communicate back to us the port // that we will connect to const char *hostname = nullptr; uint16_t port = 0; #endif StreamString url_str; const char* url = nullptr; if (hostname != nullptr) { url_str.Printf("%s:%u", hostname, port); url = url_str.GetData(); } error = m_gdb_comm.StartDebugserverProcess (url, GetTarget().GetPlatform().get(), debugserver_launch_info, &port); if (error.Success ()) m_debugserver_pid = debugserver_launch_info.GetProcessID(); else m_debugserver_pid = LLDB_INVALID_PROCESS_ID; if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) StartAsyncThread (); if (error.Fail()) { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf("failed to start debugserver process: %s", error.AsCString()); return error; } if (m_gdb_comm.IsConnected()) { // Finish the connection process by doing the handshake without connecting (send NULL URL) ConnectToDebugserver (NULL); } else { StreamString connect_url; connect_url.Printf("connect://%s:%u", hostname, port); error = ConnectToDebugserver (connect_url.GetString().c_str()); } } return error; } bool ProcessGDBRemote::MonitorDebugserverProcess(std::weak_ptr process_wp, lldb::pid_t debugserver_pid, bool exited, // True if the process did exit int signo, // Zero for no signal int exit_status // Exit value of process if signal is zero ) { // "debugserver_pid" argument passed in is the process ID for // debugserver that we are tracking... Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); const bool handled = true; if (log) log->Printf("ProcessGDBRemote::%s(process_wp, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", __FUNCTION__, debugserver_pid, signo, signo, exit_status); std::shared_ptr process_sp = process_wp.lock(); if (log) log->Printf("ProcessGDBRemote::%s(process = %p)", __FUNCTION__, static_cast(process_sp.get())); if (!process_sp || process_sp->m_debugserver_pid != debugserver_pid) return handled; // Sleep for a half a second to make sure our inferior process has // time to set its exit status before we set it incorrectly when // both the debugserver and the inferior process shut down. usleep(500000); // If our process hasn't yet exited, debugserver might have died. // If the process did exit, then we are reaping it. const StateType state = process_sp->GetState(); if (state != eStateInvalid && state != eStateUnloaded && state != eStateExited && state != eStateDetached) { char error_str[1024]; if (signo) { const char *signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); if (signal_cstr) ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr); else ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with signal %i", signo); } else { ::snprintf(error_str, sizeof(error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status); } process_sp->SetExitStatus(-1, error_str); } // Debugserver has exited we need to let our ProcessGDBRemote // know that it no longer has a debugserver instance process_sp->m_debugserver_pid = LLDB_INVALID_PROCESS_ID; return handled; } void ProcessGDBRemote::KillDebugserverProcess () { m_gdb_comm.Disconnect(); if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID) { Host::Kill (m_debugserver_pid, SIGINT); m_debugserver_pid = LLDB_INVALID_PROCESS_ID; } } void ProcessGDBRemote::Initialize() { static std::once_flag g_once_flag; std::call_once(g_once_flag, []() { PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, DebuggerInitialize); }); } void ProcessGDBRemote::DebuggerInitialize (Debugger &debugger) { if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName())) { const bool is_global_setting = true; PluginManager::CreateSettingForProcessPlugin (debugger, GetGlobalPluginProperties()->GetValueProperties(), ConstString ("Properties for the gdb-remote process plug-in."), is_global_setting); } } bool ProcessGDBRemote::StartAsyncThread () { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); std::lock_guard guard(m_async_thread_state_mutex); if (!m_async_thread.IsJoinable()) { // Create a thread that watches our internal state and controls which // events make it to clients (into the DCProcess event queue). m_async_thread = ThreadLauncher::LaunchThread("", ProcessGDBRemote::AsyncThread, this, NULL); } else if (log) log->Printf("ProcessGDBRemote::%s () - Called when Async thread was already running.", __FUNCTION__); return m_async_thread.IsJoinable(); } void ProcessGDBRemote::StopAsyncThread () { Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__); std::lock_guard guard(m_async_thread_state_mutex); if (m_async_thread.IsJoinable()) { m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit); // This will shut down the async thread. m_gdb_comm.Disconnect(); // Disconnect from the debug server. // Stop the stdio thread m_async_thread.Join(nullptr); m_async_thread.Reset(); } else if (log) log->Printf("ProcessGDBRemote::%s () - Called when Async thread was not running.", __FUNCTION__); } bool ProcessGDBRemote::HandleNotifyPacket (StringExtractorGDBRemote &packet) { // get the packet at a string const std::string &pkt = packet.GetStringRef(); // skip %stop: StringExtractorGDBRemote stop_info(pkt.c_str() + 5); // pass as a thread stop info packet SetLastStopPacket(stop_info); // check for more stop reasons HandleStopReplySequence(); // if the process is stopped then we need to fake a resume // so that we can stop properly with the new break. This // is possible due to SetPrivateState() broadcasting the // state change as a side effect. if (GetPrivateState() == lldb::StateType::eStateStopped) { SetPrivateState(lldb::StateType::eStateRunning); } // since we have some stopped packets we can halt the process SetPrivateState(lldb::StateType::eStateStopped); return true; } thread_result_t ProcessGDBRemote::AsyncThread (void *arg) { ProcessGDBRemote *process = (ProcessGDBRemote*) arg; Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS)); if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID()); EventSP event_sp; bool done = false; while (!done) { if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID()); if (process->m_async_listener_sp->WaitForEvent (NULL, event_sp)) { const uint32_t event_type = event_sp->GetType(); if (event_sp->BroadcasterIs (&process->m_async_broadcaster)) { if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type); switch (event_type) { case eBroadcastBitAsyncContinue: { const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get()); if (continue_packet) { const char *continue_cstr = (const char *)continue_packet->GetBytes (); const size_t continue_cstr_len = continue_packet->GetByteSize (); if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr); if (::strstr (continue_cstr, "vAttach") == NULL) process->SetPrivateState(eStateRunning); StringExtractorGDBRemote response; // If in Non-Stop-Mode if (process->GetTarget().GetNonStopModeEnabled()) { // send the vCont packet if (!process->GetGDBRemote().SendvContPacket(process, continue_cstr, continue_cstr_len, response)) { // Something went wrong done = true; break; } } // If in All-Stop-Mode else { StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response); // We need to immediately clear the thread ID list so we are sure to get a valid list of threads. // The thread ID list might be contained within the "response", or the stop reply packet that // caused the stop. So clear it now before we give the stop reply packet to the process // using the process->SetLastStopPacket()... process->ClearThreadIDList (); switch (stop_state) { case eStateStopped: case eStateCrashed: case eStateSuspended: process->SetLastStopPacket (response); process->SetPrivateState (stop_state); break; case eStateExited: { process->SetLastStopPacket (response); process->ClearThreadIDList(); response.SetFilePos(1); int exit_status = response.GetHexU8(); const char *desc_cstr = NULL; StringExtractor extractor; std::string desc_string; if (response.GetBytesLeft() > 0 && response.GetChar('-') == ';') { std::string desc_token; while (response.GetNameColonValue (desc_token, desc_string)) { if (desc_token == "description") { extractor.GetStringRef().swap(desc_string); extractor.SetFilePos(0); extractor.GetHexByteString (desc_string); desc_cstr = desc_string.c_str(); } } } process->SetExitStatus(exit_status, desc_cstr); done = true; break; } case eStateInvalid: { // Check to see if we were trying to attach and if we got back // the "E87" error code from debugserver -- this indicates that // the process is not debuggable. Return a slightly more helpful // error message about why the attach failed. if (::strstr (continue_cstr, "vAttach") != NULL && response.GetError() == 0x87) { process->SetExitStatus(-1, "cannot attach to process due to System Integrity Protection"); } // E01 code from vAttach means that the attach failed if (::strstr (continue_cstr, "vAttach") != NULL && response.GetError() == 0x1) { process->SetExitStatus(-1, "unable to attach"); } else { process->SetExitStatus(-1, "lost connection"); } break; } default: process->SetPrivateState (stop_state); break; } // switch(stop_state) } // else // if in All-stop-mode } // if (continue_packet) } // case eBroadcastBitAysncContinue break; case eBroadcastBitAsyncThreadShouldExit: if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID()); done = true; break; default: if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); done = true; break; } } else if (event_sp->BroadcasterIs (&process->m_gdb_comm)) { switch (event_type) { case Communication::eBroadcastBitReadThreadDidExit: process->SetExitStatus (-1, "lost connection"); done = true; break; case GDBRemoteCommunication::eBroadcastBitGdbReadThreadGotNotify: { lldb_private::Event *event = event_sp.get(); const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event); StringExtractorGDBRemote notify((const char*)continue_packet->GetBytes()); // Hand this over to the process to handle process->HandleNotifyPacket(notify); break; } default: if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type); done = true; break; } } } else { if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID()); done = true; } } if (log) log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID()); return NULL; } //uint32_t //ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector &pids) //{ // // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver // // process and ask it for the list of processes. But if we are local, we can let the Host do it. // if (m_local_debugserver) // { // return Host::ListProcessesMatchingName (name, matches, pids); // } // else // { // // FIXME: Implement talking to the remote debugserver. // return 0; // } // //} // bool ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id) { // I don't think I have to do anything here, just make sure I notice the new thread when it starts to // run so I can stop it if that's what I want to do. Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); if (log) log->Printf("Hit New Thread Notification breakpoint."); return false; } bool ProcessGDBRemote::StartNoticingNewThreads() { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) log->Printf("Enabled noticing new thread breakpoint."); m_thread_create_bp_sp->SetEnabled(true); } else { PlatformSP platform_sp (GetTarget().GetPlatform()); if (platform_sp) { m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(GetTarget()); if (m_thread_create_bp_sp) { if (log && log->GetVerbose()) log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID()); m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true); } else { if (log) log->Printf("Failed to create new thread notification breakpoint."); } } } return m_thread_create_bp_sp.get() != NULL; } bool ProcessGDBRemote::StopNoticingNewThreads() { Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); if (log && log->GetVerbose()) log->Printf ("Disabling new thread notification breakpoint."); if (m_thread_create_bp_sp) m_thread_create_bp_sp->SetEnabled(false); return true; } DynamicLoader * ProcessGDBRemote::GetDynamicLoader () { if (m_dyld_ap.get() == NULL) m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL)); return m_dyld_ap.get(); } Error ProcessGDBRemote::SendEventData(const char *data) { int return_value; bool was_supported; Error error; return_value = m_gdb_comm.SendLaunchEventDataPacket (data, &was_supported); if (return_value != 0) { if (!was_supported) error.SetErrorString("Sending events is not supported for this process."); else error.SetErrorStringWithFormat("Error sending event data: %d.", return_value); } return error; } const DataBufferSP ProcessGDBRemote::GetAuxvData() { DataBufferSP buf; if (m_gdb_comm.GetQXferAuxvReadSupported()) { std::string response_string; if (m_gdb_comm.SendPacketsAndConcatenateResponses("qXfer:auxv:read::", response_string) == GDBRemoteCommunication::PacketResult::Success) buf.reset(new DataBufferHeap(response_string.c_str(), response_string.length())); } return buf; } StructuredData::ObjectSP ProcessGDBRemote::GetExtendedInfoForThread (lldb::tid_t tid) { StructuredData::ObjectSP object_sp; if (m_gdb_comm.GetThreadExtendedInfoSupported()) { StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); SystemRuntime *runtime = GetSystemRuntime(); if (runtime) { runtime->AddThreadExtendedInfoPacketHints (args_dict); } args_dict->GetAsDictionary()->AddIntegerItem ("thread", tid); StreamString packet; packet << "jThreadExtendedInfo:"; args_dict->Dump (packet); // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape // these characters in its packet output -- so we add the quoted version // of the } character here manually in case we talk to a debugserver which // un-escapes the characters at packet read time. packet << (char) (0x7d ^ 0x20); StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) { StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { if (!response.Empty()) { object_sp = StructuredData::ParseJSON (response.GetStringRef()); } } } } return object_sp; } StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos (lldb::addr_t image_list_address, lldb::addr_t image_count) { StructuredData::ObjectSP object_sp; if (m_gdb_comm.GetLoadedDynamicLibrariesInfosSupported()) { // Scope for the scoped timeout object GDBRemoteCommunication::ScopedTimeout timeout (m_gdb_comm, 10); StructuredData::ObjectSP args_dict(new StructuredData::Dictionary()); args_dict->GetAsDictionary()->AddIntegerItem ("image_list_address", image_list_address); args_dict->GetAsDictionary()->AddIntegerItem ("image_count", image_count); StreamString packet; packet << "jGetLoadedDynamicLibrariesInfos:"; args_dict->Dump (packet); // FIXME the final character of a JSON dictionary, '}', is the escape // character in gdb-remote binary mode. lldb currently doesn't escape // these characters in its packet output -- so we add the quoted version // of the } character here manually in case we talk to a debugserver which // un-escapes the characters at packet read time. packet << (char) (0x7d ^ 0x20); StringExtractorGDBRemote response; response.SetResponseValidatorToJSON(); if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, false) == GDBRemoteCommunication::PacketResult::Success) { StringExtractorGDBRemote::ResponseType response_type = response.GetResponseType(); if (response_type == StringExtractorGDBRemote::eResponse) { if (!response.Empty()) { object_sp = StructuredData::ParseJSON (response.GetStringRef()); } } } } return object_sp; } // Establish the largest memory read/write payloads we should use. // If the remote stub has a max packet size, stay under that size. // // If the remote stub's max packet size is crazy large, use a // reasonable largeish default. // // If the remote stub doesn't advertise a max packet size, use a // conservative default. void ProcessGDBRemote::GetMaxMemorySize() { const uint64_t reasonable_largeish_default = 128 * 1024; const uint64_t conservative_default = 512; if (m_max_memory_size == 0) { uint64_t stub_max_size = m_gdb_comm.GetRemoteMaxPacketSize(); if (stub_max_size != UINT64_MAX && stub_max_size != 0) { // Save the stub's claimed maximum packet size m_remote_stub_max_memory_size = stub_max_size; // Even if the stub says it can support ginormous packets, // don't exceed our reasonable largeish default packet size. if (stub_max_size > reasonable_largeish_default) { stub_max_size = reasonable_largeish_default; } m_max_memory_size = stub_max_size; } else { m_max_memory_size = conservative_default; } } } void ProcessGDBRemote::SetUserSpecifiedMaxMemoryTransferSize (uint64_t user_specified_max) { if (user_specified_max != 0) { GetMaxMemorySize (); if (m_remote_stub_max_memory_size != 0) { if (m_remote_stub_max_memory_size < user_specified_max) { m_max_memory_size = m_remote_stub_max_memory_size; // user specified a packet size too big, go as big // as the remote stub says we can go. } else { m_max_memory_size = user_specified_max; // user's packet size is good } } else { m_max_memory_size = user_specified_max; // user's packet size is probably fine } } } bool ProcessGDBRemote::GetModuleSpec(const FileSpec& module_file_spec, const ArchSpec& arch, ModuleSpec &module_spec) { Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); if (!m_gdb_comm.GetModuleInfo (module_file_spec, arch, module_spec)) { if (log) log->Printf ("ProcessGDBRemote::%s - failed to get module info for %s:%s", __FUNCTION__, module_file_spec.GetPath ().c_str (), arch.GetTriple ().getTriple ().c_str ()); return false; } if (log) { StreamString stream; module_spec.Dump (stream); log->Printf ("ProcessGDBRemote::%s - got module info for (%s:%s) : %s", __FUNCTION__, module_file_spec.GetPath ().c_str (), arch.GetTriple ().getTriple ().c_str (), stream.GetString ().c_str ()); } return true; } bool ProcessGDBRemote::GetHostOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update) { if (m_gdb_comm.GetOSVersion(major, minor, update)) return true; // We failed to get the host OS version, defer to the base // implementation to correctly invalidate the arguments. return Process::GetHostOSVersion(major, minor, update); } namespace { typedef std::vector stringVec; typedef std::vector GDBServerRegisterVec; struct RegisterSetInfo { ConstString name; }; typedef std::map RegisterSetMap; struct GdbServerTargetInfo { std::string arch; std::string osabi; stringVec includes; RegisterSetMap reg_set_map; XMLNode feature_node; }; bool ParseRegisters (XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, uint32_t &cur_reg_num, uint32_t ®_offset) { if (!feature_node) return false; feature_node.ForEachChildElementWithName("reg", [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; ConstString alt_name; ConstString set_name; std::vector value_regs; std::vector invalidate_regs; + std::vector dwarf_opcode_bytes; bool encoding_set = false; bool format_set = false; RegisterInfo reg_info = { NULL, // Name NULL, // Alt name 0, // byte size reg_offset, // offset eEncodingUint, // encoding eFormatHex, // format { LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num cur_reg_num, // process plugin reg num cur_reg_num // native register number }, NULL, - NULL + NULL, + NULL, // Dwarf Expression opcode bytes pointer + 0 // Dwarf Expression opcode bytes length }; - reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &cur_reg_num, ®_offset](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { + reg_node.ForEachAttribute([&target_info, &gdb_group, &gdb_type, ®_name, &alt_name, &set_name, &value_regs, &invalidate_regs, &encoding_set, &format_set, ®_info, &cur_reg_num, ®_offset, &dwarf_opcode_bytes](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { if (name == "name") { reg_name.SetString(value); } else if (name == "bitsize") { reg_info.byte_size = StringConvert::ToUInt32(value.data(), 0, 0) / CHAR_BIT; } else if (name == "type") { gdb_type = value.str(); } else if (name == "group") { gdb_group = value.str(); } else if (name == "regnum") { const uint32_t regnum = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); if (regnum != LLDB_INVALID_REGNUM) { reg_info.kinds[eRegisterKindProcessPlugin] = regnum; } } else if (name == "offset") { reg_offset = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); } else if (name == "altname") { alt_name.SetString(value); } else if (name == "encoding") { encoding_set = true; reg_info.encoding = Args::StringToEncoding (value.data(), eEncodingUint); } else if (name == "format") { format_set = true; Format format = eFormatInvalid; if (Args::StringToFormat (value.data(), format, NULL).Success()) reg_info.format = format; else if (value == "vector-sint8") reg_info.format = eFormatVectorOfSInt8; else if (value == "vector-uint8") reg_info.format = eFormatVectorOfUInt8; else if (value == "vector-sint16") reg_info.format = eFormatVectorOfSInt16; else if (value == "vector-uint16") reg_info.format = eFormatVectorOfUInt16; else if (value == "vector-sint32") reg_info.format = eFormatVectorOfSInt32; else if (value == "vector-uint32") reg_info.format = eFormatVectorOfUInt32; else if (value == "vector-float32") reg_info.format = eFormatVectorOfFloat32; else if (value == "vector-uint128") reg_info.format = eFormatVectorOfUInt128; } else if (name == "group_id") { const uint32_t set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); RegisterSetMap::const_iterator pos = target_info.reg_set_map.find(set_id); if (pos != target_info.reg_set_map.end()) set_name = pos->second.name; } else if (name == "gcc_regnum" || name == "ehframe_regnum") { reg_info.kinds[eRegisterKindEHFrame] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); } else if (name == "dwarf_regnum") { reg_info.kinds[eRegisterKindDWARF] = StringConvert::ToUInt32(value.data(), LLDB_INVALID_REGNUM, 0); } else if (name == "generic") { reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister(value.data()); } else if (name == "value_regnums") { SplitCommaSeparatedRegisterNumberString(value, value_regs, 0); } else if (name == "invalidate_regnums") { SplitCommaSeparatedRegisterNumberString(value, invalidate_regs, 0); + } + else if (name == "dynamic_size_dwarf_expr_bytes") + { + StringExtractor opcode_extractor; + std::string opcode_string = value.str (); + size_t dwarf_opcode_len = opcode_string.length () / 2; + assert (dwarf_opcode_len > 0); + + dwarf_opcode_bytes.resize (dwarf_opcode_len); + reg_info.dynamic_size_dwarf_len = dwarf_opcode_len; + opcode_extractor.GetStringRef ().swap (opcode_string); + uint32_t ret_val = opcode_extractor.GetHexBytesAvail (dwarf_opcode_bytes.data (), + dwarf_opcode_len); + assert (dwarf_opcode_len == ret_val); + + reg_info.dynamic_size_dwarf_expr_bytes = dwarf_opcode_bytes.data (); } else { printf("unhandled attribute %s = %s\n", name.data(), value.data()); } return true; // Keep iterating through all attributes }); if (!gdb_type.empty() && !(encoding_set || format_set)) { if (gdb_type.find("int") == 0) { reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } else if (gdb_type == "data_ptr" || gdb_type == "code_ptr") { reg_info.format = eFormatAddressInfo; reg_info.encoding = eEncodingUint; } else if (gdb_type == "i387_ext" || gdb_type == "float") { reg_info.format = eFormatFloat; reg_info.encoding = eEncodingIEEE754; } } // Only update the register set name if we didn't get a "reg_set" attribute. // "set_name" will be empty if we didn't have a "reg_set" attribute. if (!set_name && !gdb_group.empty()) set_name.SetCString(gdb_group.c_str()); reg_info.byte_offset = reg_offset; assert (reg_info.byte_size != 0); reg_offset += reg_info.byte_size; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); } if (!invalidate_regs.empty()) { invalidate_regs.push_back(LLDB_INVALID_REGNUM); reg_info.invalidate_regs = invalidate_regs.data(); } ++cur_reg_num; AugmentRegisterInfoViaABI (reg_info, reg_name, abi_sp); dyn_reg_info.AddRegister(reg_info, reg_name, alt_name, set_name); return true; // Keep iterating through all "reg" elements }); return true; } } // namespace {} // query the target of gdb-remote for extended target information // return: 'true' on success // 'false' on failure bool ProcessGDBRemote::GetGDBServerRegisterInfo (ArchSpec &arch_to_use) { // Make sure LLDB has an XML parser it can use first if (!XMLDocument::XMLEnabled()) return false; // redirect libxml2's error handler since the default prints to stdout GDBRemoteCommunicationClient & comm = m_gdb_comm; // check that we have extended feature read support if ( !comm.GetQXferFeaturesReadSupported( ) ) return false; // request the target xml file std::string raw; lldb_private::Error lldberr; if (!comm.ReadExtFeature(ConstString("features"), ConstString("target.xml"), raw, lldberr)) { return false; } XMLDocument xml_document; if (xml_document.ParseMemory(raw.c_str(), raw.size(), "target.xml")) { GdbServerTargetInfo target_info; XMLNode target_node = xml_document.GetRootElement("target"); if (target_node) { XMLNode feature_node; target_node.ForEachChildElement([&target_info, this, &feature_node](const XMLNode &node) -> bool { llvm::StringRef name = node.GetName(); if (name == "architecture") { node.GetElementText(target_info.arch); } else if (name == "osabi") { node.GetElementText(target_info.osabi); } else if (name == "xi:include" || name == "include") { llvm::StringRef href = node.GetAttributeValue("href"); if (!href.empty()) target_info.includes.push_back(href.str()); } else if (name == "feature") { feature_node = node; } else if (name == "groups") { node.ForEachChildElementWithName("group", [&target_info](const XMLNode &node) -> bool { uint32_t set_id = UINT32_MAX; RegisterSetInfo set_info; node.ForEachAttribute([&set_id, &set_info](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { if (name == "id") set_id = StringConvert::ToUInt32(value.data(), UINT32_MAX, 0); if (name == "name") set_info.name = ConstString(value); return true; // Keep iterating through all attributes }); if (set_id != UINT32_MAX) target_info.reg_set_map[set_id] = set_info; return true; // Keep iterating through all "group" elements }); } return true; // Keep iterating through all children of the target_node }); // Initialize these outside of ParseRegisters, since they should not be reset inside each include feature uint32_t cur_reg_num = 0; uint32_t reg_offset = 0; // Don't use Process::GetABI, this code gets called from DidAttach, and in that context we haven't // set the Target's architecture yet, so the ABI is also potentially incorrect. ABISP abi_to_use_sp = ABI::FindPlugin(arch_to_use); if (feature_node) { ParseRegisters(feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); } for (const auto &include : target_info.includes) { // request register file std::string xml_data; if (!comm.ReadExtFeature(ConstString("features"), ConstString(include), xml_data, lldberr)) continue; XMLDocument include_xml_document; include_xml_document.ParseMemory(xml_data.data(), xml_data.size(), include.c_str()); XMLNode include_feature_node = include_xml_document.GetRootElement("feature"); if (include_feature_node) { ParseRegisters(include_feature_node, target_info, this->m_register_info, abi_to_use_sp, cur_reg_num, reg_offset); } } this->m_register_info.Finalize(arch_to_use); } } return m_register_info.GetNumRegisters() > 0; } Error ProcessGDBRemote::GetLoadedModuleList (LoadedModuleInfoList & list) { // Make sure LLDB has an XML parser it can use first if (!XMLDocument::XMLEnabled()) return Error (0, ErrorType::eErrorTypeGeneric); Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS); if (log) log->Printf ("ProcessGDBRemote::%s", __FUNCTION__); GDBRemoteCommunicationClient & comm = m_gdb_comm; // check that we have extended feature read support if (comm.GetQXferLibrariesSVR4ReadSupported ()) { list.clear (); // request the loaded library list std::string raw; lldb_private::Error lldberr; if (!comm.ReadExtFeature (ConstString ("libraries-svr4"), ConstString (""), raw, lldberr)) return Error (0, ErrorType::eErrorTypeGeneric); // parse the xml file in memory if (log) log->Printf ("parsing: %s", raw.c_str()); XMLDocument doc; if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) return Error (0, ErrorType::eErrorTypeGeneric); XMLNode root_element = doc.GetRootElement("library-list-svr4"); if (!root_element) return Error(); // main link map structure llvm::StringRef main_lm = root_element.GetAttributeValue("main-lm"); if (!main_lm.empty()) { list.m_link_map = StringConvert::ToUInt64(main_lm.data(), LLDB_INVALID_ADDRESS, 0); } root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { LoadedModuleInfoList::LoadedModuleInfo module; library.ForEachAttribute([log, &module](const llvm::StringRef &name, const llvm::StringRef &value) -> bool { if (name == "name") module.set_name (value.str()); else if (name == "lm") { // the address of the link_map struct. module.set_link_map(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); } else if (name == "l_addr") { // the displacement as read from the field 'l_addr' of the link_map struct. module.set_base(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); // base address is always a displacement, not an absolute value. module.set_base_is_offset(true); } else if (name == "l_ld") { // the memory address of the libraries PT_DYAMIC section. module.set_dynamic(StringConvert::ToUInt64(value.data(), LLDB_INVALID_ADDRESS, 0)); } return true; // Keep iterating over all properties of "library" }); if (log) { std::string name; lldb::addr_t lm=0, base=0, ld=0; bool base_is_offset; module.get_name (name); module.get_link_map (lm); module.get_base (base); module.get_base_is_offset (base_is_offset); module.get_dynamic (ld); log->Printf ("found (link_map:0x%08" PRIx64 ", base:0x%08" PRIx64 "[%s], ld:0x%08" PRIx64 ", name:'%s')", lm, base, (base_is_offset ? "offset" : "absolute"), ld, name.c_str()); } list.add (module); return true; // Keep iterating over all "library" elements in the root node }); if (log) log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); } else if (comm.GetQXferLibrariesReadSupported ()) { list.clear (); // request the loaded library list std::string raw; lldb_private::Error lldberr; if (!comm.ReadExtFeature (ConstString ("libraries"), ConstString (""), raw, lldberr)) return Error (0, ErrorType::eErrorTypeGeneric); if (log) log->Printf ("parsing: %s", raw.c_str()); XMLDocument doc; if (!doc.ParseMemory(raw.c_str(), raw.size(), "noname.xml")) return Error (0, ErrorType::eErrorTypeGeneric); XMLNode root_element = doc.GetRootElement("library-list"); if (!root_element) return Error(); root_element.ForEachChildElementWithName("library", [log, &list](const XMLNode &library) -> bool { LoadedModuleInfoList::LoadedModuleInfo module; llvm::StringRef name = library.GetAttributeValue("name"); module.set_name(name.str()); // The base address of a given library will be the address of its // first section. Most remotes send only one section for Windows // targets for example. const XMLNode §ion = library.FindFirstChildElementWithName("section"); llvm::StringRef address = section.GetAttributeValue("address"); module.set_base(StringConvert::ToUInt64(address.data(), LLDB_INVALID_ADDRESS, 0)); // These addresses are absolute values. module.set_base_is_offset(false); if (log) { std::string name; lldb::addr_t base = 0; bool base_is_offset; module.get_name (name); module.get_base (base); module.get_base_is_offset (base_is_offset); log->Printf ("found (base:0x%08" PRIx64 "[%s], name:'%s')", base, (base_is_offset ? "offset" : "absolute"), name.c_str()); } list.add (module); return true; // Keep iterating over all "library" elements in the root node }); if (log) log->Printf ("found %" PRId32 " modules in total", (int) list.m_list.size()); } else { return Error (0, ErrorType::eErrorTypeGeneric); } return Error(); } lldb::ModuleSP ProcessGDBRemote::LoadModuleAtAddress (const FileSpec &file, lldb::addr_t link_map, lldb::addr_t base_addr, bool value_is_offset) { DynamicLoader *loader = GetDynamicLoader(); if (!loader) return nullptr; return loader->LoadModuleAtAddress(file, link_map, base_addr, value_is_offset); } size_t ProcessGDBRemote::LoadModules (LoadedModuleInfoList &module_list) { using lldb_private::process_gdb_remote::ProcessGDBRemote; // request a list of loaded libraries from GDBServer if (GetLoadedModuleList (module_list).Fail()) return 0; // get a list of all the modules ModuleList new_modules; for (LoadedModuleInfoList::LoadedModuleInfo & modInfo : module_list.m_list) { std::string mod_name; lldb::addr_t mod_base; lldb::addr_t link_map; bool mod_base_is_offset; bool valid = true; valid &= modInfo.get_name (mod_name); valid &= modInfo.get_base (mod_base); valid &= modInfo.get_base_is_offset (mod_base_is_offset); if (!valid) continue; if (!modInfo.get_link_map (link_map)) link_map = LLDB_INVALID_ADDRESS; FileSpec file (mod_name.c_str(), true); lldb::ModuleSP module_sp = LoadModuleAtAddress (file, link_map, mod_base, mod_base_is_offset); if (module_sp.get()) new_modules.Append (module_sp); } if (new_modules.GetSize() > 0) { ModuleList removed_modules; Target &target = GetTarget(); ModuleList &loaded_modules = m_process->GetTarget().GetImages(); for (size_t i = 0; i < loaded_modules.GetSize(); ++i) { const lldb::ModuleSP loaded_module = loaded_modules.GetModuleAtIndex(i); bool found = false; for (size_t j = 0; j < new_modules.GetSize(); ++j) { if (new_modules.GetModuleAtIndex(j).get() == loaded_module.get()) found = true; } // The main executable will never be included in libraries-svr4, don't remove it if (!found && loaded_module.get() != target.GetExecutableModulePointer()) { removed_modules.Append (loaded_module); } } loaded_modules.Remove (removed_modules); m_process->GetTarget().ModulesDidUnload (removed_modules, false); new_modules.ForEach ([&target](const lldb::ModuleSP module_sp) -> bool { lldb_private::ObjectFile * obj = module_sp->GetObjectFile (); if (!obj) return true; if (obj->GetType () != ObjectFile::Type::eTypeExecutable) return true; lldb::ModuleSP module_copy_sp = module_sp; target.SetExecutableModule (module_copy_sp, false); return false; }); loaded_modules.AppendIfNeeded (new_modules); m_process->GetTarget().ModulesDidLoad (new_modules); } return new_modules.GetSize(); } size_t ProcessGDBRemote::LoadModules () { LoadedModuleInfoList module_list; return LoadModules (module_list); } Error ProcessGDBRemote::GetFileLoadAddress(const FileSpec& file, bool& is_loaded, lldb::addr_t& load_addr) { is_loaded = false; load_addr = LLDB_INVALID_ADDRESS; std::string file_path = file.GetPath(false); if (file_path.empty ()) return Error("Empty file name specified"); StreamString packet; packet.PutCString("qFileLoadAddress:"); packet.PutCStringAsRawHex8(file_path.c_str()); StringExtractorGDBRemote response; if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(), response, false) != GDBRemoteCommunication::PacketResult::Success) return Error("Sending qFileLoadAddress packet failed"); if (response.IsErrorResponse()) { if (response.GetError() == 1) { // The file is not loaded into the inferior is_loaded = false; load_addr = LLDB_INVALID_ADDRESS; return Error(); } return Error("Fetching file load address from remote server returned an error"); } if (response.IsNormalResponse()) { is_loaded = true; load_addr = response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS); return Error(); } return Error("Unknown error happened during sending the load address packet"); } void ProcessGDBRemote::ModulesDidLoad (ModuleList &module_list) { // We must call the lldb_private::Process::ModulesDidLoad () first before we do anything Process::ModulesDidLoad (module_list); // After loading shared libraries, we can ask our remote GDB server if // it needs any symbols. m_gdb_comm.ServeSymbolLookups(this); } class CommandObjectProcessGDBRemoteSpeedTest: public CommandObjectParsed { public: CommandObjectProcessGDBRemoteSpeedTest(CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "process plugin packet speed-test", "Tests packet speeds of various sizes to determine the performance characteristics of the GDB remote connection. ", NULL), m_option_group (interpreter), m_num_packets (LLDB_OPT_SET_1, false, "count", 'c', 0, eArgTypeCount, "The number of packets to send of each varying size (default is 1000).", 1000), m_max_send (LLDB_OPT_SET_1, false, "max-send", 's', 0, eArgTypeCount, "The maximum number of bytes to send in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), m_max_recv (LLDB_OPT_SET_1, false, "max-receive", 'r', 0, eArgTypeCount, "The maximum number of bytes to receive in a packet. Sizes increase in powers of 2 while the size is less than or equal to this option value. (default 1024).", 1024), m_json (LLDB_OPT_SET_1, false, "json", 'j', "Print the output as JSON data for easy parsing.", false, true) { m_option_group.Append (&m_num_packets, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_max_send, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_max_recv, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Append (&m_json, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1); m_option_group.Finalize(); } ~CommandObjectProcessGDBRemoteSpeedTest () { } Options * GetOptions () override { return &m_option_group; } bool DoExecute (Args& command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { StreamSP output_stream_sp (m_interpreter.GetDebugger().GetAsyncOutputStream()); result.SetImmediateOutputStream (output_stream_sp); const uint32_t num_packets = (uint32_t)m_num_packets.GetOptionValue().GetCurrentValue(); const uint64_t max_send = m_max_send.GetOptionValue().GetCurrentValue(); const uint64_t max_recv = m_max_recv.GetOptionValue().GetCurrentValue(); const bool json = m_json.GetOptionValue().GetCurrentValue(); if (output_stream_sp) process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, *output_stream_sp); else { process->GetGDBRemote().TestPacketSpeed (num_packets, max_send, max_recv, json, result.GetOutputStream()); } result.SetStatus (eReturnStatusSuccessFinishResult); return true; } } else { result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); } result.SetStatus (eReturnStatusFailed); return false; } protected: OptionGroupOptions m_option_group; OptionGroupUInt64 m_num_packets; OptionGroupUInt64 m_max_send; OptionGroupUInt64 m_max_recv; OptionGroupBoolean m_json; }; class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed { private: public: CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "process plugin packet history", "Dumps the packet history buffer. ", NULL) { } ~CommandObjectProcessGDBRemotePacketHistory () { } bool DoExecute (Args& command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { process->GetGDBRemote().DumpHistory(result.GetOutputStream()); result.SetStatus (eReturnStatusSuccessFinishResult); return true; } } else { result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str()); } result.SetStatus (eReturnStatusFailed); return false; } }; class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed { private: public: CommandObjectProcessGDBRemotePacketXferSize(CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "process plugin packet xfer-size", "Maximum size that lldb will try to read/write one one chunk.", NULL) { } ~CommandObjectProcessGDBRemotePacketXferSize () { } bool DoExecute (Args& command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { result.AppendErrorWithFormat ("'%s' takes an argument to specify the max amount to be transferred when reading/writing", m_cmd_name.c_str()); result.SetStatus (eReturnStatusFailed); return false; } ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { const char *packet_size = command.GetArgumentAtIndex(0); errno = 0; uint64_t user_specified_max = strtoul (packet_size, NULL, 10); if (errno == 0 && user_specified_max != 0) { process->SetUserSpecifiedMaxMemoryTransferSize (user_specified_max); result.SetStatus (eReturnStatusSuccessFinishResult); return true; } } result.SetStatus (eReturnStatusFailed); return false; } }; class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed { private: public: CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) : CommandObjectParsed (interpreter, "process plugin packet send", "Send a custom packet through the GDB remote protocol and print the answer. " "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.", NULL) { } ~CommandObjectProcessGDBRemotePacketSend () { } bool DoExecute (Args& command, CommandReturnObject &result) override { const size_t argc = command.GetArgumentCount(); if (argc == 0) { result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str()); result.SetStatus (eReturnStatusFailed); return false; } ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { for (size_t i=0; iGetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); result.SetStatus (eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); output_strm.Printf (" packet: %s\n", packet_cstr); std::string &response_str = response.GetStringRef(); if (strstr(packet_cstr, "qGetProfileData") != NULL) { response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response); } if (response_str.empty()) output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); else output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); } } return true; } }; class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw { private: public: CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) : CommandObjectRaw (interpreter, "process plugin packet monitor", "Send a qRcmd packet through the GDB remote protocol and print the response." "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.", NULL) { } ~CommandObjectProcessGDBRemotePacketMonitor () { } bool DoExecute (const char *command, CommandReturnObject &result) override { if (command == NULL || command[0] == '\0') { result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str()); result.SetStatus (eReturnStatusFailed); return false; } ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr(); if (process) { StreamString packet; packet.PutCString("qRcmd,"); packet.PutBytesAsRawHex8(command, strlen(command)); const char *packet_cstr = packet.GetString().c_str(); bool send_async = true; StringExtractorGDBRemote response; process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async); result.SetStatus (eReturnStatusSuccessFinishResult); Stream &output_strm = result.GetOutputStream(); output_strm.Printf (" packet: %s\n", packet_cstr); const std::string &response_str = response.GetStringRef(); if (response_str.empty()) output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n"); else output_strm.Printf ("response: %s\n", response.GetStringRef().c_str()); } return true; } }; class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword { private: public: CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) : CommandObjectMultiword (interpreter, "process plugin packet", "Commands that deal with GDB remote packets.", NULL) { LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter))); LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter))); LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter))); LoadSubCommand ("xfer-size", CommandObjectSP (new CommandObjectProcessGDBRemotePacketXferSize (interpreter))); LoadSubCommand ("speed-test", CommandObjectSP (new CommandObjectProcessGDBRemoteSpeedTest (interpreter))); } ~CommandObjectProcessGDBRemotePacket () { } }; class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword { public: CommandObjectMultiwordProcessGDBRemote(CommandInterpreter &interpreter) : CommandObjectMultiword(interpreter, "process plugin", "Commands for operating on a ProcessGDBRemote process.", "process plugin []") { LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter))); } ~CommandObjectMultiwordProcessGDBRemote () { } }; CommandObject * ProcessGDBRemote::GetPluginCommandObject() { if (!m_command_sp) m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter())); return m_command_sp.get(); } Index: vendor/lldb/dist/source/Target/RegisterContext.cpp =================================================================== --- vendor/lldb/dist/source/Target/RegisterContext.cpp (revision 304307) +++ vendor/lldb/dist/source/Target/RegisterContext.cpp (revision 304308) @@ -1,628 +1,671 @@ //===-- RegisterContext.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 // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Endian.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/Process.h" #include "lldb/Target/Thread.h" #include "lldb/Target/Target.h" +#include "lldb/Core/Module.h" +#include "lldb/Expression/DWARFExpression.h" +#include "lldb/Core/Value.h" using namespace lldb; using namespace lldb_private; RegisterContext::RegisterContext (Thread &thread, uint32_t concrete_frame_idx) : m_thread (thread), m_concrete_frame_idx (concrete_frame_idx), m_stop_id (thread.GetProcess()->GetStopID()) { } RegisterContext::~RegisterContext() = default; void RegisterContext::InvalidateIfNeeded (bool force) { ProcessSP process_sp (m_thread.GetProcess()); bool invalidate = force; uint32_t process_stop_id = UINT32_MAX; if (process_sp) process_stop_id = process_sp->GetStopID(); else invalidate = true; if (!invalidate) invalidate = process_stop_id != GetStopID(); if (invalidate) { InvalidateAllRegisters (); SetStopID (process_stop_id); } } const RegisterInfo * RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx) { if (reg_name && reg_name[0]) { const uint32_t num_registers = GetRegisterCount(); for (uint32_t reg = start_idx; reg < num_registers; ++reg) { const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) || (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0)) { return reg_info; } } } return nullptr; +} + +uint32_t +RegisterContext::UpdateDynamicRegisterSize (const lldb_private::ArchSpec &arch, + RegisterInfo* reg_info) +{ + ExecutionContext exe_ctx (CalculateThread()); + + // In MIPS, the floating point registers size is depends on FR bit of SR register. + // if SR.FR == 1 then all floating point registers are 64 bits. + // else they are all 32 bits. + + int expr_result; + uint32_t addr_size = arch.GetAddressByteSize (); + const uint8_t* dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes; + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + + DataExtractor dwarf_data (dwarf_opcode_ptr, dwarf_opcode_len, + arch.GetByteOrder (), addr_size); + ModuleSP opcode_ctx; + DWARFExpression dwarf_expr (opcode_ctx, dwarf_data, nullptr, 0, dwarf_opcode_len); + Value result; + Error error; + const lldb::offset_t offset = 0; + if (dwarf_expr.Evaluate (&exe_ctx, nullptr, nullptr, this, opcode_ctx, dwarf_data, nullptr, + offset, dwarf_opcode_len, eRegisterKindDWARF, nullptr, nullptr, result, &error)) + { + expr_result = result.GetScalar ().SInt (-1); + switch (expr_result) + { + case 0: return 4; + case 1: return 8; + default: return reg_info->byte_size; + } + } + else + { + printf ("Error executing DwarfExpression::Evaluate %s\n", error.AsCString()); + return reg_info->byte_size; + } } const RegisterInfo * RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num) { const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); if (reg_num == LLDB_INVALID_REGNUM) return nullptr; return GetRegisterInfoAtIndex (reg_num); } const char * RegisterContext::GetRegisterName (uint32_t reg) { const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); if (reg_info) return reg_info->name; return nullptr; } uint64_t RegisterContext::GetPC(uint64_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); uint64_t pc = ReadRegisterAsUnsigned (reg, fail_value); if (pc != fail_value) { TargetSP target_sp = m_thread.CalculateTarget(); if (target_sp) { Target *target = target_sp.get(); if (target) pc = target->GetOpcodeLoadAddress (pc, eAddressClassCode); } } return pc; } bool RegisterContext::SetPC(uint64_t pc) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); bool success = WriteRegisterFromUnsigned (reg, pc); if (success) { StackFrameSP frame_sp(m_thread.GetFrameWithConcreteFrameIndex (m_concrete_frame_idx)); if (frame_sp) frame_sp->ChangePC(pc); else m_thread.ClearStackFrames (); } return success; } bool RegisterContext::SetPC(Address addr) { TargetSP target_sp = m_thread.CalculateTarget(); Target *target = target_sp.get(); lldb::addr_t callAddr = addr.GetCallableLoadAddress (target); if (callAddr == LLDB_INVALID_ADDRESS) return false; return SetPC (callAddr); } uint64_t RegisterContext::GetSP(uint64_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); return ReadRegisterAsUnsigned (reg, fail_value); } bool RegisterContext::SetSP(uint64_t sp) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); return WriteRegisterFromUnsigned (reg, sp); } uint64_t RegisterContext::GetFP(uint64_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); return ReadRegisterAsUnsigned (reg, fail_value); } bool RegisterContext::SetFP(uint64_t fp) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); return WriteRegisterFromUnsigned (reg, fp); } uint64_t RegisterContext::GetReturnAddress (uint64_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); return ReadRegisterAsUnsigned (reg, fail_value); } uint64_t RegisterContext::GetFlags (uint64_t fail_value) { uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); return ReadRegisterAsUnsigned (reg, fail_value); } uint64_t RegisterContext::ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value) { if (reg != LLDB_INVALID_REGNUM) return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value); return fail_value; } uint64_t RegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value) { if (reg_info) { RegisterValue value; if (ReadRegister (reg_info, value)) return value.GetAsUInt64(); } return fail_value; } bool RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval) { if (reg == LLDB_INVALID_REGNUM) return false; return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval); } bool RegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval) { if (reg_info) { RegisterValue value; if (value.SetUInt(uval, reg_info->byte_size)) return WriteRegister (reg_info, value); } return false; } bool RegisterContext::CopyFromRegisterContext (lldb::RegisterContextSP context) { uint32_t num_register_sets = context->GetRegisterSetCount(); // We don't know that two threads have the same register context, so require the threads to be the same. if (context->GetThreadID() != GetThreadID()) return false; if (num_register_sets != GetRegisterSetCount()) return false; RegisterContextSP frame_zero_context = m_thread.GetRegisterContext(); for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx) { const RegisterSet * const reg_set = GetRegisterSet(set_idx); const uint32_t num_registers = reg_set->num_registers; for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { const uint32_t reg = reg_set->registers[reg_idx]; const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); if (!reg_info || reg_info->value_regs) continue; RegisterValue reg_value; // If we can reconstruct the register from the frame we are copying from, then do so, otherwise // use the value from frame 0. if (context->ReadRegister(reg_info, reg_value)) { WriteRegister(reg_info, reg_value); } else if (frame_zero_context->ReadRegister(reg_info, reg_value)) { WriteRegister(reg_info, reg_value); } } } return true; } lldb::tid_t RegisterContext::GetThreadID() const { return m_thread.GetID(); } uint32_t RegisterContext::NumSupportedHardwareBreakpoints () { return 0; } uint32_t RegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) { return LLDB_INVALID_INDEX32; } bool RegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx) { return false; } uint32_t RegisterContext::NumSupportedHardwareWatchpoints () { return 0; } uint32_t RegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) { return LLDB_INVALID_INDEX32; } bool RegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) { return false; } bool RegisterContext::HardwareSingleStep (bool enable) { return false; } Error RegisterContext::ReadRegisterValueFromMemory (const RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue ®_value) { Error error; if (reg_info == nullptr) { error.SetErrorString ("invalid register info argument."); return error; } // Moving from addr into a register // // Case 1: src_len == dst_len // // |AABBCCDD| Address contents // |AABBCCDD| Register contents // // Case 2: src_len > dst_len // // Error! (The register should always be big enough to hold the data) // // Case 3: src_len < dst_len // // |AABB| Address contents // |AABB0000| Register contents [on little-endian hardware] // |0000AABB| Register contents [on big-endian hardware] if (src_len > RegisterValue::kMaxRegisterByteSize) { error.SetErrorString ("register too small to receive memory data"); return error; } const uint32_t dst_len = reg_info->byte_size; if (src_len > dst_len) { error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len); return error; } ProcessSP process_sp (m_thread.GetProcess()); if (process_sp) { uint8_t src[RegisterValue::kMaxRegisterByteSize]; // Read the memory const uint32_t bytes_read = process_sp->ReadMemory (src_addr, src, src_len, error); // Make sure the memory read succeeded... if (bytes_read != src_len) { if (error.Success()) { // This might happen if we read _some_ bytes but not all error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read, src_len); } return error; } // We now have a memory buffer that contains the part or all of the register // value. Set the register value using this memory data. // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are assuming // they are the same. reg_value.SetFromMemoryData (reg_info, src, src_len, process_sp->GetByteOrder(), error); } else error.SetErrorString("invalid process"); return error; } Error RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue ®_value) { uint8_t dst[RegisterValue::kMaxRegisterByteSize]; Error error; ProcessSP process_sp (m_thread.GetProcess()); if (process_sp) { // TODO: we might need to add a parameter to this function in case the byte // order of the memory data doesn't match the process. For now we are assuming // they are the same. const uint32_t bytes_copied = reg_value.GetAsMemoryData (reg_info, dst, dst_len, process_sp->GetByteOrder(), error); if (error.Success()) { if (bytes_copied == 0) { error.SetErrorString("byte copy failed."); } else { const uint32_t bytes_written = process_sp->WriteMemory (dst_addr, dst, bytes_copied, error); if (bytes_written != bytes_copied) { if (error.Success()) { // This might happen if we read _some_ bytes but not all error.SetErrorStringWithFormat("only wrote %u of %u bytes", bytes_written, bytes_copied); } } } } } else error.SetErrorString("invalid process"); return error; } bool RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) { return ReadAllRegisterValues(reg_checkpoint.GetData()); } bool RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) { return WriteAllRegisterValues(reg_checkpoint.GetData()); } TargetSP RegisterContext::CalculateTarget () { return m_thread.CalculateTarget(); } ProcessSP RegisterContext::CalculateProcess () { return m_thread.CalculateProcess (); } ThreadSP RegisterContext::CalculateThread () { return m_thread.shared_from_this(); } StackFrameSP RegisterContext::CalculateStackFrame () { // Register contexts might belong to many frames if we have inlined // functions inside a frame since all inlined functions share the // same registers, so we can't definitively say which frame we come from... return StackFrameSP(); } void RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx) { m_thread.CalculateExecutionContext (exe_ctx); } bool RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum) { const uint32_t num_registers = GetRegisterCount(); for (uint32_t reg = 0; reg < num_registers; ++reg) { const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg); if (reg_info->kinds[source_rk] == source_regnum) { target_regnum = reg_info->kinds[target_rk]; return (target_regnum != LLDB_INVALID_REGNUM); } } return false; } //bool //RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) //{ // DataExtractor data; // if (!ReadRegisterBytes (reg, data)) // return false; // // const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg); // uint32_t offset = 0; // switch (reg_info->encoding) // { // case eEncodingInvalid: // case eEncodingVector: // break; // // case eEncodingUint: // switch (reg_info->byte_size) // { // case 1: // { // value = data.GetU8 (&offset); // return true; // } // case 2: // { // value = data.GetU16 (&offset); // return true; // } // case 4: // { // value = data.GetU32 (&offset); // return true; // } // case 8: // { // value = data.GetU64 (&offset); // return true; // } // } // break; // case eEncodingSint: // switch (reg_info->byte_size) // { // case 1: // { // int8_t v; // if (data.ExtractBytes (0, sizeof (int8_t), endian::InlHostByteOrder(), &v) != sizeof (int8_t)) // return false; // value = v; // return true; // } // case 2: // { // int16_t v; // if (data.ExtractBytes (0, sizeof (int16_t), endian::InlHostByteOrder(), &v) != sizeof (int16_t)) // return false; // value = v; // return true; // } // case 4: // { // int32_t v; // if (data.ExtractBytes (0, sizeof (int32_t), endian::InlHostByteOrder(), &v) != sizeof (int32_t)) // return false; // value = v; // return true; // } // case 8: // { // int64_t v; // if (data.ExtractBytes (0, sizeof (int64_t), endian::InlHostByteOrder(), &v) != sizeof (int64_t)) // return false; // value = v; // return true; // } // } // break; // case eEncodingIEEE754: // switch (reg_info->byte_size) // { // case sizeof (float): // { // float v; // if (data.ExtractBytes (0, sizeof (float), endian::InlHostByteOrder(), &v) != sizeof (float)) // return false; // value = v; // return true; // } // case sizeof (double): // { // double v; // if (data.ExtractBytes (0, sizeof (double), endian::InlHostByteOrder(), &v) != sizeof (double)) // return false; // value = v; // return true; // } // case sizeof (long double): // { // double v; // if (data.ExtractBytes (0, sizeof (long double), endian::InlHostByteOrder(), &v) != sizeof (long double)) // return false; // value = v; // return true; // } // } // break; // } // return false; //} // //bool //RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) //{ // DataExtractor data; // if (!value.IsValid()) // return false; // if (!value.GetData (data)) // return false; // // return WriteRegisterBytes (reg, data); //}