diff options
Diffstat (limited to 'lldb/tools/debugserver')
103 files changed, 32473 insertions, 33925 deletions
diff --git a/lldb/tools/debugserver/source/ARM_DWARF_Registers.h b/lldb/tools/debugserver/source/ARM_DWARF_Registers.h index 845260ba187..037d28bf130 100644 --- a/lldb/tools/debugserver/source/ARM_DWARF_Registers.h +++ b/lldb/tools/debugserver/source/ARM_DWARF_Registers.h @@ -10,200 +10,197 @@ #ifndef ARM_DWARF_Registers_h_ #define ARM_DWARF_Registers_h_ +enum { + dwarf_r0 = 0, + dwarf_r1, + dwarf_r2, + dwarf_r3, + dwarf_r4, + dwarf_r5, + dwarf_r6, + dwarf_r7, + dwarf_r8, + dwarf_r9, + dwarf_r10, + dwarf_r11, + dwarf_r12, + dwarf_sp, + dwarf_lr, + dwarf_pc, + dwarf_cpsr, -enum -{ - dwarf_r0 = 0, - dwarf_r1, - dwarf_r2, - dwarf_r3, - dwarf_r4, - dwarf_r5, - dwarf_r6, - dwarf_r7, - dwarf_r8, - dwarf_r9, - dwarf_r10, - dwarf_r11, - dwarf_r12, - dwarf_sp, - dwarf_lr, - dwarf_pc, - dwarf_cpsr, + dwarf_s0 = 64, + dwarf_s1, + dwarf_s2, + dwarf_s3, + dwarf_s4, + dwarf_s5, + dwarf_s6, + dwarf_s7, + dwarf_s8, + dwarf_s9, + dwarf_s10, + dwarf_s11, + dwarf_s12, + dwarf_s13, + dwarf_s14, + dwarf_s15, + dwarf_s16, + dwarf_s17, + dwarf_s18, + dwarf_s19, + dwarf_s20, + dwarf_s21, + dwarf_s22, + dwarf_s23, + dwarf_s24, + dwarf_s25, + dwarf_s26, + dwarf_s27, + dwarf_s28, + dwarf_s29, + dwarf_s30, + dwarf_s31, - dwarf_s0 = 64, - dwarf_s1, - dwarf_s2, - dwarf_s3, - dwarf_s4, - dwarf_s5, - dwarf_s6, - dwarf_s7, - dwarf_s8, - dwarf_s9, - dwarf_s10, - dwarf_s11, - dwarf_s12, - dwarf_s13, - dwarf_s14, - dwarf_s15, - dwarf_s16, - dwarf_s17, - dwarf_s18, - dwarf_s19, - dwarf_s20, - dwarf_s21, - dwarf_s22, - dwarf_s23, - dwarf_s24, - dwarf_s25, - dwarf_s26, - dwarf_s27, - dwarf_s28, - dwarf_s29, - dwarf_s30, - dwarf_s31, + // FPA Registers 0-7 + dwarf_f0 = 96, + dwarf_f1, + dwarf_f2, + dwarf_f3, + dwarf_f4, + dwarf_f5, + dwarf_f6, + dwarf_f7, - // FPA Registers 0-7 - dwarf_f0 = 96, - dwarf_f1, - dwarf_f2, - dwarf_f3, - dwarf_f4, - dwarf_f5, - dwarf_f6, - dwarf_f7, + // Intel wireless MMX general purpose registers 0 - 7 + dwarf_wCGR0 = 104, + dwarf_wCGR1, + dwarf_wCGR2, + dwarf_wCGR3, + dwarf_wCGR4, + dwarf_wCGR5, + dwarf_wCGR6, + dwarf_wCGR7, - // Intel wireless MMX general purpose registers 0 - 7 - dwarf_wCGR0 = 104, - dwarf_wCGR1, - dwarf_wCGR2, - dwarf_wCGR3, - dwarf_wCGR4, - dwarf_wCGR5, - dwarf_wCGR6, - dwarf_wCGR7, + // XScale accumulator register 0–7 (they do overlap with wCGR0 - wCGR7) + dwarf_ACC0 = 104, + dwarf_ACC1, + dwarf_ACC2, + dwarf_ACC3, + dwarf_ACC4, + dwarf_ACC5, + dwarf_ACC6, + dwarf_ACC7, - // XScale accumulator register 0–7 (they do overlap with wCGR0 - wCGR7) - dwarf_ACC0 = 104, - dwarf_ACC1, - dwarf_ACC2, - dwarf_ACC3, - dwarf_ACC4, - dwarf_ACC5, - dwarf_ACC6, - dwarf_ACC7, + // Intel wireless MMX data registers 0 - 15 + dwarf_wR0 = 112, + dwarf_wR1, + dwarf_wR2, + dwarf_wR3, + dwarf_wR4, + dwarf_wR5, + dwarf_wR6, + dwarf_wR7, + dwarf_wR8, + dwarf_wR9, + dwarf_wR10, + dwarf_wR11, + dwarf_wR12, + dwarf_wR13, + dwarf_wR14, + dwarf_wR15, - // Intel wireless MMX data registers 0 - 15 - dwarf_wR0 = 112, - dwarf_wR1, - dwarf_wR2, - dwarf_wR3, - dwarf_wR4, - dwarf_wR5, - dwarf_wR6, - dwarf_wR7, - dwarf_wR8, - dwarf_wR9, - dwarf_wR10, - dwarf_wR11, - dwarf_wR12, - dwarf_wR13, - dwarf_wR14, - dwarf_wR15, + dwarf_spsr = 128, + dwarf_spsr_fiq, + dwarf_spsr_irq, + dwarf_spsr_abt, + dwarf_spsr_und, + dwarf_spsr_svc, - dwarf_spsr = 128, - dwarf_spsr_fiq, - dwarf_spsr_irq, - dwarf_spsr_abt, - dwarf_spsr_und, - dwarf_spsr_svc, + dwarf_r8_usr = 144, + dwarf_r9_usr, + dwarf_r10_usr, + dwarf_r11_usr, + dwarf_r12_usr, + dwarf_r13_usr, + dwarf_r14_usr, + dwarf_r8_fiq, + dwarf_r9_fiq, + dwarf_r10_fiq, + dwarf_r11_fiq, + dwarf_r12_fiq, + dwarf_r13_fiq, + dwarf_r14_fiq, + dwarf_r13_irq, + dwarf_r14_irq, + dwarf_r13_abt, + dwarf_r14_abt, + dwarf_r13_und, + dwarf_r14_und, + dwarf_r13_svc, + dwarf_r14_svc, - dwarf_r8_usr = 144, - dwarf_r9_usr, - dwarf_r10_usr, - dwarf_r11_usr, - dwarf_r12_usr, - dwarf_r13_usr, - dwarf_r14_usr, - dwarf_r8_fiq, - dwarf_r9_fiq, - dwarf_r10_fiq, - dwarf_r11_fiq, - dwarf_r12_fiq, - dwarf_r13_fiq, - dwarf_r14_fiq, - dwarf_r13_irq, - dwarf_r14_irq, - dwarf_r13_abt, - dwarf_r14_abt, - dwarf_r13_und, - dwarf_r14_und, - dwarf_r13_svc, - dwarf_r14_svc, + // Intel wireless MMX control register in co-processor 0 - 7 + dwarf_wC0 = 192, + dwarf_wC1, + dwarf_wC2, + dwarf_wC3, + dwarf_wC4, + dwarf_wC5, + dwarf_wC6, + dwarf_wC7, - // Intel wireless MMX control register in co-processor 0 - 7 - dwarf_wC0 = 192, - dwarf_wC1, - dwarf_wC2, - dwarf_wC3, - dwarf_wC4, - dwarf_wC5, - dwarf_wC6, - dwarf_wC7, + // VFP-v3/Neon + dwarf_d0 = 256, + dwarf_d1, + dwarf_d2, + dwarf_d3, + dwarf_d4, + dwarf_d5, + dwarf_d6, + dwarf_d7, + dwarf_d8, + dwarf_d9, + dwarf_d10, + dwarf_d11, + dwarf_d12, + dwarf_d13, + dwarf_d14, + dwarf_d15, + dwarf_d16, + dwarf_d17, + dwarf_d18, + dwarf_d19, + dwarf_d20, + dwarf_d21, + dwarf_d22, + dwarf_d23, + dwarf_d24, + dwarf_d25, + dwarf_d26, + dwarf_d27, + dwarf_d28, + dwarf_d29, + dwarf_d30, + dwarf_d31, - // VFP-v3/Neon - dwarf_d0 = 256, - dwarf_d1, - dwarf_d2, - dwarf_d3, - dwarf_d4, - dwarf_d5, - dwarf_d6, - dwarf_d7, - dwarf_d8, - dwarf_d9, - dwarf_d10, - dwarf_d11, - dwarf_d12, - dwarf_d13, - dwarf_d14, - dwarf_d15, - dwarf_d16, - dwarf_d17, - dwarf_d18, - dwarf_d19, - dwarf_d20, - dwarf_d21, - dwarf_d22, - dwarf_d23, - dwarf_d24, - dwarf_d25, - dwarf_d26, - dwarf_d27, - dwarf_d28, - dwarf_d29, - dwarf_d30, - dwarf_d31, - - // Neon quadword registers - dwarf_q0 = 288, - dwarf_q1, - dwarf_q2, - dwarf_q3, - dwarf_q4, - dwarf_q5, - dwarf_q6, - dwarf_q7, - dwarf_q8, - dwarf_q9, - dwarf_q10, - dwarf_q11, - dwarf_q12, - dwarf_q13, - dwarf_q14, - dwarf_q15 + // Neon quadword registers + dwarf_q0 = 288, + dwarf_q1, + dwarf_q2, + dwarf_q3, + dwarf_q4, + dwarf_q5, + dwarf_q6, + dwarf_q7, + dwarf_q8, + dwarf_q9, + dwarf_q10, + dwarf_q11, + dwarf_q12, + dwarf_q13, + dwarf_q14, + dwarf_q15 }; #endif // ARM_DWARF_Registers_h_ - diff --git a/lldb/tools/debugserver/source/ARM_ehframe_Registers.h b/lldb/tools/debugserver/source/ARM_ehframe_Registers.h index f6d93b3cee0..9d644b7dc50 100644 --- a/lldb/tools/debugserver/source/ARM_ehframe_Registers.h +++ b/lldb/tools/debugserver/source/ARM_ehframe_Registers.h @@ -1,4 +1,5 @@ -//===-- ARM_ehframe_Registers.h -------------------------------------*- C++ -*-===// +//===-- ARM_ehframe_Registers.h -------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -10,26 +11,24 @@ #ifndef utility_ARM_ehframe_Registers_h_ #define utility_ARM_ehframe_Registers_h_ -enum -{ - ehframe_r0 = 0, - ehframe_r1, - ehframe_r2, - ehframe_r3, - ehframe_r4, - ehframe_r5, - ehframe_r6, - ehframe_r7, - ehframe_r8, - ehframe_r9, - ehframe_r10, - ehframe_r11, - ehframe_r12, - ehframe_sp, - ehframe_lr, - ehframe_pc, - ehframe_cpsr +enum { + ehframe_r0 = 0, + ehframe_r1, + ehframe_r2, + ehframe_r3, + ehframe_r4, + ehframe_r5, + ehframe_r6, + ehframe_r7, + ehframe_r8, + ehframe_r9, + ehframe_r10, + ehframe_r11, + ehframe_r12, + ehframe_sp, + ehframe_lr, + ehframe_pc, + ehframe_cpsr }; #endif // utility_ARM_ehframe_Registers_h_ - diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp index fc36dcec078..9c6c44d18df 100644 --- a/lldb/tools/debugserver/source/DNB.cpp +++ b/lldb/tools/debugserver/source/DNB.cpp @@ -13,20 +13,20 @@ #include "DNB.h" #include <inttypes.h> +#include <libproc.h> +#include <map> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <sys/resource.h> #include <sys/stat.h> +#include <sys/sysctl.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> -#include <sys/sysctl.h> -#include <map> #include <vector> -#include <libproc.h> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <pthread.h> #include <sched.h> #endif @@ -34,33 +34,34 @@ #define TRY_KQUEUE 1 #ifdef TRY_KQUEUE - #include <sys/event.h> - #include <sys/time.h> - #ifdef NOTE_EXIT_DETAIL - #define USE_KQUEUE - #endif +#include <sys/event.h> +#include <sys/time.h> +#ifdef NOTE_EXIT_DETAIL +#define USE_KQUEUE +#endif #endif -#include "MacOSX/DarwinLog/DarwinLogCollector.h" -#include "MacOSX/MachProcess.h" -#include "MacOSX/MachTask.h" -#include "MacOSX/Genealogy.h" -#include "MacOSX/ThreadInfo.h" +#include "CFBundle.h" #include "CFString.h" -#include "DNBLog.h" #include "DNBDataRef.h" +#include "DNBLog.h" #include "DNBThreadResumeActions.h" #include "DNBTimer.h" -#include "CFBundle.h" - +#include "MacOSX/DarwinLog/DarwinLogCollector.h" +#include "MacOSX/Genealogy.h" +#include "MacOSX/MachProcess.h" +#include "MacOSX/MachTask.h" +#include "MacOSX/ThreadInfo.h" typedef std::shared_ptr<MachProcess> MachProcessSP; typedef std::map<nub_process_t, MachProcessSP> ProcessMap; typedef ProcessMap::iterator ProcessMapIter; typedef ProcessMap::const_iterator ProcessMapConstIter; -size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos); -static size_t GetAllInfosMatchingName (const char *process_name, std::vector<struct kinfo_proc>& matching_proc_infos); +size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos); +static size_t +GetAllInfosMatchingName(const char *process_name, + std::vector<struct kinfo_proc> &matching_proc_infos); //---------------------------------------------------------------------- // A Thread safe singleton to get a process map pointer. @@ -68,19 +69,16 @@ static size_t GetAllInfosMatchingName (const char *process_name, std::vector<str // Returns a pointer to the existing process map, or a pointer to a // newly created process map if CAN_CREATE is non-zero. //---------------------------------------------------------------------- -static ProcessMap* -GetProcessMap(bool can_create) -{ - static ProcessMap* g_process_map_ptr = NULL; - - if (can_create && g_process_map_ptr == NULL) - { - static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER; - PTHREAD_MUTEX_LOCKER (locker, &g_process_map_mutex); - if (g_process_map_ptr == NULL) - g_process_map_ptr = new ProcessMap; - } - return g_process_map_ptr; +static ProcessMap *GetProcessMap(bool can_create) { + static ProcessMap *g_process_map_ptr = NULL; + + if (can_create && g_process_map_ptr == NULL) { + static pthread_mutex_t g_process_map_mutex = PTHREAD_MUTEX_INITIALIZER; + PTHREAD_MUTEX_LOCKER(locker, &g_process_map_mutex); + if (g_process_map_ptr == NULL) + g_process_map_ptr = new ProcessMap; + } + return g_process_map_ptr; } //---------------------------------------------------------------------- @@ -90,16 +88,13 @@ GetProcessMap(bool can_create) // The only time this should fail is if we run out of memory and can't // allocate a ProcessMap. //---------------------------------------------------------------------- -static nub_bool_t -AddProcessToMap (nub_process_t pid, MachProcessSP& procSP) -{ - ProcessMap* process_map = GetProcessMap(true); - if (process_map) - { - process_map->insert(std::make_pair(pid, procSP)); - return true; - } - return false; +static nub_bool_t AddProcessToMap(nub_process_t pid, MachProcessSP &procSP) { + ProcessMap *process_map = GetProcessMap(true); + if (process_map) { + process_map->insert(std::make_pair(pid, procSP)); + return true; + } + return false; } //---------------------------------------------------------------------- @@ -107,8 +102,8 @@ AddProcessToMap (nub_process_t pid, MachProcessSP& procSP) // // Returns the number of items removed from the process map. //---------------------------------------------------------------------- -//static size_t -//RemoveProcessFromMap (nub_process_t pid) +// static size_t +// RemoveProcessFromMap (nub_process_t pid) //{ // ProcessMap* process_map = GetProcessMap(false); // if (process_map) @@ -124,1079 +119,958 @@ AddProcessToMap (nub_process_t pid, MachProcessSP& procSP) // Returns true if we successfully find a shared pointer to a // MachProcess object. //---------------------------------------------------------------------- -static nub_bool_t -GetProcessSP (nub_process_t pid, MachProcessSP& procSP) -{ - ProcessMap* process_map = GetProcessMap(false); - if (process_map != NULL) - { - ProcessMapIter pos = process_map->find(pid); - if (pos != process_map->end()) - { - procSP = pos->second; - return true; - } +static nub_bool_t GetProcessSP(nub_process_t pid, MachProcessSP &procSP) { + ProcessMap *process_map = GetProcessMap(false); + if (process_map != NULL) { + ProcessMapIter pos = process_map->find(pid); + if (pos != process_map->end()) { + procSP = pos->second; + return true; } - procSP.reset(); - return false; + } + procSP.reset(); + return false; } #ifdef USE_KQUEUE -void * -kqueue_thread (void *arg) -{ - int kq_id = (int) (intptr_t) arg; - -#if defined (__APPLE__) - pthread_setname_np ("kqueue thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } +void *kqueue_thread(void *arg) { + int kq_id = (int)(intptr_t)arg; + +#if defined(__APPLE__) + pthread_setname_np("kqueue thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } #endif #endif - struct kevent death_event; - while (1) - { - int n_events = kevent (kq_id, NULL, 0, &death_event, 1, NULL); - if (n_events == -1) - { - if (errno == EINTR) - continue; - else - { - DNBLogError ("kqueue failed with error: (%d): %s", errno, strerror(errno)); - return NULL; - } - } - else if (death_event.flags & EV_ERROR) - { - int error_no = static_cast<int>(death_event.data); - const char *error_str = strerror(error_no); - if (error_str == NULL) - error_str = "Unknown error"; - DNBLogError ("Failed to initialize kqueue event: (%d): %s", error_no, error_str ); - return NULL; + struct kevent death_event; + while (1) { + int n_events = kevent(kq_id, NULL, 0, &death_event, 1, NULL); + if (n_events == -1) { + if (errno == EINTR) + continue; + else { + DNBLogError("kqueue failed with error: (%d): %s", errno, + strerror(errno)); + return NULL; + } + } else if (death_event.flags & EV_ERROR) { + int error_no = static_cast<int>(death_event.data); + const char *error_str = strerror(error_no); + if (error_str == NULL) + error_str = "Unknown error"; + DNBLogError("Failed to initialize kqueue event: (%d): %s", error_no, + error_str); + return NULL; + } else { + int status; + const pid_t pid = (pid_t)death_event.ident; + const pid_t child_pid = waitpid(pid, &status, 0); + + bool exited = false; + int signal = 0; + int exit_status = 0; + if (WIFSTOPPED(status)) { + signal = WSTOPSIG(status); + DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)", + child_pid, signal); + } else if (WIFEXITED(status)) { + exit_status = WEXITSTATUS(status); + exited = true; + DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)", + child_pid, exit_status); + } else if (WIFSIGNALED(status)) { + signal = WTERMSIG(status); + if (child_pid == abs(pid)) { + DNBLogThreadedIf(LOG_PROCESS, + "waitpid (%i) -> SIGNALED and EXITED (signal = %i)", + child_pid, signal); + char exit_info[64]; + ::snprintf(exit_info, sizeof(exit_info), + "Terminated due to signal %i", signal); + DNBProcessSetExitInfo(child_pid, exit_info); + exited = true; + exit_status = INT8_MAX; + } else { + DNBLogThreadedIf(LOG_PROCESS, + "waitpid (%i) -> SIGNALED (signal = %i)", child_pid, + signal); } - else - { - int status; - const pid_t pid = (pid_t)death_event.ident; - const pid_t child_pid = waitpid (pid, &status, 0); - - - bool exited = false; - int signal = 0; - int exit_status = 0; - if (WIFSTOPPED(status)) - { - signal = WSTOPSIG(status); - DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> STOPPED (signal = %i)", child_pid, signal); - } - else if (WIFEXITED(status)) - { - exit_status = WEXITSTATUS(status); - exited = true; - DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> EXITED (status = %i)", child_pid, exit_status); - } - else if (WIFSIGNALED(status)) - { - signal = WTERMSIG(status); - if (child_pid == abs(pid)) - { - DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED and EXITED (signal = %i)", child_pid, signal); - char exit_info[64]; - ::snprintf (exit_info, sizeof(exit_info), "Terminated due to signal %i", signal); - DNBProcessSetExitInfo (child_pid, exit_info); - exited = true; - exit_status = INT8_MAX; - } - else - { - DNBLogThreadedIf(LOG_PROCESS, "waitpid (%i) -> SIGNALED (signal = %i)", child_pid, signal); - } - } - - if (exited) - { - if (death_event.data & NOTE_EXIT_MEMORY) - DNBProcessSetExitInfo (child_pid, "Terminated due to memory issue"); - else if (death_event.data & NOTE_EXIT_DECRYPTFAIL) - DNBProcessSetExitInfo (child_pid, "Terminated due to decrypt failure"); - else if (death_event.data & NOTE_EXIT_CSERROR) - DNBProcessSetExitInfo (child_pid, "Terminated due to code signing error"); - - DNBLogThreadedIf(LOG_PROCESS, "waitpid_process_thread (): setting exit status for pid = %i to %i", child_pid, exit_status); - DNBProcessSetExitStatus (child_pid, status); - return NULL; - } - } - } -} + } + + if (exited) { + if (death_event.data & NOTE_EXIT_MEMORY) + DNBProcessSetExitInfo(child_pid, "Terminated due to memory issue"); + else if (death_event.data & NOTE_EXIT_DECRYPTFAIL) + DNBProcessSetExitInfo(child_pid, "Terminated due to decrypt failure"); + else if (death_event.data & NOTE_EXIT_CSERROR) + DNBProcessSetExitInfo(child_pid, + "Terminated due to code signing error"); + + DNBLogThreadedIf( + LOG_PROCESS, + "waitpid_process_thread (): setting exit status for pid = %i to %i", + child_pid, exit_status); + DNBProcessSetExitStatus(child_pid, status); + return NULL; + } + } + } +} + +static bool spawn_kqueue_thread(pid_t pid) { + pthread_t thread; + int kq_id; + + kq_id = kqueue(); + if (kq_id == -1) { + DNBLogError("Could not get kqueue for pid = %i.", pid); + return false; + } + + struct kevent reg_event; + + EV_SET(®_event, pid, EVFILT_PROC, EV_ADD, + NOTE_EXIT | NOTE_EXITSTATUS | NOTE_EXIT_DETAIL, 0, NULL); + // Register the event: + int result = kevent(kq_id, ®_event, 1, NULL, 0, NULL); + if (result != 0) { + DNBLogError( + "Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, + result); + return false; + } -static bool -spawn_kqueue_thread (pid_t pid) -{ - pthread_t thread; - int kq_id; - - kq_id = kqueue(); - if (kq_id == -1) - { - DNBLogError ("Could not get kqueue for pid = %i.", pid); - return false; - } + int ret = + ::pthread_create(&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id); - struct kevent reg_event; - - EV_SET(®_event, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT|NOTE_EXITSTATUS|NOTE_EXIT_DETAIL, 0, NULL); - // Register the event: - int result = kevent (kq_id, ®_event, 1, NULL, 0, NULL); - if (result != 0) - { - DNBLogError ("Failed to register kqueue NOTE_EXIT event for pid %i, error: %d.", pid, result); - return false; - } - - int ret = ::pthread_create (&thread, NULL, kqueue_thread, (void *)(intptr_t)kq_id); - - // pthread_create returns 0 if successful - if (ret == 0) - { - ::pthread_detach (thread); - return true; - } - return false; + // pthread_create returns 0 if successful + if (ret == 0) { + ::pthread_detach(thread); + return true; + } + return false; } #endif // #if USE_KQUEUE -static void * -waitpid_thread (void *arg) -{ - const pid_t pid = (pid_t)(intptr_t)arg; - int status; - -#if defined (__APPLE__) - pthread_setname_np ("waitpid thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } +static void *waitpid_thread(void *arg) { + const pid_t pid = (pid_t)(intptr_t)arg; + int status; + +#if defined(__APPLE__) + pthread_setname_np("waitpid thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } #endif #endif - while (1) - { - pid_t child_pid = waitpid(pid, &status, 0); - DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, &status, 0) => %i, status = %i, errno = %i", pid, child_pid, status, errno); - - if (child_pid < 0) - { - if (errno == EINTR) - continue; - break; - } - else - { - if (WIFSTOPPED(status)) - { - continue; - } - else// if (WIFEXITED(status) || WIFSIGNALED(status)) - { - DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): setting exit status for pid = %i to %i", child_pid, status); - DNBProcessSetExitStatus (child_pid, status); - return NULL; - } - } - } - - // We should never exit as long as our child process is alive, so if we - // do something else went wrong and we should exit... - DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting exit status to an invalid value (-1) for pid %i", pid); - DNBProcessSetExitStatus (pid, -1); - return NULL; -} -static bool -spawn_waitpid_thread (pid_t pid) -{ + while (1) { + pid_t child_pid = waitpid(pid, &status, 0); + DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): waitpid (pid = %i, " + "&status, 0) => %i, status = %i, errno = %i", + pid, child_pid, status, errno); + + if (child_pid < 0) { + if (errno == EINTR) + continue; + break; + } else { + if (WIFSTOPPED(status)) { + continue; + } else // if (WIFEXITED(status) || WIFSIGNALED(status)) + { + DNBLogThreadedIf( + LOG_PROCESS, + "waitpid_thread (): setting exit status for pid = %i to %i", + child_pid, status); + DNBProcessSetExitStatus(child_pid, status); + return NULL; + } + } + } + + // We should never exit as long as our child process is alive, so if we + // do something else went wrong and we should exit... + DNBLogThreadedIf(LOG_PROCESS, "waitpid_thread (): main loop exited, setting " + "exit status to an invalid value (-1) for pid " + "%i", + pid); + DNBProcessSetExitStatus(pid, -1); + return NULL; +} +static bool spawn_waitpid_thread(pid_t pid) { #ifdef USE_KQUEUE - bool success = spawn_kqueue_thread (pid); - if (success) - return true; + bool success = spawn_kqueue_thread(pid); + if (success) + return true; #endif - pthread_t thread; - int ret = ::pthread_create (&thread, NULL, waitpid_thread, (void *)(intptr_t)pid); - // pthread_create returns 0 if successful - if (ret == 0) - { - ::pthread_detach (thread); - return true; - } - return false; -} - -nub_process_t -DNBProcessLaunch (const char *path, - char const *argv[], - const char *envp[], - const char *working_directory, // NULL => don't change, non-NULL => set working directory for inferior to this - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - nub_launch_flavor_t launch_flavor, - int disable_aslr, - const char *event_data, - char *err_str, - size_t err_len) -{ - DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, working_dir=%s, stdin=%s, stdout=%s, " - "stderr=%s, no-stdio=%i, launch_flavor = %u, disable_aslr = %d, err = %p, err_len = " - "%llu) called...", - __FUNCTION__, path, static_cast<void *>(argv), static_cast<void *>(envp), working_directory, - stdin_path, stdout_path, stderr_path, no_stdio, launch_flavor, disable_aslr, - static_cast<void *>(err_str), static_cast<uint64_t>(err_len)); - - if (err_str && err_len > 0) - err_str[0] = '\0'; - struct stat path_stat; - if (::stat(path, &path_stat) == -1) - { - char stat_error[256]; - ::strerror_r (errno, stat_error, sizeof(stat_error)); - snprintf(err_str, err_len, "%s (%s)", stat_error, path); - return INVALID_NUB_PROCESS; - } - - MachProcessSP processSP (new MachProcess); - if (processSP.get()) - { - DNBError launch_err; - pid_t pid = processSP->LaunchForDebug (path, - argv, - envp, - working_directory, - stdin_path, - stdout_path, - stderr_path, - no_stdio, - launch_flavor, - disable_aslr, - event_data, - launch_err); - if (err_str) - { - *err_str = '\0'; - if (launch_err.Fail()) - { - const char *launch_err_str = launch_err.AsString(); - if (launch_err_str) - { - strncpy(err_str, launch_err_str, err_len-1); - err_str[err_len-1] = '\0'; // Make sure the error string is terminated - } - } + pthread_t thread; + int ret = + ::pthread_create(&thread, NULL, waitpid_thread, (void *)(intptr_t)pid); + // pthread_create returns 0 if successful + if (ret == 0) { + ::pthread_detach(thread); + return true; + } + return false; +} + +nub_process_t DNBProcessLaunch( + const char *path, char const *argv[], const char *envp[], + const char *working_directory, // NULL => don't change, non-NULL => set + // working directory for inferior to this + const char *stdin_path, const char *stdout_path, const char *stderr_path, + bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, + const char *event_data, char *err_str, size_t err_len) { + DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv = %p, envp = %p, " + "working_dir=%s, stdin=%s, stdout=%s, " + "stderr=%s, no-stdio=%i, launch_flavor = %u, " + "disable_aslr = %d, err = %p, err_len = " + "%llu) called...", + __FUNCTION__, path, static_cast<void *>(argv), + static_cast<void *>(envp), working_directory, stdin_path, + stdout_path, stderr_path, no_stdio, launch_flavor, + disable_aslr, static_cast<void *>(err_str), + static_cast<uint64_t>(err_len)); + + if (err_str && err_len > 0) + err_str[0] = '\0'; + struct stat path_stat; + if (::stat(path, &path_stat) == -1) { + char stat_error[256]; + ::strerror_r(errno, stat_error, sizeof(stat_error)); + snprintf(err_str, err_len, "%s (%s)", stat_error, path); + return INVALID_NUB_PROCESS; + } + + MachProcessSP processSP(new MachProcess); + if (processSP.get()) { + DNBError launch_err; + pid_t pid = processSP->LaunchForDebug(path, argv, envp, working_directory, + stdin_path, stdout_path, stderr_path, + no_stdio, launch_flavor, disable_aslr, + event_data, launch_err); + if (err_str) { + *err_str = '\0'; + if (launch_err.Fail()) { + const char *launch_err_str = launch_err.AsString(); + if (launch_err_str) { + strncpy(err_str, launch_err_str, err_len - 1); + err_str[err_len - 1] = + '\0'; // Make sure the error string is terminated } - - DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid); - - if (pid != INVALID_NUB_PROCESS) - { - // Spawn a thread to reap our child inferior process... - spawn_waitpid_thread (pid); - - if (processSP->Task().TaskPortForProcessID (launch_err) == TASK_NULL) - { - // We failed to get the task for our process ID which is bad. - // Kill our process otherwise it will be stopped at the entry - // point and get reparented to someone else and never go away. - DNBLog ("Could not get task port for process, sending SIGKILL and exiting."); - kill (SIGKILL, pid); - - if (err_str && err_len > 0) - { - if (launch_err.AsString()) - { - ::snprintf (err_str, err_len, "failed to get the task for process %i (%s)", pid, launch_err.AsString()); - } - else - { - ::snprintf (err_str, err_len, "failed to get the task for process %i", pid); - } - } - } - else - { - bool res = AddProcessToMap(pid, processSP); - UNUSED_IF_ASSERT_DISABLED(res); - assert(res && "Couldn't add process to map!"); - return pid; - } + } + } + + DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) new pid is %d...", pid); + + if (pid != INVALID_NUB_PROCESS) { + // Spawn a thread to reap our child inferior process... + spawn_waitpid_thread(pid); + + if (processSP->Task().TaskPortForProcessID(launch_err) == TASK_NULL) { + // We failed to get the task for our process ID which is bad. + // Kill our process otherwise it will be stopped at the entry + // point and get reparented to someone else and never go away. + DNBLog("Could not get task port for process, sending SIGKILL and " + "exiting."); + kill(SIGKILL, pid); + + if (err_str && err_len > 0) { + if (launch_err.AsString()) { + ::snprintf(err_str, err_len, + "failed to get the task for process %i (%s)", pid, + launch_err.AsString()); + } else { + ::snprintf(err_str, err_len, + "failed to get the task for process %i", pid); + } } + } else { + bool res = AddProcessToMap(pid, processSP); + UNUSED_IF_ASSERT_DISABLED(res); + assert(res && "Couldn't add process to map!"); + return pid; + } } - return INVALID_NUB_PROCESS; + } + return INVALID_NUB_PROCESS; } // If there is one process with a given name, return the pid for that process. -nub_process_t -DNBProcessGetPIDByName (const char *name) -{ - std::vector<struct kinfo_proc> matching_proc_infos; - size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos); - if (num_matching_proc_infos == 1) - { - return matching_proc_infos[0].kp_proc.p_pid; - } +nub_process_t DNBProcessGetPIDByName(const char *name) { + std::vector<struct kinfo_proc> matching_proc_infos; + size_t num_matching_proc_infos = + GetAllInfosMatchingName(name, matching_proc_infos); + if (num_matching_proc_infos == 1) { + return matching_proc_infos[0].kp_proc.p_pid; + } + return INVALID_NUB_PROCESS; +} + +nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, + char *err_str, size_t err_len) { + if (err_str && err_len > 0) + err_str[0] = '\0'; + std::vector<struct kinfo_proc> matching_proc_infos; + size_t num_matching_proc_infos = + GetAllInfosMatchingName(name, matching_proc_infos); + if (num_matching_proc_infos == 0) { + DNBLogError("error: no processes match '%s'\n", name); return INVALID_NUB_PROCESS; -} - -nub_process_t -DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len) -{ - if (err_str && err_len > 0) - err_str[0] = '\0'; - std::vector<struct kinfo_proc> matching_proc_infos; - size_t num_matching_proc_infos = GetAllInfosMatchingName(name, matching_proc_infos); - if (num_matching_proc_infos == 0) - { - DNBLogError ("error: no processes match '%s'\n", name); - return INVALID_NUB_PROCESS; - } - else if (num_matching_proc_infos > 1) - { - DNBLogError ("error: %llu processes match '%s':\n", (uint64_t)num_matching_proc_infos, name); - size_t i; - for (i=0; i<num_matching_proc_infos; ++i) - DNBLogError ("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, matching_proc_infos[i].kp_proc.p_comm); - return INVALID_NUB_PROCESS; - } - - return DNBProcessAttach (matching_proc_infos[0].kp_proc.p_pid, timeout, err_str, err_len); -} - -nub_process_t -DNBProcessAttach (nub_process_t attach_pid, struct timespec *timeout, char *err_str, size_t err_len) -{ - if (err_str && err_len > 0) - err_str[0] = '\0'; - - pid_t pid = INVALID_NUB_PROCESS; - MachProcessSP processSP(new MachProcess); - if (processSP.get()) - { - DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", attach_pid); - pid = processSP->AttachForDebug (attach_pid, err_str, err_len); - - if (pid != INVALID_NUB_PROCESS) - { - bool res = AddProcessToMap(pid, processSP); - UNUSED_IF_ASSERT_DISABLED(res); - assert(res && "Couldn't add process to map!"); - spawn_waitpid_thread(pid); + } else if (num_matching_proc_infos > 1) { + DNBLogError("error: %llu processes match '%s':\n", + (uint64_t)num_matching_proc_infos, name); + size_t i; + for (i = 0; i < num_matching_proc_infos; ++i) + DNBLogError("%6u - %s\n", matching_proc_infos[i].kp_proc.p_pid, + matching_proc_infos[i].kp_proc.p_comm); + return INVALID_NUB_PROCESS; + } + + return DNBProcessAttach(matching_proc_infos[0].kp_proc.p_pid, timeout, + err_str, err_len); +} + +nub_process_t DNBProcessAttach(nub_process_t attach_pid, + struct timespec *timeout, char *err_str, + size_t err_len) { + if (err_str && err_len > 0) + err_str[0] = '\0'; + + pid_t pid = INVALID_NUB_PROCESS; + MachProcessSP processSP(new MachProcess); + if (processSP.get()) { + DNBLogThreadedIf(LOG_PROCESS, "(DebugNub) attaching to pid %d...", + attach_pid); + pid = processSP->AttachForDebug(attach_pid, err_str, err_len); + + if (pid != INVALID_NUB_PROCESS) { + bool res = AddProcessToMap(pid, processSP); + UNUSED_IF_ASSERT_DISABLED(res); + assert(res && "Couldn't add process to map!"); + spawn_waitpid_thread(pid); + } + } + + while (pid != INVALID_NUB_PROCESS) { + // Wait for process to start up and hit entry point + DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE)...", + __FUNCTION__, pid); + nub_event_t set_events = + DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged, + true, timeout); + + DNBLogThreadedIf(LOG_PROCESS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE) => 0x%8.8x", + __FUNCTION__, pid, set_events); + + if (set_events == 0) { + if (err_str && err_len > 0) + snprintf(err_str, err_len, "operation timed out"); + pid = INVALID_NUB_PROCESS; + } else { + if (set_events & (eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged)) { + nub_state_t pid_state = DNBProcessGetState(pid); + DNBLogThreadedIf( + LOG_PROCESS, + "%s process %4.4x state changed (eEventProcessStateChanged): %s", + __FUNCTION__, pid, DNBStateAsString(pid_state)); + + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + case eStateAttaching: + case eStateLaunching: + case eStateSuspended: + break; // Ignore + + case eStateRunning: + case eStateStepping: + // Still waiting to stop at entry point... + break; + + case eStateStopped: + case eStateCrashed: + return pid; + + case eStateDetached: + case eStateExited: + if (err_str && err_len > 0) + snprintf(err_str, err_len, "process exited"); + return INVALID_NUB_PROCESS; } - } + } - while (pid != INVALID_NUB_PROCESS) - { - // Wait for process to start up and hit entry point - DNBLogThreadedIf (LOG_PROCESS, - "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", - __FUNCTION__, - pid); - nub_event_t set_events = DNBProcessWaitForEvents (pid, - eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, - true, - timeout); - - DNBLogThreadedIf (LOG_PROCESS, - "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", - __FUNCTION__, - pid, - set_events); - - if (set_events == 0) - { - if (err_str && err_len > 0) - snprintf(err_str, err_len, "operation timed out"); - pid = INVALID_NUB_PROCESS; - } - else - { - if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) - { - nub_state_t pid_state = DNBProcessGetState (pid); - DNBLogThreadedIf (LOG_PROCESS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", - __FUNCTION__, pid, DNBStateAsString(pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateAttaching: - case eStateLaunching: - case eStateSuspended: - break; // Ignore - - case eStateRunning: - case eStateStepping: - // Still waiting to stop at entry point... - break; - - case eStateStopped: - case eStateCrashed: - return pid; - - case eStateDetached: - case eStateExited: - if (err_str && err_len > 0) - snprintf(err_str, err_len, "process exited"); - return INVALID_NUB_PROCESS; - } - } - - DNBProcessResetEvents(pid, set_events); - } + DNBProcessResetEvents(pid, set_events); } + } - return INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; } -size_t -GetAllInfos (std::vector<struct kinfo_proc>& proc_infos) -{ - size_t size = 0; - int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL }; - u_int namelen = sizeof(name)/sizeof(int); - int err; - - // Try to find out how many processes are around so we can - // size the buffer appropriately. sysctl's man page specifically suggests - // this approach, and says it returns a bit larger size than needed to - // handle any new processes created between then and now. - - err = ::sysctl (name, namelen, NULL, &size, NULL, 0); +size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos) { + size_t size = 0; + int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL}; + u_int namelen = sizeof(name) / sizeof(int); + int err; - if ((err < 0) && (err != ENOMEM)) - { - proc_infos.clear(); - perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)"); - return 0; - } + // Try to find out how many processes are around so we can + // size the buffer appropriately. sysctl's man page specifically suggests + // this approach, and says it returns a bit larger size than needed to + // handle any new processes created between then and now. + err = ::sysctl(name, namelen, NULL, &size, NULL, 0); - // Increase the size of the buffer by a few processes in case more have - // been spawned - proc_infos.resize (size / sizeof(struct kinfo_proc)); - size = proc_infos.size() * sizeof(struct kinfo_proc); // Make sure we don't exceed our resize... - err = ::sysctl (name, namelen, &proc_infos[0], &size, NULL, 0); - if (err < 0) - { - proc_infos.clear(); - return 0; - } + if ((err < 0) && (err != ENOMEM)) { + proc_infos.clear(); + perror("sysctl (mib, miblen, NULL, &num_processes, NULL, 0)"); + return 0; + } + + // Increase the size of the buffer by a few processes in case more have + // been spawned + proc_infos.resize(size / sizeof(struct kinfo_proc)); + size = proc_infos.size() * + sizeof(struct kinfo_proc); // Make sure we don't exceed our resize... + err = ::sysctl(name, namelen, &proc_infos[0], &size, NULL, 0); + if (err < 0) { + proc_infos.clear(); + return 0; + } - // Trim down our array to fit what we actually got back - proc_infos.resize(size / sizeof(struct kinfo_proc)); - return proc_infos.size(); + // Trim down our array to fit what we actually got back + proc_infos.resize(size / sizeof(struct kinfo_proc)); + return proc_infos.size(); } static size_t -GetAllInfosMatchingName(const char *full_process_name, std::vector<struct kinfo_proc>& matching_proc_infos) -{ - - matching_proc_infos.clear(); - if (full_process_name && full_process_name[0]) - { - // We only get the process name, not the full path, from the proc_info. So just take the - // base name of the process name... - const char *process_name; - process_name = strrchr (full_process_name, '/'); - if (process_name == NULL) - process_name = full_process_name; - else - process_name++; - - const size_t process_name_len = strlen(process_name); - std::vector<struct kinfo_proc> proc_infos; - const size_t num_proc_infos = GetAllInfos(proc_infos); - if (num_proc_infos > 0) - { - uint32_t i; - for (i=0; i<num_proc_infos; i++) - { - // Skip zombie processes and processes with unset status - if (proc_infos[i].kp_proc.p_stat == 0 || proc_infos[i].kp_proc.p_stat == SZOMB) - continue; - - // Check for process by name. We only check the first MAXCOMLEN - // chars as that is all that kp_proc.p_comm holds. - - if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, MAXCOMLEN) == 0) - { - if (process_name_len > MAXCOMLEN) - { - // We found a matching process name whose first MAXCOMLEN - // characters match, but there is more to the name than - // this. We need to get the full process name. Use proc_pidpath, which will get - // us the full path to the executed process. - - char proc_path_buf[PATH_MAX]; - - int return_val = proc_pidpath (proc_infos[i].kp_proc.p_pid, proc_path_buf, PATH_MAX); - if (return_val > 0) - { - // Okay, now search backwards from that to see if there is a - // slash in the name. Note, even though we got all the args we don't care - // because the list data is just a bunch of concatenated null terminated strings - // so strrchr will start from the end of argv0. - - const char *argv_basename = strrchr(proc_path_buf, '/'); - if (argv_basename) - { - // Skip the '/' - ++argv_basename; - } - else - { - // We didn't find a directory delimiter in the process argv[0], just use what was in there - argv_basename = proc_path_buf; - } - - if (argv_basename) - { - if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) - { - matching_proc_infos.push_back(proc_infos[i]); - } - } - } - } - else - { - // We found a matching process, add it to our list - matching_proc_infos.push_back(proc_infos[i]); - } +GetAllInfosMatchingName(const char *full_process_name, + std::vector<struct kinfo_proc> &matching_proc_infos) { + + matching_proc_infos.clear(); + if (full_process_name && full_process_name[0]) { + // We only get the process name, not the full path, from the proc_info. So + // just take the + // base name of the process name... + const char *process_name; + process_name = strrchr(full_process_name, '/'); + if (process_name == NULL) + process_name = full_process_name; + else + process_name++; + + const size_t process_name_len = strlen(process_name); + std::vector<struct kinfo_proc> proc_infos; + const size_t num_proc_infos = GetAllInfos(proc_infos); + if (num_proc_infos > 0) { + uint32_t i; + for (i = 0; i < num_proc_infos; i++) { + // Skip zombie processes and processes with unset status + if (proc_infos[i].kp_proc.p_stat == 0 || + proc_infos[i].kp_proc.p_stat == SZOMB) + continue; + + // Check for process by name. We only check the first MAXCOMLEN + // chars as that is all that kp_proc.p_comm holds. + + if (::strncasecmp(process_name, proc_infos[i].kp_proc.p_comm, + MAXCOMLEN) == 0) { + if (process_name_len > MAXCOMLEN) { + // We found a matching process name whose first MAXCOMLEN + // characters match, but there is more to the name than + // this. We need to get the full process name. Use proc_pidpath, + // which will get + // us the full path to the executed process. + + char proc_path_buf[PATH_MAX]; + + int return_val = proc_pidpath(proc_infos[i].kp_proc.p_pid, + proc_path_buf, PATH_MAX); + if (return_val > 0) { + // Okay, now search backwards from that to see if there is a + // slash in the name. Note, even though we got all the args we + // don't care + // because the list data is just a bunch of concatenated null + // terminated strings + // so strrchr will start from the end of argv0. + + const char *argv_basename = strrchr(proc_path_buf, '/'); + if (argv_basename) { + // Skip the '/' + ++argv_basename; + } else { + // We didn't find a directory delimiter in the process argv[0], + // just use what was in there + argv_basename = proc_path_buf; + } + + if (argv_basename) { + if (::strncasecmp(process_name, argv_basename, PATH_MAX) == 0) { + matching_proc_infos.push_back(proc_infos[i]); } + } } + } else { + // We found a matching process, add it to our list + matching_proc_infos.push_back(proc_infos[i]); + } } + } } - // return the newly added matches. - return matching_proc_infos.size(); -} - -nub_process_t -DNBProcessAttachWait (const char *waitfor_process_name, - nub_launch_flavor_t launch_flavor, - bool ignore_existing, - struct timespec *timeout_abstime, - useconds_t waitfor_interval, - char *err_str, - size_t err_len, - DNBShouldCancelCallback should_cancel_callback, - void *callback_data) -{ - DNBError prepare_error; - std::vector<struct kinfo_proc> exclude_proc_infos; - size_t num_exclude_proc_infos; - - // If the PrepareForAttach returns a valid token, use MachProcess to check - // for the process, otherwise scan the process table. - - const void *attach_token = MachProcess::PrepareForAttach (waitfor_process_name, launch_flavor, true, prepare_error); - - if (prepare_error.Fail()) - { - DNBLogError ("Error in PrepareForAttach: %s", prepare_error.AsString()); - return INVALID_NUB_PROCESS; - } + } + // return the newly added matches. + return matching_proc_infos.size(); +} - if (attach_token == NULL) - { - if (ignore_existing) - num_exclude_proc_infos = GetAllInfosMatchingName (waitfor_process_name, exclude_proc_infos); - else - num_exclude_proc_infos = 0; - } +nub_process_t DNBProcessAttachWait( + const char *waitfor_process_name, nub_launch_flavor_t launch_flavor, + bool ignore_existing, struct timespec *timeout_abstime, + useconds_t waitfor_interval, char *err_str, size_t err_len, + DNBShouldCancelCallback should_cancel_callback, void *callback_data) { + DNBError prepare_error; + std::vector<struct kinfo_proc> exclude_proc_infos; + size_t num_exclude_proc_infos; - DNBLogThreadedIf (LOG_PROCESS, "Waiting for '%s' to appear...\n", waitfor_process_name); - - // Loop and try to find the process by name - nub_process_t waitfor_pid = INVALID_NUB_PROCESS; - - while (waitfor_pid == INVALID_NUB_PROCESS) - { - if (attach_token != NULL) - { - nub_process_t pid; - pid = MachProcess::CheckForProcess(attach_token, launch_flavor); - if (pid != INVALID_NUB_PROCESS) - { - waitfor_pid = pid; - break; - } - } - else - { - - // Get the current process list, and check for matches that - // aren't in our original list. If anyone wants to attach - // to an existing process by name, they should do it with - // --attach=PROCNAME. Else we will wait for the first matching - // process that wasn't in our exclusion list. - std::vector<struct kinfo_proc> proc_infos; - const size_t num_proc_infos = GetAllInfosMatchingName (waitfor_process_name, proc_infos); - for (size_t i=0; i<num_proc_infos; i++) - { - nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid; - for (size_t j=0; j<num_exclude_proc_infos; j++) - { - if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) - { - // This process was in our exclusion list, don't use it. - curr_pid = INVALID_NUB_PROCESS; - break; - } - } + // If the PrepareForAttach returns a valid token, use MachProcess to check + // for the process, otherwise scan the process table. - // If we didn't find CURR_PID in our exclusion list, then use it. - if (curr_pid != INVALID_NUB_PROCESS) - { - // We found our process! - waitfor_pid = curr_pid; - break; - } - } + const void *attach_token = MachProcess::PrepareForAttach( + waitfor_process_name, launch_flavor, true, prepare_error); + + if (prepare_error.Fail()) { + DNBLogError("Error in PrepareForAttach: %s", prepare_error.AsString()); + return INVALID_NUB_PROCESS; + } + + if (attach_token == NULL) { + if (ignore_existing) + num_exclude_proc_infos = + GetAllInfosMatchingName(waitfor_process_name, exclude_proc_infos); + else + num_exclude_proc_infos = 0; + } + + DNBLogThreadedIf(LOG_PROCESS, "Waiting for '%s' to appear...\n", + waitfor_process_name); + + // Loop and try to find the process by name + nub_process_t waitfor_pid = INVALID_NUB_PROCESS; + + while (waitfor_pid == INVALID_NUB_PROCESS) { + if (attach_token != NULL) { + nub_process_t pid; + pid = MachProcess::CheckForProcess(attach_token, launch_flavor); + if (pid != INVALID_NUB_PROCESS) { + waitfor_pid = pid; + break; + } + } else { + + // Get the current process list, and check for matches that + // aren't in our original list. If anyone wants to attach + // to an existing process by name, they should do it with + // --attach=PROCNAME. Else we will wait for the first matching + // process that wasn't in our exclusion list. + std::vector<struct kinfo_proc> proc_infos; + const size_t num_proc_infos = + GetAllInfosMatchingName(waitfor_process_name, proc_infos); + for (size_t i = 0; i < num_proc_infos; i++) { + nub_process_t curr_pid = proc_infos[i].kp_proc.p_pid; + for (size_t j = 0; j < num_exclude_proc_infos; j++) { + if (curr_pid == exclude_proc_infos[j].kp_proc.p_pid) { + // This process was in our exclusion list, don't use it. + curr_pid = INVALID_NUB_PROCESS; + break; + } } - // If we haven't found our process yet, check for a timeout - // and then sleep for a bit until we poll again. - if (waitfor_pid == INVALID_NUB_PROCESS) - { - if (timeout_abstime != NULL) - { - // Check to see if we have a waitfor-duration option that - // has timed out? - if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) - { - if (err_str && err_len > 0) - snprintf(err_str, err_len, "operation timed out"); - DNBLogError ("error: waiting for process '%s' timed out.\n", waitfor_process_name); - return INVALID_NUB_PROCESS; - } - } + // If we didn't find CURR_PID in our exclusion list, then use it. + if (curr_pid != INVALID_NUB_PROCESS) { + // We found our process! + waitfor_pid = curr_pid; + break; + } + } + } + + // If we haven't found our process yet, check for a timeout + // and then sleep for a bit until we poll again. + if (waitfor_pid == INVALID_NUB_PROCESS) { + if (timeout_abstime != NULL) { + // Check to see if we have a waitfor-duration option that + // has timed out? + if (DNBTimer::TimeOfDayLaterThan(*timeout_abstime)) { + if (err_str && err_len > 0) + snprintf(err_str, err_len, "operation timed out"); + DNBLogError("error: waiting for process '%s' timed out.\n", + waitfor_process_name); + return INVALID_NUB_PROCESS; + } + } - // Call the should cancel callback as well... + // Call the should cancel callback as well... - if (should_cancel_callback != NULL - && should_cancel_callback (callback_data)) - { - DNBLogThreadedIf (LOG_PROCESS, "DNBProcessAttachWait cancelled by should_cancel callback."); - waitfor_pid = INVALID_NUB_PROCESS; - break; - } + if (should_cancel_callback != NULL && + should_cancel_callback(callback_data)) { + DNBLogThreadedIf( + LOG_PROCESS, + "DNBProcessAttachWait cancelled by should_cancel callback."); + waitfor_pid = INVALID_NUB_PROCESS; + break; + } - ::usleep (waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again - } + ::usleep(waitfor_interval); // Sleep for WAITFOR_INTERVAL, then poll again } + } - if (waitfor_pid != INVALID_NUB_PROCESS) - { - DNBLogThreadedIf (LOG_PROCESS, "Attaching to %s with pid %i...\n", waitfor_process_name, waitfor_pid); - waitfor_pid = DNBProcessAttach (waitfor_pid, timeout_abstime, err_str, err_len); - } + if (waitfor_pid != INVALID_NUB_PROCESS) { + DNBLogThreadedIf(LOG_PROCESS, "Attaching to %s with pid %i...\n", + waitfor_process_name, waitfor_pid); + waitfor_pid = + DNBProcessAttach(waitfor_pid, timeout_abstime, err_str, err_len); + } - bool success = waitfor_pid != INVALID_NUB_PROCESS; - MachProcess::CleanupAfterAttach (attach_token, launch_flavor, success, prepare_error); + bool success = waitfor_pid != INVALID_NUB_PROCESS; + MachProcess::CleanupAfterAttach(attach_token, launch_flavor, success, + prepare_error); - return waitfor_pid; + return waitfor_pid; } -nub_bool_t -DNBProcessDetach (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - const bool remove = true; - DNBLogThreaded("Disabling breakpoints and watchpoints, and detaching from %d.", pid); - procSP->DisableAllBreakpoints(remove); - procSP->DisableAllWatchpoints (remove); - return procSP->Detach(); - } - return false; +nub_bool_t DNBProcessDetach(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + const bool remove = true; + DNBLogThreaded( + "Disabling breakpoints and watchpoints, and detaching from %d.", pid); + procSP->DisableAllBreakpoints(remove); + procSP->DisableAllWatchpoints(remove); + return procSP->Detach(); + } + return false; } -nub_bool_t -DNBProcessKill (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->Kill (); - } - return false; +nub_bool_t DNBProcessKill(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->Kill(); + } + return false; } -nub_bool_t -DNBProcessSignal (nub_process_t pid, int signal) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->Signal (signal); - } - return false; +nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->Signal(signal); + } + return false; } - -nub_bool_t -DNBProcessInterrupt(nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Interrupt(); - return false; +nub_bool_t DNBProcessInterrupt(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Interrupt(); + return false; } -nub_bool_t -DNBProcessSendEvent (nub_process_t pid, const char *event) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - // FIXME: Do something with the error... - DNBError send_error; - return procSP->SendEvent (event, send_error); - } - return false; +nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + // FIXME: Do something with the error... + DNBError send_error; + return procSP->SendEvent(event, send_error); + } + return false; } - -nub_bool_t -DNBProcessIsAlive (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return MachTask::IsValid (procSP->Task().TaskPort()); - } - return eStateInvalid; +nub_bool_t DNBProcessIsAlive(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return MachTask::IsValid(procSP->Task().TaskPort()); + } + return eStateInvalid; } //---------------------------------------------------------------------- // Process and Thread state information //---------------------------------------------------------------------- -nub_state_t -DNBProcessGetState (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetState(); - } - return eStateInvalid; +nub_state_t DNBProcessGetState(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetState(); + } + return eStateInvalid; } //---------------------------------------------------------------------- // Process and Thread state information //---------------------------------------------------------------------- -nub_bool_t -DNBProcessGetExitStatus (nub_process_t pid, int* status) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetExitStatus(status); - } - return false; +nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetExitStatus(status); + } + return false; } -nub_bool_t -DNBProcessSetExitStatus (nub_process_t pid, int status) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SetExitStatus(status); - return true; - } - return false; +nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SetExitStatus(status); + return true; + } + return false; } -const char * -DNBProcessGetExitInfo (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetExitInfo(); - } - return NULL; +const char *DNBProcessGetExitInfo(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetExitInfo(); + } + return NULL; } -nub_bool_t -DNBProcessSetExitInfo (nub_process_t pid, const char *info) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SetExitInfo(info); - return true; - } - return false; +nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, const char *info) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SetExitInfo(info); + return true; + } + return false; } -const char * -DNBThreadGetName (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->ThreadGetName(tid); - return NULL; +const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->ThreadGetName(tid); + return NULL; } - nub_bool_t -DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info); - return false; -} - -nub_state_t -DNBThreadGetState (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->ThreadGetState(tid); - } - return eStateInvalid; -} - -const char * -DNBStateAsString(nub_state_t state) -{ - switch (state) - { - case eStateInvalid: return "Invalid"; - case eStateUnloaded: return "Unloaded"; - case eStateAttaching: return "Attaching"; - case eStateLaunching: return "Launching"; - case eStateStopped: return "Stopped"; - case eStateRunning: return "Running"; - case eStateStepping: return "Stepping"; - case eStateCrashed: return "Crashed"; - case eStateDetached: return "Detached"; - case eStateExited: return "Exited"; - case eStateSuspended: return "Suspended"; - } - return "nub_state_t ???"; -} - -Genealogy::ThreadActivitySP -DNBGetGenealogyInfoForThread (nub_process_t pid, nub_thread_t tid, bool &timed_out) -{ - Genealogy::ThreadActivitySP thread_activity_sp; - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - thread_activity_sp = procSP->GetGenealogyInfoForThread (tid, timed_out); - return thread_activity_sp; -} - -Genealogy::ProcessExecutableInfoSP -DNBGetGenealogyImageInfo (nub_process_t pid, size_t idx) -{ - Genealogy::ProcessExecutableInfoSP image_info_sp; - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - image_info_sp = procSP->GetGenealogyImageInfo (idx); - } - return image_info_sp; -} - -ThreadInfo::QoS -DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetRequestedQoS (tid, tsd, dti_qos_class_index); - } - return ThreadInfo::QoS(); +DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid, + thread_identifier_info_data_t *ident_info) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadList().GetIdentifierInfo(tid, ident_info); + return false; +} + +nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->ThreadGetState(tid); + } + return eStateInvalid; +} + +const char *DNBStateAsString(nub_state_t state) { + switch (state) { + case eStateInvalid: + return "Invalid"; + case eStateUnloaded: + return "Unloaded"; + case eStateAttaching: + return "Attaching"; + case eStateLaunching: + return "Launching"; + case eStateStopped: + return "Stopped"; + case eStateRunning: + return "Running"; + case eStateStepping: + return "Stepping"; + case eStateCrashed: + return "Crashed"; + case eStateDetached: + return "Detached"; + case eStateExited: + return "Exited"; + case eStateSuspended: + return "Suspended"; + } + return "nub_state_t ???"; +} + +Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid, + nub_thread_t tid, + bool &timed_out) { + Genealogy::ThreadActivitySP thread_activity_sp; + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + thread_activity_sp = procSP->GetGenealogyInfoForThread(tid, timed_out); + return thread_activity_sp; +} + +Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid, + size_t idx) { + Genealogy::ProcessExecutableInfoSP image_info_sp; + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + image_info_sp = procSP->GetGenealogyImageInfo(idx); + } + return image_info_sp; +} + +ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid, + nub_addr_t tsd, + uint64_t dti_qos_class_index) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetRequestedQoS(tid, tsd, dti_qos_class_index); + } + return ThreadInfo::QoS(); +} + +nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetPThreadT(tid); + } + return INVALID_NUB_ADDRESS; +} + +nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetDispatchQueueT(tid); + } + return INVALID_NUB_ADDRESS; } nub_addr_t -DNBGetPThreadT (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetPThreadT (tid); - } - return INVALID_NUB_ADDRESS; -} - -nub_addr_t -DNBGetDispatchQueueT (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetDispatchQueueT (tid); - } - return INVALID_NUB_ADDRESS; +DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid, + uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetTSDAddressForThread( + tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, + plo_pthread_tsd_entry_size); + } + return INVALID_NUB_ADDRESS; +} + +JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos( + nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetLoadedDynamicLibrariesInfos(pid, image_list_address, + image_count); + } + return JSONGenerator::ObjectSP(); +} + +JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetAllLoadedLibrariesInfos(pid); + } + return JSONGenerator::ObjectSP(); +} + +JSONGenerator::ObjectSP +DNBGetLibrariesInfoForAddresses(nub_process_t pid, + std::vector<uint64_t> &macho_addresses) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses); + } + return JSONGenerator::ObjectSP(); +} + +JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->GetSharedCacheInfo(pid); + } + return JSONGenerator::ObjectSP(); +} + +const char *DNBProcessGetExecutablePath(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->Path(); + } + return NULL; +} + +nub_size_t DNBProcessGetArgumentCount(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->ArgumentCount(); + } + return 0; +} + +const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->ArgumentAtIndex(idx); + } + return NULL; } -nub_addr_t -DNBGetTSDAddressForThread (nub_process_t pid, nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); - } - return INVALID_NUB_ADDRESS; -} - -JSONGenerator::ObjectSP -DNBGetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count); - } - return JSONGenerator::ObjectSP(); -} - -JSONGenerator::ObjectSP -DNBGetAllLoadedLibrariesInfos (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetAllLoadedLibrariesInfos (pid); - } - return JSONGenerator::ObjectSP(); -} - -JSONGenerator::ObjectSP -DNBGetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetLibrariesInfoForAddresses (pid, macho_addresses); - } - return JSONGenerator::ObjectSP(); -} - -JSONGenerator::ObjectSP -DNBGetSharedCacheInfo (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->GetSharedCacheInfo (pid); - } - return JSONGenerator::ObjectSP(); -} - - - -const char * -DNBProcessGetExecutablePath (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->Path(); - } - return NULL; -} - -nub_size_t -DNBProcessGetArgumentCount (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->ArgumentCount(); - } - return 0; -} - -const char * -DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->ArgumentAtIndex (idx); - } - return NULL; -} - - //---------------------------------------------------------------------- // Execution control //---------------------------------------------------------------------- -nub_bool_t -DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) -{ - DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - DNBThreadResumeActions thread_actions (actions, num_actions); - - // Below we add a default thread plan just in case one wasn't - // provided so all threads always know what they were supposed to do - if (thread_actions.IsEmpty()) - { - // No thread plans were given, so the default it to run all threads - thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0); - } - else - { - // Some thread plans were given which means anything that wasn't - // specified should remain stopped. - thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); - } - return procSP->Resume (thread_actions); - } - return false; -} - -nub_bool_t -DNBProcessHalt (nub_process_t pid) -{ - DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Signal (SIGSTOP); - return false; +nub_bool_t DNBProcessResume(nub_process_t pid, + const DNBThreadResumeAction *actions, + size_t num_actions) { + DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + DNBThreadResumeActions thread_actions(actions, num_actions); + + // Below we add a default thread plan just in case one wasn't + // provided so all threads always know what they were supposed to do + if (thread_actions.IsEmpty()) { + // No thread plans were given, so the default it to run all threads + thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); + } else { + // Some thread plans were given which means anything that wasn't + // specified should remain stopped. + thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + } + return procSP->Resume(thread_actions); + } + return false; +} + +nub_bool_t DNBProcessHalt(nub_process_t pid) { + DNBLogThreadedIf(LOG_PROCESS, "%s(pid = %4.4x)", __FUNCTION__, pid); + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Signal(SIGSTOP); + return false; } // -//nub_bool_t -//DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step) +// nub_bool_t +// DNBThreadResume (nub_process_t pid, nub_thread_t tid, nub_bool_t step) //{ -// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", __FUNCTION__, pid, tid, (uint32_t)step); +// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u)", +// __FUNCTION__, pid, tid, (uint32_t)step); // MachProcessSP procSP; // if (GetProcessSP (pid, procSP)) // { @@ -1205,10 +1079,12 @@ DNBProcessHalt (nub_process_t pid) // return false; //} // -//nub_bool_t -//DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t step, int signal) +// nub_bool_t +// DNBThreadResumeWithSignal (nub_process_t pid, nub_thread_t tid, nub_bool_t +// step, int signal) //{ -// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal); +// DNBLogThreadedIf(LOG_THREAD, "%s(pid = %4.4x, tid = %4.4x, step = %u, +// signal = %i)", __FUNCTION__, pid, tid, (uint32_t)step, signal); // MachProcessSP procSP; // if (GetProcessSP (pid, procSP)) // { @@ -1217,80 +1093,68 @@ DNBProcessHalt (nub_process_t pid) // return false; //} -nub_event_t -DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout) -{ - nub_event_t result = 0; - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - if (wait_for_set) - result = procSP->Events().WaitForSetEvents(event_mask, timeout); - else - result = procSP->Events().WaitForEventsToReset(event_mask, timeout); - } - return result; +nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask, + bool wait_for_set, + struct timespec *timeout) { + nub_event_t result = 0; + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + if (wait_for_set) + result = procSP->Events().WaitForSetEvents(event_mask, timeout); + else + result = procSP->Events().WaitForEventsToReset(event_mask, timeout); + } + return result; } -void -DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - procSP->Events().ResetEvents(event_mask); +void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + procSP->Events().ResetEvents(event_mask); } // Breakpoints -nub_bool_t -DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->CreateBreakpoint(addr, size, hardware) != NULL; - return false; +nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, + nub_bool_t hardware) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->CreateBreakpoint(addr, size, hardware) != NULL; + return false; } -nub_bool_t -DNBBreakpointClear (nub_process_t pid, nub_addr_t addr) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->DisableBreakpoint(addr, true); - return false; // Failed +nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->DisableBreakpoint(addr, true); + return false; // Failed } - //---------------------------------------------------------------------- // Watchpoints //---------------------------------------------------------------------- -nub_bool_t -DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL; - return false; +nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, + uint32_t watch_flags, nub_bool_t hardware) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->CreateWatchpoint(addr, size, watch_flags, hardware) != NULL; + return false; } -nub_bool_t -DNBWatchpointClear (nub_process_t pid, nub_addr_t addr) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->DisableWatchpoint(addr, true); - return false; // Failed +nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->DisableWatchpoint(addr, true); + return false; // Failed } //---------------------------------------------------------------------- // Return the number of supported hardware watchpoints. //---------------------------------------------------------------------- -uint32_t -DNBWatchpointGetNumSupportedHWP (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetNumSupportedHardwareWatchpoints(); - return 0; +uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetNumSupportedHardwareWatchpoints(); + return 0; } //---------------------------------------------------------------------- @@ -1300,95 +1164,89 @@ DNBWatchpointGetNumSupportedHWP (nub_process_t pid) // // RETURNS: number of bytes actually read //---------------------------------------------------------------------- -nub_size_t -DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->ReadMemory(addr, size, buf); - return 0; -} - -uint64_t -DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value) -{ - union Integers - { - uint8_t u8; - uint16_t u16; - uint32_t u32; - uint64_t u64; - }; - - if (integer_size <= sizeof(uint64_t)) - { - Integers ints; - if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) - { - switch (integer_size) - { - case 1: return ints.u8; - case 2: return ints.u16; - case 3: return ints.u32 & 0xffffffu; - case 4: return ints.u32; - case 5: return ints.u32 & 0x000000ffffffffffull; - case 6: return ints.u32 & 0x0000ffffffffffffull; - case 7: return ints.u32 & 0x00ffffffffffffffull; - case 8: return ints.u64; - } - } - } - return fail_value; - -} - -nub_addr_t -DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr) -{ - cpu_type_t cputype = DNBProcessGetCPUType (pid); - if (cputype) - { - const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4; - return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0); - } - return 0; - +nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr, + nub_size_t size, void *buf) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->ReadMemory(addr, size, buf); + return 0; +} + +uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr, + nub_size_t integer_size, + uint64_t fail_value) { + union Integers { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + }; + + if (integer_size <= sizeof(uint64_t)) { + Integers ints; + if (DNBProcessMemoryRead(pid, addr, integer_size, &ints) == integer_size) { + switch (integer_size) { + case 1: + return ints.u8; + case 2: + return ints.u16; + case 3: + return ints.u32 & 0xffffffu; + case 4: + return ints.u32; + case 5: + return ints.u32 & 0x000000ffffffffffull; + case 6: + return ints.u32 & 0x0000ffffffffffffull; + case 7: + return ints.u32 & 0x00ffffffffffffffull; + case 8: + return ints.u64; + } + } + } + return fail_value; +} + +nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, nub_addr_t addr) { + cpu_type_t cputype = DNBProcessGetCPUType(pid); + if (cputype) { + const nub_size_t pointer_size = (cputype & CPU_ARCH_ABI64) ? 8 : 4; + return DNBProcessMemoryReadInteger(pid, addr, pointer_size, 0); + } + return 0; +} + +std::string DNBProcessMemoryReadCString(nub_process_t pid, nub_addr_t addr) { + std::string cstr; + char buffer[256]; + const nub_size_t max_buffer_cstr_length = sizeof(buffer) - 1; + buffer[max_buffer_cstr_length] = '\0'; + nub_size_t length = 0; + nub_addr_t curr_addr = addr; + do { + nub_size_t bytes_read = + DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer); + if (bytes_read == 0) + break; + length = strlen(buffer); + cstr.append(buffer, length); + curr_addr += length; + } while (length == max_buffer_cstr_length); + return cstr; +} + +std::string DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr, + nub_size_t fixed_length) { + std::string cstr; + char buffer[fixed_length + 1]; + buffer[fixed_length] = '\0'; + nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer); + if (bytes_read > 0) + cstr.assign(buffer); + return cstr; } -std::string -DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr) -{ - std::string cstr; - char buffer[256]; - const nub_size_t max_buffer_cstr_length = sizeof(buffer)-1; - buffer[max_buffer_cstr_length] = '\0'; - nub_size_t length = 0; - nub_addr_t curr_addr = addr; - do - { - nub_size_t bytes_read = DNBProcessMemoryRead(pid, curr_addr, max_buffer_cstr_length, buffer); - if (bytes_read == 0) - break; - length = strlen(buffer); - cstr.append(buffer, length); - curr_addr += length; - } while (length == max_buffer_cstr_length); - return cstr; -} - -std::string -DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length) -{ - std::string cstr; - char buffer[fixed_length+1]; - buffer[fixed_length] = '\0'; - nub_size_t bytes_read = DNBProcessMemoryRead(pid, addr, fixed_length, buffer); - if (bytes_read > 0) - cstr.assign(buffer); - return cstr; -} - - //---------------------------------------------------------------------- // Write memory to the address space of process PID. This call will take // care of setting and restoring permissions and breaking up the memory @@ -1396,31 +1254,27 @@ DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t // // RETURNS: number of bytes actually written //---------------------------------------------------------------------- -nub_size_t -DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->WriteMemory(addr, size, buf); - return 0; +nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr, + nub_size_t size, const void *buf) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->WriteMemory(addr, size, buf); + return 0; } -nub_addr_t -DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Task().AllocateMemory (size, permissions); - return 0; +nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size, + uint32_t permissions) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Task().AllocateMemory(size, permissions); + return 0; } -nub_bool_t -DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Task().DeallocateMemory (addr); - return 0; +nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, nub_addr_t addr) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Task().DeallocateMemory(addr); + return 0; } //---------------------------------------------------------------------- @@ -1437,99 +1291,87 @@ DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) // or if we do not yet have a valid launched process. // //---------------------------------------------------------------------- -int -DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Task().GetMemoryRegionInfo (addr, region_info); +int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr, + DNBRegionInfo *region_info) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Task().GetMemoryRegionInfo(addr, region_info); - return -1; + return -1; } -std::string -DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->Task().GetProfileData(scanType); - - return std::string(""); +std::string DNBProcessGetProfileData(nub_process_t pid, + DNBProfileDataScanType scanType) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->Task().GetProfileData(scanType); + + return std::string(""); } -nub_bool_t -DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type); - return true; - } - - return false; +nub_bool_t DNBProcessSetEnableAsyncProfiling(nub_process_t pid, + nub_bool_t enable, + uint64_t interval_usec, + DNBProfileDataScanType scan_type) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SetEnableAsyncProfiling(enable, interval_usec, scan_type); + return true; + } + + return false; } //---------------------------------------------------------------------- // Get the number of threads for the specified process. //---------------------------------------------------------------------- -nub_size_t -DNBProcessGetNumThreads (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetNumThreads(); - return 0; +nub_size_t DNBProcessGetNumThreads(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetNumThreads(); + return 0; } //---------------------------------------------------------------------- // Get the thread ID of the current thread. //---------------------------------------------------------------------- -nub_thread_t -DNBProcessGetCurrentThread (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetCurrentThread(); - return 0; +nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetCurrentThread(); + return 0; } //---------------------------------------------------------------------- // Get the mach port number of the current thread. //---------------------------------------------------------------------- -nub_thread_t -DNBProcessGetCurrentThreadMachPort (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetCurrentThreadMachPort(); - return 0; +nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetCurrentThreadMachPort(); + return 0; } //---------------------------------------------------------------------- // Change the current thread. //---------------------------------------------------------------------- -nub_thread_t -DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->SetCurrentThread (tid); - return INVALID_NUB_THREAD; +nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->SetCurrentThread(tid); + return INVALID_NUB_THREAD; } - //---------------------------------------------------------------------- // Dump a string describing a thread's stop reason to the specified file // handle //---------------------------------------------------------------------- -nub_bool_t -DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadStopInfo *stop_info) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadStoppedReason (tid, stop_info); - return false; +nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid, + struct DNBThreadStopInfo *stop_info) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadStoppedReason(tid, stop_info); + return false; } //---------------------------------------------------------------------- @@ -1539,61 +1381,49 @@ DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, struct DNBThreadSto // string from a static buffer that must be copied prior to subsequent // calls. //---------------------------------------------------------------------- -const char * -DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadInfo (tid); - return NULL; +const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadInfo(tid); + return NULL; } //---------------------------------------------------------------------- // Get the thread ID given a thread index. //---------------------------------------------------------------------- -nub_thread_t -DNBProcessGetThreadAtIndex (nub_process_t pid, size_t thread_idx) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadAtIndex (thread_idx); - return INVALID_NUB_THREAD; +nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, size_t thread_idx) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadAtIndex(thread_idx); + return INVALID_NUB_THREAD; } //---------------------------------------------------------------------- -// Do whatever is needed to sync the thread's register state with it's kernel values. +// Do whatever is needed to sync the thread's register state with it's kernel +// values. //---------------------------------------------------------------------- -nub_bool_t -DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->SyncThreadState (tid); - return false; - +nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, nub_thread_t tid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->SyncThreadState(tid); + return false; } -nub_addr_t -DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) -{ - MachProcessSP procSP; - DNBError err; - if (GetProcessSP (pid, procSP)) - return procSP->Task().GetDYLDAllImageInfosAddress (err); - return INVALID_NUB_ADDRESS; +nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) { + MachProcessSP procSP; + DNBError err; + if (GetProcessSP(pid, procSP)) + return procSP->Task().GetDYLDAllImageInfosAddress(err); + return INVALID_NUB_ADDRESS; } - -nub_bool_t -DNBProcessSharedLibrariesUpdated(nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SharedLibrariesUpdated (); - return true; - } - return false; +nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SharedLibrariesUpdated(); + return true; + } + return false; } //---------------------------------------------------------------------- @@ -1602,409 +1432,334 @@ DNBProcessSharedLibrariesUpdated(nub_process_t pid) // state changed event if only_changed is non-zero. //---------------------------------------------------------------------- nub_size_t -DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, struct DNBExecutableImageInfo **image_infos) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->CopyImageInfos (image_infos, only_changed); +DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed, + struct DNBExecutableImageInfo **image_infos) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->CopyImageInfos(image_infos, only_changed); - // If we have no process, then return NULL for the shared library info - // and zero for shared library count - *image_infos = NULL; - return 0; + // If we have no process, then return NULL for the shared library info + // and zero for shared library count + *image_infos = NULL; + return 0; } -uint32_t -DNBGetRegisterCPUType() -{ - return DNBArchProtocol::GetRegisterCPUType (); - +uint32_t DNBGetRegisterCPUType() { + return DNBArchProtocol::GetRegisterCPUType(); } //---------------------------------------------------------------------- // Get the register set information for a specific thread. //---------------------------------------------------------------------- -const DNBRegisterSetInfo * -DNBGetRegisterSetInfo (nub_size_t *num_reg_sets) -{ - return DNBArchProtocol::GetRegisterSetInfo (num_reg_sets); +const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets) { + return DNBArchProtocol::GetRegisterSetInfo(num_reg_sets); } - //---------------------------------------------------------------------- // Read a register value by register set and register index. //---------------------------------------------------------------------- -nub_bool_t -DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value) -{ - MachProcessSP procSP; - ::bzero (value, sizeof(DNBRegisterValue)); - if (GetProcessSP (pid, procSP)) - { - if (tid != INVALID_NUB_THREAD) - return procSP->GetRegisterValue (tid, set, reg, value); - } - return false; -} - -nub_bool_t -DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) -{ +nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid, + uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + MachProcessSP procSP; + ::bzero(value, sizeof(DNBRegisterValue)); + if (GetProcessSP(pid, procSP)) { if (tid != INVALID_NUB_THREAD) - { - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->SetRegisterValue (tid, set, reg, value); - } - return false; + return procSP->GetRegisterValue(tid, set, reg, value); + } + return false; } -nub_size_t -DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len) -{ +nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid, + uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + if (tid != INVALID_NUB_THREAD) { MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - if (tid != INVALID_NUB_THREAD) - return procSP->GetThreadList().GetRegisterContext (tid, buf, buf_len); - } - ::bzero (buf, buf_len); - return 0; - + if (GetProcessSP(pid, procSP)) + return procSP->SetRegisterValue(tid, set, reg, value); + } + return false; } -nub_size_t -DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - if (tid != INVALID_NUB_THREAD) - return procSP->GetThreadList().SetRegisterContext (tid, buf, buf_len); - } - return 0; -} - -uint32_t -DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid) -{ +nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid, + void *buf, size_t buf_len) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { if (tid != INVALID_NUB_THREAD) - { - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadList().SaveRegisterState (tid); - } - return 0; + return procSP->GetThreadList().GetRegisterContext(tid, buf, buf_len); + } + ::bzero(buf, buf_len); + return 0; } -nub_bool_t -DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id) -{ + +nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid, + const void *buf, size_t buf_len) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { if (tid != INVALID_NUB_THREAD) - { - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetThreadList().RestoreRegisterState (tid, save_id); - } - return false; + return procSP->GetThreadList().SetRegisterContext(tid, buf, buf_len); + } + return 0; } - +uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid) { + if (tid != INVALID_NUB_THREAD) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadList().SaveRegisterState(tid); + } + return 0; +} +nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid, + uint32_t save_id) { + if (tid != INVALID_NUB_THREAD) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetThreadList().RestoreRegisterState(tid, save_id); + } + return false; +} //---------------------------------------------------------------------- // Read a register value by name. //---------------------------------------------------------------------- -nub_bool_t -DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t reg_set, const char *reg_name, DNBRegisterValue *value) -{ - MachProcessSP procSP; - ::bzero (value, sizeof(DNBRegisterValue)); - if (GetProcessSP (pid, procSP)) - { - const struct DNBRegisterSetInfo *set_info; - nub_size_t num_reg_sets = 0; - set_info = DNBGetRegisterSetInfo (&num_reg_sets); - if (set_info) - { - uint32_t set = reg_set; - uint32_t reg; - if (set == REGISTER_SET_ALL) - { - for (set = 1; set < num_reg_sets; ++set) - { - for (reg = 0; reg < set_info[set].num_registers; ++reg) - { - if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) - return procSP->GetRegisterValue (tid, set, reg, value); - } - } - } - else - { - for (reg = 0; reg < set_info[set].num_registers; ++reg) - { - if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) - return procSP->GetRegisterValue (tid, set, reg, value); - } - } +nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid, + uint32_t reg_set, + const char *reg_name, + DNBRegisterValue *value) { + MachProcessSP procSP; + ::bzero(value, sizeof(DNBRegisterValue)); + if (GetProcessSP(pid, procSP)) { + const struct DNBRegisterSetInfo *set_info; + nub_size_t num_reg_sets = 0; + set_info = DNBGetRegisterSetInfo(&num_reg_sets); + if (set_info) { + uint32_t set = reg_set; + uint32_t reg; + if (set == REGISTER_SET_ALL) { + for (set = 1; set < num_reg_sets; ++set) { + for (reg = 0; reg < set_info[set].num_registers; ++reg) { + if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) + return procSP->GetRegisterValue(tid, set, reg, value); + } } + } else { + for (reg = 0; reg < set_info[set].num_registers; ++reg) { + if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) + return procSP->GetRegisterValue(tid, set, reg, value); + } + } } - return false; + } + return false; } - //---------------------------------------------------------------------- // Read a register set and register number from the register name. //---------------------------------------------------------------------- -nub_bool_t -DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info) -{ - const struct DNBRegisterSetInfo *set_info; - nub_size_t num_reg_sets = 0; - set_info = DNBGetRegisterSetInfo (&num_reg_sets); - if (set_info) - { - uint32_t set, reg; - for (set = 1; set < num_reg_sets; ++set) - { - for (reg = 0; reg < set_info[set].num_registers; ++reg) - { - if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) - { - *info = set_info[set].registers[reg]; - return true; - } - } +nub_bool_t DNBGetRegisterInfoByName(const char *reg_name, + DNBRegisterInfo *info) { + const struct DNBRegisterSetInfo *set_info; + nub_size_t num_reg_sets = 0; + set_info = DNBGetRegisterSetInfo(&num_reg_sets); + if (set_info) { + uint32_t set, reg; + for (set = 1; set < num_reg_sets; ++set) { + for (reg = 0; reg < set_info[set].num_registers; ++reg) { + if (strcasecmp(reg_name, set_info[set].registers[reg].name) == 0) { + *info = set_info[set].registers[reg]; + return true; } + } + } - for (set = 1; set < num_reg_sets; ++set) - { - uint32_t reg; - for (reg = 0; reg < set_info[set].num_registers; ++reg) - { - if (set_info[set].registers[reg].alt == NULL) - continue; - - if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) - { - *info = set_info[set].registers[reg]; - return true; - } - } + for (set = 1; set < num_reg_sets; ++set) { + uint32_t reg; + for (reg = 0; reg < set_info[set].num_registers; ++reg) { + if (set_info[set].registers[reg].alt == NULL) + continue; + + if (strcasecmp(reg_name, set_info[set].registers[reg].alt) == 0) { + *info = set_info[set].registers[reg]; + return true; } + } } + } - ::bzero (info, sizeof(DNBRegisterInfo)); - return false; + ::bzero(info, sizeof(DNBRegisterInfo)); + return false; } - //---------------------------------------------------------------------- // Set the name to address callback function that this nub can use // for any name to address lookups that are needed. //---------------------------------------------------------------------- -nub_bool_t -DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SetNameToAddressCallback (callback, baton); - return true; - } - return false; +nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid, + DNBCallbackNameToAddress callback, + void *baton) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SetNameToAddressCallback(callback, baton); + return true; + } + return false; } - //---------------------------------------------------------------------- // Set the name to address callback function that this nub can use // for any name to address lookups that are needed. //---------------------------------------------------------------------- -nub_bool_t -DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - procSP->SetSharedLibraryInfoCallback (callback, baton); - return true; - } - return false; +nub_bool_t DNBProcessSetSharedLibraryInfoCallback( + nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, + void *baton) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + procSP->SetSharedLibraryInfoCallback(callback, baton); + return true; + } + return false; } -nub_addr_t -DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - { - return procSP->LookupSymbol (name, shlib); - } - return INVALID_NUB_ADDRESS; +nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name, + const char *shlib) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) { + return procSP->LookupSymbol(name, shlib); + } + return INVALID_NUB_ADDRESS; } - -nub_size_t -DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetAvailableSTDOUT (buf, buf_size); - return 0; +nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf, + nub_size_t buf_size) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetAvailableSTDOUT(buf, buf_size); + return 0; } -nub_size_t -DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetAvailableSTDERR (buf, buf_size); - return 0; +nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf, + nub_size_t buf_size) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetAvailableSTDERR(buf, buf_size); + return 0; } -nub_size_t -DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetAsyncProfileData (buf, buf_size); - return 0; +nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf, + nub_size_t buf_size) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetAsyncProfileData(buf, buf_size); + return 0; } -DarwinLogEventVector -DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) -{ - return DarwinLogCollector::GetEventsForProcess(pid); +DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid) { + return DarwinLogCollector::GetEventsForProcess(pid); } -nub_size_t -DNBProcessGetStopCount (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->StopCount(); - return 0; +nub_size_t DNBProcessGetStopCount(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->StopCount(); + return 0; } -uint32_t -DNBProcessGetCPUType (nub_process_t pid) -{ - MachProcessSP procSP; - if (GetProcessSP (pid, procSP)) - return procSP->GetCPUType (); - return 0; - +uint32_t DNBProcessGetCPUType(nub_process_t pid) { + MachProcessSP procSP; + if (GetProcessSP(pid, procSP)) + return procSP->GetCPUType(); + return 0; } -nub_bool_t -DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size) -{ - if (path == NULL || path[0] == '\0') - return false; - - char max_path[PATH_MAX]; - std::string result; - CFString::GlobPath(path, result); - - if (result.empty()) - result = path; - - struct stat path_stat; - if (::stat(path, &path_stat) == 0) - { - if ((path_stat.st_mode & S_IFMT) == S_IFDIR) - { - CFBundle bundle (path); - CFReleaser<CFURLRef> url(bundle.CopyExecutableURL ()); - if (url.get()) - { - if (::CFURLGetFileSystemRepresentation (url.get(), true, (UInt8*)resolved_path, resolved_path_size)) - return true; - } - } - } +nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path, + size_t resolved_path_size) { + if (path == NULL || path[0] == '\0') + return false; - if (realpath(path, max_path)) - { - // Found the path relatively... - ::strncpy(resolved_path, max_path, resolved_path_size); - return strlen(resolved_path) + 1 < resolved_path_size; - } - else - { - // Not a relative path, check the PATH environment variable if the - const char *PATH = getenv("PATH"); - if (PATH) - { - const char *curr_path_start = PATH; - const char *curr_path_end; - while (curr_path_start && *curr_path_start) - { - curr_path_end = strchr(curr_path_start, ':'); - if (curr_path_end == NULL) - { - result.assign(curr_path_start); - curr_path_start = NULL; - } - else if (curr_path_end > curr_path_start) - { - size_t len = curr_path_end - curr_path_start; - result.assign(curr_path_start, len); - curr_path_start += len + 1; - } - else - break; - - result += '/'; - result += path; - struct stat s; - if (stat(result.c_str(), &s) == 0) - { - ::strncpy(resolved_path, result.c_str(), resolved_path_size); - return result.size() + 1 < resolved_path_size; - } - } + char max_path[PATH_MAX]; + std::string result; + CFString::GlobPath(path, result); + + if (result.empty()) + result = path; + + struct stat path_stat; + if (::stat(path, &path_stat) == 0) { + if ((path_stat.st_mode & S_IFMT) == S_IFDIR) { + CFBundle bundle(path); + CFReleaser<CFURLRef> url(bundle.CopyExecutableURL()); + if (url.get()) { + if (::CFURLGetFileSystemRepresentation( + url.get(), true, (UInt8 *)resolved_path, resolved_path_size)) + return true; + } + } + } + + if (realpath(path, max_path)) { + // Found the path relatively... + ::strncpy(resolved_path, max_path, resolved_path_size); + return strlen(resolved_path) + 1 < resolved_path_size; + } else { + // Not a relative path, check the PATH environment variable if the + const char *PATH = getenv("PATH"); + if (PATH) { + const char *curr_path_start = PATH; + const char *curr_path_end; + while (curr_path_start && *curr_path_start) { + curr_path_end = strchr(curr_path_start, ':'); + if (curr_path_end == NULL) { + result.assign(curr_path_start); + curr_path_start = NULL; + } else if (curr_path_end > curr_path_start) { + size_t len = curr_path_end - curr_path_start; + result.assign(curr_path_start, len); + curr_path_start += len + 1; + } else + break; + + result += '/'; + result += path; + struct stat s; + if (stat(result.c_str(), &s) == 0) { + ::strncpy(resolved_path, result.c_str(), resolved_path_size); + return result.size() + 1 < resolved_path_size; } + } } - return false; + } + return false; } -bool -DNBGetOSVersionNumbers (uint64_t *major, uint64_t *minor, uint64_t *patch) -{ - return MachProcess::GetOSVersionNumbers (major, minor, patch); +bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch) { + return MachProcess::GetOSVersionNumbers(major, minor, patch); } - -void -DNBInitialize() -{ - DNBLogThreadedIf (LOG_PROCESS, "DNBInitialize ()"); -#if defined (__i386__) || defined (__x86_64__) - DNBArchImplI386::Initialize(); - DNBArchImplX86_64::Initialize(); -#elif defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - DNBArchMachARM::Initialize(); - DNBArchMachARM64::Initialize(); +void DNBInitialize() { + DNBLogThreadedIf(LOG_PROCESS, "DNBInitialize ()"); +#if defined(__i386__) || defined(__x86_64__) + DNBArchImplI386::Initialize(); + DNBArchImplX86_64::Initialize(); +#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + DNBArchMachARM::Initialize(); + DNBArchMachARM64::Initialize(); #endif } -void -DNBTerminate() -{ -} - -nub_bool_t -DNBSetArchitecture (const char *arch) -{ - if (arch && arch[0]) - { - if (strcasecmp (arch, "i386") == 0) - return DNBArchProtocol::SetArchitecture (CPU_TYPE_I386); - else if ((strcasecmp (arch, "x86_64") == 0) || (strcasecmp (arch, "x86_64h") == 0)) - return DNBArchProtocol::SetArchitecture (CPU_TYPE_X86_64); - else if (strstr (arch, "arm64") == arch || strstr (arch, "armv8") == arch || strstr (arch, "aarch64") == arch) - return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM64); - else if (strstr (arch, "arm") == arch) - return DNBArchProtocol::SetArchitecture (CPU_TYPE_ARM); - } - return false; +void DNBTerminate() {} + +nub_bool_t DNBSetArchitecture(const char *arch) { + if (arch && arch[0]) { + if (strcasecmp(arch, "i386") == 0) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); + else if ((strcasecmp(arch, "x86_64") == 0) || + (strcasecmp(arch, "x86_64h") == 0)) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); + else if (strstr(arch, "arm64") == arch || strstr(arch, "armv8") == arch || + strstr(arch, "aarch64") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); + else if (strstr(arch, "arm") == arch) + return DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); + } + return false; } diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h index 3e928e663d7..7acbd42810c 100644 --- a/lldb/tools/debugserver/source/DNB.h +++ b/lldb/tools/debugserver/source/DNB.h @@ -14,48 +14,49 @@ #ifndef __DNB_h__ #define __DNB_h__ +#include "DNBDefs.h" +#include "JSONGenerator.h" #include "MacOSX/DarwinLog/DarwinLogEvent.h" #include "MacOSX/Genealogy.h" #include "MacOSX/ThreadInfo.h" -#include "JSONGenerator.h" -#include "DNBDefs.h" #include <mach/thread_info.h> #include <string> #define DNB_EXPORT __attribute__((visibility("default"))) #ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 ((cpu_type_t) 12 | 0x01000000) +#define CPU_TYPE_ARM64 ((cpu_type_t)12 | 0x01000000) #endif -typedef bool (*DNBShouldCancelCallback) (void *); +typedef bool (*DNBShouldCancelCallback)(void *); -void DNBInitialize (); -void DNBTerminate (); +void DNBInitialize(); +void DNBTerminate(); -nub_bool_t DNBSetArchitecture (const char *arch); +nub_bool_t DNBSetArchitecture(const char *arch); //---------------------------------------------------------------------- // Process control //---------------------------------------------------------------------- -nub_process_t DNBProcessLaunch (const char *path, - char const *argv[], - const char *envp[], - const char *working_directory, // NULL => don't change, non-NULL => set working directory for inferior to this - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - nub_launch_flavor_t launch_flavor, - int disable_aslr, - const char *event_data, - char *err_str, - size_t err_len); - -nub_process_t DNBProcessGetPIDByName (const char *name); -nub_process_t DNBProcessAttach (nub_process_t pid, struct timespec *timeout, char *err_str, size_t err_len); -nub_process_t DNBProcessAttachByName (const char *name, struct timespec *timeout, char *err_str, size_t err_len); -nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavor_t launch_flavor, bool ignore_existing, struct timespec *timeout, useconds_t interval, char *err_str, size_t err_len, DNBShouldCancelCallback should_cancel = NULL, void *callback_data = NULL); +nub_process_t DNBProcessLaunch( + const char *path, char const *argv[], const char *envp[], + const char *working_directory, // NULL => don't change, non-NULL => set + // working directory for inferior to this + const char *stdin_path, const char *stdout_path, const char *stderr_path, + bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, + const char *event_data, char *err_str, size_t err_len); + +nub_process_t DNBProcessGetPIDByName(const char *name); +nub_process_t DNBProcessAttach(nub_process_t pid, struct timespec *timeout, + char *err_str, size_t err_len); +nub_process_t DNBProcessAttachByName(const char *name, struct timespec *timeout, + char *err_str, size_t err_len); +nub_process_t +DNBProcessAttachWait(const char *wait_name, nub_launch_flavor_t launch_flavor, + bool ignore_existing, struct timespec *timeout, + useconds_t interval, char *err_str, size_t err_len, + DNBShouldCancelCallback should_cancel = NULL, + void *callback_data = NULL); // Resume a process with exact instructions on what to do with each thread: // - If no thread actions are supplied (actions is NULL or num_actions is zero), // then all threads are continued. @@ -64,117 +65,177 @@ nub_process_t DNBProcessAttachWait (const char *wait_name, nub_launch_flavo // explicit thread action can be made by making a thread action with a tid of // INVALID_NUB_THREAD. If there is no default action, those threads will // remain stopped. -nub_bool_t DNBProcessResume (nub_process_t pid, const DNBThreadResumeAction *actions, size_t num_actions) DNB_EXPORT; -nub_bool_t DNBProcessHalt (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessDetach (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSignal (nub_process_t pid, int signal) DNB_EXPORT; -nub_bool_t DNBProcessInterrupt (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessKill (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSendEvent (nub_process_t pid, const char *event) DNB_EXPORT; -nub_size_t DNBProcessMemoryRead (nub_process_t pid, nub_addr_t addr, nub_size_t size, void *buf) DNB_EXPORT; -uint64_t DNBProcessMemoryReadInteger (nub_process_t pid, nub_addr_t addr, nub_size_t integer_size, uint64_t fail_value) DNB_EXPORT; -nub_addr_t DNBProcessMemoryReadPointer (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; -std::string DNBProcessMemoryReadCString (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; -std::string DNBProcessMemoryReadCStringFixed (nub_process_t pid, nub_addr_t addr, nub_size_t fixed_length) DNB_EXPORT; -nub_size_t DNBProcessMemoryWrite (nub_process_t pid, nub_addr_t addr, nub_size_t size, const void *buf) DNB_EXPORT; -nub_addr_t DNBProcessMemoryAllocate (nub_process_t pid, nub_size_t size, uint32_t permissions) DNB_EXPORT; -nub_bool_t DNBProcessMemoryDeallocate (nub_process_t pid, nub_addr_t addr) DNB_EXPORT; -int DNBProcessMemoryRegionInfo (nub_process_t pid, nub_addr_t addr, DNBRegionInfo *region_info) DNB_EXPORT; -std::string DNBProcessGetProfileData (nub_process_t pid, DNBProfileDataScanType scanType) DNB_EXPORT; -nub_bool_t DNBProcessSetEnableAsyncProfiling (nub_process_t pid, nub_bool_t enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) DNB_EXPORT; +nub_bool_t DNBProcessResume(nub_process_t pid, + const DNBThreadResumeAction *actions, + size_t num_actions) DNB_EXPORT; +nub_bool_t DNBProcessHalt(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessDetach(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSignal(nub_process_t pid, int signal) DNB_EXPORT; +nub_bool_t DNBProcessInterrupt(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessKill(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSendEvent(nub_process_t pid, const char *event) DNB_EXPORT; +nub_size_t DNBProcessMemoryRead(nub_process_t pid, nub_addr_t addr, + nub_size_t size, void *buf) DNB_EXPORT; +uint64_t DNBProcessMemoryReadInteger(nub_process_t pid, nub_addr_t addr, + nub_size_t integer_size, + uint64_t fail_value) DNB_EXPORT; +nub_addr_t DNBProcessMemoryReadPointer(nub_process_t pid, + nub_addr_t addr) DNB_EXPORT; +std::string DNBProcessMemoryReadCString(nub_process_t pid, + nub_addr_t addr) DNB_EXPORT; +std::string +DNBProcessMemoryReadCStringFixed(nub_process_t pid, nub_addr_t addr, + nub_size_t fixed_length) DNB_EXPORT; +nub_size_t DNBProcessMemoryWrite(nub_process_t pid, nub_addr_t addr, + nub_size_t size, const void *buf) DNB_EXPORT; +nub_addr_t DNBProcessMemoryAllocate(nub_process_t pid, nub_size_t size, + uint32_t permissions) DNB_EXPORT; +nub_bool_t DNBProcessMemoryDeallocate(nub_process_t pid, + nub_addr_t addr) DNB_EXPORT; +int DNBProcessMemoryRegionInfo(nub_process_t pid, nub_addr_t addr, + DNBRegionInfo *region_info) DNB_EXPORT; +std::string +DNBProcessGetProfileData(nub_process_t pid, + DNBProfileDataScanType scanType) DNB_EXPORT; +nub_bool_t +DNBProcessSetEnableAsyncProfiling(nub_process_t pid, nub_bool_t enable, + uint64_t interval_usec, + DNBProfileDataScanType scan_type) DNB_EXPORT; DarwinLogEventVector DNBProcessGetAvailableDarwinLogEvents(nub_process_t pid); - //---------------------------------------------------------------------- // Process status //---------------------------------------------------------------------- -nub_bool_t DNBProcessIsAlive (nub_process_t pid) DNB_EXPORT; -nub_state_t DNBProcessGetState (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessGetExitStatus (nub_process_t pid, int *status) DNB_EXPORT; -nub_bool_t DNBProcessSetExitStatus (nub_process_t pid, int status) DNB_EXPORT; -const char * DNBProcessGetExitInfo (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSetExitInfo (nub_process_t pid, const char *info) DNB_EXPORT; -nub_size_t DNBProcessGetNumThreads (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessGetCurrentThread (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessGetCurrentThreadMachPort (nub_process_t pid) DNB_EXPORT; -nub_thread_t DNBProcessSetCurrentThread (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_thread_t DNBProcessGetThreadAtIndex (nub_process_t pid, nub_size_t thread_idx) DNB_EXPORT; -nub_bool_t DNBProcessSyncThreadState (nub_process_t pid, nub_thread_t tid) DNB_EXPORT; -nub_addr_t DNBProcessGetSharedLibraryInfoAddress (nub_process_t pid) DNB_EXPORT; -nub_bool_t DNBProcessSharedLibrariesUpdated (nub_process_t pid) DNB_EXPORT; -nub_size_t DNBProcessGetSharedLibraryInfo (nub_process_t pid, nub_bool_t only_changed, DNBExecutableImageInfo **image_infos) DNB_EXPORT; -nub_bool_t DNBProcessSetNameToAddressCallback (nub_process_t pid, DNBCallbackNameToAddress callback, void *baton) DNB_EXPORT; -nub_bool_t DNBProcessSetSharedLibraryInfoCallback (nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, void *baton) DNB_EXPORT; -nub_addr_t DNBProcessLookupAddress (nub_process_t pid, const char *name, const char *shlib) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableSTDOUT (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableSTDERR (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetAvailableProfileData (nub_process_t pid, char *buf, nub_size_t buf_size) DNB_EXPORT; -nub_size_t DNBProcessGetStopCount (nub_process_t pid) DNB_EXPORT; -uint32_t DNBProcessGetCPUType (nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessIsAlive(nub_process_t pid) DNB_EXPORT; +nub_state_t DNBProcessGetState(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessGetExitStatus(nub_process_t pid, int *status) DNB_EXPORT; +nub_bool_t DNBProcessSetExitStatus(nub_process_t pid, int status) DNB_EXPORT; +const char *DNBProcessGetExitInfo(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSetExitInfo(nub_process_t pid, + const char *info) DNB_EXPORT; +nub_size_t DNBProcessGetNumThreads(nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessGetCurrentThread(nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessGetCurrentThreadMachPort(nub_process_t pid) DNB_EXPORT; +nub_thread_t DNBProcessSetCurrentThread(nub_process_t pid, + nub_thread_t tid) DNB_EXPORT; +nub_thread_t DNBProcessGetThreadAtIndex(nub_process_t pid, + nub_size_t thread_idx) DNB_EXPORT; +nub_bool_t DNBProcessSyncThreadState(nub_process_t pid, + nub_thread_t tid) DNB_EXPORT; +nub_addr_t DNBProcessGetSharedLibraryInfoAddress(nub_process_t pid) DNB_EXPORT; +nub_bool_t DNBProcessSharedLibrariesUpdated(nub_process_t pid) DNB_EXPORT; +nub_size_t +DNBProcessGetSharedLibraryInfo(nub_process_t pid, nub_bool_t only_changed, + DNBExecutableImageInfo **image_infos) DNB_EXPORT; +nub_bool_t DNBProcessSetNameToAddressCallback(nub_process_t pid, + DNBCallbackNameToAddress callback, + void *baton) DNB_EXPORT; +nub_bool_t DNBProcessSetSharedLibraryInfoCallback( + nub_process_t pid, DNBCallbackCopyExecutableImageInfos callback, + void *baton) DNB_EXPORT; +nub_addr_t DNBProcessLookupAddress(nub_process_t pid, const char *name, + const char *shlib) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableSTDOUT(nub_process_t pid, char *buf, + nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableSTDERR(nub_process_t pid, char *buf, + nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetAvailableProfileData(nub_process_t pid, char *buf, + nub_size_t buf_size) DNB_EXPORT; +nub_size_t DNBProcessGetStopCount(nub_process_t pid) DNB_EXPORT; +uint32_t DNBProcessGetCPUType(nub_process_t pid) DNB_EXPORT; //---------------------------------------------------------------------- // Process executable and arguments //---------------------------------------------------------------------- -const char * DNBProcessGetExecutablePath (nub_process_t pid); -const char * DNBProcessGetArgumentAtIndex (nub_process_t pid, nub_size_t idx); -nub_size_t DNBProcessGetArgumentCount (nub_process_t pid); +const char *DNBProcessGetExecutablePath(nub_process_t pid); +const char *DNBProcessGetArgumentAtIndex(nub_process_t pid, nub_size_t idx); +nub_size_t DNBProcessGetArgumentCount(nub_process_t pid); //---------------------------------------------------------------------- // Process events //---------------------------------------------------------------------- -nub_event_t DNBProcessWaitForEvents (nub_process_t pid, nub_event_t event_mask, bool wait_for_set, struct timespec* timeout); -void DNBProcessResetEvents (nub_process_t pid, nub_event_t event_mask); +nub_event_t DNBProcessWaitForEvents(nub_process_t pid, nub_event_t event_mask, + bool wait_for_set, + struct timespec *timeout); +void DNBProcessResetEvents(nub_process_t pid, nub_event_t event_mask); //---------------------------------------------------------------------- // Thread functions //---------------------------------------------------------------------- -const char * DNBThreadGetName (nub_process_t pid, nub_thread_t tid); -nub_bool_t DNBThreadGetIdentifierInfo (nub_process_t pid, nub_thread_t tid, thread_identifier_info_data_t *ident_info); -nub_state_t DNBThreadGetState (nub_process_t pid, nub_thread_t tid); -nub_bool_t DNBThreadGetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value); -nub_bool_t DNBThreadSetRegisterValueByID (nub_process_t pid, nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value); -nub_size_t DNBThreadGetRegisterContext (nub_process_t pid, nub_thread_t tid, void *buf, size_t buf_len); -nub_size_t DNBThreadSetRegisterContext (nub_process_t pid, nub_thread_t tid, const void *buf, size_t buf_len); -uint32_t DNBThreadSaveRegisterState (nub_process_t pid, nub_thread_t tid); -nub_bool_t DNBThreadRestoreRegisterState (nub_process_t pid, nub_thread_t tid, uint32_t save_id); -nub_bool_t DNBThreadGetRegisterValueByName (nub_process_t pid, nub_thread_t tid, uint32_t set, const char *name, DNBRegisterValue *value); -nub_bool_t DNBThreadGetStopReason (nub_process_t pid, nub_thread_t tid, DNBThreadStopInfo *stop_info); -const char * DNBThreadGetInfo (nub_process_t pid, nub_thread_t tid); -Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread (nub_process_t pid, nub_thread_t tid, bool &timed_out); -Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo (nub_process_t pid, size_t idx); -ThreadInfo::QoS DNBGetRequestedQoSForThread (nub_process_t pid, nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index); -nub_addr_t DNBGetPThreadT (nub_process_t pid, nub_thread_t tid); -nub_addr_t DNBGetDispatchQueueT (nub_process_t pid, nub_thread_t tid); -nub_addr_t DNBGetTSDAddressForThread (nub_process_t pid, nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); -JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count); -JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos (nub_process_t pid); -JSONGenerator::ObjectSP DNBGetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses); -JSONGenerator::ObjectSP DNBGetSharedCacheInfo (nub_process_t pid); +const char *DNBThreadGetName(nub_process_t pid, nub_thread_t tid); +nub_bool_t +DNBThreadGetIdentifierInfo(nub_process_t pid, nub_thread_t tid, + thread_identifier_info_data_t *ident_info); +nub_state_t DNBThreadGetState(nub_process_t pid, nub_thread_t tid); +nub_bool_t DNBThreadGetRegisterValueByID(nub_process_t pid, nub_thread_t tid, + uint32_t set, uint32_t reg, + DNBRegisterValue *value); +nub_bool_t DNBThreadSetRegisterValueByID(nub_process_t pid, nub_thread_t tid, + uint32_t set, uint32_t reg, + const DNBRegisterValue *value); +nub_size_t DNBThreadGetRegisterContext(nub_process_t pid, nub_thread_t tid, + void *buf, size_t buf_len); +nub_size_t DNBThreadSetRegisterContext(nub_process_t pid, nub_thread_t tid, + const void *buf, size_t buf_len); +uint32_t DNBThreadSaveRegisterState(nub_process_t pid, nub_thread_t tid); +nub_bool_t DNBThreadRestoreRegisterState(nub_process_t pid, nub_thread_t tid, + uint32_t save_id); +nub_bool_t DNBThreadGetRegisterValueByName(nub_process_t pid, nub_thread_t tid, + uint32_t set, const char *name, + DNBRegisterValue *value); +nub_bool_t DNBThreadGetStopReason(nub_process_t pid, nub_thread_t tid, + DNBThreadStopInfo *stop_info); +const char *DNBThreadGetInfo(nub_process_t pid, nub_thread_t tid); +Genealogy::ThreadActivitySP DNBGetGenealogyInfoForThread(nub_process_t pid, + nub_thread_t tid, + bool &timed_out); +Genealogy::ProcessExecutableInfoSP DNBGetGenealogyImageInfo(nub_process_t pid, + size_t idx); +ThreadInfo::QoS DNBGetRequestedQoSForThread(nub_process_t pid, nub_thread_t tid, + nub_addr_t tsd, + uint64_t dti_qos_class_index); +nub_addr_t DNBGetPThreadT(nub_process_t pid, nub_thread_t tid); +nub_addr_t DNBGetDispatchQueueT(nub_process_t pid, nub_thread_t tid); +nub_addr_t +DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid, + uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size); +JSONGenerator::ObjectSP DNBGetLoadedDynamicLibrariesInfos( + nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count); +JSONGenerator::ObjectSP DNBGetAllLoadedLibrariesInfos(nub_process_t pid); +JSONGenerator::ObjectSP +DNBGetLibrariesInfoForAddresses(nub_process_t pid, + std::vector<uint64_t> &macho_addresses); +JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid); // //---------------------------------------------------------------------- // Breakpoint functions //---------------------------------------------------------------------- -nub_bool_t DNBBreakpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, nub_bool_t hardware); -nub_bool_t DNBBreakpointClear (nub_process_t pid, nub_addr_t addr); +nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, + nub_bool_t hardware); +nub_bool_t DNBBreakpointClear(nub_process_t pid, nub_addr_t addr); //---------------------------------------------------------------------- // Watchpoint functions //---------------------------------------------------------------------- -nub_bool_t DNBWatchpointSet (nub_process_t pid, nub_addr_t addr, nub_size_t size, uint32_t watch_flags, nub_bool_t hardware); -nub_bool_t DNBWatchpointClear (nub_process_t pid, nub_addr_t addr); -uint32_t DNBWatchpointGetNumSupportedHWP (nub_process_t pid); +nub_bool_t DNBWatchpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size, + uint32_t watch_flags, nub_bool_t hardware); +nub_bool_t DNBWatchpointClear(nub_process_t pid, nub_addr_t addr); +uint32_t DNBWatchpointGetNumSupportedHWP(nub_process_t pid); -uint32_t DNBGetRegisterCPUType (); -const DNBRegisterSetInfo * - DNBGetRegisterSetInfo (nub_size_t *num_reg_sets); -nub_bool_t DNBGetRegisterInfoByName (const char *reg_name, DNBRegisterInfo* info); +uint32_t DNBGetRegisterCPUType(); +const DNBRegisterSetInfo *DNBGetRegisterSetInfo(nub_size_t *num_reg_sets); +nub_bool_t DNBGetRegisterInfoByName(const char *reg_name, + DNBRegisterInfo *info); //---------------------------------------------------------------------- // Other static nub information calls. //---------------------------------------------------------------------- -const char * DNBStateAsString (nub_state_t state); -nub_bool_t DNBResolveExecutablePath (const char *path, char *resolved_path, size_t resolved_path_size); -bool DNBGetOSVersionNumbers (uint64_t *major, uint64_t *minor, uint64_t *patch); +const char *DNBStateAsString(nub_state_t state); +nub_bool_t DNBResolveExecutablePath(const char *path, char *resolved_path, + size_t resolved_path_size); +bool DNBGetOSVersionNumbers(uint64_t *major, uint64_t *minor, uint64_t *patch); #endif diff --git a/lldb/tools/debugserver/source/DNBArch.cpp b/lldb/tools/debugserver/source/DNBArch.cpp index f17a719e92e..1312bcf7dfd 100644 --- a/lldb/tools/debugserver/source/DNBArch.cpp +++ b/lldb/tools/debugserver/source/DNBArch.cpp @@ -24,74 +24,57 @@ typedef std::map<uint32_t, DNBArchPluginInfo> CPUPluginInfoMap; static uint32_t g_current_cpu_type = 0; CPUPluginInfoMap g_arch_plugins; - -static const DNBArchPluginInfo * -GetArchInfo () -{ - CPUPluginInfoMap::const_iterator pos = g_arch_plugins.find(g_current_cpu_type); - if (pos != g_arch_plugins.end()) - return &pos->second; - return NULL; +static const DNBArchPluginInfo *GetArchInfo() { + CPUPluginInfoMap::const_iterator pos = + g_arch_plugins.find(g_current_cpu_type); + if (pos != g_arch_plugins.end()) + return &pos->second; + return NULL; } +uint32_t DNBArchProtocol::GetArchitecture() { return g_current_cpu_type; } -uint32_t -DNBArchProtocol::GetArchitecture () -{ - return g_current_cpu_type; -} - -bool -DNBArchProtocol::SetArchitecture (uint32_t cpu_type) -{ - g_current_cpu_type = cpu_type; - bool result = g_arch_plugins.find(g_current_cpu_type) != g_arch_plugins.end(); - DNBLogThreadedIf (LOG_PROCESS, "DNBArchProtocol::SetDefaultArchitecture (cpu_type=0x%8.8x) => %i", cpu_type, result); - return result; +bool DNBArchProtocol::SetArchitecture(uint32_t cpu_type) { + g_current_cpu_type = cpu_type; + bool result = g_arch_plugins.find(g_current_cpu_type) != g_arch_plugins.end(); + DNBLogThreadedIf( + LOG_PROCESS, + "DNBArchProtocol::SetDefaultArchitecture (cpu_type=0x%8.8x) => %i", + cpu_type, result); + return result; } -void -DNBArchProtocol::RegisterArchPlugin (const DNBArchPluginInfo &arch_info) -{ - if (arch_info.cpu_type) - g_arch_plugins[arch_info.cpu_type] = arch_info; +void DNBArchProtocol::RegisterArchPlugin(const DNBArchPluginInfo &arch_info) { + if (arch_info.cpu_type) + g_arch_plugins[arch_info.cpu_type] = arch_info; } -uint32_t -DNBArchProtocol::GetRegisterCPUType () -{ - const DNBArchPluginInfo *arch_info = GetArchInfo (); - if (arch_info) - return arch_info->cpu_type; - return 0; +uint32_t DNBArchProtocol::GetRegisterCPUType() { + const DNBArchPluginInfo *arch_info = GetArchInfo(); + if (arch_info) + return arch_info->cpu_type; + return 0; } const DNBRegisterSetInfo * -DNBArchProtocol::GetRegisterSetInfo (nub_size_t *num_reg_sets) -{ - const DNBArchPluginInfo *arch_info = GetArchInfo (); - if (arch_info) - return arch_info->GetRegisterSetInfo (num_reg_sets); - *num_reg_sets = 0; - return NULL; +DNBArchProtocol::GetRegisterSetInfo(nub_size_t *num_reg_sets) { + const DNBArchPluginInfo *arch_info = GetArchInfo(); + if (arch_info) + return arch_info->GetRegisterSetInfo(num_reg_sets); + *num_reg_sets = 0; + return NULL; } -DNBArchProtocol * -DNBArchProtocol::Create (MachThread *thread) -{ - const DNBArchPluginInfo *arch_info = GetArchInfo (); - if (arch_info) - return arch_info->Create (thread); - return NULL; - +DNBArchProtocol *DNBArchProtocol::Create(MachThread *thread) { + const DNBArchPluginInfo *arch_info = GetArchInfo(); + if (arch_info) + return arch_info->Create(thread); + return NULL; } -const uint8_t * -DNBArchProtocol::GetBreakpointOpcode (nub_size_t byte_size) -{ - const DNBArchPluginInfo *arch_info = GetArchInfo (); - if (arch_info) - return arch_info->GetBreakpointOpcode (byte_size); - return NULL; +const uint8_t *DNBArchProtocol::GetBreakpointOpcode(nub_size_t byte_size) { + const DNBArchPluginInfo *arch_info = GetArchInfo(); + if (arch_info) + return arch_info->GetBreakpointOpcode(byte_size); + return NULL; } - diff --git a/lldb/tools/debugserver/source/DNBArch.h b/lldb/tools/debugserver/source/DNBArch.h index c07d3a67400..317da70e642 100644 --- a/lldb/tools/debugserver/source/DNBArch.h +++ b/lldb/tools/debugserver/source/DNBArch.h @@ -25,105 +25,103 @@ struct DNBRegisterSetInfo; class DNBArchProtocol; class MachThread; -typedef DNBArchProtocol * (* DNBArchCallbackCreate)(MachThread *thread); -typedef const DNBRegisterSetInfo * (* DNBArchCallbackGetRegisterSetInfo)(nub_size_t *num_reg_sets); -typedef const uint8_t * (* DNBArchCallbackGetBreakpointOpcode)(nub_size_t byte_size); - -typedef struct DNBArchPluginInfoTag -{ - uint32_t cpu_type; - DNBArchCallbackCreate Create; - DNBArchCallbackGetRegisterSetInfo GetRegisterSetInfo; - DNBArchCallbackGetBreakpointOpcode GetBreakpointOpcode; +typedef DNBArchProtocol *(*DNBArchCallbackCreate)(MachThread *thread); +typedef const DNBRegisterSetInfo *(*DNBArchCallbackGetRegisterSetInfo)( + nub_size_t *num_reg_sets); +typedef const uint8_t *(*DNBArchCallbackGetBreakpointOpcode)( + nub_size_t byte_size); + +typedef struct DNBArchPluginInfoTag { + uint32_t cpu_type; + DNBArchCallbackCreate Create; + DNBArchCallbackGetRegisterSetInfo GetRegisterSetInfo; + DNBArchCallbackGetBreakpointOpcode GetBreakpointOpcode; } DNBArchPluginInfo; -class DNBArchProtocol -{ +class DNBArchProtocol { public: - static DNBArchProtocol * - Create (MachThread *thread); - - static uint32_t - GetRegisterCPUType (); - - static const DNBRegisterSetInfo * - GetRegisterSetInfo (nub_size_t *num_reg_sets); - - static const uint8_t * - GetBreakpointOpcode (nub_size_t byte_size); - - static void - RegisterArchPlugin (const DNBArchPluginInfo &arch_info); - - static uint32_t - GetArchitecture (); - - static bool - SetArchitecture (uint32_t cpu_type); - - DNBArchProtocol () : - m_save_id(0) - { - - } - - virtual ~DNBArchProtocol () - { - - } - virtual bool GetRegisterValue (uint32_t set, uint32_t reg, DNBRegisterValue *value) = 0; - virtual bool SetRegisterValue (uint32_t set, uint32_t reg, const DNBRegisterValue *value) = 0; - virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len) = 0; - virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len) = 0; - virtual uint32_t SaveRegisterState () = 0; - virtual bool RestoreRegisterState (uint32_t save_id) = 0; - - virtual kern_return_t GetRegisterState (int set, bool force) = 0; - virtual kern_return_t SetRegisterState (int set) = 0; - virtual bool RegisterSetStateIsValid (int set) const = 0; - - virtual uint64_t GetPC (uint64_t failValue) = 0; // Get program counter - virtual kern_return_t SetPC (uint64_t value) = 0; - virtual uint64_t GetSP (uint64_t failValue) = 0; // Get stack pointer - virtual void ThreadWillResume () = 0; - virtual bool ThreadDidStop () = 0; - virtual bool NotifyException (MachException::Data& exc) { return false; } - virtual uint32_t NumSupportedHardwareBreakpoints() { return 0; } - virtual uint32_t NumSupportedHardwareWatchpoints() { return 0; } - virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size) { return INVALID_NUB_HW_INDEX; } - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) { return INVALID_NUB_HW_INDEX; } - virtual bool DisableHardwareBreakpoint (uint32_t hw_index) { return false; } - virtual bool DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) { return false; } - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) { return INVALID_NUB_HW_INDEX; } - virtual bool StepNotComplete () { return false; } + static DNBArchProtocol *Create(MachThread *thread); + + static uint32_t GetRegisterCPUType(); + + static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); + + static const uint8_t *GetBreakpointOpcode(nub_size_t byte_size); + + static void RegisterArchPlugin(const DNBArchPluginInfo &arch_info); + + static uint32_t GetArchitecture(); + + static bool SetArchitecture(uint32_t cpu_type); + + DNBArchProtocol() : m_save_id(0) {} + + virtual ~DNBArchProtocol() {} + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) = 0; + virtual bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) = 0; + virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len) = 0; + virtual nub_size_t SetRegisterContext(const void *buf, + nub_size_t buf_len) = 0; + virtual uint32_t SaveRegisterState() = 0; + virtual bool RestoreRegisterState(uint32_t save_id) = 0; + + virtual kern_return_t GetRegisterState(int set, bool force) = 0; + virtual kern_return_t SetRegisterState(int set) = 0; + virtual bool RegisterSetStateIsValid(int set) const = 0; + + virtual uint64_t GetPC(uint64_t failValue) = 0; // Get program counter + virtual kern_return_t SetPC(uint64_t value) = 0; + virtual uint64_t GetSP(uint64_t failValue) = 0; // Get stack pointer + virtual void ThreadWillResume() = 0; + virtual bool ThreadDidStop() = 0; + virtual bool NotifyException(MachException::Data &exc) { return false; } + virtual uint32_t NumSupportedHardwareBreakpoints() { return 0; } + virtual uint32_t NumSupportedHardwareWatchpoints() { return 0; } + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size) { + return INVALID_NUB_HW_INDEX; + } + virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task) { + return INVALID_NUB_HW_INDEX; + } + virtual bool DisableHardwareBreakpoint(uint32_t hw_index) { return false; } + virtual bool DisableHardwareWatchpoint(uint32_t hw_index, + bool also_set_on_task) { + return false; + } + virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr) { + return INVALID_NUB_HW_INDEX; + } + virtual bool StepNotComplete() { return false; } protected: - friend class MachThread; - - uint32_t GetNextRegisterStateSaveID () - { - return ++m_save_id; - } - - enum - { - Trans_Pending = 0, // Transaction is pending, and checkpoint state has been snapshotted. - Trans_Done = 1, // Transaction is done, the current state is committed, and checkpoint state is irrelevant. - Trans_Rolled_Back = 2 // Transaction is done, the current state has been rolled back to the checkpoint state. - }; - virtual bool StartTransForHWP() { return true; } - virtual bool RollbackTransForHWP() { return true; } - virtual bool FinishTransForHWP() { return true; } - - uint32_t m_save_id; // An always incrementing integer ID used with SaveRegisterState/RestoreRegisterState - + friend class MachThread; + + uint32_t GetNextRegisterStateSaveID() { return ++m_save_id; } + + enum { + Trans_Pending = + 0, // Transaction is pending, and checkpoint state has been snapshotted. + Trans_Done = 1, // Transaction is done, the current state is committed, and + // checkpoint state is irrelevant. + Trans_Rolled_Back = 2 // Transaction is done, the current state has been + // rolled back to the checkpoint state. + }; + virtual bool StartTransForHWP() { return true; } + virtual bool RollbackTransForHWP() { return true; } + virtual bool FinishTransForHWP() { return true; } + + uint32_t m_save_id; // An always incrementing integer ID used with + // SaveRegisterState/RestoreRegisterState }; - #include "MacOSX/arm/DNBArchImpl.h" #include "MacOSX/arm64/DNBArchImplARM64.h" #include "MacOSX/i386/DNBArchImplI386.h" -#include "MacOSX/x86_64/DNBArchImplX86_64.h" #include "MacOSX/ppc/DNBArchImpl.h" +#include "MacOSX/x86_64/DNBArchImplX86_64.h" #endif diff --git a/lldb/tools/debugserver/source/DNBBreakpoint.cpp b/lldb/tools/debugserver/source/DNBBreakpoint.cpp index 2645f173306..89a91287f9e 100644 --- a/lldb/tools/debugserver/source/DNBBreakpoint.cpp +++ b/lldb/tools/debugserver/source/DNBBreakpoint.cpp @@ -12,214 +12,167 @@ //===----------------------------------------------------------------------===// #include "DNBBreakpoint.h" +#include "DNBLog.h" #include "MachProcess.h" -#include <assert.h> #include <algorithm> +#include <assert.h> #include <inttypes.h> -#include "DNBLog.h" - - -#pragma mark -- DNBBreakpoint -DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, bool hardware) : - m_retain_count (1), - m_byte_size (static_cast<uint32_t>(byte_size)), - m_opcode(), - m_addr(addr), - m_enabled(0), - m_hw_preferred(hardware), - m_is_watchpoint(0), - m_watch_read(0), - m_watch_write(0), - m_hw_index(INVALID_NUB_HW_INDEX) -{ -} - -DNBBreakpoint::~DNBBreakpoint() -{ -} - -void -DNBBreakpoint::Dump() const -{ - if (IsBreakpoint()) - { - DNBLog ("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint hw_index = %i", - (uint64_t)m_addr, - m_enabled ? "enabled " : "disabled", - IsHardware() ? "hardware" : "software", - GetHardwareIndex()); - } - else - { - DNBLog ("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s watchpoint (%s%s) hw_index = %i", - (uint64_t)m_addr, - (uint64_t)m_byte_size, - m_enabled ? "enabled " : "disabled", - IsHardware() ? "hardware" : "software", - m_watch_read ? "r" : "", - m_watch_write ? "w" : "", - GetHardwareIndex()); - } -} - -#pragma mark -- DNBBreakpointList - -DNBBreakpointList::DNBBreakpointList() -{ -} -DNBBreakpointList::~DNBBreakpointList() -{ -} - - -DNBBreakpoint * -DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length, bool hardware) -{ - m_breakpoints.insert(std::make_pair(addr, DNBBreakpoint(addr, length, hardware))); - iterator pos = m_breakpoints.find (addr); +#pragma mark-- DNBBreakpoint +DNBBreakpoint::DNBBreakpoint(nub_addr_t addr, nub_size_t byte_size, + bool hardware) + : m_retain_count(1), m_byte_size(static_cast<uint32_t>(byte_size)), + m_opcode(), m_addr(addr), m_enabled(0), m_hw_preferred(hardware), + m_is_watchpoint(0), m_watch_read(0), m_watch_write(0), + m_hw_index(INVALID_NUB_HW_INDEX) {} + +DNBBreakpoint::~DNBBreakpoint() {} + +void DNBBreakpoint::Dump() const { + if (IsBreakpoint()) { + DNBLog("DNBBreakpoint addr = 0x%llx state = %s type = %s breakpoint " + "hw_index = %i", + (uint64_t)m_addr, m_enabled ? "enabled " : "disabled", + IsHardware() ? "hardware" : "software", GetHardwareIndex()); + } else { + DNBLog("DNBBreakpoint addr = 0x%llx size = %llu state = %s type = %s " + "watchpoint (%s%s) hw_index = %i", + (uint64_t)m_addr, (uint64_t)m_byte_size, + m_enabled ? "enabled " : "disabled", + IsHardware() ? "hardware" : "software", m_watch_read ? "r" : "", + m_watch_write ? "w" : "", GetHardwareIndex()); + } +} + +#pragma mark-- DNBBreakpointList + +DNBBreakpointList::DNBBreakpointList() {} + +DNBBreakpointList::~DNBBreakpointList() {} + +DNBBreakpoint *DNBBreakpointList::Add(nub_addr_t addr, nub_size_t length, + bool hardware) { + m_breakpoints.insert( + std::make_pair(addr, DNBBreakpoint(addr, length, hardware))); + iterator pos = m_breakpoints.find(addr); + return &pos->second; +} + +bool DNBBreakpointList::Remove(nub_addr_t addr) { + iterator pos = m_breakpoints.find(addr); + if (pos != m_breakpoints.end()) { + m_breakpoints.erase(pos); + return true; + } + return false; +} + +DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) { + iterator pos = m_breakpoints.find(addr); + if (pos != m_breakpoints.end()) return &pos->second; -} -bool -DNBBreakpointList::Remove (nub_addr_t addr) -{ - iterator pos = m_breakpoints.find(addr); - if (pos != m_breakpoints.end()) - { - m_breakpoints.erase(pos); - return true; - } - return false; + return NULL; } -DNBBreakpoint * -DNBBreakpointList::FindByAddress (nub_addr_t addr) -{ - iterator pos = m_breakpoints.find(addr); - if (pos != m_breakpoints.end()) - return &pos->second; - - return NULL; -} +const DNBBreakpoint *DNBBreakpointList::FindByAddress(nub_addr_t addr) const { + const_iterator pos = m_breakpoints.find(addr); + if (pos != m_breakpoints.end()) + return &pos->second; -const DNBBreakpoint * -DNBBreakpointList::FindByAddress (nub_addr_t addr) const -{ - const_iterator pos = m_breakpoints.find(addr); - if (pos != m_breakpoints.end()) - return &pos->second; - - return NULL; + return NULL; } // Finds the next breakpoint at an address greater than or equal to "addr" -size_t -DNBBreakpointList::FindBreakpointsThatOverlapRange (nub_addr_t addr, - nub_addr_t size, - std::vector<DNBBreakpoint *> &bps) -{ - bps.clear(); - iterator end = m_breakpoints.end(); - // Find the first breakpoint with an address >= to "addr" - iterator pos = m_breakpoints.lower_bound(addr); - if (pos != end) - { - if (pos != m_breakpoints.begin()) - { - // Watch out for a breakpoint at an address less than "addr" that might still overlap - iterator prev_pos = pos; - --prev_pos; - if (prev_pos->second.IntersectsRange (addr, size, NULL, NULL, NULL)) - bps.push_back (&pos->second); - - } - - while (pos != end) - { - // When we hit a breakpoint whose start address is greater than "addr + size" we are done. - // Do the math in a way that doesn't risk unsigned overflow with bad input. - if ((pos->second.Address() - addr) >= size) - break; - - // Check if this breakpoint overlaps, and if it does, add it to the list - if (pos->second.IntersectsRange (addr, size, NULL, NULL, NULL)) - { - bps.push_back (&pos->second); - ++pos; - } - } +size_t DNBBreakpointList::FindBreakpointsThatOverlapRange( + nub_addr_t addr, nub_addr_t size, std::vector<DNBBreakpoint *> &bps) { + bps.clear(); + iterator end = m_breakpoints.end(); + // Find the first breakpoint with an address >= to "addr" + iterator pos = m_breakpoints.lower_bound(addr); + if (pos != end) { + if (pos != m_breakpoints.begin()) { + // Watch out for a breakpoint at an address less than "addr" that might + // still overlap + iterator prev_pos = pos; + --prev_pos; + if (prev_pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) + bps.push_back(&pos->second); } - return bps.size(); -} -void -DNBBreakpointList::Dump() const -{ - const_iterator pos; - const_iterator end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - pos->second.Dump(); -} - -void -DNBBreakpointList::DisableAll () -{ - iterator pos, end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - pos->second.SetEnabled(false); -} - - -void -DNBBreakpointList::RemoveTrapsFromBuffer (nub_addr_t addr, nub_size_t size, void *p) const -{ - uint8_t *buf = (uint8_t *)p; - const_iterator end = m_breakpoints.end(); - const_iterator pos = m_breakpoints.lower_bound(addr); - while (pos != end && (pos->first < (addr + size))) - { - nub_addr_t intersect_addr; - nub_size_t intersect_size; - nub_size_t opcode_offset; - const DNBBreakpoint &bp = pos->second; - if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset)) - { - assert(addr <= intersect_addr && intersect_addr < addr + size); - assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size); - assert(opcode_offset + intersect_size <= bp.ByteSize()); - nub_size_t buf_offset = intersect_addr - addr; - ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset, intersect_size); - } + while (pos != end) { + // When we hit a breakpoint whose start address is greater than "addr + + // size" we are done. + // Do the math in a way that doesn't risk unsigned overflow with bad + // input. + if ((pos->second.Address() - addr) >= size) + break; + + // Check if this breakpoint overlaps, and if it does, add it to the list + if (pos->second.IntersectsRange(addr, size, NULL, NULL, NULL)) { + bps.push_back(&pos->second); ++pos; + } + } + } + return bps.size(); +} + +void DNBBreakpointList::Dump() const { + const_iterator pos; + const_iterator end = m_breakpoints.end(); + for (pos = m_breakpoints.begin(); pos != end; ++pos) + pos->second.Dump(); +} + +void DNBBreakpointList::DisableAll() { + iterator pos, end = m_breakpoints.end(); + for (pos = m_breakpoints.begin(); pos != end; ++pos) + pos->second.SetEnabled(false); +} + +void DNBBreakpointList::RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size, + void *p) const { + uint8_t *buf = (uint8_t *)p; + const_iterator end = m_breakpoints.end(); + const_iterator pos = m_breakpoints.lower_bound(addr); + while (pos != end && (pos->first < (addr + size))) { + nub_addr_t intersect_addr; + nub_size_t intersect_size; + nub_size_t opcode_offset; + const DNBBreakpoint &bp = pos->second; + if (bp.IntersectsRange(addr, size, &intersect_addr, &intersect_size, + &opcode_offset)) { + assert(addr <= intersect_addr && intersect_addr < addr + size); + assert(addr < intersect_addr + intersect_size && + intersect_addr + intersect_size <= addr + size); + assert(opcode_offset + intersect_size <= bp.ByteSize()); + nub_size_t buf_offset = intersect_addr - addr; + ::memcpy(buf + buf_offset, bp.SavedOpcodeBytes() + opcode_offset, + intersect_size); } + ++pos; + } } -void -DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) -{ - iterator pos, end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - process->DisableBreakpoint(pos->second.Address(), false); +void DNBBreakpointList::DisableAllBreakpoints(MachProcess *process) { + iterator pos, end = m_breakpoints.end(); + for (pos = m_breakpoints.begin(); pos != end; ++pos) + process->DisableBreakpoint(pos->second.Address(), false); } -void -DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) -{ - iterator pos, end = m_breakpoints.end(); - for (pos = m_breakpoints.begin(); pos != end; ++pos) - process->DisableWatchpoint(pos->second.Address(), false); +void DNBBreakpointList::DisableAllWatchpoints(MachProcess *process) { + iterator pos, end = m_breakpoints.end(); + for (pos = m_breakpoints.begin(); pos != end; ++pos) + process->DisableWatchpoint(pos->second.Address(), false); } -void -DNBBreakpointList::RemoveDisabled() -{ - iterator pos = m_breakpoints.begin(); - while (pos != m_breakpoints.end()) - { - if (!pos->second.IsEnabled()) - pos = m_breakpoints.erase(pos); - else - ++pos; - } +void DNBBreakpointList::RemoveDisabled() { + iterator pos = m_breakpoints.begin(); + while (pos != m_breakpoints.end()) { + if (!pos->second.IsEnabled()) + pos = m_breakpoints.erase(pos); + else + ++pos; + } } diff --git a/lldb/tools/debugserver/source/DNBBreakpoint.h b/lldb/tools/debugserver/source/DNBBreakpoint.h index c764dbd6cf2..889478b2895 100644 --- a/lldb/tools/debugserver/source/DNBBreakpoint.h +++ b/lldb/tools/debugserver/source/DNBBreakpoint.h @@ -23,143 +23,127 @@ class MachProcess; -class DNBBreakpoint -{ +class DNBBreakpoint { public: - DNBBreakpoint(nub_addr_t m_addr, nub_size_t byte_size, bool hardware); - ~DNBBreakpoint(); - - nub_size_t ByteSize() const { return m_byte_size; } - uint8_t * SavedOpcodeBytes() { return &m_opcode[0]; } - const uint8_t * - SavedOpcodeBytes() const { return &m_opcode[0]; } - nub_addr_t Address() const { return m_addr; } -// nub_thread_t ThreadID() const { return m_tid; } - bool IsEnabled() const { return m_enabled; } - bool IntersectsRange(nub_addr_t addr, - nub_size_t size, - nub_addr_t *intersect_addr, - nub_size_t *intersect_size, - nub_size_t *opcode_offset) const - { - // We only use software traps for software breakpoints - if (IsBreakpoint() && IsEnabled() && !IsHardware()) - { - if (m_byte_size > 0) - { - const nub_addr_t bp_end_addr = m_addr + m_byte_size; - const nub_addr_t end_addr = addr + size; - // Is the breakpoint end address before the passed in start address? - if (bp_end_addr <= addr) - return false; - // Is the breakpoint start address after passed in end address? - if (end_addr <= m_addr) - return false; - if (intersect_addr || intersect_size || opcode_offset) - { - if (m_addr < addr) - { - if (intersect_addr) - *intersect_addr = addr; - if (intersect_size) - *intersect_size = std::min<nub_addr_t>(bp_end_addr, end_addr) - addr; - if (opcode_offset) - *opcode_offset = addr - m_addr; - } - else - { - if (intersect_addr) - *intersect_addr = m_addr; - if (intersect_size) - *intersect_size = std::min<nub_addr_t>(bp_end_addr, end_addr) - m_addr; - if (opcode_offset) - *opcode_offset = 0; - } - } - return true; - } - } - return false; - } - void SetEnabled(bool enabled) - { - if (!enabled) - SetHardwareIndex(INVALID_NUB_HW_INDEX); - m_enabled = enabled; - } - void SetIsWatchpoint (uint32_t type) - { - m_is_watchpoint = 1; - m_watch_read = (type & WATCH_TYPE_READ) != 0; - m_watch_write = (type & WATCH_TYPE_WRITE) != 0; - } - bool IsBreakpoint() const { return m_is_watchpoint == 0; } - bool IsWatchpoint() const { return m_is_watchpoint == 1; } - bool WatchpointRead() const { return m_watch_read != 0; } - bool WatchpointWrite() const { return m_watch_write != 0; } - bool HardwarePreferred() const { return m_hw_preferred; } - bool IsHardware() const { return m_hw_index != INVALID_NUB_HW_INDEX; } - uint32_t GetHardwareIndex() const { return m_hw_index; } - void SetHardwareIndex(uint32_t hw_index) { m_hw_index = hw_index; } - void Dump() const; - uint32_t Retain () - { - return ++m_retain_count; - } - uint32_t Release () - { - if (m_retain_count == 0) - return 0; - return --m_retain_count; - } + DNBBreakpoint(nub_addr_t m_addr, nub_size_t byte_size, bool hardware); + ~DNBBreakpoint(); + + nub_size_t ByteSize() const { return m_byte_size; } + uint8_t *SavedOpcodeBytes() { return &m_opcode[0]; } + const uint8_t *SavedOpcodeBytes() const { return &m_opcode[0]; } + nub_addr_t Address() const { return m_addr; } + // nub_thread_t ThreadID() const { return m_tid; } + bool IsEnabled() const { return m_enabled; } + bool IntersectsRange(nub_addr_t addr, nub_size_t size, + nub_addr_t *intersect_addr, nub_size_t *intersect_size, + nub_size_t *opcode_offset) const { + // We only use software traps for software breakpoints + if (IsBreakpoint() && IsEnabled() && !IsHardware()) { + if (m_byte_size > 0) { + const nub_addr_t bp_end_addr = m_addr + m_byte_size; + const nub_addr_t end_addr = addr + size; + // Is the breakpoint end address before the passed in start address? + if (bp_end_addr <= addr) + return false; + // Is the breakpoint start address after passed in end address? + if (end_addr <= m_addr) + return false; + if (intersect_addr || intersect_size || opcode_offset) { + if (m_addr < addr) { + if (intersect_addr) + *intersect_addr = addr; + if (intersect_size) + *intersect_size = + std::min<nub_addr_t>(bp_end_addr, end_addr) - addr; + if (opcode_offset) + *opcode_offset = addr - m_addr; + } else { + if (intersect_addr) + *intersect_addr = m_addr; + if (intersect_size) + *intersect_size = + std::min<nub_addr_t>(bp_end_addr, end_addr) - m_addr; + if (opcode_offset) + *opcode_offset = 0; + } + } + return true; + } + } + return false; + } + void SetEnabled(bool enabled) { + if (!enabled) + SetHardwareIndex(INVALID_NUB_HW_INDEX); + m_enabled = enabled; + } + void SetIsWatchpoint(uint32_t type) { + m_is_watchpoint = 1; + m_watch_read = (type & WATCH_TYPE_READ) != 0; + m_watch_write = (type & WATCH_TYPE_WRITE) != 0; + } + bool IsBreakpoint() const { return m_is_watchpoint == 0; } + bool IsWatchpoint() const { return m_is_watchpoint == 1; } + bool WatchpointRead() const { return m_watch_read != 0; } + bool WatchpointWrite() const { return m_watch_write != 0; } + bool HardwarePreferred() const { return m_hw_preferred; } + bool IsHardware() const { return m_hw_index != INVALID_NUB_HW_INDEX; } + uint32_t GetHardwareIndex() const { return m_hw_index; } + void SetHardwareIndex(uint32_t hw_index) { m_hw_index = hw_index; } + void Dump() const; + uint32_t Retain() { return ++m_retain_count; } + uint32_t Release() { + if (m_retain_count == 0) + return 0; + return --m_retain_count; + } private: - uint32_t m_retain_count; // Each breakpoint is maintained by address and is ref counted in case multiple people set a breakpoint at the same address - uint32_t m_byte_size; // Length in bytes of the breakpoint if set in memory - uint8_t m_opcode[8]; // Saved opcode bytes - nub_addr_t m_addr; // Address of this breakpoint - uint32_t m_enabled:1, // Flags for this breakpoint - m_hw_preferred:1, // 1 if this point has been requested to be set using hardware (which may fail due to lack of resources) - m_is_watchpoint:1, // 1 if this is a watchpoint - m_watch_read:1, // 1 if we stop when the watched data is read from - m_watch_write:1; // 1 if we stop when the watched data is written to - uint32_t m_hw_index; // The hardware resource index for this breakpoint/watchpoint + uint32_t m_retain_count; // Each breakpoint is maintained by address and is + // ref counted in case multiple people set a + // breakpoint at the same address + uint32_t m_byte_size; // Length in bytes of the breakpoint if set in memory + uint8_t m_opcode[8]; // Saved opcode bytes + nub_addr_t m_addr; // Address of this breakpoint + uint32_t m_enabled : 1, // Flags for this breakpoint + m_hw_preferred : 1, // 1 if this point has been requested to be set using + // hardware (which may fail due to lack of resources) + m_is_watchpoint : 1, // 1 if this is a watchpoint + m_watch_read : 1, // 1 if we stop when the watched data is read from + m_watch_write : 1; // 1 if we stop when the watched data is written to + uint32_t + m_hw_index; // The hardware resource index for this breakpoint/watchpoint }; - -class DNBBreakpointList -{ +class DNBBreakpointList { public: - DNBBreakpointList(); - ~DNBBreakpointList(); + DNBBreakpointList(); + ~DNBBreakpointList(); + + DNBBreakpoint *Add(nub_addr_t addr, nub_size_t length, bool hardware); + bool Remove(nub_addr_t addr); + DNBBreakpoint *FindByAddress(nub_addr_t addr); + const DNBBreakpoint *FindByAddress(nub_addr_t addr) const; - DNBBreakpoint * Add (nub_addr_t addr, nub_size_t length, bool hardware); - bool Remove (nub_addr_t addr); - DNBBreakpoint * FindByAddress (nub_addr_t addr); - const DNBBreakpoint * FindByAddress (nub_addr_t addr) const; + size_t FindBreakpointsThatOverlapRange(nub_addr_t addr, nub_addr_t size, + std::vector<DNBBreakpoint *> &bps); - size_t FindBreakpointsThatOverlapRange (nub_addr_t addr, - nub_addr_t size, - std::vector<DNBBreakpoint *> &bps); + void Dump() const; - void Dump () const; + size_t Size() const { return m_breakpoints.size(); } + void DisableAll(); - size_t Size() const { return m_breakpoints.size(); } - void DisableAll (); + void RemoveTrapsFromBuffer(nub_addr_t addr, nub_size_t size, void *buf) const; - void RemoveTrapsFromBuffer (nub_addr_t addr, - nub_size_t size, - void *buf) const; + void DisableAllBreakpoints(MachProcess *process); + void DisableAllWatchpoints(MachProcess *process); + void RemoveDisabled(); - void DisableAllBreakpoints (MachProcess *process); - void DisableAllWatchpoints(MachProcess *process); - void RemoveDisabled (); protected: - typedef std::map<nub_addr_t, DNBBreakpoint> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - collection m_breakpoints; + typedef std::map<nub_addr_t, DNBBreakpoint> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + collection m_breakpoints; }; #endif - diff --git a/lldb/tools/debugserver/source/DNBDataRef.cpp b/lldb/tools/debugserver/source/DNBDataRef.cpp index d52f28ee2fb..d7dce1ab733 100644 --- a/lldb/tools/debugserver/source/DNBDataRef.cpp +++ b/lldb/tools/debugserver/source/DNBDataRef.cpp @@ -21,165 +21,139 @@ // Constructor //---------------------------------------------------------------------- -DNBDataRef::DNBDataRef() : - m_start(NULL), - m_end(NULL), - m_swap(false), - m_ptrSize(0), - m_addrPCRelative(INVALID_NUB_ADDRESS), - m_addrTEXT(INVALID_NUB_ADDRESS), - m_addrDATA(INVALID_NUB_ADDRESS) -{ -} - +DNBDataRef::DNBDataRef() + : m_start(NULL), m_end(NULL), m_swap(false), m_ptrSize(0), + m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), + m_addrDATA(INVALID_NUB_ADDRESS) {} //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) : - m_start(start), - m_end(start+size), - m_swap(swap), - m_ptrSize(0), - m_addrPCRelative(INVALID_NUB_ADDRESS), - m_addrTEXT(INVALID_NUB_ADDRESS), - m_addrDATA(INVALID_NUB_ADDRESS) -{ -} - +DNBDataRef::DNBDataRef(const uint8_t *start, size_t size, bool swap) + : m_start(start), m_end(start + size), m_swap(swap), m_ptrSize(0), + m_addrPCRelative(INVALID_NUB_ADDRESS), m_addrTEXT(INVALID_NUB_ADDRESS), + m_addrDATA(INVALID_NUB_ADDRESS) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -DNBDataRef::~DNBDataRef() -{ -} - +DNBDataRef::~DNBDataRef() {} //---------------------------------------------------------------------- // Get8 //---------------------------------------------------------------------- -uint8_t -DNBDataRef::Get8(offset_t *offset_ptr) const -{ - uint8_t val = 0; - if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) - { - val = *(m_start + *offset_ptr); - *offset_ptr += sizeof(val); - } - return val; +uint8_t DNBDataRef::Get8(offset_t *offset_ptr) const { + uint8_t val = 0; + if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { + val = *(m_start + *offset_ptr); + *offset_ptr += sizeof(val); + } + return val; } - //---------------------------------------------------------------------- // Get16 //---------------------------------------------------------------------- -uint16_t -DNBDataRef::Get16(offset_t *offset_ptr) const -{ - uint16_t val = 0; - if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) - { - const uint8_t *p = m_start + *offset_ptr; - val = *(uint16_t*)p; - - if (m_swap) - val = OSSwapInt16(val); - - // Advance the offset - *offset_ptr += sizeof(val); - } - return val; +uint16_t DNBDataRef::Get16(offset_t *offset_ptr) const { + uint16_t val = 0; + if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { + const uint8_t *p = m_start + *offset_ptr; + val = *(uint16_t *)p; + + if (m_swap) + val = OSSwapInt16(val); + + // Advance the offset + *offset_ptr += sizeof(val); + } + return val; } - //---------------------------------------------------------------------- // Get32 //---------------------------------------------------------------------- -uint32_t -DNBDataRef::Get32(offset_t *offset_ptr) const -{ - uint32_t val = 0; - if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) - { - const uint8_t *p = m_start + *offset_ptr; - val = *(uint32_t*)p; - if (m_swap) - val = OSSwapInt32(val); - - // Advance the offset - *offset_ptr += sizeof(val); - } - return val; +uint32_t DNBDataRef::Get32(offset_t *offset_ptr) const { + uint32_t val = 0; + if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { + const uint8_t *p = m_start + *offset_ptr; + val = *(uint32_t *)p; + if (m_swap) + val = OSSwapInt32(val); + + // Advance the offset + *offset_ptr += sizeof(val); + } + return val; } - //---------------------------------------------------------------------- // Get64 //---------------------------------------------------------------------- -uint64_t -DNBDataRef::Get64(offset_t *offset_ptr) const -{ - uint64_t val = 0; - if ( ValidOffsetForDataOfSize(*offset_ptr, sizeof(val)) ) - { - const uint8_t *p = m_start + *offset_ptr; - val = *(uint64_t*)p; - if (m_swap) - val = OSSwapInt64(val); - - // Advance the offset - *offset_ptr += sizeof(val); - } - return val; +uint64_t DNBDataRef::Get64(offset_t *offset_ptr) const { + uint64_t val = 0; + if (ValidOffsetForDataOfSize(*offset_ptr, sizeof(val))) { + const uint8_t *p = m_start + *offset_ptr; + val = *(uint64_t *)p; + if (m_swap) + val = OSSwapInt64(val); + + // Advance the offset + *offset_ptr += sizeof(val); + } + return val; } - //---------------------------------------------------------------------- // GetMax32 // // Used for calls when the size can vary. Fill in extra cases if they // are ever needed. //---------------------------------------------------------------------- -uint32_t -DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const -{ - switch (byte_size) - { - case 1: return Get8 (offset_ptr); break; - case 2: return Get16(offset_ptr); break; - case 4: return Get32(offset_ptr); break; - default: - assert(!"GetMax32 unhandled case!"); - break; - } - return 0; +uint32_t DNBDataRef::GetMax32(offset_t *offset_ptr, uint32_t byte_size) const { + switch (byte_size) { + case 1: + return Get8(offset_ptr); + break; + case 2: + return Get16(offset_ptr); + break; + case 4: + return Get32(offset_ptr); + break; + default: + assert(!"GetMax32 unhandled case!"); + break; + } + return 0; } - //---------------------------------------------------------------------- // GetMax64 // // Used for calls when the size can vary. Fill in extra cases if they // are ever needed. //---------------------------------------------------------------------- -uint64_t -DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const -{ - switch (size) - { - case 1: return Get8 (offset_ptr); break; - case 2: return Get16(offset_ptr); break; - case 4: return Get32(offset_ptr); break; - case 8: return Get64(offset_ptr); break; - default: - assert(!"GetMax64 unhandled case!"); - break; - } - return 0; +uint64_t DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const { + switch (size) { + case 1: + return Get8(offset_ptr); + break; + case 2: + return Get16(offset_ptr); + break; + case 4: + return Get32(offset_ptr); + break; + case 8: + return Get64(offset_ptr); + break; + default: + assert(!"GetMax64 unhandled case!"); + break; + } + return 0; } //---------------------------------------------------------------------- @@ -188,198 +162,190 @@ DNBDataRef::GetMax64(offset_t *offset_ptr, uint32_t size) const // Extract a pointer value from the buffer. The pointer size must be // set prior to using this using one of the SetPointerSize functions. //---------------------------------------------------------------------- -uint64_t -DNBDataRef::GetPointer(offset_t *offset_ptr) const -{ - // Must set pointer size prior to using this call - assert(m_ptrSize != 0); - return GetMax64(offset_ptr, m_ptrSize); +uint64_t DNBDataRef::GetPointer(offset_t *offset_ptr) const { + // Must set pointer size prior to using this call + assert(m_ptrSize != 0); + return GetMax64(offset_ptr, m_ptrSize); } //---------------------------------------------------------------------- // GetCStr //---------------------------------------------------------------------- -const char * -DNBDataRef::GetCStr(offset_t *offset_ptr, uint32_t fixed_length) const -{ - const char *s = NULL; - if ( m_start < m_end ) - { - s = (char*)m_start + *offset_ptr; - - // Advance the offset - if (fixed_length) - *offset_ptr += fixed_length; - else - *offset_ptr += strlen(s) + 1; - } - return s; +const char *DNBDataRef::GetCStr(offset_t *offset_ptr, + uint32_t fixed_length) const { + const char *s = NULL; + if (m_start < m_end) { + s = (char *)m_start + *offset_ptr; + + // Advance the offset + if (fixed_length) + *offset_ptr += fixed_length; + else + *offset_ptr += strlen(s) + 1; + } + return s; } - //---------------------------------------------------------------------- // GetData //---------------------------------------------------------------------- -const uint8_t * -DNBDataRef::GetData(offset_t *offset_ptr, uint32_t length) const -{ - const uint8_t *data = NULL; - if ( length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length) ) - { - data = m_start + *offset_ptr; - *offset_ptr += length; - } - return data; +const uint8_t *DNBDataRef::GetData(offset_t *offset_ptr, + uint32_t length) const { + const uint8_t *data = NULL; + if (length > 0 && ValidOffsetForDataOfSize(*offset_ptr, length)) { + data = m_start + *offset_ptr; + *offset_ptr += length; + } + return data; } - //---------------------------------------------------------------------- // Get_ULEB128 //---------------------------------------------------------------------- -uint64_t -DNBDataRef::Get_ULEB128 (offset_t *offset_ptr) const -{ - uint64_t result = 0; - if ( m_start < m_end ) - { - int shift = 0; - const uint8_t *src = m_start + *offset_ptr; - uint8_t byte; - int bytecount = 0; - - while (src < m_end) - { - bytecount++; - byte = *src++; - result |= (uint64_t)(byte & 0x7f) << shift; - shift += 7; - if ((byte & 0x80) == 0) - break; - } - - *offset_ptr += bytecount; +uint64_t DNBDataRef::Get_ULEB128(offset_t *offset_ptr) const { + uint64_t result = 0; + if (m_start < m_end) { + int shift = 0; + const uint8_t *src = m_start + *offset_ptr; + uint8_t byte; + int bytecount = 0; + + while (src < m_end) { + bytecount++; + byte = *src++; + result |= (uint64_t)(byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; } - return result; -} + *offset_ptr += bytecount; + } + return result; +} //---------------------------------------------------------------------- // Get_SLEB128 //---------------------------------------------------------------------- -int64_t -DNBDataRef::Get_SLEB128 (offset_t *offset_ptr) const -{ - int64_t result = 0; - - if ( m_start < m_end ) - { - int shift = 0; - int size = sizeof (uint32_t) * 8; - const uint8_t *src = m_start + *offset_ptr; - - uint8_t byte = 0; - int bytecount = 0; - - while (src < m_end) - { - bytecount++; - byte = *src++; - result |= (int64_t)(byte & 0x7f) << shift; - shift += 7; - if ((byte & 0x80) == 0) - break; - } - - // Sign bit of byte is 2nd high order bit (0x40) - if (shift < size && (byte & 0x40)) - result |= - (1ll << shift); - - *offset_ptr += bytecount; +int64_t DNBDataRef::Get_SLEB128(offset_t *offset_ptr) const { + int64_t result = 0; + + if (m_start < m_end) { + int shift = 0; + int size = sizeof(uint32_t) * 8; + const uint8_t *src = m_start + *offset_ptr; + + uint8_t byte = 0; + int bytecount = 0; + + while (src < m_end) { + bytecount++; + byte = *src++; + result |= (int64_t)(byte & 0x7f) << shift; + shift += 7; + if ((byte & 0x80) == 0) + break; } - return result; -} + // Sign bit of byte is 2nd high order bit (0x40) + if (shift < size && (byte & 0x40)) + result |= -(1ll << shift); + + *offset_ptr += bytecount; + } + return result; +} //---------------------------------------------------------------------- // Skip_LEB128 // // Skips past ULEB128 and SLEB128 numbers (just updates the offset) //---------------------------------------------------------------------- -void -DNBDataRef::Skip_LEB128 (offset_t *offset_ptr) const -{ - if ( m_start < m_end ) - { - const uint8_t *start = m_start + *offset_ptr; - const uint8_t *src = start; - - while ((src < m_end) && (*src++ & 0x80)) - /* Do nothing */; - - *offset_ptr += src - start; - } +void DNBDataRef::Skip_LEB128(offset_t *offset_ptr) const { + if (m_start < m_end) { + const uint8_t *start = m_start + *offset_ptr; + const uint8_t *src = start; + + while ((src < m_end) && (*src++ & 0x80)) + /* Do nothing */; + + *offset_ptr += src - start; + } } -uint32_t -DNBDataRef::Dump -( - uint32_t startOffset, - uint32_t endOffset, - uint64_t offsetBase, - DNBDataRef::Type type, - uint32_t numPerLine, - const char *format -) -{ - uint32_t offset; - uint32_t count; - char str[1024]; - str[0] = '\0'; - size_t str_offset = 0; - - for (offset = startOffset, count = 0; ValidOffset(offset) && offset < endOffset; ++count) - { - if ((count % numPerLine) == 0) - { - // Print out any previous string - if (str[0] != '\0') - DNBLog("%s", str); - // Reset string offset and fill the current line string with address: - str_offset = 0; - str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", (uint64_t)(offsetBase + (offset - startOffset))); - } - - // Make sure we don't pass the bounds of our current string buffer on each iteration through this loop - if (str_offset >= sizeof(str)) - { - // The last snprintf consumed our string buffer, we will need to dump this out - // and reset the string with no address - DNBLog("%s", str); - str_offset = 0; - str[0] = '\0'; - } - - // We already checked that there is at least some room in the string str above, so it is safe to make - // the snprintf call each time through this loop - switch (type) - { - case TypeUInt8: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %2.2x", Get8(&offset)); break; - case TypeChar: - { - char ch = Get8(&offset); - str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %c", isprint(ch) ? ch : ' '); - } - break; - case TypeUInt16: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %4.4x", Get16(&offset)); break; - case TypeUInt32: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %8.8x", Get32(&offset)); break; - case TypeUInt64: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %16.16llx", Get64(&offset)); break; - case TypePointer: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", GetPointer(&offset)); break; - case TypeULEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " 0x%llx", Get_ULEB128(&offset)); break; - case TypeSLEB128: str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, format ? format : " %lld", Get_SLEB128(&offset)); break; - } +uint32_t DNBDataRef::Dump(uint32_t startOffset, uint32_t endOffset, + uint64_t offsetBase, DNBDataRef::Type type, + uint32_t numPerLine, const char *format) { + uint32_t offset; + uint32_t count; + char str[1024]; + str[0] = '\0'; + size_t str_offset = 0; + + for (offset = startOffset, count = 0; + ValidOffset(offset) && offset < endOffset; ++count) { + if ((count % numPerLine) == 0) { + // Print out any previous string + if (str[0] != '\0') + DNBLog("%s", str); + // Reset string offset and fill the current line string with address: + str_offset = 0; + str_offset += snprintf(str, sizeof(str), "0x%8.8llx:", + (uint64_t)(offsetBase + (offset - startOffset))); } - if (str[0] != '\0') - DNBLog("%s", str); + // Make sure we don't pass the bounds of our current string buffer on each + // iteration through this loop + if (str_offset >= sizeof(str)) { + // The last snprintf consumed our string buffer, we will need to dump this + // out + // and reset the string with no address + DNBLog("%s", str); + str_offset = 0; + str[0] = '\0'; + } + + // We already checked that there is at least some room in the string str + // above, so it is safe to make + // the snprintf call each time through this loop + switch (type) { + case TypeUInt8: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %2.2x", Get8(&offset)); + break; + case TypeChar: { + char ch = Get8(&offset); + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %c", isprint(ch) ? ch : ' '); + } break; + case TypeUInt16: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %4.4x", Get16(&offset)); + break; + case TypeUInt32: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %8.8x", Get32(&offset)); + break; + case TypeUInt64: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %16.16llx", Get64(&offset)); + break; + case TypePointer: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " 0x%llx", GetPointer(&offset)); + break; + case TypeULEB128: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " 0x%llx", Get_ULEB128(&offset)); + break; + case TypeSLEB128: + str_offset += snprintf(str + str_offset, sizeof(str) - str_offset, + format ? format : " %lld", Get_SLEB128(&offset)); + break; + } + } + + if (str[0] != '\0') + DNBLog("%s", str); - return offset; // Return the offset at which we ended up + return offset; // Return the offset at which we ended up } diff --git a/lldb/tools/debugserver/source/DNBDataRef.h b/lldb/tools/debugserver/source/DNBDataRef.h index d0c34ced623..9a19f20227e 100644 --- a/lldb/tools/debugserver/source/DNBDataRef.h +++ b/lldb/tools/debugserver/source/DNBDataRef.h @@ -24,102 +24,102 @@ #define __DNBDataRef_h__ #include "DNBDefs.h" +#include <limits.h> #include <stdint.h> #include <stdio.h> #include <string.h> -#include <limits.h> -class DNBDataRef -{ +class DNBDataRef { public: - // For use with Dump - typedef enum - { - TypeUInt8 = 0, - TypeChar, - TypeUInt16, - TypeUInt32, - TypeUInt64, - TypePointer, - TypeULEB128, - TypeSLEB128 - } Type; - typedef uint32_t offset_t; - typedef nub_addr_t addr_t; + // For use with Dump + typedef enum { + TypeUInt8 = 0, + TypeChar, + TypeUInt16, + TypeUInt32, + TypeUInt64, + TypePointer, + TypeULEB128, + TypeSLEB128 + } Type; + typedef uint32_t offset_t; + typedef nub_addr_t addr_t; + + DNBDataRef(); + DNBDataRef(const uint8_t *start, size_t size, bool swap); + ~DNBDataRef(); + void Clear() { + DNBDataRef::SetData(NULL, 0); + m_swap = false; + } - DNBDataRef(); - DNBDataRef(const uint8_t *start, size_t size, bool swap); - ~DNBDataRef(); - void Clear() - { - DNBDataRef::SetData(NULL, 0); - m_swap = false; - } + size_t BytesLeft(size_t offset) const { + const size_t size = GetSize(); + if (size > offset) + return size - offset; + return 0; + } - size_t BytesLeft (size_t offset) const - { - const size_t size = GetSize(); - if (size > offset) - return size - offset; - return 0; - } + bool ValidOffset(offset_t offset) const { return BytesLeft(offset) > 0; } + bool ValidOffsetForDataOfSize(offset_t offset, uint32_t num_bytes) const { + return num_bytes <= BytesLeft(offset); + } + size_t GetSize() const { return m_end - m_start; } + const uint8_t *GetDataStart() const { return m_start; } + const uint8_t *GetDataEnd() const { return m_end; } + bool GetSwap() const { return m_swap; } + void SetSwap(bool swap) { m_swap = swap; } + void SetData(const uint8_t *start, size_t size) { + m_start = start; + if (m_start != NULL) + m_end = start + size; + else + m_end = NULL; + } + uint8_t GetPointerSize() const { return m_ptrSize; } + void SetPointerSize(uint8_t size) { m_ptrSize = size; } + void SetEHPtrBaseAddrPCRelative(addr_t addr = INVALID_NUB_ADDRESS) { + m_addrPCRelative = addr; + } + void SetEHPtrBaseAddrTEXT(addr_t addr = INVALID_NUB_ADDRESS) { + m_addrTEXT = addr; + } + void SetEHPtrBaseAddrDATA(addr_t addr = INVALID_NUB_ADDRESS) { + m_addrDATA = addr; + } + uint8_t Get8(offset_t *offset_ptr) const; + uint16_t Get16(offset_t *offset_ptr) const; + uint32_t Get32(offset_t *offset_ptr) const; + uint64_t Get64(offset_t *offset_ptr) const; + uint32_t GetMax32(offset_t *offset_ptr, uint32_t byte_size) const; + uint64_t GetMax64(offset_t *offset_ptr, uint32_t byte_size) const; + uint64_t GetPointer(offset_t *offset_ptr) const; + // uint64_t GetDwarfEHPtr(offset_t *offset_ptr, uint32_t eh_ptr_enc) + // const; + const char *GetCStr(offset_t *offset_ptr, uint32_t fixed_length = 0) const; + const char *PeekCStr(offset_t offset) const { + if (ValidOffset(offset)) + return (const char *)m_start + offset; + return NULL; + } - bool ValidOffset(offset_t offset) const - { - return BytesLeft(offset) > 0; - } - bool ValidOffsetForDataOfSize(offset_t offset, uint32_t num_bytes) const - { - return num_bytes <= BytesLeft (offset); - } - size_t GetSize() const { return m_end - m_start; } - const uint8_t * GetDataStart() const { return m_start; } - const uint8_t * GetDataEnd() const { return m_end; } - bool GetSwap() const { return m_swap; } - void SetSwap(bool swap) { m_swap = swap; } - void SetData(const uint8_t *start, size_t size) - { - m_start = start; - if (m_start != NULL) - m_end = start + size; - else - m_end = NULL; - } - uint8_t GetPointerSize() const { return m_ptrSize; } - void SetPointerSize(uint8_t size) { m_ptrSize = size; } - void SetEHPtrBaseAddrPCRelative(addr_t addr = INVALID_NUB_ADDRESS) { m_addrPCRelative = addr; } - void SetEHPtrBaseAddrTEXT(addr_t addr = INVALID_NUB_ADDRESS) { m_addrTEXT = addr; } - void SetEHPtrBaseAddrDATA(addr_t addr = INVALID_NUB_ADDRESS) { m_addrDATA = addr; } - uint8_t Get8(offset_t *offset_ptr) const; - uint16_t Get16(offset_t *offset_ptr) const; - uint32_t Get32(offset_t *offset_ptr) const; - uint64_t Get64(offset_t *offset_ptr) const; - uint32_t GetMax32(offset_t *offset_ptr, uint32_t byte_size) const; - uint64_t GetMax64(offset_t *offset_ptr, uint32_t byte_size) const; - uint64_t GetPointer(offset_t *offset_ptr) const; -// uint64_t GetDwarfEHPtr(offset_t *offset_ptr, uint32_t eh_ptr_enc) const; - const char * GetCStr(offset_t *offset_ptr, uint32_t fixed_length = 0) const; - const char * PeekCStr(offset_t offset) const - { - if (ValidOffset(offset)) - return (const char*)m_start + offset; - return NULL; - } + const uint8_t *GetData(offset_t *offset_ptr, uint32_t length) const; + uint64_t Get_ULEB128(offset_t *offset_ptr) const; + int64_t Get_SLEB128(offset_t *offset_ptr) const; + void Skip_LEB128(offset_t *offset_ptr) const; - const uint8_t * GetData( offset_t *offset_ptr, uint32_t length) const; - uint64_t Get_ULEB128 (offset_t *offset_ptr) const; - int64_t Get_SLEB128 (offset_t *offset_ptr) const; - void Skip_LEB128 (offset_t *offset_ptr) const; + uint32_t Dump(offset_t startOffset, offset_t endOffset, uint64_t offsetBase, + DNBDataRef::Type type, uint32_t numPerLine, + const char *typeFormat = NULL); - uint32_t Dump(offset_t startOffset, offset_t endOffset, uint64_t offsetBase, DNBDataRef::Type type, uint32_t numPerLine, const char *typeFormat = NULL); protected: - const uint8_t * m_start; - const uint8_t * m_end; - bool m_swap; - uint8_t m_ptrSize; - addr_t m_addrPCRelative; - addr_t m_addrTEXT; - addr_t m_addrDATA; + const uint8_t *m_start; + const uint8_t *m_end; + bool m_swap; + uint8_t m_ptrSize; + addr_t m_addrPCRelative; + addr_t m_addrTEXT; + addr_t m_addrDATA; }; #endif // #ifndef __DNBDataRef_h__ diff --git a/lldb/tools/debugserver/source/DNBDefs.h b/lldb/tools/debugserver/source/DNBDefs.h index 36efad22417..5762bd16e2b 100644 --- a/lldb/tools/debugserver/source/DNBDefs.h +++ b/lldb/tools/debugserver/source/DNBDefs.h @@ -14,8 +14,8 @@ #ifndef __DNBDefs_h__ #define __DNBDefs_h__ -#include <stdint.h> #include <signal.h> +#include <stdint.h> #include <stdio.h> #include <sys/syslimits.h> #include <unistd.h> @@ -23,22 +23,24 @@ //---------------------------------------------------------------------- // Define nub_addr_t and the invalid address value from the architecture //---------------------------------------------------------------------- -#if defined (__x86_64__) || defined (__ppc64__) || defined (__arm64__) || defined (__aarch64__) +#if defined(__x86_64__) || defined(__ppc64__) || defined(__arm64__) || \ + defined(__aarch64__) //---------------------------------------------------------------------- // 64 bit address architectures //---------------------------------------------------------------------- -typedef uint64_t nub_addr_t; -#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull) +typedef uint64_t nub_addr_t; +#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull) -#elif defined (__i386__) || defined (__powerpc__) || defined (__ppc__) || defined (__arm__) +#elif defined(__i386__) || defined(__powerpc__) || defined(__ppc__) || \ + defined(__arm__) //---------------------------------------------------------------------- // 32 bit address architectures //---------------------------------------------------------------------- -typedef uint32_t nub_addr_t; -#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ul) +typedef uint32_t nub_addr_t; +#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ul) #else @@ -47,327 +49,325 @@ typedef uint32_t nub_addr_t; //---------------------------------------------------------------------- #warning undefined architecture, defaulting to 8 byte addresses -typedef uint64_t nub_addr_t; -#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull) - +typedef uint64_t nub_addr_t; +#define INVALID_NUB_ADDRESS ((nub_addr_t)~0ull) #endif -typedef size_t nub_size_t; -typedef ssize_t nub_ssize_t; -typedef uint32_t nub_index_t; -typedef pid_t nub_process_t; -typedef uint64_t nub_thread_t; -typedef uint32_t nub_event_t; -typedef uint32_t nub_bool_t; - -#define INVALID_NUB_PROCESS ((nub_process_t)0) -#define INVALID_NUB_THREAD ((nub_thread_t)0) -#define INVALID_NUB_WATCH_ID ((nub_watch_t)0) -#define INVALID_NUB_HW_INDEX UINT32_MAX -#define INVALID_NUB_REGNUM UINT32_MAX -#define NUB_GENERIC_ERROR UINT32_MAX +typedef size_t nub_size_t; +typedef ssize_t nub_ssize_t; +typedef uint32_t nub_index_t; +typedef pid_t nub_process_t; +typedef uint64_t nub_thread_t; +typedef uint32_t nub_event_t; +typedef uint32_t nub_bool_t; + +#define INVALID_NUB_PROCESS ((nub_process_t)0) +#define INVALID_NUB_THREAD ((nub_thread_t)0) +#define INVALID_NUB_WATCH_ID ((nub_watch_t)0) +#define INVALID_NUB_HW_INDEX UINT32_MAX +#define INVALID_NUB_REGNUM UINT32_MAX +#define NUB_GENERIC_ERROR UINT32_MAX // Watchpoint types -#define WATCH_TYPE_READ (1u << 0) -#define WATCH_TYPE_WRITE (1u << 1) - -typedef enum -{ - eStateInvalid = 0, - eStateUnloaded, - eStateAttaching, - eStateLaunching, - eStateStopped, - eStateRunning, - eStateStepping, - eStateCrashed, - eStateDetached, - eStateExited, - eStateSuspended +#define WATCH_TYPE_READ (1u << 0) +#define WATCH_TYPE_WRITE (1u << 1) + +typedef enum { + eStateInvalid = 0, + eStateUnloaded, + eStateAttaching, + eStateLaunching, + eStateStopped, + eStateRunning, + eStateStepping, + eStateCrashed, + eStateDetached, + eStateExited, + eStateSuspended } nub_state_t; -typedef enum -{ - eLaunchFlavorDefault = 0, - eLaunchFlavorPosixSpawn = 1, - eLaunchFlavorForkExec = 2, +typedef enum { + eLaunchFlavorDefault = 0, + eLaunchFlavorPosixSpawn = 1, + eLaunchFlavorForkExec = 2, #ifdef WITH_SPRINGBOARD - eLaunchFlavorSpringBoard = 3, + eLaunchFlavorSpringBoard = 3, #endif #ifdef WITH_BKS - eLaunchFlavorBKS = 4, + eLaunchFlavorBKS = 4, #endif #ifdef WITH_FBS - eLaunchFlavorFBS = 5 + eLaunchFlavorFBS = 5 #endif } nub_launch_flavor_t; -#define NUB_STATE_IS_RUNNING(s) ((s) == eStateAttaching ||\ - (s) == eStateLaunching ||\ - (s) == eStateRunning ||\ - (s) == eStateStepping ||\ - (s) == eStateDetached) - -#define NUB_STATE_IS_STOPPED(s) ((s) == eStateUnloaded ||\ - (s) == eStateStopped ||\ - (s) == eStateCrashed ||\ - (s) == eStateExited) - -enum -{ - eEventProcessRunningStateChanged = 1 << 0, // The process has changed state to running - eEventProcessStoppedStateChanged = 1 << 1, // The process has changed state to stopped - eEventSharedLibsStateChange = 1 << 2, // Shared libraries loaded/unloaded state has changed - eEventStdioAvailable = 1 << 3, // Something is available on stdout/stderr - eEventProfileDataAvailable = 1 << 4, // Profile data ready for retrieval - kAllEventsMask = eEventProcessRunningStateChanged | - eEventProcessStoppedStateChanged | - eEventSharedLibsStateChange | - eEventStdioAvailable | - eEventProfileDataAvailable +#define NUB_STATE_IS_RUNNING(s) \ + ((s) == eStateAttaching || (s) == eStateLaunching || (s) == eStateRunning || \ + (s) == eStateStepping || (s) == eStateDetached) + +#define NUB_STATE_IS_STOPPED(s) \ + ((s) == eStateUnloaded || (s) == eStateStopped || (s) == eStateCrashed || \ + (s) == eStateExited) + +enum { + eEventProcessRunningStateChanged = + 1 << 0, // The process has changed state to running + eEventProcessStoppedStateChanged = + 1 << 1, // The process has changed state to stopped + eEventSharedLibsStateChange = + 1 << 2, // Shared libraries loaded/unloaded state has changed + eEventStdioAvailable = 1 << 3, // Something is available on stdout/stderr + eEventProfileDataAvailable = 1 << 4, // Profile data ready for retrieval + kAllEventsMask = eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged | + eEventSharedLibsStateChange | eEventStdioAvailable | + eEventProfileDataAvailable }; -#define LOG_VERBOSE (1u << 0) -#define LOG_PROCESS (1u << 1) -#define LOG_THREAD (1u << 2) -#define LOG_EXCEPTIONS (1u << 3) -#define LOG_SHLIB (1u << 4) -#define LOG_MEMORY (1u << 5) // Log memory reads/writes calls -#define LOG_MEMORY_DATA_SHORT (1u << 6) // Log short memory reads/writes bytes -#define LOG_MEMORY_DATA_LONG (1u << 7) // Log all memory reads/writes bytes -#define LOG_MEMORY_PROTECTIONS (1u << 8) // Log memory protection changes -#define LOG_BREAKPOINTS (1u << 9) -#define LOG_EVENTS (1u << 10) -#define LOG_WATCHPOINTS (1u << 11) -#define LOG_STEP (1u << 12) -#define LOG_TASK (1u << 13) -#define LOG_DARWIN_LOG (1u << 14) -#define LOG_LO_USER (1u << 16) -#define LOG_HI_USER (1u << 31) -#define LOG_ALL 0xFFFFFFFFu -#define LOG_DEFAULT ((LOG_PROCESS) |\ - (LOG_TASK) |\ - (LOG_THREAD) |\ - (LOG_EXCEPTIONS) |\ - (LOG_SHLIB) |\ - (LOG_MEMORY) |\ - (LOG_BREAKPOINTS) |\ - (LOG_WATCHPOINTS) |\ - (LOG_STEP)) - - -#define REGISTER_SET_ALL 0 +#define LOG_VERBOSE (1u << 0) +#define LOG_PROCESS (1u << 1) +#define LOG_THREAD (1u << 2) +#define LOG_EXCEPTIONS (1u << 3) +#define LOG_SHLIB (1u << 4) +#define LOG_MEMORY (1u << 5) // Log memory reads/writes calls +#define LOG_MEMORY_DATA_SHORT (1u << 6) // Log short memory reads/writes bytes +#define LOG_MEMORY_DATA_LONG (1u << 7) // Log all memory reads/writes bytes +#define LOG_MEMORY_PROTECTIONS (1u << 8) // Log memory protection changes +#define LOG_BREAKPOINTS (1u << 9) +#define LOG_EVENTS (1u << 10) +#define LOG_WATCHPOINTS (1u << 11) +#define LOG_STEP (1u << 12) +#define LOG_TASK (1u << 13) +#define LOG_DARWIN_LOG (1u << 14) +#define LOG_LO_USER (1u << 16) +#define LOG_HI_USER (1u << 31) +#define LOG_ALL 0xFFFFFFFFu +#define LOG_DEFAULT \ + ((LOG_PROCESS) | (LOG_TASK) | (LOG_THREAD) | (LOG_EXCEPTIONS) | \ + (LOG_SHLIB) | (LOG_MEMORY) | (LOG_BREAKPOINTS) | (LOG_WATCHPOINTS) | \ + (LOG_STEP)) + +#define REGISTER_SET_ALL 0 // Generic Register set to be defined by each architecture for access to common // register values. -#define REGISTER_SET_GENERIC ((uint32_t)0xFFFFFFFFu) -#define GENERIC_REGNUM_PC 0 // Program Counter -#define GENERIC_REGNUM_SP 1 // Stack Pointer -#define GENERIC_REGNUM_FP 2 // Frame Pointer -#define GENERIC_REGNUM_RA 3 // Return Address -#define GENERIC_REGNUM_FLAGS 4 // Processor flags register -#define GENERIC_REGNUM_ARG1 5 // The register that would contain pointer size or less argument 1 (if any) -#define GENERIC_REGNUM_ARG2 6 // The register that would contain pointer size or less argument 2 (if any) -#define GENERIC_REGNUM_ARG3 7 // The register that would contain pointer size or less argument 3 (if any) -#define GENERIC_REGNUM_ARG4 8 // The register that would contain pointer size or less argument 4 (if any) -#define GENERIC_REGNUM_ARG5 9 // The register that would contain pointer size or less argument 5 (if any) -#define GENERIC_REGNUM_ARG6 10 // The register that would contain pointer size or less argument 6 (if any) -#define GENERIC_REGNUM_ARG7 11 // The register that would contain pointer size or less argument 7 (if any) -#define GENERIC_REGNUM_ARG8 12 // The register that would contain pointer size or less argument 8 (if any) - -enum DNBRegisterType -{ - InvalidRegType = 0, - Uint, // unsigned integer - Sint, // signed integer - IEEE754, // float - Vector // vector registers +#define REGISTER_SET_GENERIC ((uint32_t)0xFFFFFFFFu) +#define GENERIC_REGNUM_PC 0 // Program Counter +#define GENERIC_REGNUM_SP 1 // Stack Pointer +#define GENERIC_REGNUM_FP 2 // Frame Pointer +#define GENERIC_REGNUM_RA 3 // Return Address +#define GENERIC_REGNUM_FLAGS 4 // Processor flags register +#define GENERIC_REGNUM_ARG1 \ + 5 // The register that would contain pointer size or less argument 1 (if any) +#define GENERIC_REGNUM_ARG2 \ + 6 // The register that would contain pointer size or less argument 2 (if any) +#define GENERIC_REGNUM_ARG3 \ + 7 // The register that would contain pointer size or less argument 3 (if any) +#define GENERIC_REGNUM_ARG4 \ + 8 // The register that would contain pointer size or less argument 4 (if any) +#define GENERIC_REGNUM_ARG5 \ + 9 // The register that would contain pointer size or less argument 5 (if any) +#define GENERIC_REGNUM_ARG6 \ + 10 // The register that would contain pointer size or less argument 6 (if any) +#define GENERIC_REGNUM_ARG7 \ + 11 // The register that would contain pointer size or less argument 7 (if any) +#define GENERIC_REGNUM_ARG8 \ + 12 // The register that would contain pointer size or less argument 8 (if any) + +enum DNBRegisterType { + InvalidRegType = 0, + Uint, // unsigned integer + Sint, // signed integer + IEEE754, // float + Vector // vector registers }; -enum DNBRegisterFormat -{ - InvalidRegFormat = 0, - Binary, - Decimal, - Hex, - Float, - VectorOfSInt8, - VectorOfUInt8, - VectorOfSInt16, - VectorOfUInt16, - VectorOfSInt32, - VectorOfUInt32, - VectorOfFloat32, - VectorOfUInt128 +enum DNBRegisterFormat { + InvalidRegFormat = 0, + Binary, + Decimal, + Hex, + Float, + VectorOfSInt8, + VectorOfUInt8, + VectorOfSInt16, + VectorOfUInt16, + VectorOfSInt32, + VectorOfUInt32, + VectorOfFloat32, + VectorOfUInt128 }; -struct DNBRegisterInfo -{ - uint32_t set; // Register set - uint32_t reg; // Register number - const char *name; // Name of this register - const char *alt; // Alternate name - uint16_t type; // Type of the register bits (DNBRegisterType) - uint16_t format; // Default format for display (DNBRegisterFormat), - uint32_t size; // Size in bytes of the register - uint32_t offset; // Offset from the beginning of the register context - uint32_t reg_ehframe; // eh_frame register number (INVALID_NUB_REGNUM when none) - uint32_t reg_dwarf; // DWARF register number (INVALID_NUB_REGNUM when none) - uint32_t reg_generic; // Generic register number (INVALID_NUB_REGNUM when none) - uint32_t reg_debugserver;// The debugserver register number we'll use over gdb-remote protocol (INVALID_NUB_REGNUM when none) - const char **value_regs; // If this register is a part of other registers, list the register names terminated by NULL - const char **update_regs; // If modifying this register will invalidate other registers, list the register names terminated by NULL +struct DNBRegisterInfo { + uint32_t set; // Register set + uint32_t reg; // Register number + const char *name; // Name of this register + const char *alt; // Alternate name + uint16_t type; // Type of the register bits (DNBRegisterType) + uint16_t format; // Default format for display (DNBRegisterFormat), + uint32_t size; // Size in bytes of the register + uint32_t offset; // Offset from the beginning of the register context + uint32_t + reg_ehframe; // eh_frame register number (INVALID_NUB_REGNUM when none) + uint32_t reg_dwarf; // DWARF register number (INVALID_NUB_REGNUM when none) + uint32_t + reg_generic; // Generic register number (INVALID_NUB_REGNUM when none) + uint32_t reg_debugserver; // The debugserver register number we'll use over + // gdb-remote protocol (INVALID_NUB_REGNUM when + // none) + const char **value_regs; // If this register is a part of other registers, + // list the register names terminated by NULL + const char **update_regs; // If modifying this register will invalidate other + // registers, list the register names terminated by + // NULL }; -struct DNBRegisterSetInfo -{ - const char *name; // Name of this register set - const struct DNBRegisterInfo *registers; // An array of register descriptions - nub_size_t num_registers; // The number of registers in REGISTERS array above +struct DNBRegisterSetInfo { + const char *name; // Name of this register set + const struct DNBRegisterInfo *registers; // An array of register descriptions + nub_size_t num_registers; // The number of registers in REGISTERS array above }; -struct DNBThreadResumeAction -{ - nub_thread_t tid; // The thread ID that this action applies to, INVALID_NUB_THREAD for the default thread action - nub_state_t state; // Valid values are eStateStopped/eStateSuspended, eStateRunning, and eStateStepping. - int signal; // When resuming this thread, resume it with this signal - nub_addr_t addr; // If not INVALID_NUB_ADDRESS, then set the PC for the thread to ADDR before resuming/stepping +struct DNBThreadResumeAction { + nub_thread_t tid; // The thread ID that this action applies to, + // INVALID_NUB_THREAD for the default thread action + nub_state_t state; // Valid values are eStateStopped/eStateSuspended, + // eStateRunning, and eStateStepping. + int signal; // When resuming this thread, resume it with this signal + nub_addr_t addr; // If not INVALID_NUB_ADDRESS, then set the PC for the thread + // to ADDR before resuming/stepping }; -enum DNBThreadStopType -{ - eStopTypeInvalid = 0, - eStopTypeSignal, - eStopTypeException, - eStopTypeExec +enum DNBThreadStopType { + eStopTypeInvalid = 0, + eStopTypeSignal, + eStopTypeException, + eStopTypeExec }; -enum DNBMemoryPermissions -{ - eMemoryPermissionsWritable = (1 << 0), - eMemoryPermissionsReadable = (1 << 1), - eMemoryPermissionsExecutable = (1 << 2) +enum DNBMemoryPermissions { + eMemoryPermissionsWritable = (1 << 0), + eMemoryPermissionsReadable = (1 << 1), + eMemoryPermissionsExecutable = (1 << 2) }; -#define DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH 256 -#define DNB_THREAD_STOP_INFO_MAX_EXC_DATA 8 +#define DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH 256 +#define DNB_THREAD_STOP_INFO_MAX_EXC_DATA 8 //---------------------------------------------------------------------- // DNBThreadStopInfo // // Describes the reason a thread stopped. //---------------------------------------------------------------------- -struct DNBThreadStopInfo -{ - DNBThreadStopType reason; - char description[DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH]; - union - { - // eStopTypeSignal - struct - { - uint32_t signo; - } signal; - - // eStopTypeException - struct - { - uint32_t type; - nub_size_t data_count; - nub_addr_t data[DNB_THREAD_STOP_INFO_MAX_EXC_DATA]; - } exception; - } details; +struct DNBThreadStopInfo { + DNBThreadStopType reason; + char description[DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH]; + union { + // eStopTypeSignal + struct { + uint32_t signo; + } signal; + + // eStopTypeException + struct { + uint32_t type; + nub_size_t data_count; + nub_addr_t data[DNB_THREAD_STOP_INFO_MAX_EXC_DATA]; + } exception; + } details; }; - -struct DNBRegisterValue -{ - struct DNBRegisterInfo info; // Register information for this register - union - { - int8_t sint8; - int16_t sint16; - int32_t sint32; - int64_t sint64; - uint8_t uint8; - uint16_t uint16; - uint32_t uint32; - uint64_t uint64; - float float32; - double float64; - int8_t v_sint8[32]; - int16_t v_sint16[16]; - int32_t v_sint32[8]; - int64_t v_sint64[4]; - uint8_t v_uint8[32]; - uint16_t v_uint16[16]; - uint32_t v_uint32[8]; - uint64_t v_uint64[4]; - float v_float32[8]; - double v_float64[4]; - void *pointer; - char *c_str; - } value; +struct DNBRegisterValue { + struct DNBRegisterInfo info; // Register information for this register + union { + int8_t sint8; + int16_t sint16; + int32_t sint32; + int64_t sint64; + uint8_t uint8; + uint16_t uint16; + uint32_t uint32; + uint64_t uint64; + float float32; + double float64; + int8_t v_sint8[32]; + int16_t v_sint16[16]; + int32_t v_sint32[8]; + int64_t v_sint64[4]; + uint8_t v_uint8[32]; + uint16_t v_uint16[16]; + uint32_t v_uint32[8]; + uint64_t v_uint64[4]; + float v_float32[8]; + double v_float64[4]; + void *pointer; + char *c_str; + } value; }; -enum DNBSharedLibraryState -{ - eShlibStateUnloaded = 0, - eShlibStateLoaded = 1 -}; +enum DNBSharedLibraryState { eShlibStateUnloaded = 0, eShlibStateLoaded = 1 }; #ifndef DNB_MAX_SEGMENT_NAME_LENGTH -#define DNB_MAX_SEGMENT_NAME_LENGTH 32 +#define DNB_MAX_SEGMENT_NAME_LENGTH 32 #endif -struct DNBSegment -{ - char name[DNB_MAX_SEGMENT_NAME_LENGTH]; - nub_addr_t addr; - nub_addr_t size; +struct DNBSegment { + char name[DNB_MAX_SEGMENT_NAME_LENGTH]; + nub_addr_t addr; + nub_addr_t size; }; -struct DNBExecutableImageInfo -{ - char name[PATH_MAX]; // Name of the executable image (usually a full path) - uint32_t state; // State of the executable image (see enum DNBSharedLibraryState) - nub_addr_t header_addr; // Executable header address - uuid_t uuid; // Unique identifier for matching with symbols - uint32_t num_segments; // Number of contiguous memory segments to in SEGMENTS array - DNBSegment *segments; // Array of contiguous memory segments in executable +struct DNBExecutableImageInfo { + char name[PATH_MAX]; // Name of the executable image (usually a full path) + uint32_t + state; // State of the executable image (see enum DNBSharedLibraryState) + nub_addr_t header_addr; // Executable header address + uuid_t uuid; // Unique identifier for matching with symbols + uint32_t + num_segments; // Number of contiguous memory segments to in SEGMENTS array + DNBSegment *segments; // Array of contiguous memory segments in executable }; -struct DNBRegionInfo -{ - nub_addr_t addr; - nub_addr_t size; - uint32_t permissions; +struct DNBRegionInfo { + nub_addr_t addr; + nub_addr_t size; + uint32_t permissions; }; -enum DNBProfileDataScanType -{ - eProfileHostCPU = (1 << 0), - eProfileCPU = (1 << 1), - - eProfileThreadsCPU = (1 << 2), // By default excludes eProfileThreadName and eProfileQueueName. - eProfileThreadName = (1 << 3), // Assume eProfileThreadsCPU, get thread name as well. - eProfileQueueName = (1 << 4), // Assume eProfileThreadsCPU, get queue name as well. - - eProfileHostMemory = (1 << 5), - - eProfileMemory = (1 << 6), // By default, excludes eProfileMemoryDirtyPage. - eProfileMemoryDirtyPage = (1 << 7), // Assume eProfileMemory, get Dirty Page size as well. - eProfileMemoryAnonymous = (1 << 8), // Assume eProfileMemory, get Anonymous memory as well. - - eProfileEnergy = (1 << 9), - - eProfileAll = 0xffffffff +enum DNBProfileDataScanType { + eProfileHostCPU = (1 << 0), + eProfileCPU = (1 << 1), + + eProfileThreadsCPU = + (1 << 2), // By default excludes eProfileThreadName and eProfileQueueName. + eProfileThreadName = + (1 << 3), // Assume eProfileThreadsCPU, get thread name as well. + eProfileQueueName = + (1 << 4), // Assume eProfileThreadsCPU, get queue name as well. + + eProfileHostMemory = (1 << 5), + + eProfileMemory = (1 << 6), // By default, excludes eProfileMemoryDirtyPage. + eProfileMemoryDirtyPage = + (1 << 7), // Assume eProfileMemory, get Dirty Page size as well. + eProfileMemoryAnonymous = + (1 << 8), // Assume eProfileMemory, get Anonymous memory as well. + + eProfileEnergy = (1 << 9), + + eProfileAll = 0xffffffff }; -typedef nub_addr_t (*DNBCallbackNameToAddress)(nub_process_t pid, const char *name, const char *shlib_regex, void *baton); -typedef nub_size_t (*DNBCallbackCopyExecutableImageInfos)(nub_process_t pid, struct DNBExecutableImageInfo **image_infos, nub_bool_t only_changed, void *baton); -typedef void (*DNBCallbackLog)(void *baton, uint32_t flags, const char *format, va_list args); +typedef nub_addr_t (*DNBCallbackNameToAddress)(nub_process_t pid, + const char *name, + const char *shlib_regex, + void *baton); +typedef nub_size_t (*DNBCallbackCopyExecutableImageInfos)( + nub_process_t pid, struct DNBExecutableImageInfo **image_infos, + nub_bool_t only_changed, void *baton); +typedef void (*DNBCallbackLog)(void *baton, uint32_t flags, const char *format, + va_list args); #define UNUSED_IF_ASSERT_DISABLED(x) ((void)(x)) -#endif // #ifndef __DNBDefs_h__ +#endif // #ifndef __DNBDefs_h__ diff --git a/lldb/tools/debugserver/source/DNBError.cpp b/lldb/tools/debugserver/source/DNBError.cpp index c9d8ebd58d8..cd04358a4ec 100644 --- a/lldb/tools/debugserver/source/DNBError.cpp +++ b/lldb/tools/debugserver/source/DNBError.cpp @@ -20,109 +20,97 @@ #include <SpringBoardServices/SpringBoardServer.h> #endif -const char * -DNBError::AsString() const -{ - if (Success()) - return NULL; +const char *DNBError::AsString() const { + if (Success()) + return NULL; - if (m_str.empty()) - { - const char *s = NULL; - switch (m_flavor) - { - case MachKernel: - s = ::mach_error_string (m_err); - break; + if (m_str.empty()) { + const char *s = NULL; + switch (m_flavor) { + case MachKernel: + s = ::mach_error_string(m_err); + break; - case POSIX: - s = ::strerror (m_err); - break; + case POSIX: + s = ::strerror(m_err); + break; #ifdef WITH_SPRINGBOARD - case SpringBoard: - { - CFStringRef statusStr = SBSApplicationLaunchingErrorString (m_err); - if (CFString::UTF8 (statusStr, m_str) == NULL) - m_str.clear(); - } - break; + case SpringBoard: { + CFStringRef statusStr = SBSApplicationLaunchingErrorString(m_err); + if (CFString::UTF8(statusStr, m_str) == NULL) + m_str.clear(); + } break; #endif #ifdef WITH_BKS - case BackBoard: - { - // You have to call ObjC routines to get the error string from BackBoardServices. - // Not sure I want to make DNBError.cpp an .mm file. For now just make sure you - // pre-populate the error string when you make the DNBError of type BackBoard. - m_str.assign("Should have set BackBoard error when making the error string."); - } - break; + case BackBoard: { + // You have to call ObjC routines to get the error string from + // BackBoardServices. + // Not sure I want to make DNBError.cpp an .mm file. For now just make + // sure you + // pre-populate the error string when you make the DNBError of type + // BackBoard. + m_str.assign( + "Should have set BackBoard error when making the error string."); + } break; #endif #ifdef WITH_FBS - case FrontBoard: - { - // You have to call ObjC routines to get the error string from FrontBoardServices. - // Not sure I want to make DNBError.cpp an .mm file. For now just make sure you - // pre-populate the error string when you make the DNBError of type FrontBoard. - m_str.assign("Should have set FrontBoard error when making the error string."); - } - break; + case FrontBoard: { + // You have to call ObjC routines to get the error string from + // FrontBoardServices. + // Not sure I want to make DNBError.cpp an .mm file. For now just make + // sure you + // pre-populate the error string when you make the DNBError of type + // FrontBoard. + m_str.assign( + "Should have set FrontBoard error when making the error string."); + } break; #endif - default: - break; - } - if (s) - m_str.assign(s); + default: + break; } - if (m_str.empty()) - return NULL; - return m_str.c_str(); + if (s) + m_str.assign(s); + } + if (m_str.empty()) + return NULL; + return m_str.c_str(); } -void -DNBError::LogThreadedIfError(const char *format, ...) const -{ - if (Fail()) - { - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); +void DNBError::LogThreadedIfError(const char *format, ...) const { + if (Fail()) { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); - if (arg_msg != NULL) - { - const char *err_str = AsString(); - if (err_str == NULL) - err_str = "???"; - DNBLogThreaded ("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err); - free (arg_msg); - } + if (arg_msg != NULL) { + const char *err_str = AsString(); + if (err_str == NULL) + err_str = "???"; + DNBLogThreaded("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err); + free(arg_msg); } + } } -void -DNBError::LogThreaded(const char *format, ...) const -{ - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); +void DNBError::LogThreaded(const char *format, ...) const { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); - if (arg_msg != NULL) - { - if (Fail()) - { - const char *err_str = AsString(); - if (err_str == NULL) - err_str = "???"; - DNBLogThreaded ("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err); - } - else - { - DNBLogThreaded ("%s err = 0x%8.8x", arg_msg, m_err); - } - free (arg_msg); + if (arg_msg != NULL) { + if (Fail()) { + const char *err_str = AsString(); + if (err_str == NULL) + err_str = "???"; + DNBLogThreaded("error: %s err = %s (0x%8.8x)", arg_msg, err_str, m_err); + } else { + DNBLogThreaded("%s err = 0x%8.8x", arg_msg, m_err); } + free(arg_msg); + } } diff --git a/lldb/tools/debugserver/source/DNBError.h b/lldb/tools/debugserver/source/DNBError.h index 274ae0d4477..edca38ad6db 100644 --- a/lldb/tools/debugserver/source/DNBError.h +++ b/lldb/tools/debugserver/source/DNBError.h @@ -19,84 +19,80 @@ #include <stdio.h> #include <string> -class DNBError -{ +class DNBError { public: - typedef uint32_t ValueType; - typedef enum - { - Generic = 0, - MachKernel = 1, - POSIX = 2 + typedef uint32_t ValueType; + typedef enum { + Generic = 0, + MachKernel = 1, + POSIX = 2 #ifdef WITH_SPRINGBOARD - , SpringBoard = 3 + , + SpringBoard = 3 #endif #ifdef WITH_BKS - , BackBoard = 4 + , + BackBoard = 4 #endif #ifdef WITH_FBS - , FrontBoard = 5 + , + FrontBoard = 5 #endif - } FlavorType; + } FlavorType; - explicit DNBError( ValueType err = 0, - FlavorType flavor = Generic) : - m_err(err), - m_flavor(flavor) - { - } + explicit DNBError(ValueType err = 0, FlavorType flavor = Generic) + : m_err(err), m_flavor(flavor) {} - const char * AsString() const; - void Clear() { m_err = 0; m_flavor = Generic; m_str.clear(); } - ValueType Error() const { return m_err; } - FlavorType Flavor() const { return m_flavor; } + const char *AsString() const; + void Clear() { + m_err = 0; + m_flavor = Generic; + m_str.clear(); + } + ValueType Error() const { return m_err; } + FlavorType Flavor() const { return m_flavor; } - ValueType operator = (kern_return_t err) - { - m_err = err; - m_flavor = MachKernel; - m_str.clear(); - return m_err; - } + ValueType operator=(kern_return_t err) { + m_err = err; + m_flavor = MachKernel; + m_str.clear(); + return m_err; + } - void SetError(kern_return_t err) - { - m_err = err; - m_flavor = MachKernel; - m_str.clear(); - } + void SetError(kern_return_t err) { + m_err = err; + m_flavor = MachKernel; + m_str.clear(); + } - void SetErrorToErrno() - { - m_err = errno; - m_flavor = POSIX; - m_str.clear(); - } + void SetErrorToErrno() { + m_err = errno; + m_flavor = POSIX; + m_str.clear(); + } - void SetError(ValueType err, FlavorType flavor) - { - m_err = err; - m_flavor = flavor; - m_str.clear(); - } + void SetError(ValueType err, FlavorType flavor) { + m_err = err; + m_flavor = flavor; + m_str.clear(); + } + + // Generic errors can set their own string values + void SetErrorString(const char *err_str) { + if (err_str && err_str[0]) + m_str = err_str; + else + m_str.clear(); + } + bool Success() const { return m_err == 0; } + bool Fail() const { return m_err != 0; } + void LogThreadedIfError(const char *format, ...) const; + void LogThreaded(const char *format, ...) const; - // Generic errors can set their own string values - void SetErrorString(const char *err_str) - { - if (err_str && err_str[0]) - m_str = err_str; - else - m_str.clear(); - } - bool Success() const { return m_err == 0; } - bool Fail() const { return m_err != 0; } - void LogThreadedIfError(const char *format, ...) const; - void LogThreaded(const char *format, ...) const; protected: - ValueType m_err; - FlavorType m_flavor; - mutable std::string m_str; + ValueType m_err; + FlavorType m_flavor; + mutable std::string m_str; }; - -#endif // #ifndef __DNBError_h__ +#endif // #ifndef __DNBError_h__ diff --git a/lldb/tools/debugserver/source/DNBLog.cpp b/lldb/tools/debugserver/source/DNBLog.cpp index 18d8d2ad3a6..c3d42a2a84d 100644 --- a/lldb/tools/debugserver/source/DNBLog.cpp +++ b/lldb/tools/debugserver/source/DNBLog.cpp @@ -16,362 +16,272 @@ static int g_debug = 0; static int g_verbose = 0; -#if defined (DNBLOG_ENABLED) +#if defined(DNBLOG_ENABLED) -#include <stdio.h> +#include "PThreadMutex.h" +#include <mach/mach.h> +#include <pthread.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <sys/time.h> #include <unistd.h> -#include <mach/mach.h> -#include <pthread.h> -#include "PThreadMutex.h" uint32_t g_log_bits = 0; static DNBCallbackLog g_log_callback = NULL; static void *g_log_baton = NULL; +int DNBLogGetDebug() { return g_debug; } -int -DNBLogGetDebug () -{ - return g_debug; -} - +void DNBLogSetDebug(int g) { g_debug = g; } -void -DNBLogSetDebug (int g) -{ - g_debug = g; -} +int DNBLogGetVerbose() { return g_verbose; } -int -DNBLogGetVerbose () -{ - return g_verbose; -} +void DNBLogSetVerbose(int v) { g_verbose = v; } -void -DNBLogSetVerbose (int v) -{ - g_verbose = v; -} +bool DNBLogCheckLogBit(uint32_t bit) { return (g_log_bits & bit) != 0; } -bool -DNBLogCheckLogBit (uint32_t bit) -{ - return (g_log_bits & bit) != 0; +uint32_t DNBLogSetLogMask(uint32_t mask) { + uint32_t old = g_log_bits; + g_log_bits = mask; + return old; } -uint32_t -DNBLogSetLogMask (uint32_t mask) -{ - uint32_t old = g_log_bits; - g_log_bits = mask; - return old; -} +uint32_t DNBLogGetLogMask() { return g_log_bits; } -uint32_t -DNBLogGetLogMask () -{ - return g_log_bits; +void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton) { + g_log_callback = callback; + g_log_baton = baton; } -void -DNBLogSetLogCallback (DNBCallbackLog callback, void *baton) -{ - g_log_callback = callback; - g_log_baton = baton; -} +DNBCallbackLog DNBLogGetLogCallback() { return g_log_callback; } -DNBCallbackLog -DNBLogGetLogCallback () -{ - return g_log_callback; -} +bool DNBLogEnabled() { return g_log_callback != NULL; } -bool -DNBLogEnabled () -{ - return g_log_callback != NULL; +bool DNBLogEnabledForAny(uint32_t mask) { + if (g_log_callback) + return (g_log_bits & mask) != 0; + return false; } +static inline void _DNBLogVAPrintf(uint32_t flags, const char *format, + va_list args) { + static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE); + PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex); -bool -DNBLogEnabledForAny (uint32_t mask) -{ - if (g_log_callback) - return (g_log_bits & mask) != 0; - return false; -} -static inline void -_DNBLogVAPrintf(uint32_t flags, const char *format, va_list args) -{ - static PThreadMutex g_LogThreadedMutex(PTHREAD_MUTEX_RECURSIVE); - PTHREAD_MUTEX_LOCKER(locker, g_LogThreadedMutex); - - if (g_log_callback) - g_log_callback(g_log_baton, flags, format, args); + if (g_log_callback) + g_log_callback(g_log_baton, flags, format, args); } -void -_DNBLog(uint32_t flags, const char *format, ...) -{ - va_list args; - va_start (args, format); - _DNBLogVAPrintf(flags, format, args); - va_end (args); +void _DNBLog(uint32_t flags, const char *format, ...) { + va_list args; + va_start(args, format); + _DNBLogVAPrintf(flags, format, args); + va_end(args); } //---------------------------------------------------------------------- // Print debug strings if and only if the global g_debug is set to // a non-zero value. //---------------------------------------------------------------------- -void -_DNBLogDebug (const char *format, ...) -{ - if (DNBLogEnabled () && g_debug) - { - va_list args; - va_start (args, format); - _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args); - va_end (args); - } +void _DNBLogDebug(const char *format, ...) { + if (DNBLogEnabled() && g_debug) { + va_list args; + va_start(args, format); + _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG, format, args); + va_end(args); + } } - //---------------------------------------------------------------------- // Print debug strings if and only if the global g_debug is set to // a non-zero value. //---------------------------------------------------------------------- -void -_DNBLogDebugVerbose (const char *format, ...) -{ - if (DNBLogEnabled () && g_debug && g_verbose) - { - va_list args; - va_start (args, format); - _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args); - va_end (args); - } +void _DNBLogDebugVerbose(const char *format, ...) { + if (DNBLogEnabled() && g_debug && g_verbose) { + va_list args; + va_start(args, format); + _DNBLogVAPrintf(DNBLOG_FLAG_DEBUG | DNBLOG_FLAG_VERBOSE, format, args); + va_end(args); + } } - static uint32_t g_message_id = 0; //---------------------------------------------------------------------- // Prefix the formatted log string with process and thread IDs and // suffix it with a newline. //---------------------------------------------------------------------- -void -_DNBLogThreaded (const char *format, ...) -{ - if (DNBLogEnabled ()) - { - //PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); - - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - static struct timeval g_timeval = { 0 , 0 }; - static struct timeval tv; - static struct timeval delta; - gettimeofday(&tv, NULL); - if (g_timeval.tv_sec == 0) - { - delta.tv_sec = 0; - delta.tv_usec = 0; - } - else - { - timersub (&tv, &g_timeval, &delta); - } - g_timeval = tv; - - // Calling "mach_port_deallocate()" bumps the reference count on the thread - // port, so we need to deallocate it. mach_task_self() doesn't bump the ref - // count. - thread_port_t thread_self = mach_thread_self(); - - _DNBLog (DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", - ++g_message_id, - delta.tv_sec, - delta.tv_usec, - getpid(), - thread_self, - arg_msg); - - mach_port_deallocate(mach_task_self(), thread_self); - free (arg_msg); - } +void _DNBLogThreaded(const char *format, ...) { + if (DNBLogEnabled()) { + // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); + + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + static struct timeval g_timeval = {0, 0}; + static struct timeval tv; + static struct timeval delta; + gettimeofday(&tv, NULL); + if (g_timeval.tv_sec == 0) { + delta.tv_sec = 0; + delta.tv_usec = 0; + } else { + timersub(&tv, &g_timeval, &delta); + } + g_timeval = tv; + + // Calling "mach_port_deallocate()" bumps the reference count on the + // thread + // port, so we need to deallocate it. mach_task_self() doesn't bump the + // ref + // count. + thread_port_t thread_self = mach_thread_self(); + + _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", + ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(), + thread_self, arg_msg); + + mach_port_deallocate(mach_task_self(), thread_self); + free(arg_msg); } + } } //---------------------------------------------------------------------- // Prefix the formatted log string with process and thread IDs and // suffix it with a newline. //---------------------------------------------------------------------- -void -_DNBLogThreadedIf (uint32_t log_bit, const char *format, ...) -{ - if (DNBLogEnabled () && (log_bit & g_log_bits) == log_bit) - { - //PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); - - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - static struct timeval g_timeval = { 0 , 0 }; - static struct timeval tv; - static struct timeval delta; - gettimeofday(&tv, NULL); - if (g_timeval.tv_sec == 0) - { - delta.tv_sec = 0; - delta.tv_usec = 0; - } - else - { - timersub (&tv, &g_timeval, &delta); - } - g_timeval = tv; - - // Calling "mach_port_deallocate()" bumps the reference count on the thread - // port, so we need to deallocate it. mach_task_self() doesn't bump the ref - // count. - thread_port_t thread_self = mach_thread_self(); - - _DNBLog (DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", - ++g_message_id, - delta.tv_sec, - delta.tv_usec, - getpid(), - thread_self, - arg_msg); - - mach_port_deallocate(mach_task_self(), thread_self); - - free (arg_msg); - } +void _DNBLogThreadedIf(uint32_t log_bit, const char *format, ...) { + if (DNBLogEnabled() && (log_bit & g_log_bits) == log_bit) { + // PTHREAD_MUTEX_LOCKER(locker, GetLogThreadedMutex()); + + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + static struct timeval g_timeval = {0, 0}; + static struct timeval tv; + static struct timeval delta; + gettimeofday(&tv, NULL); + if (g_timeval.tv_sec == 0) { + delta.tv_sec = 0; + delta.tv_usec = 0; + } else { + timersub(&tv, &g_timeval, &delta); + } + g_timeval = tv; + + // Calling "mach_port_deallocate()" bumps the reference count on the + // thread + // port, so we need to deallocate it. mach_task_self() doesn't bump the + // ref + // count. + thread_port_t thread_self = mach_thread_self(); + + _DNBLog(DNBLOG_FLAG_THREADED, "%u +%lu.%06u sec [%4.4x/%4.4x]: %s", + ++g_message_id, delta.tv_sec, delta.tv_usec, getpid(), + thread_self, arg_msg); + + mach_port_deallocate(mach_task_self(), thread_self); + + free(arg_msg); } + } } - - //---------------------------------------------------------------------- // Printing of errors that are not fatal. //---------------------------------------------------------------------- -void -_DNBLogError (const char *format, ...) -{ - if (DNBLogEnabled ()) - { - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - _DNBLog (DNBLOG_FLAG_ERROR, "error: %s", arg_msg); - free (arg_msg); - } +void _DNBLogError(const char *format, ...) { + if (DNBLogEnabled()) { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + _DNBLog(DNBLOG_FLAG_ERROR, "error: %s", arg_msg); + free(arg_msg); } + } } //---------------------------------------------------------------------- // Printing of errors that ARE fatal. Exit with ERR exit code // immediately. //---------------------------------------------------------------------- -void -_DNBLogFatalError (int err, const char *format, ...) -{ - if (DNBLogEnabled ()) - { - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - _DNBLog (DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg); - free (arg_msg); - } - ::exit (err); +void _DNBLogFatalError(int err, const char *format, ...) { + if (DNBLogEnabled()) { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + _DNBLog(DNBLOG_FLAG_ERROR | DNBLOG_FLAG_FATAL, "error: %s", arg_msg); + free(arg_msg); } + ::exit(err); + } } - //---------------------------------------------------------------------- // Printing of warnings that are not fatal only if verbose mode is // enabled. //---------------------------------------------------------------------- -void -_DNBLogVerbose (const char *format, ...) -{ - if (DNBLogEnabled () && g_verbose) - { - va_list args; - va_start (args, format); - _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args); - va_end (args); - } +void _DNBLogVerbose(const char *format, ...) { + if (DNBLogEnabled() && g_verbose) { + va_list args; + va_start(args, format); + _DNBLogVAPrintf(DNBLOG_FLAG_VERBOSE, format, args); + va_end(args); + } } //---------------------------------------------------------------------- // Printing of warnings that are not fatal only if verbose mode is // enabled. //---------------------------------------------------------------------- -void -_DNBLogWarningVerbose (const char *format, ...) -{ - if (DNBLogEnabled () && g_verbose) - { - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - _DNBLog (DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s", arg_msg); - free (arg_msg); - } +void _DNBLogWarningVerbose(const char *format, ...) { + if (DNBLogEnabled() && g_verbose) { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + _DNBLog(DNBLOG_FLAG_WARNING | DNBLOG_FLAG_VERBOSE, "warning: %s", + arg_msg); + free(arg_msg); } + } } //---------------------------------------------------------------------- // Printing of warnings that are not fatal. //---------------------------------------------------------------------- -void -_DNBLogWarning (const char *format, ...) -{ - if (DNBLogEnabled ()) - { - char *arg_msg = NULL; - va_list args; - va_start (args, format); - ::vasprintf (&arg_msg, format, args); - va_end (args); - - if (arg_msg != NULL) - { - _DNBLog (DNBLOG_FLAG_WARNING, "warning: %s", arg_msg); - free (arg_msg); - } +void _DNBLogWarning(const char *format, ...) { + if (DNBLogEnabled()) { + char *arg_msg = NULL; + va_list args; + va_start(args, format); + ::vasprintf(&arg_msg, format, args); + va_end(args); + + if (arg_msg != NULL) { + _DNBLog(DNBLOG_FLAG_WARNING, "warning: %s", arg_msg); + free(arg_msg); } + } } #endif diff --git a/lldb/tools/debugserver/source/DNBLog.h b/lldb/tools/debugserver/source/DNBLog.h index 01add065abc..65181caa412 100644 --- a/lldb/tools/debugserver/source/DNBLog.h +++ b/lldb/tools/debugserver/source/DNBLog.h @@ -14,78 +14,135 @@ #ifndef __DNBLog_h__ #define __DNBLog_h__ -#include <stdio.h> -#include <stdint.h> #include "DNBDefs.h" +#include <stdint.h> +#include <stdio.h> #ifdef __cplusplus extern "C" { #endif -// Flags that get filled in automatically before calling the log callback function -#define DNBLOG_FLAG_FATAL (1u << 0) -#define DNBLOG_FLAG_ERROR (1u << 1) -#define DNBLOG_FLAG_WARNING (1u << 2) -#define DNBLOG_FLAG_DEBUG (1u << 3) -#define DNBLOG_FLAG_VERBOSE (1u << 4) -#define DNBLOG_FLAG_THREADED (1u << 5) +// Flags that get filled in automatically before calling the log callback +// function +#define DNBLOG_FLAG_FATAL (1u << 0) +#define DNBLOG_FLAG_ERROR (1u << 1) +#define DNBLOG_FLAG_WARNING (1u << 2) +#define DNBLOG_FLAG_DEBUG (1u << 3) +#define DNBLOG_FLAG_VERBOSE (1u << 4) +#define DNBLOG_FLAG_THREADED (1u << 5) #define DNBLOG_ENABLED -#if defined (DNBLOG_ENABLED) +#if defined(DNBLOG_ENABLED) -void _DNBLog(uint32_t flags, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -void _DNBLogDebug (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -void _DNBLogDebugVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))) ; -void _DNBLogThreaded (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -void _DNBLogThreadedIf (uint32_t mask, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -void _DNBLogError (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -void _DNBLogFatalError (int err, const char *fmt, ...) __attribute__ ((format (printf, 2, 3))); -void _DNBLogVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -void _DNBLogWarning (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -void _DNBLogWarningVerbose (const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -bool DNBLogCheckLogBit (uint32_t bit); -uint32_t DNBLogSetLogMask (uint32_t mask); -uint32_t DNBLogGetLogMask (); -void DNBLogSetLogCallback (DNBCallbackLog callback, void *baton); -DNBCallbackLog DNBLogGetLogCallback (); -bool DNBLogEnabled (); -bool DNBLogEnabledForAny (uint32_t mask); -int DNBLogGetDebug (); -void DNBLogSetDebug (int g); -int DNBLogGetVerbose (); -void DNBLogSetVerbose (int g); +void _DNBLog(uint32_t flags, const char *format, ...) + __attribute__((format(printf, 2, 3))); +void _DNBLogDebug(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void _DNBLogDebugVerbose(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void _DNBLogThreaded(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +void _DNBLogThreadedIf(uint32_t mask, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void _DNBLogError(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void _DNBLogFatalError(int err, const char *fmt, ...) + __attribute__((format(printf, 2, 3))); +void _DNBLogVerbose(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void _DNBLogWarning(const char *fmt, ...) __attribute__((format(printf, 1, 2))); +void _DNBLogWarningVerbose(const char *fmt, ...) + __attribute__((format(printf, 1, 2))); +bool DNBLogCheckLogBit(uint32_t bit); +uint32_t DNBLogSetLogMask(uint32_t mask); +uint32_t DNBLogGetLogMask(); +void DNBLogSetLogCallback(DNBCallbackLog callback, void *baton); +DNBCallbackLog DNBLogGetLogCallback(); +bool DNBLogEnabled(); +bool DNBLogEnabledForAny(uint32_t mask); +int DNBLogGetDebug(); +void DNBLogSetDebug(int g); +int DNBLogGetVerbose(); +void DNBLogSetVerbose(int g); -#define DNBLog(fmt, ...) do { if (DNBLogEnabled()) { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogDebug(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogDebug(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogDebugVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogDebugVerbose(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogThreaded(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogThreaded(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogThreadedIf(mask, fmt, ...) do { if (DNBLogEnabledForAny(mask)) { _DNBLogThreaded(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogError(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogError(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogFatalError(err, fmt, ...) do { if (DNBLogEnabled()) { _DNBLogFatalError(err, fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogVerbose(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogWarning(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogWarning(fmt, ## __VA_ARGS__); } } while (0) -#define DNBLogWarningVerbose(fmt, ...) do { if (DNBLogEnabled()) { _DNBLogWarningVerbose(fmt, ## __VA_ARGS__); } } while (0) +#define DNBLog(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogDebug(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogDebug(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogDebugVerbose(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogDebugVerbose(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogThreaded(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogThreaded(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogThreadedIf(mask, fmt, ...) \ + do { \ + if (DNBLogEnabledForAny(mask)) { \ + _DNBLogThreaded(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogError(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogError(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogFatalError(err, fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogFatalError(err, fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogVerbose(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogVerbose(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogWarning(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogWarning(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define DNBLogWarningVerbose(fmt, ...) \ + do { \ + if (DNBLogEnabled()) { \ + _DNBLogWarningVerbose(fmt, ##__VA_ARGS__); \ + } \ + } while (0) -#else // #if defined(DNBLOG_ENABLED) +#else // #if defined(DNBLOG_ENABLED) -#define DNBLogDebug(...) ((void)0) -#define DNBLogDebugVerbose(...) ((void)0) -#define DNBLogThreaded(...) ((void)0) -#define DNBLogThreadedIf(...) ((void)0) -#define DNBLogError(...) ((void)0) -#define DNBLogFatalError(...) ((void)0) -#define DNBLogVerbose(...) ((void)0) -#define DNBLogWarning(...) ((void)0) -#define DNBLogWarningVerbose(...) ((void)0) -#define DNBLogGetLogFile() ((FILE *)NULL) -#define DNBLogSetLogFile(f) ((void)0) -#define DNBLogCheckLogBit(bit) ((bool)false) -#define DNBLogSetLogMask(mask) ((uint32_t)0u) -#define DNBLogGetLogMask() ((uint32_t)0u) -#define DNBLogToASL() ((void)0) -#define DNBLogToFile() ((void)0) -#define DNBLogCloseLogFile() ((void)0) +#define DNBLogDebug(...) ((void)0) +#define DNBLogDebugVerbose(...) ((void)0) +#define DNBLogThreaded(...) ((void)0) +#define DNBLogThreadedIf(...) ((void)0) +#define DNBLogError(...) ((void)0) +#define DNBLogFatalError(...) ((void)0) +#define DNBLogVerbose(...) ((void)0) +#define DNBLogWarning(...) ((void)0) +#define DNBLogWarningVerbose(...) ((void)0) +#define DNBLogGetLogFile() ((FILE *)NULL) +#define DNBLogSetLogFile(f) ((void)0) +#define DNBLogCheckLogBit(bit) ((bool)false) +#define DNBLogSetLogMask(mask) ((uint32_t)0u) +#define DNBLogGetLogMask() ((uint32_t)0u) +#define DNBLogToASL() ((void)0) +#define DNBLogToFile() ((void)0) +#define DNBLogCloseLogFile() ((void)0) #endif // #else defined(DNBLOG_ENABLED) diff --git a/lldb/tools/debugserver/source/DNBRegisterInfo.cpp b/lldb/tools/debugserver/source/DNBRegisterInfo.cpp index acc7ba9946b..fadcc5ddb06 100644 --- a/lldb/tools/debugserver/source/DNBRegisterInfo.cpp +++ b/lldb/tools/debugserver/source/DNBRegisterInfo.cpp @@ -15,205 +15,237 @@ #include "DNBLog.h" #include <string.h> -DNBRegisterValueClass::DNBRegisterValueClass(const DNBRegisterInfo *regInfo) -{ - Clear(); - if (regInfo) - info = *regInfo; +DNBRegisterValueClass::DNBRegisterValueClass(const DNBRegisterInfo *regInfo) { + Clear(); + if (regInfo) + info = *regInfo; } -void -DNBRegisterValueClass::Clear() -{ - memset(&info, 0, sizeof(DNBRegisterInfo)); - memset(&value, 0, sizeof(value)); +void DNBRegisterValueClass::Clear() { + memset(&info, 0, sizeof(DNBRegisterInfo)); + memset(&value, 0, sizeof(value)); } -bool -DNBRegisterValueClass::IsValid() const -{ - return - info.name != NULL && - info.type != InvalidRegType && - info.size > 0 && info.size <= sizeof(value); +bool DNBRegisterValueClass::IsValid() const { + return info.name != NULL && info.type != InvalidRegType && info.size > 0 && + info.size <= sizeof(value); } -#define PRINT_COMMA_SEPARATOR do { if (pos < end) { if (i > 0) { strncpy(pos, ", ", end - pos); pos += 2; } } } while (0) - -void -DNBRegisterValueClass::Dump(const char *pre, const char *post) const -{ - if (info.name != NULL) - { - char str[1024]; - char *pos; - char *end = str + sizeof(str); - if (info.format == Hex) - { - switch (info.size) - { - case 0: snprintf(str, sizeof(str), "%s", "error: invalid register size of zero."); break; - case 1: snprintf(str, sizeof(str), "0x%2.2x", value.uint8); break; - case 2: snprintf(str, sizeof(str), "0x%4.4x", value.uint16); break; - case 4: snprintf(str, sizeof(str), "0x%8.8x", value.uint32); break; - case 8: snprintf(str, sizeof(str), "0x%16.16llx", value.uint64); break; - case 16: snprintf(str, sizeof(str), "0x%16.16llx%16.16llx", value.v_uint64[0], value.v_uint64[1]); break; - default: - strncpy(str, "0x", 3); - pos = str + 2; - for (uint32_t i=0; i<info.size; ++i) - { - if (pos < end) - pos += snprintf(pos, end - pos, "%2.2x", (uint32_t)value.v_uint8[i]); - } - break; - } +#define PRINT_COMMA_SEPARATOR \ + do { \ + if (pos < end) { \ + if (i > 0) { \ + strncpy(pos, ", ", end - pos); \ + pos += 2; \ + } \ + } \ + } while (0) + +void DNBRegisterValueClass::Dump(const char *pre, const char *post) const { + if (info.name != NULL) { + char str[1024]; + char *pos; + char *end = str + sizeof(str); + if (info.format == Hex) { + switch (info.size) { + case 0: + snprintf(str, sizeof(str), "%s", + "error: invalid register size of zero."); + break; + case 1: + snprintf(str, sizeof(str), "0x%2.2x", value.uint8); + break; + case 2: + snprintf(str, sizeof(str), "0x%4.4x", value.uint16); + break; + case 4: + snprintf(str, sizeof(str), "0x%8.8x", value.uint32); + break; + case 8: + snprintf(str, sizeof(str), "0x%16.16llx", value.uint64); + break; + case 16: + snprintf(str, sizeof(str), "0x%16.16llx%16.16llx", value.v_uint64[0], + value.v_uint64[1]); + break; + default: + strncpy(str, "0x", 3); + pos = str + 2; + for (uint32_t i = 0; i < info.size; ++i) { + if (pos < end) + pos += + snprintf(pos, end - pos, "%2.2x", (uint32_t)value.v_uint8[i]); + } + break; + } + } else { + switch (info.type) { + case Uint: + switch (info.size) { + case 1: + snprintf(str, sizeof(str), "%u", value.uint8); + break; + case 2: + snprintf(str, sizeof(str), "%u", value.uint16); + break; + case 4: + snprintf(str, sizeof(str), "%u", value.uint32); + break; + case 8: + snprintf(str, sizeof(str), "%llu", value.uint64); + break; + default: + snprintf(str, sizeof(str), "error: unsupported uint byte size %d.", + info.size); + break; + } + break; + + case Sint: + switch (info.size) { + case 1: + snprintf(str, sizeof(str), "%d", value.sint8); + break; + case 2: + snprintf(str, sizeof(str), "%d", value.sint16); + break; + case 4: + snprintf(str, sizeof(str), "%d", value.sint32); + break; + case 8: + snprintf(str, sizeof(str), "%lld", value.sint64); + break; + default: + snprintf(str, sizeof(str), "error: unsupported sint byte size %d.", + info.size); + break; } - else - { - switch (info.type) - { - case Uint: - switch (info.size) - { - case 1: snprintf(str, sizeof(str), "%u", value.uint8); break; - case 2: snprintf(str, sizeof(str), "%u", value.uint16); break; - case 4: snprintf(str, sizeof(str), "%u", value.uint32); break; - case 8: snprintf(str, sizeof(str), "%llu", value.uint64); break; - default: snprintf(str, sizeof(str), "error: unsupported uint byte size %d.", info.size); break; - } - break; - - case Sint: - switch (info.size) - { - case 1: snprintf(str, sizeof(str), "%d", value.sint8); break; - case 2: snprintf(str, sizeof(str), "%d", value.sint16); break; - case 4: snprintf(str, sizeof(str), "%d", value.sint32); break; - case 8: snprintf(str, sizeof(str), "%lld", value.sint64); break; - default: snprintf(str, sizeof(str), "error: unsupported sint byte size %d.", info.size); break; - } - break; - - case IEEE754: - switch (info.size) - { - case 4: snprintf(str, sizeof(str), "%f", value.float32); break; - case 8: snprintf(str, sizeof(str), "%g", value.float64); break; - default: snprintf(str, sizeof(str), "error: unsupported float byte size %d.", info.size); break; - } - break; - - case Vector: - if (info.size > 0) - { - switch (info.format) - { - case VectorOfSInt8: - snprintf(str, sizeof(str), "%s", "sint8 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint8[i]); - } - strlcat(str, " }", sizeof(str)); - break; - - default: - DNBLogError("unsupported vector format %d, defaulting to hex bytes.", info.format); - case VectorOfUInt8: - snprintf(str, sizeof(str), "%s", "uint8 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint8[i]); - } - break; - - case VectorOfSInt16: - snprintf(str, sizeof(str), "%s", "sint16 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/2; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint16[i]); - } - break; - - case VectorOfUInt16: - snprintf(str, sizeof(str), "%s", "uint16 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/2; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint16[i]); - } - break; - - case VectorOfSInt32: - snprintf(str, sizeof(str), "%s", "sint32 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/4; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%d", (int32_t)value.v_sint32[i]); - } - break; - - case VectorOfUInt32: - snprintf(str, sizeof(str), "%s", "uint32 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/4; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint32[i]); - } - break; - - case VectorOfFloat32: - snprintf(str, sizeof(str), "%s", "float32 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/4; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "%f", value.v_float32[i]); - } - break; - - case VectorOfUInt128: - snprintf(str, sizeof(str), "%s", "uint128 { "); - pos = str + strlen(str); - for (uint32_t i=0; i<info.size/16; ++i) - { - PRINT_COMMA_SEPARATOR; - if (pos < end) - pos += snprintf(pos, end - pos, "0x%16.16llx%16.16llx", value.v_uint64[i], value.v_uint64[i+1]); - } - break; - } - strlcat(str, " }", sizeof(str)); - } - else - { - snprintf(str, sizeof(str), "error: unsupported vector size %d.", info.size); - } - break; - - default: - snprintf(str, sizeof(str), "error: unsupported register type %d.", info.type); - break; + break; + + case IEEE754: + switch (info.size) { + case 4: + snprintf(str, sizeof(str), "%f", value.float32); + break; + case 8: + snprintf(str, sizeof(str), "%g", value.float64); + break; + default: + snprintf(str, sizeof(str), "error: unsupported float byte size %d.", + info.size); + break; + } + break; + + case Vector: + if (info.size > 0) { + switch (info.format) { + case VectorOfSInt8: + snprintf(str, sizeof(str), "%s", "sint8 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%d", (int32_t)value.v_sint8[i]); + } + strlcat(str, " }", sizeof(str)); + break; + + default: + DNBLogError( + "unsupported vector format %d, defaulting to hex bytes.", + info.format); + case VectorOfUInt8: + snprintf(str, sizeof(str), "%s", "uint8 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint8[i]); + } + break; + + case VectorOfSInt16: + snprintf(str, sizeof(str), "%s", "sint16 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 2; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%d", (int32_t)value.v_sint16[i]); } + break; + + case VectorOfUInt16: + snprintf(str, sizeof(str), "%s", "uint16 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 2; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint16[i]); + } + break; + + case VectorOfSInt32: + snprintf(str, sizeof(str), "%s", "sint32 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 4; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%d", (int32_t)value.v_sint32[i]); + } + break; + + case VectorOfUInt32: + snprintf(str, sizeof(str), "%s", "uint32 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 4; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += + snprintf(pos, end - pos, "%u", (uint32_t)value.v_uint32[i]); + } + break; + + case VectorOfFloat32: + snprintf(str, sizeof(str), "%s", "float32 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 4; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += snprintf(pos, end - pos, "%f", value.v_float32[i]); + } + break; + + case VectorOfUInt128: + snprintf(str, sizeof(str), "%s", "uint128 { "); + pos = str + strlen(str); + for (uint32_t i = 0; i < info.size / 16; ++i) { + PRINT_COMMA_SEPARATOR; + if (pos < end) + pos += snprintf(pos, end - pos, "0x%16.16llx%16.16llx", + value.v_uint64[i], value.v_uint64[i + 1]); + } + break; + } + strlcat(str, " }", sizeof(str)); + } else { + snprintf(str, sizeof(str), "error: unsupported vector size %d.", + info.size); } + break; - DNBLog("%s%4s = %s%s", pre ? pre : "", info.name, str, post ? post : ""); + default: + snprintf(str, sizeof(str), "error: unsupported register type %d.", + info.type); + break; + } } + + DNBLog("%s%4s = %s%s", pre ? pre : "", info.name, str, post ? post : ""); + } } diff --git a/lldb/tools/debugserver/source/DNBRegisterInfo.h b/lldb/tools/debugserver/source/DNBRegisterInfo.h index 666c397e0b5..d665e3cb948 100644 --- a/lldb/tools/debugserver/source/DNBRegisterInfo.h +++ b/lldb/tools/debugserver/source/DNBRegisterInfo.h @@ -14,17 +14,16 @@ #ifndef __DNBRegisterInfo_h__ #define __DNBRegisterInfo_h__ +#include "DNBDefs.h" #include <stdint.h> #include <stdio.h> -#include "DNBDefs.h" -struct DNBRegisterValueClass : public DNBRegisterValue -{ +struct DNBRegisterValueClass : public DNBRegisterValue { #ifdef __cplusplus - DNBRegisterValueClass(const DNBRegisterInfo *regInfo = NULL); - void Clear(); - void Dump(const char *pre, const char *post) const; - bool IsValid() const; + DNBRegisterValueClass(const DNBRegisterInfo *regInfo = NULL); + void Clear(); + void Dump(const char *pre, const char *post) const; + bool IsValid() const; #endif }; diff --git a/lldb/tools/debugserver/source/DNBRuntimeAction.h b/lldb/tools/debugserver/source/DNBRuntimeAction.h index d77bda8c604..85d7bc1df0a 100644 --- a/lldb/tools/debugserver/source/DNBRuntimeAction.h +++ b/lldb/tools/debugserver/source/DNBRuntimeAction.h @@ -14,12 +14,11 @@ #ifndef __DNBRuntimeAction_h__ #define __DNBRuntimeAction_h__ -class DNBRuntimeAction -{ - virtual void Initialize (nub_process_t pid) = 0; - virtual void ProcessStateChanged (nub_state_t state) = 0; - virtual void SharedLibraryStateChanged (DNBExecutableImageInfo *image_infos, nub_size_t num_image_infos) = 0; +class DNBRuntimeAction { + virtual void Initialize(nub_process_t pid) = 0; + virtual void ProcessStateChanged(nub_state_t state) = 0; + virtual void SharedLibraryStateChanged(DNBExecutableImageInfo *image_infos, + nub_size_t num_image_infos) = 0; }; - #endif // #ifndef __DNBRuntimeAction_h__ diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp b/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp index b50dd061784..4a97abc20e2 100644 --- a/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp +++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.cpp @@ -13,104 +13,77 @@ #include "DNBThreadResumeActions.h" -DNBThreadResumeActions::DNBThreadResumeActions() : - m_actions (), - m_signal_handled () -{ -} +DNBThreadResumeActions::DNBThreadResumeActions() + : m_actions(), m_signal_handled() {} -DNBThreadResumeActions::DNBThreadResumeActions (const DNBThreadResumeAction *actions, size_t num_actions) : - m_actions (), - m_signal_handled () -{ - if (actions && num_actions) - { - m_actions.assign (actions, actions + num_actions); - m_signal_handled.assign (num_actions, false); - } +DNBThreadResumeActions::DNBThreadResumeActions( + const DNBThreadResumeAction *actions, size_t num_actions) + : m_actions(), m_signal_handled() { + if (actions && num_actions) { + m_actions.assign(actions, actions + num_actions); + m_signal_handled.assign(num_actions, false); + } } -DNBThreadResumeActions::DNBThreadResumeActions (nub_state_t default_action, int signal) : - m_actions(), - m_signal_handled () -{ - SetDefaultThreadActionIfNeeded (default_action, signal); +DNBThreadResumeActions::DNBThreadResumeActions(nub_state_t default_action, + int signal) + : m_actions(), m_signal_handled() { + SetDefaultThreadActionIfNeeded(default_action, signal); } -void -DNBThreadResumeActions::Append (const DNBThreadResumeAction &action) -{ - m_actions.push_back (action); - m_signal_handled.push_back (false); +void DNBThreadResumeActions::Append(const DNBThreadResumeAction &action) { + m_actions.push_back(action); + m_signal_handled.push_back(false); } -void -DNBThreadResumeActions::AppendAction -( - nub_thread_t tid, - nub_state_t state, - int signal, - nub_addr_t addr -) -{ - DNBThreadResumeAction action = { tid, state, signal, addr }; - Append (action); +void DNBThreadResumeActions::AppendAction(nub_thread_t tid, nub_state_t state, + int signal, nub_addr_t addr) { + DNBThreadResumeAction action = {tid, state, signal, addr}; + Append(action); } - const DNBThreadResumeAction * -DNBThreadResumeActions::GetActionForThread (nub_thread_t tid, bool default_ok) const -{ - const size_t num_actions = m_actions.size(); - for (size_t i=0; i<num_actions; ++i) - { - if (m_actions[i].tid == tid) - return &m_actions[i]; - } - if (default_ok && tid != INVALID_NUB_THREAD) - return GetActionForThread (INVALID_NUB_THREAD, false); - return NULL; +DNBThreadResumeActions::GetActionForThread(nub_thread_t tid, + bool default_ok) const { + const size_t num_actions = m_actions.size(); + for (size_t i = 0; i < num_actions; ++i) { + if (m_actions[i].tid == tid) + return &m_actions[i]; + } + if (default_ok && tid != INVALID_NUB_THREAD) + return GetActionForThread(INVALID_NUB_THREAD, false); + return NULL; } -size_t -DNBThreadResumeActions::NumActionsWithState (nub_state_t state) const -{ - size_t count = 0; - const size_t num_actions = m_actions.size(); - for (size_t i=0; i<num_actions; ++i) - { - if (m_actions[i].state == state) - ++count; - } - return count; +size_t DNBThreadResumeActions::NumActionsWithState(nub_state_t state) const { + size_t count = 0; + const size_t num_actions = m_actions.size(); + for (size_t i = 0; i < num_actions; ++i) { + if (m_actions[i].state == state) + ++count; + } + return count; } - -bool -DNBThreadResumeActions::SetDefaultThreadActionIfNeeded (nub_state_t action, int signal) -{ - if (GetActionForThread (INVALID_NUB_THREAD, true) == NULL) - { - // There isn't a default action so we do need to set it. - DNBThreadResumeAction default_action = {INVALID_NUB_THREAD, action, signal, INVALID_NUB_ADDRESS }; - m_actions.push_back (default_action); - m_signal_handled.push_back (false); - return true; // Return true as we did add the default action - } - return false; +bool DNBThreadResumeActions::SetDefaultThreadActionIfNeeded(nub_state_t action, + int signal) { + if (GetActionForThread(INVALID_NUB_THREAD, true) == NULL) { + // There isn't a default action so we do need to set it. + DNBThreadResumeAction default_action = {INVALID_NUB_THREAD, action, signal, + INVALID_NUB_ADDRESS}; + m_actions.push_back(default_action); + m_signal_handled.push_back(false); + return true; // Return true as we did add the default action + } + return false; } - -void -DNBThreadResumeActions::SetSignalHandledForThread (nub_thread_t tid) const -{ - if (tid != INVALID_NUB_THREAD) - { - const size_t num_actions = m_actions.size(); - for (size_t i=0; i<num_actions; ++i) - { - if (m_actions[i].tid == tid) - m_signal_handled[i] = true; - } +void DNBThreadResumeActions::SetSignalHandledForThread(nub_thread_t tid) const { + if (tid != INVALID_NUB_THREAD) { + const size_t num_actions = m_actions.size(); + for (size_t i = 0; i < num_actions; ++i) { + if (m_actions[i].tid == tid) + m_signal_handled[i] = true; } + } } diff --git a/lldb/tools/debugserver/source/DNBThreadResumeActions.h b/lldb/tools/debugserver/source/DNBThreadResumeActions.h index 81c7c43b722..40d2da03e9e 100644 --- a/lldb/tools/debugserver/source/DNBThreadResumeActions.h +++ b/lldb/tools/debugserver/source/DNBThreadResumeActions.h @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// - #ifndef __DNBThreadResumeActions_h__ #define __DNBThreadResumeActions_h__ @@ -19,84 +18,49 @@ #include "DNBDefs.h" - -class DNBThreadResumeActions -{ +class DNBThreadResumeActions { public: - DNBThreadResumeActions (); - - DNBThreadResumeActions (nub_state_t default_action, int signal); - - DNBThreadResumeActions (const DNBThreadResumeAction *actions, size_t num_actions); - - bool - IsEmpty() const - { - return m_actions.empty(); - } - - void - Append (const DNBThreadResumeAction &action); - - void - AppendAction (nub_thread_t tid, - nub_state_t state, - int signal = 0, - nub_addr_t addr = INVALID_NUB_ADDRESS); - - void - AppendResumeAll () - { - AppendAction (INVALID_NUB_THREAD, eStateRunning); - } - - void - AppendSuspendAll () - { - AppendAction (INVALID_NUB_THREAD, eStateStopped); - } - - void - AppendStepAll () - { - AppendAction (INVALID_NUB_THREAD, eStateStepping); - } - - const DNBThreadResumeAction * - GetActionForThread (nub_thread_t tid, bool default_ok) const; - - size_t - NumActionsWithState (nub_state_t state) const; - - bool - SetDefaultThreadActionIfNeeded (nub_state_t action, int signal); - - void - SetSignalHandledForThread (nub_thread_t tid) const; - - const DNBThreadResumeAction * - GetFirst() const - { - return m_actions.data(); - } - - size_t - GetSize () const - { - return m_actions.size(); - } - - void - Clear() - { - m_actions.clear(); - m_signal_handled.clear(); - } + DNBThreadResumeActions(); + + DNBThreadResumeActions(nub_state_t default_action, int signal); + + DNBThreadResumeActions(const DNBThreadResumeAction *actions, + size_t num_actions); + + bool IsEmpty() const { return m_actions.empty(); } + + void Append(const DNBThreadResumeAction &action); + + void AppendAction(nub_thread_t tid, nub_state_t state, int signal = 0, + nub_addr_t addr = INVALID_NUB_ADDRESS); + + void AppendResumeAll() { AppendAction(INVALID_NUB_THREAD, eStateRunning); } + + void AppendSuspendAll() { AppendAction(INVALID_NUB_THREAD, eStateStopped); } + + void AppendStepAll() { AppendAction(INVALID_NUB_THREAD, eStateStepping); } + + const DNBThreadResumeAction *GetActionForThread(nub_thread_t tid, + bool default_ok) const; + + size_t NumActionsWithState(nub_state_t state) const; + + bool SetDefaultThreadActionIfNeeded(nub_state_t action, int signal); + + void SetSignalHandledForThread(nub_thread_t tid) const; + + const DNBThreadResumeAction *GetFirst() const { return m_actions.data(); } + + size_t GetSize() const { return m_actions.size(); } + + void Clear() { + m_actions.clear(); + m_signal_handled.clear(); + } protected: - std::vector<DNBThreadResumeAction> m_actions; - mutable std::vector<bool> m_signal_handled; + std::vector<DNBThreadResumeAction> m_actions; + mutable std::vector<bool> m_signal_handled; }; - -#endif // #ifndef __DNBThreadResumeActions_h__ +#endif // #ifndef __DNBThreadResumeActions_h__ diff --git a/lldb/tools/debugserver/source/DNBTimer.h b/lldb/tools/debugserver/source/DNBTimer.h index ca56e30c709..881b8cdcde7 100644 --- a/lldb/tools/debugserver/source/DNBTimer.h +++ b/lldb/tools/debugserver/source/DNBTimer.h @@ -14,150 +14,132 @@ #ifndef __DNBTimer_h__ #define __DNBTimer_h__ -#include <sys/time.h> -#include <stdint.h> -#include <memory> #include "DNBDefs.h" #include "PThreadMutex.h" +#include <memory> +#include <stdint.h> +#include <sys/time.h> -class DNBTimer -{ +class DNBTimer { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - DNBTimer (bool threadSafe) : - m_mutexAP() - { - if (threadSafe) - m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); - Reset(); - } + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + DNBTimer(bool threadSafe) : m_mutexAP() { + if (threadSafe) + m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); + Reset(); + } + + DNBTimer(const DNBTimer &rhs) : m_mutexAP() { + // Create a new mutex to make this timer thread safe as well if + // the timer we are copying is thread safe + if (rhs.IsThreadSafe()) + m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); + m_timeval = rhs.m_timeval; + } - DNBTimer (const DNBTimer& rhs) : - m_mutexAP() - { - // Create a new mutex to make this timer thread safe as well if - // the timer we are copying is thread safe - if (rhs.IsThreadSafe()) - m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); - m_timeval = rhs.m_timeval; - } + DNBTimer &operator=(const DNBTimer &rhs) { + // Create a new mutex to make this timer thread safe as well if + // the timer we are copying is thread safe + if (rhs.IsThreadSafe()) + m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); + m_timeval = rhs.m_timeval; + return *this; + } - DNBTimer& operator= (const DNBTimer& rhs) - { - // Create a new mutex to make this timer thread safe as well if - // the timer we are copying is thread safe - if (rhs.IsThreadSafe()) - m_mutexAP.reset(new PThreadMutex(PTHREAD_MUTEX_RECURSIVE)); - m_timeval = rhs.m_timeval; - return *this; - } + ~DNBTimer() {} - ~DNBTimer () - { - } + bool IsThreadSafe() const { return m_mutexAP.get() != NULL; } + //------------------------------------------------------------------ + // Reset the time value to now + //------------------------------------------------------------------ + void Reset() { + PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); + gettimeofday(&m_timeval, NULL); + } + //------------------------------------------------------------------ + // Get the total mircoseconds since Jan 1, 1970 + //------------------------------------------------------------------ + uint64_t TotalMicroSeconds() const { + PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); + return (uint64_t)(m_timeval.tv_sec) * 1000000ull + + (uint64_t)m_timeval.tv_usec; + } - bool - IsThreadSafe() const - { - return m_mutexAP.get() != NULL; - } - //------------------------------------------------------------------ - // Reset the time value to now - //------------------------------------------------------------------ - void - Reset () - { - PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get()); - gettimeofday (&m_timeval, NULL); - } - //------------------------------------------------------------------ - // Get the total mircoseconds since Jan 1, 1970 - //------------------------------------------------------------------ - uint64_t - TotalMicroSeconds () const - { - PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get()); - return (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec; - } + void GetTime(uint64_t &sec, uint32_t &usec) const { + PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); + sec = m_timeval.tv_sec; + usec = m_timeval.tv_usec; + } + //------------------------------------------------------------------ + // Return the number of microseconds elapsed between now and the + // m_timeval + //------------------------------------------------------------------ + uint64_t ElapsedMicroSeconds(bool update) { + PTHREAD_MUTEX_LOCKER(locker, m_mutexAP.get()); + struct timeval now; + gettimeofday(&now, NULL); + uint64_t now_usec = + (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; + uint64_t this_usec = + (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec; + uint64_t elapsed = now_usec - this_usec; + // Update the timer time value if requeseted + if (update) + m_timeval = now; + return elapsed; + } - void - GetTime (uint64_t& sec, uint32_t& usec) const - { - PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get()); - sec = m_timeval.tv_sec; - usec = m_timeval.tv_usec; - } - //------------------------------------------------------------------ - // Return the number of microseconds elapsed between now and the - // m_timeval - //------------------------------------------------------------------ - uint64_t - ElapsedMicroSeconds (bool update) - { - PTHREAD_MUTEX_LOCKER (locker, m_mutexAP.get()); - struct timeval now; - gettimeofday (&now, NULL); - uint64_t now_usec = (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; - uint64_t this_usec = (uint64_t)(m_timeval.tv_sec) * 1000000ull + (uint64_t)m_timeval.tv_usec; - uint64_t elapsed = now_usec - this_usec; - // Update the timer time value if requeseted - if (update) - m_timeval = now; - return elapsed; - } + static uint64_t GetTimeOfDay() { + struct timeval now; + gettimeofday(&now, NULL); + uint64_t now_usec = + (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; + return now_usec; + } - static uint64_t GetTimeOfDay() - { - struct timeval now; - gettimeofday (&now, NULL); - uint64_t now_usec = (uint64_t)(now.tv_sec) * 1000000ull + (uint64_t)now.tv_usec; - return now_usec; - } + static void OffsetTimeOfDay(struct timespec *ts, + __darwin_time_t sec_offset = 0, + long nsec_offset = 0) { + if (ts == NULL) + return; + // Get the current time in a timeval structure + struct timeval now; + gettimeofday(&now, NULL); + // Morph it into a timespec + TIMEVAL_TO_TIMESPEC(&now, ts); + // Offset the timespec if requested + if (sec_offset != 0 || nsec_offset != 0) { + // Offset the nano seconds + ts->tv_nsec += nsec_offset; + // Offset the seconds taking into account a nano-second overflow + ts->tv_sec = ts->tv_sec + ts->tv_nsec / 1000000000 + sec_offset; + // Trim the nanoseconds back there was an overflow + ts->tv_nsec = ts->tv_nsec % 1000000000; + } + } + static bool TimeOfDayLaterThan(struct timespec &ts) { + struct timespec now; + OffsetTimeOfDay(&now); + if (now.tv_sec > ts.tv_sec) + return true; + else if (now.tv_sec < ts.tv_sec) + return false; + else { + if (now.tv_nsec > ts.tv_nsec) + return true; + else + return false; + } + } - static void OffsetTimeOfDay (struct timespec* ts, __darwin_time_t sec_offset = 0, long nsec_offset = 0) - { - if (ts == NULL) - return; - // Get the current time in a timeval structure - struct timeval now; - gettimeofday (&now, NULL); - // Morph it into a timespec - TIMEVAL_TO_TIMESPEC(&now, ts); - // Offset the timespec if requested - if (sec_offset != 0 || nsec_offset != 0) - { - // Offset the nano seconds - ts->tv_nsec += nsec_offset; - // Offset the seconds taking into account a nano-second overflow - ts->tv_sec = ts->tv_sec + ts->tv_nsec / 1000000000 + sec_offset; - // Trim the nanoseconds back there was an overflow - ts->tv_nsec = ts->tv_nsec % 1000000000; - } - } - static bool TimeOfDayLaterThan (struct timespec &ts) - { - struct timespec now; - OffsetTimeOfDay(&now); - if (now.tv_sec > ts.tv_sec) - return true; - else if (now.tv_sec < ts.tv_sec) - return false; - else - { - if (now.tv_nsec > ts.tv_nsec) - return true; - else - return false; - } - } protected: - //------------------------------------------------------------------ - // Classes that inherit from DNBTimer can see and modify these - //------------------------------------------------------------------ - std::unique_ptr<PThreadMutex> m_mutexAP; - struct timeval m_timeval; + //------------------------------------------------------------------ + // Classes that inherit from DNBTimer can see and modify these + //------------------------------------------------------------------ + std::unique_ptr<PThreadMutex> m_mutexAP; + struct timeval m_timeval; }; #endif // #ifndef __DNBTimer_h__ diff --git a/lldb/tools/debugserver/source/JSON.cpp b/lldb/tools/debugserver/source/JSON.cpp index 34a01f4ce44..19ebfd000f5 100644 --- a/lldb/tools/debugserver/source/JSON.cpp +++ b/lldb/tools/debugserver/source/JSON.cpp @@ -14,733 +14,575 @@ #include <limits.h> // C++ includes +#include "lldb/Host/StringConvert.h" #include <iomanip> #include <sstream> -#include "lldb/Host/StringConvert.h" using namespace lldb_private; -std::string -JSONString::json_string_quote_metachars (const std::string &s) -{ - if (s.find('"') == std::string::npos) - return s; - - std::string output; - const size_t s_size = s.size(); - const char *s_chars = s.c_str(); - for (size_t i = 0; i < s_size; i++) - { - unsigned char ch = *(s_chars + i); - if (ch == '"') - { - output.push_back ('\\'); - } - output.push_back (ch); +std::string JSONString::json_string_quote_metachars(const std::string &s) { + if (s.find('"') == std::string::npos) + return s; + + std::string output; + const size_t s_size = s.size(); + const char *s_chars = s.c_str(); + for (size_t i = 0; i < s_size; i++) { + unsigned char ch = *(s_chars + i); + if (ch == '"') { + output.push_back('\\'); } - return output; + output.push_back(ch); + } + return output; } -JSONString::JSONString () : - JSONValue(JSONValue::Kind::String), - m_data() -{ -} +JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {} -JSONString::JSONString (const char* s) : - JSONValue(JSONValue::Kind::String), - m_data(s ? s : "") -{ -} +JSONString::JSONString(const char *s) + : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {} -JSONString::JSONString (const std::string& s) : - JSONValue(JSONValue::Kind::String), - m_data(s) -{ -} +JSONString::JSONString(const std::string &s) + : JSONValue(JSONValue::Kind::String), m_data(s) {} -void -JSONString::Write (std::ostream& s) -{ - s << "\"" << json_string_quote_metachars(m_data).c_str() <<"\""; +void JSONString::Write(std::ostream &s) { + s << "\"" << json_string_quote_metachars(m_data).c_str() << "\""; } -uint64_t -JSONNumber::GetAsUnsigned() const -{ - switch (m_data_type) - { - case DataType::Unsigned: - return m_data.m_unsigned; - case DataType::Signed: - return (uint64_t)m_data.m_signed; - case DataType::Double: - return (uint64_t)m_data.m_double; - } - assert("Unhandled data type"); +uint64_t JSONNumber::GetAsUnsigned() const { + switch (m_data_type) { + case DataType::Unsigned: + return m_data.m_unsigned; + case DataType::Signed: + return (uint64_t)m_data.m_signed; + case DataType::Double: + return (uint64_t)m_data.m_double; + } + assert("Unhandled data type"); } -int64_t -JSONNumber::GetAsSigned() const -{ - switch (m_data_type) - { - case DataType::Unsigned: - return (int64_t)m_data.m_unsigned; - case DataType::Signed: - return m_data.m_signed; - case DataType::Double: - return (int64_t)m_data.m_double; - } - assert("Unhandled data type"); +int64_t JSONNumber::GetAsSigned() const { + switch (m_data_type) { + case DataType::Unsigned: + return (int64_t)m_data.m_unsigned; + case DataType::Signed: + return m_data.m_signed; + case DataType::Double: + return (int64_t)m_data.m_double; + } + assert("Unhandled data type"); } -double -JSONNumber::GetAsDouble() const -{ - switch (m_data_type) - { - case DataType::Unsigned: - return (double)m_data.m_unsigned; - case DataType::Signed: - return (double)m_data.m_signed; - case DataType::Double: - return m_data.m_double; - } - assert("Unhandled data type"); +double JSONNumber::GetAsDouble() const { + switch (m_data_type) { + case DataType::Unsigned: + return (double)m_data.m_unsigned; + case DataType::Signed: + return (double)m_data.m_signed; + case DataType::Double: + return m_data.m_double; + } + assert("Unhandled data type"); } -void -JSONNumber::Write (std::ostream& s) -{ - switch (m_data_type) - { - case DataType::Unsigned: - s << m_data.m_unsigned; - break; - case DataType::Signed: - s << m_data.m_signed; - break; - case DataType::Double: - // Set max precision to emulate %g. - s << std::setprecision(std::numeric_limits<double>::digits10 + 1); - s << m_data.m_double; - break; - } +void JSONNumber::Write(std::ostream &s) { + switch (m_data_type) { + case DataType::Unsigned: + s << m_data.m_unsigned; + break; + case DataType::Signed: + s << m_data.m_signed; + break; + case DataType::Double: + // Set max precision to emulate %g. + s << std::setprecision(std::numeric_limits<double>::digits10 + 1); + s << m_data.m_double; + break; + } } -JSONTrue::JSONTrue () : - JSONValue(JSONValue::Kind::True) -{ -} +JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} -void -JSONTrue::Write(std::ostream& s) -{ - s << "true"; -} +void JSONTrue::Write(std::ostream &s) { s << "true"; } -JSONFalse::JSONFalse () : - JSONValue(JSONValue::Kind::False) -{ -} +JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} -void -JSONFalse::Write(std::ostream& s) -{ - s << "false"; -} - -JSONNull::JSONNull () : - JSONValue(JSONValue::Kind::Null) -{ -} +void JSONFalse::Write(std::ostream &s) { s << "false"; } -void -JSONNull::Write(std::ostream& s) -{ - s << "null"; -} +JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} -JSONObject::JSONObject () : - JSONValue(JSONValue::Kind::Object) -{ -} +void JSONNull::Write(std::ostream &s) { s << "null"; } -void -JSONObject::Write (std::ostream& s) -{ - bool first = true; - s << '{'; - auto iter = m_elements.begin(), end = m_elements.end(); - for (;iter != end; iter++) - { - if (first) - first = false; - else - s << ','; - JSONString key(iter->first); - JSONValue::SP value(iter->second); - key.Write(s); - s << ':'; - value->Write(s); - } - s << '}'; -} +JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} -bool -JSONObject::SetObject (const std::string& key, - JSONValue::SP value) -{ - if (key.empty() || nullptr == value.get()) - return false; - m_elements[key] = value; - return true; +void JSONObject::Write(std::ostream &s) { + bool first = true; + s << '{'; + auto iter = m_elements.begin(), end = m_elements.end(); + for (; iter != end; iter++) { + if (first) + first = false; + else + s << ','; + JSONString key(iter->first); + JSONValue::SP value(iter->second); + key.Write(s); + s << ':'; + value->Write(s); + } + s << '}'; +} + +bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { + if (key.empty() || nullptr == value.get()) + return false; + m_elements[key] = value; + return true; } -JSONValue::SP -JSONObject::GetObject (const std::string& key) const -{ - auto iter = m_elements.find(key), end = m_elements.end(); - if (iter == end) - return JSONValue::SP(); - return iter->second; +JSONValue::SP JSONObject::GetObject(const std::string &key) const { + auto iter = m_elements.find(key), end = m_elements.end(); + if (iter == end) + return JSONValue::SP(); + return iter->second; } -bool -JSONObject::GetObjectAsBool (const std::string& key, bool& value) const -{ - auto value_sp = GetObject(key); - if (!value_sp) - { - // The given key doesn't exist, so we have no value. - return false; - } +bool JSONObject::GetObjectAsBool(const std::string &key, bool &value) const { + auto value_sp = GetObject(key); + if (!value_sp) { + // The given key doesn't exist, so we have no value. + return false; + } - if (JSONTrue::classof(value_sp.get())) - { - // We have the value, and it is true. - value = true; - return true; - } - else if (JSONFalse::classof(value_sp.get())) - { - // We have the value, and it is false. - value = false; - return true; - } - else - { - // We don't have a valid bool value for the given key. - return false; - } + if (JSONTrue::classof(value_sp.get())) { + // We have the value, and it is true. + value = true; + return true; + } else if (JSONFalse::classof(value_sp.get())) { + // We have the value, and it is false. + value = false; + return true; + } else { + // We don't have a valid bool value for the given key. + return false; + } } -bool -JSONObject::GetObjectAsString (const std::string& key, std::string& value) const -{ - auto value_sp = GetObject(key); - if (!value_sp) - { - // The given key doesn't exist, so we have no value. - return false; - } +bool JSONObject::GetObjectAsString(const std::string &key, + std::string &value) const { + auto value_sp = GetObject(key); + if (!value_sp) { + // The given key doesn't exist, so we have no value. + return false; + } - if (!JSONString::classof(value_sp.get())) - return false; + if (!JSONString::classof(value_sp.get())) + return false; - value = static_cast<JSONString*>(value_sp.get())->GetData(); - return true; + value = static_cast<JSONString *>(value_sp.get())->GetData(); + return true; } -JSONArray::JSONArray () : - JSONValue(JSONValue::Kind::Array) -{ -} +JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} -void -JSONArray::Write (std::ostream& s) -{ - bool first = true; - s << '['; - auto iter = m_elements.begin(), end = m_elements.end(); - for (;iter != end; iter++) - { - if (first) - first = false; - else - s << ','; - (*iter)->Write(s); - } - s << ']'; +void JSONArray::Write(std::ostream &s) { + bool first = true; + s << '['; + auto iter = m_elements.begin(), end = m_elements.end(); + for (; iter != end; iter++) { + if (first) + first = false; + else + s << ','; + (*iter)->Write(s); + } + s << ']'; } -bool -JSONArray::SetObject (Index i, - JSONValue::SP value) -{ - if (value.get() == nullptr) - return false; - if (i < m_elements.size()) - { - m_elements[i] = value; - return true; - } - if (i == m_elements.size()) - { - m_elements.push_back(value); - return true; - } +bool JSONArray::SetObject(Index i, JSONValue::SP value) { + if (value.get() == nullptr) return false; -} - -bool -JSONArray::AppendObject (JSONValue::SP value) -{ - if (value.get() == nullptr) - return false; + if (i < m_elements.size()) { + m_elements[i] = value; + return true; + } + if (i == m_elements.size()) { m_elements.push_back(value); return true; + } + return false; } -JSONValue::SP -JSONArray::GetObject (Index i) -{ - if (i < m_elements.size()) - return m_elements[i]; - return JSONValue::SP(); -} - -JSONArray::Size -JSONArray::GetNumElements () -{ - return m_elements.size(); -} - - -JSONParser::JSONParser (const char *cstr) : - StdStringExtractor(cstr) -{ -} - -JSONParser::Token -JSONParser::GetToken (std::string &value) -{ - std::ostringstream error; - - value.clear(); - SkipSpaces (); - const uint64_t start_index = m_index; - const char ch = GetChar(); - switch (ch) - { - case '{': return Token::ObjectStart; - case '}': return Token::ObjectEnd; - case '[': return Token::ArrayStart; - case ']': return Token::ArrayEnd; - case ',': return Token::Comma; - case ':': return Token::Colon; - case '\0': return Token::EndOfFile; - case 't': - if (GetChar() == 'r') - if (GetChar() == 'u') - if (GetChar() == 'e') - return Token::True; - break; - - case 'f': - if (GetChar() == 'a') - if (GetChar() == 'l') - if (GetChar() == 's') - if (GetChar() == 'e') - return Token::False; - break; - - case 'n': - if (GetChar() == 'u') - if (GetChar() == 'l') - if (GetChar() == 'l') - return Token::Null; - break; - - case '"': - { - while (1) - { - bool was_escaped = false; - int escaped_ch = GetEscapedChar(was_escaped); - if (escaped_ch == -1) - { - error << "error: an error occurred getting a character from offset " <<start_index; - value = error.str(); - return Token::Error; - - } - else - { - const bool is_end_quote = escaped_ch == '"'; - const bool is_null = escaped_ch == 0; - if (was_escaped || (!is_end_quote && !is_null)) - { - if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) - { - value.append(1, (char)escaped_ch); - } - else - { - error << "error: wide character support is needed for unicode character 0x" << std::setprecision(4) << std::hex << escaped_ch; - error << " at offset " << start_index; - value = error.str(); - return Token::Error; - } - } - else if (is_end_quote) - { - return Token::String; - } - else if (is_null) - { - value = "error: missing end quote for string"; - return Token::Error; - } - } - } - } - break; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - bool done = false; - bool got_decimal_point = false; - uint64_t exp_index = 0; - bool got_int_digits = (ch >= '0') && (ch <= '9'); - bool got_frac_digits = false; - bool got_exp_digits = false; - while (!done) - { - const char next_ch = PeekChar(); - switch (next_ch) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (exp_index != 0) - { - got_exp_digits = true; - } - else if (got_decimal_point) - { - got_frac_digits = true; - } - else - { - got_int_digits = true; - } - ++m_index; // Skip this character - break; - - case '.': - if (got_decimal_point) - { - error << "error: extra decimal point found at offset " << start_index; - value = error.str(); - return Token::Error; - } - else - { - got_decimal_point = true; - ++m_index; // Skip this character - } - break; - - case 'e': - case 'E': - if (exp_index != 0) - { - error << "error: extra exponent character found at offset " << start_index; - value = error.str(); - return Token::Error; - } - else - { - exp_index = m_index; - ++m_index; // Skip this character - } - break; - - case '+': - case '-': - // The '+' and '-' can only come after an exponent character... - if (exp_index == m_index - 1) - { - ++m_index; // Skip the exponent sign character - } - else - { - error << "error: unexpected " << next_ch << " character at offset " << start_index; - value = error.str(); - return Token::Error; - } - break; - - default: - done = true; - break; - } - } - - if (m_index > start_index) - { - value = m_packet.substr(start_index, m_index - start_index); - if (got_decimal_point) - { - if (exp_index != 0) - { - // We have an exponent, make sure we got exponent digits - if (got_exp_digits) - { - return Token::Float; - } - else - { - error << "error: got exponent character but no exponent digits at offset in float value \"" << value.c_str() << "\""; - value = error.str(); - return Token::Error; - } - } - else - { - // No exponent, but we need at least one decimal after the decimal point - if (got_frac_digits) - { - return Token::Float; - } - else - { - error << "error: no digits after decimal point \"" << value.c_str() << "\""; - value = error.str(); - return Token::Error; - } - } - } - else - { - // No decimal point - if (got_int_digits) - { - // We need at least some integer digits to make an integer - return Token::Integer; - } - else - { - error << "error: no digits negate sign \"" << value.c_str() << "\""; - value = error.str(); - return Token::Error; - } - } - } - else - { - error << "error: invalid number found at offset " << start_index; - value = error.str(); - return Token::Error; - } - } - break; - default: - break; - } - error << "error: failed to parse token at offset " << start_index << " (around character '" << ch << "')"; - value = error.str(); - return Token::Error; -} - -int -JSONParser::GetEscapedChar(bool &was_escaped) -{ - was_escaped = false; - const char ch = GetChar(); - if (ch == '\\') - { - was_escaped = true; - const char ch2 = GetChar(); - switch (ch2) - { - case '"': - case '\\': - case '/': - default: - break; - - case 'b': return '\b'; - case 'f': return '\f'; - case 'n': return '\n'; - case 'r': return '\r'; - case 't': return '\t'; - case 'u': - { - const int hi_byte = DecodeHexU8(); - const int lo_byte = DecodeHexU8(); - if (hi_byte >=0 && lo_byte >= 0) - return hi_byte << 8 | lo_byte; - return -1; - } - break; +bool JSONArray::AppendObject(JSONValue::SP value) { + if (value.get() == nullptr) + return false; + m_elements.push_back(value); + return true; +} + +JSONValue::SP JSONArray::GetObject(Index i) { + if (i < m_elements.size()) + return m_elements[i]; + return JSONValue::SP(); +} + +JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } + +JSONParser::JSONParser(const char *cstr) : StdStringExtractor(cstr) {} + +JSONParser::Token JSONParser::GetToken(std::string &value) { + std::ostringstream error; + + value.clear(); + SkipSpaces(); + const uint64_t start_index = m_index; + const char ch = GetChar(); + switch (ch) { + case '{': + return Token::ObjectStart; + case '}': + return Token::ObjectEnd; + case '[': + return Token::ArrayStart; + case ']': + return Token::ArrayEnd; + case ',': + return Token::Comma; + case ':': + return Token::Colon; + case '\0': + return Token::EndOfFile; + case 't': + if (GetChar() == 'r') + if (GetChar() == 'u') + if (GetChar() == 'e') + return Token::True; + break; + + case 'f': + if (GetChar() == 'a') + if (GetChar() == 'l') + if (GetChar() == 's') + if (GetChar() == 'e') + return Token::False; + break; + + case 'n': + if (GetChar() == 'u') + if (GetChar() == 'l') + if (GetChar() == 'l') + return Token::Null; + break; + + case '"': { + while (1) { + bool was_escaped = false; + int escaped_ch = GetEscapedChar(was_escaped); + if (escaped_ch == -1) { + error << "error: an error occurred getting a character from offset " + << start_index; + value = error.str(); + return Token::Error; + + } else { + const bool is_end_quote = escaped_ch == '"'; + const bool is_null = escaped_ch == 0; + if (was_escaped || (!is_end_quote && !is_null)) { + if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) { + value.append(1, (char)escaped_ch); + } else { + error << "error: wide character support is needed for unicode " + "character 0x" + << std::setprecision(4) << std::hex << escaped_ch; + error << " at offset " << start_index; + value = error.str(); + return Token::Error; + } + } else if (is_end_quote) { + return Token::String; + } else if (is_null) { + value = "error: missing end quote for string"; + return Token::Error; } - return ch2; + } } - return ch; -} - -JSONValue::SP -JSONParser::ParseJSONObject () -{ - // The "JSONParser::Token::ObjectStart" token should have already been consumed - // by the time this function is called - std::unique_ptr<JSONObject> dict_up(new JSONObject()); - - std::string value; - std::string key; - while (1) - { - JSONParser::Token token = GetToken(value); - - if (token == JSONParser::Token::String) - { - key.swap(value); - token = GetToken(value); - if (token == JSONParser::Token::Colon) - { - JSONValue::SP value_sp = ParseJSONValue(); - if (value_sp) - dict_up->SetObject(key, value_sp); - else - break; - } + } break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { + bool done = false; + bool got_decimal_point = false; + uint64_t exp_index = 0; + bool got_int_digits = (ch >= '0') && (ch <= '9'); + bool got_frac_digits = false; + bool got_exp_digits = false; + while (!done) { + const char next_ch = PeekChar(); + switch (next_ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (exp_index != 0) { + got_exp_digits = true; + } else if (got_decimal_point) { + got_frac_digits = true; + } else { + got_int_digits = true; } - else if (token == JSONParser::Token::ObjectEnd) - { - return JSONValue::SP(dict_up.release()); + ++m_index; // Skip this character + break; + + case '.': + if (got_decimal_point) { + error << "error: extra decimal point found at offset " << start_index; + value = error.str(); + return Token::Error; + } else { + got_decimal_point = true; + ++m_index; // Skip this character } - else if (token == JSONParser::Token::Comma) - { - continue; + break; + + case 'e': + case 'E': + if (exp_index != 0) { + error << "error: extra exponent character found at offset " + << start_index; + value = error.str(); + return Token::Error; + } else { + exp_index = m_index; + ++m_index; // Skip this character } - else - { - break; + break; + + case '+': + case '-': + // The '+' and '-' can only come after an exponent character... + if (exp_index == m_index - 1) { + ++m_index; // Skip the exponent sign character + } else { + error << "error: unexpected " << next_ch << " character at offset " + << start_index; + value = error.str(); + return Token::Error; } - } - return JSONValue::SP(); -} + break; -JSONValue::SP -JSONParser::ParseJSONArray () -{ - // The "JSONParser::Token::ObjectStart" token should have already been consumed - // by the time this function is called - std::unique_ptr<JSONArray> array_up(new JSONArray()); - - std::string value; - std::string key; - while (1) - { - JSONValue::SP value_sp = ParseJSONValue(); - if (value_sp) - array_up->AppendObject(value_sp); - else - break; + default: + done = true; + break; + } + } - JSONParser::Token token = GetToken(value); - if (token == JSONParser::Token::Comma) - { - continue; + if (m_index > start_index) { + value = m_packet.substr(start_index, m_index - start_index); + if (got_decimal_point) { + if (exp_index != 0) { + // We have an exponent, make sure we got exponent digits + if (got_exp_digits) { + return Token::Float; + } else { + error << "error: got exponent character but no exponent digits at " + "offset in float value \"" + << value.c_str() << "\""; + value = error.str(); + return Token::Error; + } + } else { + // No exponent, but we need at least one decimal after the decimal + // point + if (got_frac_digits) { + return Token::Float; + } else { + error << "error: no digits after decimal point \"" << value.c_str() + << "\""; + value = error.str(); + return Token::Error; + } } - else if (token == JSONParser::Token::ArrayEnd) - { - return JSONValue::SP(array_up.release()); + } else { + // No decimal point + if (got_int_digits) { + // We need at least some integer digits to make an integer + return Token::Integer; + } else { + error << "error: no digits negate sign \"" << value.c_str() << "\""; + value = error.str(); + return Token::Error; } + } + } else { + error << "error: invalid number found at offset " << start_index; + value = error.str(); + return Token::Error; + } + } break; + default: + break; + } + error << "error: failed to parse token at offset " << start_index + << " (around character '" << ch << "')"; + value = error.str(); + return Token::Error; +} + +int JSONParser::GetEscapedChar(bool &was_escaped) { + was_escaped = false; + const char ch = GetChar(); + if (ch == '\\') { + was_escaped = true; + const char ch2 = GetChar(); + switch (ch2) { + case '"': + case '\\': + case '/': + default: + break; + + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'u': { + const int hi_byte = DecodeHexU8(); + const int lo_byte = DecodeHexU8(); + if (hi_byte >= 0 && lo_byte >= 0) + return hi_byte << 8 | lo_byte; + return -1; + } break; + } + return ch2; + } + return ch; +} + +JSONValue::SP JSONParser::ParseJSONObject() { + // The "JSONParser::Token::ObjectStart" token should have already been + // consumed + // by the time this function is called + std::unique_ptr<JSONObject> dict_up(new JSONObject()); + + std::string value; + std::string key; + while (1) { + JSONParser::Token token = GetToken(value); + + if (token == JSONParser::Token::String) { + key.swap(value); + token = GetToken(value); + if (token == JSONParser::Token::Colon) { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + dict_up->SetObject(key, value_sp); else - { - break; - } + break; + } + } else if (token == JSONParser::Token::ObjectEnd) { + return JSONValue::SP(dict_up.release()); + } else if (token == JSONParser::Token::Comma) { + continue; + } else { + break; } - return JSONValue::SP(); -} + } + return JSONValue::SP(); +} + +JSONValue::SP JSONParser::ParseJSONArray() { + // The "JSONParser::Token::ObjectStart" token should have already been + // consumed + // by the time this function is called + std::unique_ptr<JSONArray> array_up(new JSONArray()); + + std::string value; + std::string key; + while (1) { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + array_up->AppendObject(value_sp); + else + break; + + JSONParser::Token token = GetToken(value); + if (token == JSONParser::Token::Comma) { + continue; + } else if (token == JSONParser::Token::ArrayEnd) { + return JSONValue::SP(array_up.release()); + } else { + break; + } + } + return JSONValue::SP(); +} + +JSONValue::SP JSONParser::ParseJSONValue() { + std::string value; + const JSONParser::Token token = GetToken(value); + switch (token) { + case JSONParser::Token::ObjectStart: + return ParseJSONObject(); + + case JSONParser::Token::ArrayStart: + return ParseJSONArray(); + + case JSONParser::Token::Integer: { + if (value.front() == '-') { + bool success = false; + int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); + if (success) + return JSONValue::SP(new JSONNumber(sval)); + } else { + bool success = false; + uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); + if (success) + return JSONValue::SP(new JSONNumber(uval)); + } + } break; -JSONValue::SP -JSONParser::ParseJSONValue () -{ - std::string value; - const JSONParser::Token token = GetToken(value); - switch (token) - { - case JSONParser::Token::ObjectStart: - return ParseJSONObject(); - - case JSONParser::Token::ArrayStart: - return ParseJSONArray(); - - case JSONParser::Token::Integer: - { - if (value.front() == '-') - { - bool success = false; - int64_t sval = StringConvert::ToSInt64(value.c_str(), 0, 0, &success); - if (success) - return JSONValue::SP(new JSONNumber(sval)); - } - else - { - bool success = false; - uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); - if (success) - return JSONValue::SP(new JSONNumber(uval)); - } - } - break; - - case JSONParser::Token::Float: - { - bool success = false; - double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); - if (success) - return JSONValue::SP(new JSONNumber(val)); - } - break; + case JSONParser::Token::Float: { + bool success = false; + double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); + if (success) + return JSONValue::SP(new JSONNumber(val)); + } break; - case JSONParser::Token::String: - return JSONValue::SP(new JSONString(value)); + case JSONParser::Token::String: + return JSONValue::SP(new JSONString(value)); - case JSONParser::Token::True: - return JSONValue::SP(new JSONTrue()); + case JSONParser::Token::True: + return JSONValue::SP(new JSONTrue()); - case JSONParser::Token::False: - return JSONValue::SP(new JSONFalse()); + case JSONParser::Token::False: + return JSONValue::SP(new JSONFalse()); - case JSONParser::Token::Null: - return JSONValue::SP(new JSONNull()); + case JSONParser::Token::Null: + return JSONValue::SP(new JSONNull()); - default: - break; - } - return JSONValue::SP(); - + default: + break; + } + return JSONValue::SP(); } diff --git a/lldb/tools/debugserver/source/JSON.h b/lldb/tools/debugserver/source/JSON.h index e24f928bcf7..d3951776cac 100644 --- a/lldb/tools/debugserver/source/JSON.h +++ b/lldb/tools/debugserver/source/JSON.h @@ -25,358 +25,281 @@ #include <string> #include <vector> -class JSONValue -{ +class JSONValue { public: - virtual void - Write (std::ostream& s) = 0; - - typedef std::shared_ptr<JSONValue> SP; - - enum class Kind - { - String, - Number, - True, - False, - Null, - Object, - Array - }; - - JSONValue (Kind k) : - m_kind(k) - {} - - Kind - GetKind() const - { - return m_kind; - } - - virtual - ~JSONValue () = default; - + virtual void Write(std::ostream &s) = 0; + + typedef std::shared_ptr<JSONValue> SP; + + enum class Kind { String, Number, True, False, Null, Object, Array }; + + JSONValue(Kind k) : m_kind(k) {} + + Kind GetKind() const { return m_kind; } + + virtual ~JSONValue() = default; + private: - const Kind m_kind; + const Kind m_kind; }; -class JSONString : public JSONValue -{ +class JSONString : public JSONValue { public: - JSONString (); - JSONString (const char* s); - JSONString (const std::string& s); - - JSONString (const JSONString& s) = delete; - JSONString& - operator = (const JSONString& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONString> SP; - - std::string - GetData () { return m_data; } - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::String; - } - - ~JSONString() override = default; - + JSONString(); + JSONString(const char *s); + JSONString(const std::string &s); + + JSONString(const JSONString &s) = delete; + JSONString &operator=(const JSONString &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONString> SP; + + std::string GetData() { return m_data; } + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::String; + } + + ~JSONString() override = default; + private: - - static std::string - json_string_quote_metachars (const std::string&); - - std::string m_data; + static std::string json_string_quote_metachars(const std::string &); + + std::string m_data; }; -class JSONNumber : public JSONValue -{ +class JSONNumber : public JSONValue { public: - typedef std::shared_ptr<JSONNumber> SP; - - // We cretae a constructor for all integer and floating point type with using templates and - // SFINAE to avoid having ambiguous overloads because of the implicit type promotion. If we - // would have constructors only with int64_t, uint64_t and double types then constructing a - // JSONNumber from an int32_t (or any other similar type) would fail to compile. - - template <typename T, - typename std::enable_if<std::is_integral<T>::value && - std::is_unsigned<T>::value>::type* = nullptr> - explicit JSONNumber (T u) : - JSONValue(JSONValue::Kind::Number), - m_data_type(DataType::Unsigned) - { - m_data.m_unsigned = u; - } - - template <typename T, - typename std::enable_if<std::is_integral<T>::value && - std::is_signed<T>::value>::type* = nullptr> - explicit JSONNumber (T s) : - JSONValue(JSONValue::Kind::Number), - m_data_type(DataType::Signed) - { - m_data.m_signed = s; - } - - template <typename T, - typename std::enable_if<std::is_floating_point<T>::value>::type* = nullptr> - explicit JSONNumber (T d) : - JSONValue(JSONValue::Kind::Number), - m_data_type(DataType::Double) - { - m_data.m_double = d; - } - - ~JSONNumber() override = default; - - JSONNumber (const JSONNumber& s) = delete; - JSONNumber& - operator = (const JSONNumber& s) = delete; - - void - Write(std::ostream& s) override; - - uint64_t - GetAsUnsigned() const; - - int64_t - GetAsSigned() const; - - double - GetAsDouble() const; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::Number; - } + typedef std::shared_ptr<JSONNumber> SP; + + // We cretae a constructor for all integer and floating point type with using + // templates and + // SFINAE to avoid having ambiguous overloads because of the implicit type + // promotion. If we + // would have constructors only with int64_t, uint64_t and double types then + // constructing a + // JSONNumber from an int32_t (or any other similar type) would fail to + // compile. + + template <typename T, typename std::enable_if< + std::is_integral<T>::value && + std::is_unsigned<T>::value>::type * = nullptr> + explicit JSONNumber(T u) + : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Unsigned) { + m_data.m_unsigned = u; + } + + template <typename T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value>::type * = nullptr> + explicit JSONNumber(T s) + : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Signed) { + m_data.m_signed = s; + } + + template <typename T, typename std::enable_if< + std::is_floating_point<T>::value>::type * = nullptr> + explicit JSONNumber(T d) + : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Double) { + m_data.m_double = d; + } + + ~JSONNumber() override = default; + + JSONNumber(const JSONNumber &s) = delete; + JSONNumber &operator=(const JSONNumber &s) = delete; + + void Write(std::ostream &s) override; + + uint64_t GetAsUnsigned() const; + + int64_t GetAsSigned() const; + + double GetAsDouble() const; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::Number; + } private: - enum class DataType : uint8_t - { - Unsigned, - Signed, - Double - } m_data_type; - - union - { - uint64_t m_unsigned; - int64_t m_signed; - double m_double; - } m_data; + enum class DataType : uint8_t { Unsigned, Signed, Double } m_data_type; + + union { + uint64_t m_unsigned; + int64_t m_signed; + double m_double; + } m_data; }; -class JSONTrue : public JSONValue -{ +class JSONTrue : public JSONValue { public: - JSONTrue (); - - JSONTrue (const JSONTrue& s) = delete; - JSONTrue& - operator = (const JSONTrue& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONTrue> SP; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::True; - } - - ~JSONTrue() override = default; + JSONTrue(); + + JSONTrue(const JSONTrue &s) = delete; + JSONTrue &operator=(const JSONTrue &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONTrue> SP; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::True; + } + + ~JSONTrue() override = default; }; -class JSONFalse : public JSONValue -{ +class JSONFalse : public JSONValue { public: - JSONFalse (); - - JSONFalse (const JSONFalse& s) = delete; - JSONFalse& - operator = (const JSONFalse& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONFalse> SP; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::False; - } - - ~JSONFalse() override = default; + JSONFalse(); + + JSONFalse(const JSONFalse &s) = delete; + JSONFalse &operator=(const JSONFalse &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONFalse> SP; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::False; + } + + ~JSONFalse() override = default; }; -class JSONNull : public JSONValue -{ +class JSONNull : public JSONValue { public: - JSONNull (); - - JSONNull (const JSONNull& s) = delete; - JSONNull& - operator = (const JSONNull& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONNull> SP; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::Null; - } - - ~JSONNull() override = default; + JSONNull(); + + JSONNull(const JSONNull &s) = delete; + JSONNull &operator=(const JSONNull &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONNull> SP; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::Null; + } + + ~JSONNull() override = default; }; -class JSONObject : public JSONValue -{ +class JSONObject : public JSONValue { public: - JSONObject (); - - JSONObject (const JSONObject& s) = delete; - JSONObject& - operator = (const JSONObject& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONObject> SP; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::Object; - } - - bool - SetObject (const std::string& key, - JSONValue::SP value); - - JSONValue::SP - GetObject (const std::string& key) const; - - // ------------------------------------------------------------------------- - /// Return keyed value as bool - /// - /// @param[in] key - /// The value of the key to lookup - /// - /// @param[out] value - /// The value of the key as a bool. Undefined if the key doesn't - /// exist or if the key is not either true or false. - /// - /// @return - /// true if the key existed as was a bool value; false otherwise. - /// Note the return value is *not* the value of the bool, use - /// \b value for that. - // ------------------------------------------------------------------------- - bool - GetObjectAsBool (const std::string& key, bool& value) const; - - bool - GetObjectAsString (const std::string& key, std::string& value) const; - - ~JSONObject() override = default; - + JSONObject(); + + JSONObject(const JSONObject &s) = delete; + JSONObject &operator=(const JSONObject &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONObject> SP; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::Object; + } + + bool SetObject(const std::string &key, JSONValue::SP value); + + JSONValue::SP GetObject(const std::string &key) const; + + // ------------------------------------------------------------------------- + /// Return keyed value as bool + /// + /// @param[in] key + /// The value of the key to lookup + /// + /// @param[out] value + /// The value of the key as a bool. Undefined if the key doesn't + /// exist or if the key is not either true or false. + /// + /// @return + /// true if the key existed as was a bool value; false otherwise. + /// Note the return value is *not* the value of the bool, use + /// \b value for that. + // ------------------------------------------------------------------------- + bool GetObjectAsBool(const std::string &key, bool &value) const; + + bool GetObjectAsString(const std::string &key, std::string &value) const; + + ~JSONObject() override = default; + private: - typedef std::map<std::string, JSONValue::SP> Map; - typedef Map::iterator Iterator; - Map m_elements; + typedef std::map<std::string, JSONValue::SP> Map; + typedef Map::iterator Iterator; + Map m_elements; }; -class JSONArray : public JSONValue -{ +class JSONArray : public JSONValue { public: - JSONArray (); - - JSONArray (const JSONArray& s) = delete; - JSONArray& - operator = (const JSONArray& s) = delete; - - void - Write(std::ostream& s) override; - - typedef std::shared_ptr<JSONArray> SP; - - static bool classof(const JSONValue *V) - { - return V->GetKind() == JSONValue::Kind::Array; - } - + JSONArray(); + + JSONArray(const JSONArray &s) = delete; + JSONArray &operator=(const JSONArray &s) = delete; + + void Write(std::ostream &s) override; + + typedef std::shared_ptr<JSONArray> SP; + + static bool classof(const JSONValue *V) { + return V->GetKind() == JSONValue::Kind::Array; + } + private: - typedef std::vector<JSONValue::SP> Vector; - typedef Vector::iterator Iterator; - typedef Vector::size_type Index; - typedef Vector::size_type Size; - + typedef std::vector<JSONValue::SP> Vector; + typedef Vector::iterator Iterator; + typedef Vector::size_type Index; + typedef Vector::size_type Size; + public: - bool - SetObject (Index i, - JSONValue::SP value); - - bool - AppendObject (JSONValue::SP value); - - JSONValue::SP - GetObject (Index i); - - Size - GetNumElements (); - - ~JSONArray() override = default; - - Vector m_elements; + bool SetObject(Index i, JSONValue::SP value); + + bool AppendObject(JSONValue::SP value); + + JSONValue::SP GetObject(Index i); + + Size GetNumElements(); + + ~JSONArray() override = default; + + Vector m_elements; }; -class JSONParser : public StdStringExtractor -{ +class JSONParser : public StdStringExtractor { public: - enum Token - { - Invalid, - Error, - ObjectStart, - ObjectEnd, - ArrayStart, - ArrayEnd, - Comma, - Colon, - String, - Integer, - Float, - True, - False, - Null, - EndOfFile - }; - - JSONParser (const char *cstr); - - int - GetEscapedChar (bool &was_escaped); - - Token - GetToken (std::string &value); - - JSONValue::SP - ParseJSONValue (); + enum Token { + Invalid, + Error, + ObjectStart, + ObjectEnd, + ArrayStart, + ArrayEnd, + Comma, + Colon, + String, + Integer, + Float, + True, + False, + Null, + EndOfFile + }; + + JSONParser(const char *cstr); + + int GetEscapedChar(bool &was_escaped); + + Token GetToken(std::string &value); + + JSONValue::SP ParseJSONValue(); protected: - JSONValue::SP - ParseJSONObject (); + JSONValue::SP ParseJSONObject(); - JSONValue::SP - ParseJSONArray (); + JSONValue::SP ParseJSONArray(); }; #endif // utility_JSON_h_ diff --git a/lldb/tools/debugserver/source/JSONGenerator.h b/lldb/tools/debugserver/source/JSONGenerator.h index 423b2bd5792..a85dcb6e860 100644 --- a/lldb/tools/debugserver/source/JSONGenerator.h +++ b/lldb/tools/debugserver/source/JSONGenerator.h @@ -29,462 +29,291 @@ /// and printing it as a JSON string. //---------------------------------------------------------------------- -class JSONGenerator -{ +class JSONGenerator { public: + class Object; + class Array; + class Integer; + class Float; + class Boolean; + class String; + class Dictionary; + class Generic; + + typedef std::shared_ptr<Object> ObjectSP; + typedef std::shared_ptr<Array> ArraySP; + typedef std::shared_ptr<Integer> IntegerSP; + typedef std::shared_ptr<Float> FloatSP; + typedef std::shared_ptr<Boolean> BooleanSP; + typedef std::shared_ptr<String> StringSP; + typedef std::shared_ptr<Dictionary> DictionarySP; + typedef std::shared_ptr<Generic> GenericSP; + + enum class Type { + eTypeInvalid = -1, + eTypeNull = 0, + eTypeGeneric, + eTypeArray, + eTypeInteger, + eTypeFloat, + eTypeBoolean, + eTypeString, + eTypeDictionary + }; + + class Object : public std::enable_shared_from_this<Object> { + public: + Object(Type t = Type::eTypeInvalid) : m_type(t) {} + + virtual ~Object() {} + + virtual bool IsValid() const { return true; } + + virtual void Clear() { m_type = Type::eTypeInvalid; } + + Type GetType() const { return m_type; } + + void SetType(Type t) { m_type = t; } + + Array *GetAsArray() { + if (m_type == Type::eTypeArray) + return (Array *)this; + return NULL; + } + + Dictionary *GetAsDictionary() { + if (m_type == Type::eTypeDictionary) + return (Dictionary *)this; + return NULL; + } + + Integer *GetAsInteger() { + if (m_type == Type::eTypeInteger) + return (Integer *)this; + return NULL; + } + + Float *GetAsFloat() { + if (m_type == Type::eTypeFloat) + return (Float *)this; + return NULL; + } + + Boolean *GetAsBoolean() { + if (m_type == Type::eTypeBoolean) + return (Boolean *)this; + return NULL; + } + + String *GetAsString() { + if (m_type == Type::eTypeString) + return (String *)this; + return NULL; + } + + Generic *GetAsGeneric() { + if (m_type == Type::eTypeGeneric) + return (Generic *)this; + return NULL; + } + + virtual void Dump(std::ostream &s) const = 0; + + private: + Type m_type; + }; + + class Array : public Object { + public: + Array() : Object(Type::eTypeArray) {} + + virtual ~Array() {} + + void AddItem(ObjectSP item) { m_items.push_back(item); } + + void Dump(std::ostream &s) const override { + s << "["; + const size_t arrsize = m_items.size(); + for (size_t i = 0; i < arrsize; ++i) { + m_items[i]->Dump(s); + if (i + 1 < arrsize) + s << ","; + } + s << "]"; + } + + protected: + typedef std::vector<ObjectSP> collection; + collection m_items; + }; + + class Integer : public Object { + public: + Integer(uint64_t value = 0) : Object(Type::eTypeInteger), m_value(value) {} + + virtual ~Integer() {} + + void SetValue(uint64_t value) { m_value = value; } + + void Dump(std::ostream &s) const override { s << m_value; } + + protected: + uint64_t m_value; + }; - class Object; - class Array; - class Integer; - class Float; - class Boolean; - class String; - class Dictionary; - class Generic; - - typedef std::shared_ptr<Object> ObjectSP; - typedef std::shared_ptr<Array> ArraySP; - typedef std::shared_ptr<Integer> IntegerSP; - typedef std::shared_ptr<Float> FloatSP; - typedef std::shared_ptr<Boolean> BooleanSP; - typedef std::shared_ptr<String> StringSP; - typedef std::shared_ptr<Dictionary> DictionarySP; - typedef std::shared_ptr<Generic> GenericSP; - - enum class Type - { - eTypeInvalid = -1, - eTypeNull = 0, - eTypeGeneric, - eTypeArray, - eTypeInteger, - eTypeFloat, - eTypeBoolean, - eTypeString, - eTypeDictionary - }; - - class Object : - public std::enable_shared_from_this<Object> - { - public: - - Object (Type t = Type::eTypeInvalid) : - m_type (t) - { - } - - virtual ~Object () - { - } - - virtual bool - IsValid() const - { - return true; - } - - virtual void - Clear () - { - m_type = Type::eTypeInvalid; - } - - Type - GetType () const - { - return m_type; - } - - void - SetType (Type t) - { - m_type = t; - } - - Array * - GetAsArray () - { - if (m_type == Type::eTypeArray) - return (Array *)this; - return NULL; - } - - Dictionary * - GetAsDictionary () - { - if (m_type == Type::eTypeDictionary) - return (Dictionary *)this; - return NULL; - } - - Integer * - GetAsInteger () - { - if (m_type == Type::eTypeInteger) - return (Integer *)this; - return NULL; - } - - Float * - GetAsFloat () - { - if (m_type == Type::eTypeFloat) - return (Float *)this; - return NULL; - } - - Boolean * - GetAsBoolean () - { - if (m_type == Type::eTypeBoolean) - return (Boolean *)this; - return NULL; - } - - String * - GetAsString () - { - if (m_type == Type::eTypeString) - return (String *)this; - return NULL; - } - - Generic * - GetAsGeneric() - { - if (m_type == Type::eTypeGeneric) - return (Generic *)this; - return NULL; - } - - virtual void - Dump (std::ostream &s) const = 0; - - private: - Type m_type; - }; - - class Array : public Object - { - public: - Array () : - Object (Type::eTypeArray) - { - } - - virtual - ~Array() - { - } - - void - AddItem(ObjectSP item) - { - m_items.push_back(item); - } - - void Dump(std::ostream &s) const override - { - s << "["; - const size_t arrsize = m_items.size(); - for (size_t i = 0; i < arrsize; ++i) - { - m_items[i]->Dump(s); - if (i + 1 < arrsize) - s << ","; - } - s << "]"; - } - - protected: - typedef std::vector<ObjectSP> collection; - collection m_items; - }; - - - class Integer : public Object - { - public: - Integer (uint64_t value = 0) : - Object (Type::eTypeInteger), - m_value (value) - { - } - - virtual ~Integer() - { - } - - void - SetValue (uint64_t value) - { - m_value = value; - } - - void Dump(std::ostream &s) const override - { - s << m_value; - } - - protected: - uint64_t m_value; - }; - - class Float : public Object - { - public: - Float (double d = 0.0) : - Object (Type::eTypeFloat), - m_value (d) - { - } - - virtual ~Float() - { - } - - void - SetValue (double value) - { - m_value = value; - } + class Float : public Object { + public: + Float(double d = 0.0) : Object(Type::eTypeFloat), m_value(d) {} + + virtual ~Float() {} + + void SetValue(double value) { m_value = value; } + + void Dump(std::ostream &s) const override { s << m_value; } + + protected: + double m_value; + }; + + class Boolean : public Object { + public: + Boolean(bool b = false) : Object(Type::eTypeBoolean), m_value(b) {} + + virtual ~Boolean() {} + + void SetValue(bool value) { m_value = value; } + + void Dump(std::ostream &s) const override { + if (m_value == true) + s << "true"; + else + s << "false"; + } + + protected: + bool m_value; + }; + + class String : public Object { + public: + String() : Object(Type::eTypeString), m_value() {} + + String(const std::string &s) : Object(Type::eTypeString), m_value(s) {} + + String(const std::string &&s) : Object(Type::eTypeString), m_value(s) {} + + void SetValue(const std::string &string) { m_value = string; } + + void Dump(std::ostream &s) const override { + std::string quoted; + const size_t strsize = m_value.size(); + for (size_t i = 0; i < strsize; ++i) { + char ch = m_value[i]; + if (ch == '"') + quoted.push_back('\\'); + quoted.push_back(ch); + } + s << '"' << quoted.c_str() << '"'; + } - void Dump(std::ostream &s) const override - { - s << m_value; - } - - protected: - double m_value; - }; - - class Boolean : public Object - { - public: - Boolean (bool b = false) : - Object (Type::eTypeBoolean), - m_value (b) - { - } - - virtual ~Boolean() - { - } - - void - SetValue (bool value) - { - m_value = value; - } - - void Dump(std::ostream &s) const override - { - if (m_value == true) - s << "true"; - else - s << "false"; - } - - protected: - bool m_value; - }; - - - - class String : public Object - { - public: - String () : - Object (Type::eTypeString), - m_value () - { - } + protected: + std::string m_value; + }; - String (const std::string &s) : - Object (Type::eTypeString), - m_value (s) - { - } + class Dictionary : public Object { + public: + Dictionary() : Object(Type::eTypeDictionary), m_dict() {} - String (const std::string &&s) : - Object (Type::eTypeString), - m_value (s) - { - } + virtual ~Dictionary() {} - void - SetValue (const std::string &string) - { - m_value = string; - } + void AddItem(std::string key, ObjectSP value) { + m_dict.push_back(Pair(key, value)); + } - void Dump(std::ostream &s) const override - { - std::string quoted; - const size_t strsize = m_value.size(); - for (size_t i = 0; i < strsize ; ++i) - { - char ch = m_value[i]; - if (ch == '"') - quoted.push_back ('\\'); - quoted.push_back (ch); - } - s << '"' << quoted.c_str() << '"'; - } + void AddIntegerItem(std::string key, uint64_t value) { + AddItem(key, ObjectSP(new Integer(value))); + } - protected: - std::string m_value; - }; - - class Dictionary : public Object - { - public: - Dictionary () : - Object (Type::eTypeDictionary), - m_dict () - { - } + void AddFloatItem(std::string key, double value) { + AddItem(key, ObjectSP(new Float(value))); + } - virtual ~Dictionary() - { - } + void AddStringItem(std::string key, std::string value) { + AddItem(key, ObjectSP(new String(std::move(value)))); + } - void - AddItem (std::string key, ObjectSP value) - { - m_dict.push_back(Pair(key, value)); - } - - void - AddIntegerItem (std::string key, uint64_t value) - { - AddItem (key, ObjectSP (new Integer(value))); - } + void AddBytesAsHexASCIIString(std::string key, const uint8_t *src, + size_t src_len) { + if (src && src_len) { + std::ostringstream strm; + for (size_t i = 0; i < src_len; i++) + strm << std::setfill('0') << std::hex << std::right << std::setw(2) + << ((uint32_t)(src[i])); + AddItem(key, ObjectSP(new String(std::move(strm.str())))); + } else { + AddItem(key, ObjectSP(new String())); + } + } - void - AddFloatItem (std::string key, double value) - { - AddItem (key, ObjectSP (new Float(value))); - } - - void - AddStringItem (std::string key, std::string value) - { - AddItem (key, ObjectSP (new String(std::move(value)))); - } + void AddBooleanItem(std::string key, bool value) { + AddItem(key, ObjectSP(new Boolean(value))); + } - void - AddBytesAsHexASCIIString (std::string key, const uint8_t *src, size_t src_len) - { - if (src && src_len) - { - std::ostringstream strm; - for (size_t i = 0; i < src_len; i++) - strm << std::setfill('0') << std::hex << std::right << std::setw(2) << ((uint32_t)(src[i])); - AddItem (key, ObjectSP (new String(std::move(strm.str())))); - } - else - { - AddItem (key, ObjectSP (new String())); - } + void Dump(std::ostream &s) const override { + bool have_printed_one_elem = false; + s << "{"; + for (collection::const_iterator iter = m_dict.begin(); + iter != m_dict.end(); ++iter) { + if (have_printed_one_elem == false) { + have_printed_one_elem = true; + } else { + s << ","; } + s << "\"" << iter->first.c_str() << "\":"; + iter->second->Dump(s); + } + s << "}"; + } - void - AddBooleanItem (std::string key, bool value) - { - AddItem (key, ObjectSP (new Boolean(value))); - } - - void Dump(std::ostream &s) const override - { - bool have_printed_one_elem = false; - s << "{"; - for (collection::const_iterator iter = m_dict.begin(); iter != m_dict.end(); ++iter) - { - if (have_printed_one_elem == false) - { - have_printed_one_elem = true; - } - else - { - s << ","; - } - s << "\"" << iter->first.c_str() << "\":"; - iter->second->Dump(s); - } - s << "}"; - } - - protected: - // Keep the dictionary as a vector so the dictionary doesn't reorder itself when you dump it - // We aren't accessing keys by name, so this won't affect performance - typedef std::pair<std::string, ObjectSP> Pair; - typedef std::vector<Pair> collection; - collection m_dict; - }; - - class Null : public Object - { - public: - Null () : - Object (Type::eTypeNull) - { - } - - virtual ~Null() - { - } - - bool - IsValid() const override - { - return false; - } - - void Dump(std::ostream &s) const override - { - s << "null"; - } - - protected: - }; - - class Generic : public Object - { - public: - explicit Generic(void *object = nullptr) - : Object(Type::eTypeGeneric) - , m_object(object) - { - } - - void - SetValue(void *value) - { - m_object = value; - } - - void * - GetValue() const - { - return m_object; - } - - bool - IsValid() const override - { - return m_object != nullptr; - } - - void Dump(std::ostream &s) const override; - - private: - void *m_object; - }; - -}; // class JSONGenerator - - + protected: + // Keep the dictionary as a vector so the dictionary doesn't reorder itself + // when you dump it + // We aren't accessing keys by name, so this won't affect performance + typedef std::pair<std::string, ObjectSP> Pair; + typedef std::vector<Pair> collection; + collection m_dict; + }; + + class Null : public Object { + public: + Null() : Object(Type::eTypeNull) {} + + virtual ~Null() {} + + bool IsValid() const override { return false; } + + void Dump(std::ostream &s) const override { s << "null"; } + + protected: + }; + + class Generic : public Object { + public: + explicit Generic(void *object = nullptr) + : Object(Type::eTypeGeneric), m_object(object) {} + + void SetValue(void *value) { m_object = value; } + + void *GetValue() const { return m_object; } + + bool IsValid() const override { return m_object != nullptr; } + + void Dump(std::ostream &s) const override; + + private: + void *m_object; + }; + +}; // class JSONGenerator -#endif // __JSONGenerator_h_ +#endif // __JSONGenerator_h_ diff --git a/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp b/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp index fdcb7cc2fcb..7b080e60cdb 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp +++ b/lldb/tools/debugserver/source/MacOSX/CFBundle.cpp @@ -17,81 +17,63 @@ //---------------------------------------------------------------------- // CFBundle constructor //---------------------------------------------------------------------- -CFBundle::CFBundle(const char *path) : - CFReleaser<CFBundleRef>(), - m_bundle_url() -{ - if (path && path[0]) - SetPath(path); +CFBundle::CFBundle(const char *path) + : CFReleaser<CFBundleRef>(), m_bundle_url() { + if (path && path[0]) + SetPath(path); } //---------------------------------------------------------------------- // CFBundle copy constructor //---------------------------------------------------------------------- -CFBundle::CFBundle(const CFBundle& rhs) : - CFReleaser<CFBundleRef>(rhs), - m_bundle_url(rhs.m_bundle_url) -{ - -} +CFBundle::CFBundle(const CFBundle &rhs) + : CFReleaser<CFBundleRef>(rhs), m_bundle_url(rhs.m_bundle_url) {} //---------------------------------------------------------------------- // CFBundle copy constructor //---------------------------------------------------------------------- -CFBundle& -CFBundle::operator=(const CFBundle& rhs) -{ - *this = rhs; - return *this; +CFBundle &CFBundle::operator=(const CFBundle &rhs) { + *this = rhs; + return *this; } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -CFBundle::~CFBundle() -{ -} +CFBundle::~CFBundle() {} //---------------------------------------------------------------------- // Set the path for a bundle by supplying a //---------------------------------------------------------------------- -bool -CFBundle::SetPath (const char *path) -{ - CFAllocatorRef alloc = kCFAllocatorDefault; - // Release our old bundle and ULR - reset(); // This class is a CFReleaser<CFBundleRef> - m_bundle_url.reset(); - // Make a CFStringRef from the supplied path - CFString cf_path; - cf_path.SetFileSystemRepresentation(path); - if (cf_path.get()) - { - // Make our Bundle URL - m_bundle_url.reset (::CFURLCreateWithFileSystemPath (alloc, cf_path.get(), kCFURLPOSIXPathStyle, true)); - if (m_bundle_url.get()) - { - reset (::CFBundleCreate (alloc, m_bundle_url.get())); - } +bool CFBundle::SetPath(const char *path) { + CFAllocatorRef alloc = kCFAllocatorDefault; + // Release our old bundle and ULR + reset(); // This class is a CFReleaser<CFBundleRef> + m_bundle_url.reset(); + // Make a CFStringRef from the supplied path + CFString cf_path; + cf_path.SetFileSystemRepresentation(path); + if (cf_path.get()) { + // Make our Bundle URL + m_bundle_url.reset(::CFURLCreateWithFileSystemPath( + alloc, cf_path.get(), kCFURLPOSIXPathStyle, true)); + if (m_bundle_url.get()) { + reset(::CFBundleCreate(alloc, m_bundle_url.get())); } - return get() != NULL; + } + return get() != NULL; } -CFStringRef -CFBundle::GetIdentifier () const -{ - CFBundleRef bundle = get(); - if (bundle != NULL) - return ::CFBundleGetIdentifier (bundle); - return NULL; +CFStringRef CFBundle::GetIdentifier() const { + CFBundleRef bundle = get(); + if (bundle != NULL) + return ::CFBundleGetIdentifier(bundle); + return NULL; } - -CFURLRef -CFBundle::CopyExecutableURL () const -{ - CFBundleRef bundle = get(); - if (bundle != NULL) - return CFBundleCopyExecutableURL(bundle); - return NULL; +CFURLRef CFBundle::CopyExecutableURL() const { + CFBundleRef bundle = get(); + if (bundle != NULL) + return CFBundleCopyExecutableURL(bundle); + return NULL; } diff --git a/lldb/tools/debugserver/source/MacOSX/CFBundle.h b/lldb/tools/debugserver/source/MacOSX/CFBundle.h index e08290add73..09957af534b 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFBundle.h +++ b/lldb/tools/debugserver/source/MacOSX/CFBundle.h @@ -16,28 +16,23 @@ #include "CFUtils.h" -class CFBundle : public CFReleaser<CFBundleRef> -{ +class CFBundle : public CFReleaser<CFBundleRef> { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - CFBundle(const char *path = NULL); - CFBundle(const CFBundle& rhs); - CFBundle& operator=(const CFBundle& rhs); - virtual - ~CFBundle(); - bool - SetPath (const char *path); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CFBundle(const char *path = NULL); + CFBundle(const CFBundle &rhs); + CFBundle &operator=(const CFBundle &rhs); + virtual ~CFBundle(); + bool SetPath(const char *path); - CFStringRef - GetIdentifier () const; + CFStringRef GetIdentifier() const; + + CFURLRef CopyExecutableURL() const; - CFURLRef - CopyExecutableURL () const; - protected: - CFReleaser<CFURLRef> m_bundle_url; + CFReleaser<CFURLRef> m_bundle_url; }; #endif // #ifndef __CFBundle_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/CFString.cpp b/lldb/tools/debugserver/source/MacOSX/CFString.cpp index 819024ca3bc..84ad56774d7 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFString.cpp +++ b/lldb/tools/debugserver/source/MacOSX/CFString.cpp @@ -12,136 +12,110 @@ //===----------------------------------------------------------------------===// #include "CFString.h" -#include <string> #include <glob.h> +#include <string> //---------------------------------------------------------------------- // CFString constructor //---------------------------------------------------------------------- -CFString::CFString(CFStringRef s) : - CFReleaser<CFStringRef> (s) -{ -} +CFString::CFString(CFStringRef s) : CFReleaser<CFStringRef>(s) {} //---------------------------------------------------------------------- // CFString copy constructor //---------------------------------------------------------------------- -CFString::CFString(const CFString& rhs) : - CFReleaser<CFStringRef> (rhs) -{ - -} +CFString::CFString(const CFString &rhs) : CFReleaser<CFStringRef>(rhs) {} //---------------------------------------------------------------------- // CFString copy constructor //---------------------------------------------------------------------- -CFString& -CFString::operator=(const CFString& rhs) -{ - if (this != &rhs) - *this = rhs; - return *this; +CFString &CFString::operator=(const CFString &rhs) { + if (this != &rhs) + *this = rhs; + return *this; } -CFString::CFString (const char *cstr, CFStringEncoding cstr_encoding) : - CFReleaser<CFStringRef> () -{ - if (cstr && cstr[0]) - { - reset(::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); - } +CFString::CFString(const char *cstr, CFStringEncoding cstr_encoding) + : CFReleaser<CFStringRef>() { + if (cstr && cstr[0]) { + reset( + ::CFStringCreateWithCString(kCFAllocatorDefault, cstr, cstr_encoding)); + } } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -CFString::~CFString() -{ -} +CFString::~CFString() {} -const char * -CFString::GetFileSystemRepresentation(std::string& s) -{ - return CFString::FileSystemRepresentation(get(), s); +const char *CFString::GetFileSystemRepresentation(std::string &s) { + return CFString::FileSystemRepresentation(get(), s); } -CFStringRef -CFString::SetFileSystemRepresentation (const char *path) -{ - CFStringRef new_value = NULL; - if (path && path[0]) - new_value = ::CFStringCreateWithFileSystemRepresentation (kCFAllocatorDefault, path); - reset(new_value); - return get(); +CFStringRef CFString::SetFileSystemRepresentation(const char *path) { + CFStringRef new_value = NULL; + if (path && path[0]) + new_value = + ::CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, path); + reset(new_value); + return get(); } - -CFStringRef -CFString::SetFileSystemRepresentationFromCFType (CFTypeRef cf_type) -{ - CFStringRef new_value = NULL; - if (cf_type != NULL) - { - CFTypeID cf_type_id = ::CFGetTypeID(cf_type); - - if (cf_type_id == ::CFStringGetTypeID()) - { - // Retain since we are using the existing object - new_value = (CFStringRef)::CFRetain(cf_type); - } - else if (cf_type_id == ::CFURLGetTypeID()) - { - new_value = ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle); - } +CFStringRef CFString::SetFileSystemRepresentationFromCFType(CFTypeRef cf_type) { + CFStringRef new_value = NULL; + if (cf_type != NULL) { + CFTypeID cf_type_id = ::CFGetTypeID(cf_type); + + if (cf_type_id == ::CFStringGetTypeID()) { + // Retain since we are using the existing object + new_value = (CFStringRef)::CFRetain(cf_type); + } else if (cf_type_id == ::CFURLGetTypeID()) { + new_value = + ::CFURLCopyFileSystemPath((CFURLRef)cf_type, kCFURLPOSIXPathStyle); } - reset(new_value); - return get(); + } + reset(new_value); + return get(); } CFStringRef -CFString::SetFileSystemRepresentationAndExpandTilde (const char *path) -{ - std::string expanded_path; - if (CFString::GlobPath(path, expanded_path)) - SetFileSystemRepresentation(expanded_path.c_str()); - else - reset(); - return get(); +CFString::SetFileSystemRepresentationAndExpandTilde(const char *path) { + std::string expanded_path; + if (CFString::GlobPath(path, expanded_path)) + SetFileSystemRepresentation(expanded_path.c_str()); + else + reset(); + return get(); } -const char * -CFString::UTF8(std::string& str) -{ - return CFString::UTF8(get(), str); +const char *CFString::UTF8(std::string &str) { + return CFString::UTF8(get(), str); } // Static function that puts a copy of the UTF8 contents of CF_STR into STR -// and returns the C string pointer that is contained in STR when successful, else -// NULL is returned. This allows the std::string parameter to own the extracted string, -// and also allows that string to be returned as a C string pointer that can be used. - -const char * -CFString::UTF8 (CFStringRef cf_str, std::string& str) -{ - if (cf_str) - { - const CFStringEncoding encoding = kCFStringEncodingUTF8; - CFIndex max_utf8_str_len = CFStringGetLength (cf_str); - max_utf8_str_len = CFStringGetMaximumSizeForEncoding (max_utf8_str_len, encoding); - if (max_utf8_str_len > 0) - { - str.resize(max_utf8_str_len); - if (!str.empty()) - { - if (CFStringGetCString (cf_str, &str[0], str.size(), encoding)) - { - str.resize(strlen(str.c_str())); - return str.c_str(); - } - } +// and returns the C string pointer that is contained in STR when successful, +// else +// NULL is returned. This allows the std::string parameter to own the extracted +// string, +// and also allows that string to be returned as a C string pointer that can be +// used. + +const char *CFString::UTF8(CFStringRef cf_str, std::string &str) { + if (cf_str) { + const CFStringEncoding encoding = kCFStringEncodingUTF8; + CFIndex max_utf8_str_len = CFStringGetLength(cf_str); + max_utf8_str_len = + CFStringGetMaximumSizeForEncoding(max_utf8_str_len, encoding); + if (max_utf8_str_len > 0) { + str.resize(max_utf8_str_len); + if (!str.empty()) { + if (CFStringGetCString(cf_str, &str[0], str.size(), encoding)) { + str.resize(strlen(str.c_str())); + return str.c_str(); } + } } - return NULL; + } + return NULL; } // Static function that puts a copy of the file system representation of CF_STR @@ -150,52 +124,40 @@ CFString::UTF8 (CFStringRef cf_str, std::string& str) // to own the extracted string, and also allows that string to be returned as // a C string pointer that can be used. -const char * -CFString::FileSystemRepresentation (CFStringRef cf_str, std::string& str) -{ - if (cf_str) - { - CFIndex max_length = ::CFStringGetMaximumSizeOfFileSystemRepresentation (cf_str); - if (max_length > 0) - { - str.resize(max_length); - if (!str.empty()) - { - if (::CFStringGetFileSystemRepresentation (cf_str, &str[0], str.size())) - { - str.erase(::strlen(str.c_str())); - return str.c_str(); - } - } +const char *CFString::FileSystemRepresentation(CFStringRef cf_str, + std::string &str) { + if (cf_str) { + CFIndex max_length = + ::CFStringGetMaximumSizeOfFileSystemRepresentation(cf_str); + if (max_length > 0) { + str.resize(max_length); + if (!str.empty()) { + if (::CFStringGetFileSystemRepresentation(cf_str, &str[0], + str.size())) { + str.erase(::strlen(str.c_str())); + return str.c_str(); } + } } - str.erase(); - return NULL; + } + str.erase(); + return NULL; } - -CFIndex -CFString::GetLength() const -{ - CFStringRef str = get(); - if (str) - return CFStringGetLength (str); - return 0; +CFIndex CFString::GetLength() const { + CFStringRef str = get(); + if (str) + return CFStringGetLength(str); + return 0; } +const char *CFString::GlobPath(const char *path, std::string &expanded_path) { + glob_t globbuf; + if (::glob(path, GLOB_TILDE, NULL, &globbuf) == 0) { + expanded_path = globbuf.gl_pathv[0]; + ::globfree(&globbuf); + } else + expanded_path.clear(); -const char* -CFString::GlobPath(const char* path, std::string &expanded_path) -{ - glob_t globbuf; - if (::glob (path, GLOB_TILDE, NULL, &globbuf) == 0) - { - expanded_path = globbuf.gl_pathv[0]; - ::globfree (&globbuf); - } - else - expanded_path.clear(); - - return expanded_path.c_str(); + return expanded_path.c_str(); } - diff --git a/lldb/tools/debugserver/source/MacOSX/CFString.h b/lldb/tools/debugserver/source/MacOSX/CFString.h index 73945a28a65..18d60a5a74b 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFString.h +++ b/lldb/tools/debugserver/source/MacOSX/CFString.h @@ -17,27 +17,27 @@ #include "CFUtils.h" #include <iosfwd> -class CFString : public CFReleaser<CFStringRef> -{ +class CFString : public CFReleaser<CFStringRef> { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - CFString (CFStringRef cf_str = NULL); - CFString (const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); - CFString (const CFString& rhs); - CFString& operator= (const CFString& rhs); - virtual ~CFString (); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + CFString(CFStringRef cf_str = NULL); + CFString(const char *s, CFStringEncoding encoding = kCFStringEncodingUTF8); + CFString(const CFString &rhs); + CFString &operator=(const CFString &rhs); + virtual ~CFString(); - const char * GetFileSystemRepresentation (std::string& str); - CFStringRef SetFileSystemRepresentation (const char *path); - CFStringRef SetFileSystemRepresentationFromCFType (CFTypeRef cf_type); - CFStringRef SetFileSystemRepresentationAndExpandTilde (const char *path); - const char * UTF8 (std::string& str); - CFIndex GetLength() const; - static const char *UTF8 (CFStringRef cf_str, std::string& str); - static const char *FileSystemRepresentation (CFStringRef cf_str, std::string& str); - static const char* GlobPath(const char* path, std::string &expanded_path); + const char *GetFileSystemRepresentation(std::string &str); + CFStringRef SetFileSystemRepresentation(const char *path); + CFStringRef SetFileSystemRepresentationFromCFType(CFTypeRef cf_type); + CFStringRef SetFileSystemRepresentationAndExpandTilde(const char *path); + const char *UTF8(std::string &str); + CFIndex GetLength() const; + static const char *UTF8(CFStringRef cf_str, std::string &str); + static const char *FileSystemRepresentation(CFStringRef cf_str, + std::string &str); + static const char *GlobPath(const char *path, std::string &expanded_path); }; #endif // #ifndef __CFString_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/CFUtils.h b/lldb/tools/debugserver/source/MacOSX/CFUtils.h index afa984fa11c..a904cd0ea6f 100644 --- a/lldb/tools/debugserver/source/MacOSX/CFUtils.h +++ b/lldb/tools/debugserver/source/MacOSX/CFUtils.h @@ -23,59 +23,56 @@ // call CFRelease() on any valid pointer it owns unless that pointer is // explicitly released using the release() member function. //---------------------------------------------------------------------- -template <class T> -class CFReleaser -{ +template <class T> class CFReleaser { public: - // Type names for the avlue - typedef T element_type; + // Type names for the avlue + typedef T element_type; - // Constructors and destructors - CFReleaser(T ptr = NULL) : _ptr(ptr) { } - CFReleaser(const CFReleaser& copy) : _ptr(copy.get()) - { - if (get()) - ::CFRetain(get()); - } - virtual ~CFReleaser() { reset(); } + // Constructors and destructors + CFReleaser(T ptr = NULL) : _ptr(ptr) {} + CFReleaser(const CFReleaser ©) : _ptr(copy.get()) { + if (get()) + ::CFRetain(get()); + } + virtual ~CFReleaser() { reset(); } - // Assignments - CFReleaser& operator= (const CFReleaser<T>& copy) - { - if (copy != *this) - { - // Replace our owned pointer with the new one - reset(copy.get()); - // Retain the current pointer that we own - if (get()) - ::CFRetain(get()); - } - } - // Get the address of the contained type - T * ptr_address() { return &_ptr; } + // Assignments + CFReleaser &operator=(const CFReleaser<T> ©) { + if (copy != *this) { + // Replace our owned pointer with the new one + reset(copy.get()); + // Retain the current pointer that we own + if (get()) + ::CFRetain(get()); + } + } + // Get the address of the contained type + T *ptr_address() { return &_ptr; } - // Access the pointer itself - const T get() const { return _ptr; } - T get() { return _ptr; } + // Access the pointer itself + const T get() const { return _ptr; } + T get() { return _ptr; } - // Set a new value for the pointer and CFRelease our old - // value if we had a valid one. - void reset(T ptr = NULL) - { - if (ptr != _ptr) - { - if (_ptr != NULL) - ::CFRelease(_ptr); - _ptr = ptr; - } - } + // Set a new value for the pointer and CFRelease our old + // value if we had a valid one. + void reset(T ptr = NULL) { + if (ptr != _ptr) { + if (_ptr != NULL) + ::CFRelease(_ptr); + _ptr = ptr; + } + } + + // Release ownership without calling CFRelease + T release() { + T tmp = _ptr; + _ptr = NULL; + return tmp; + } - // Release ownership without calling CFRelease - T release() { T tmp = _ptr; _ptr = NULL; return tmp; } private: - element_type _ptr; + element_type _ptr; }; -#endif // #ifdef __cplusplus -#endif // #ifndef __CFUtils_h__ - +#endif // #ifdef __cplusplus +#endif // #ifndef __CFUtils_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.cpp index e98a131512a..2cb653894db 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.cpp @@ -9,10 +9,6 @@ #include "ActivityStore.h" -ActivityStore::ActivityStore() -{ -} +ActivityStore::ActivityStore() {} -ActivityStore::~ActivityStore() -{ -} +ActivityStore::~ActivityStore() {} diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.h index 2e998ba367c..35e0a85ad51 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStore.h @@ -14,23 +14,17 @@ #include "ActivityStreamSPI.h" -class ActivityStore -{ +class ActivityStore { public: + virtual ~ActivityStore(); - virtual - ~ActivityStore(); + virtual const char *GetActivityForID(os_activity_id_t activity_id) const = 0; - virtual const char* - GetActivityForID(os_activity_id_t activity_id) const = 0; - - virtual std::string - GetActivityChainForID(os_activity_id_t activity_id) const = 0; + virtual std::string + GetActivityChainForID(os_activity_id_t activity_id) const = 0; protected: - - ActivityStore(); - + ActivityStore(); }; #endif /* ActivityStore_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h index 4ddf13b3fcd..8aebc79e6ec 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/ActivityStreamSPI.h @@ -17,48 +17,45 @@ // Enums -enum -{ - OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001, - OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002, - OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004, - OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008, - OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010, - OS_ACTIVITY_STREAM_DEBUG = 0x00000020, - OS_ACTIVITY_STREAM_BUFFERED = 0x00000040, - OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080, - OS_ACTIVITY_STREAM_INFO = 0x00000100, - OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200, - OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200 +enum { + OS_ACTIVITY_STREAM_PROCESS_ONLY = 0x00000001, + OS_ACTIVITY_STREAM_SKIP_DECODE = 0x00000002, + OS_ACTIVITY_STREAM_PAYLOAD = 0x00000004, + OS_ACTIVITY_STREAM_HISTORICAL = 0x00000008, + OS_ACTIVITY_STREAM_CALLSTACK = 0x00000010, + OS_ACTIVITY_STREAM_DEBUG = 0x00000020, + OS_ACTIVITY_STREAM_BUFFERED = 0x00000040, + OS_ACTIVITY_STREAM_NO_SENSITIVE = 0x00000080, + OS_ACTIVITY_STREAM_INFO = 0x00000100, + OS_ACTIVITY_STREAM_PROMISCUOUS = 0x00000200, + OS_ACTIVITY_STREAM_PRECISE_TIMESTAMPS = 0x00000200 }; typedef uint32_t os_activity_stream_flag_t; -enum -{ - OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201, - OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202, - OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203, +enum { + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE = 0x0201, + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION = 0x0202, + OS_ACTIVITY_STREAM_TYPE_ACTIVITY_USERACTION = 0x0203, - OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300, + OS_ACTIVITY_STREAM_TYPE_TRACE_MESSAGE = 0x0300, - OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400, - OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480, + OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE = 0x0400, + OS_ACTIVITY_STREAM_TYPE_LEGACY_LOG_MESSAGE = 0x0480, - OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601, - OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602, - OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603, + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_BEGIN = 0x0601, + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_END = 0x0602, + OS_ACTIVITY_STREAM_TYPE_SIGNPOST_EVENT = 0x0603, - OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00, + OS_ACTIVITY_STREAM_TYPE_STATEDUMP_EVENT = 0x0A00, }; typedef uint32_t os_activity_stream_type_t; -enum -{ - OS_ACTIVITY_STREAM_EVENT_STARTED = 1, - OS_ACTIVITY_STREAM_EVENT_STOPPED = 2, - OS_ACTIVITY_STREAM_EVENT_FAILED = 3, - OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4, - OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5, +enum { + OS_ACTIVITY_STREAM_EVENT_STARTED = 1, + OS_ACTIVITY_STREAM_EVENT_STOPPED = 2, + OS_ACTIVITY_STREAM_EVENT_FAILED = 3, + OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED = 4, + OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED = 5, }; typedef uint32_t os_activity_stream_event_t; @@ -68,105 +65,104 @@ typedef uint64_t os_activity_id_t; typedef struct os_activity_stream_s *os_activity_stream_t; typedef struct os_activity_stream_entry_s *os_activity_stream_entry_t; -#define OS_ACTIVITY_STREAM_COMMON() \ - uint64_t trace_id; \ - uint64_t timestamp; \ - uint64_t thread; \ - const uint8_t *image_uuid; \ - const char *image_path; \ - struct timeval tv_gmt; \ - struct timezone tz; \ - uint32_t offset \ - +#define OS_ACTIVITY_STREAM_COMMON() \ + uint64_t trace_id; \ + uint64_t timestamp; \ + uint64_t thread; \ + const uint8_t *image_uuid; \ + const char *image_path; \ + struct timeval tv_gmt; \ + struct timezone tz; \ + uint32_t offset typedef struct os_activity_stream_common_s { - OS_ACTIVITY_STREAM_COMMON(); -} *os_activity_stream_common_t; + OS_ACTIVITY_STREAM_COMMON(); +} * os_activity_stream_common_t; struct os_activity_create_s { - OS_ACTIVITY_STREAM_COMMON(); - const char *name; - os_activity_id_t creator_aid; - uint64_t unique_pid; + OS_ACTIVITY_STREAM_COMMON(); + const char *name; + os_activity_id_t creator_aid; + uint64_t unique_pid; }; struct os_activity_transition_s { - OS_ACTIVITY_STREAM_COMMON(); - os_activity_id_t transition_id; + OS_ACTIVITY_STREAM_COMMON(); + os_activity_id_t transition_id; }; typedef struct os_log_message_s { - OS_ACTIVITY_STREAM_COMMON(); - const char *format; - const uint8_t *buffer; - size_t buffer_sz; - const uint8_t *privdata; - size_t privdata_sz; - const char *subsystem; - const char *category; - uint32_t oversize_id; - uint8_t ttl; - bool persisted; -} *os_log_message_t; + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const uint8_t *buffer; + size_t buffer_sz; + const uint8_t *privdata; + size_t privdata_sz; + const char *subsystem; + const char *category; + uint32_t oversize_id; + uint8_t ttl; + bool persisted; +} * os_log_message_t; typedef struct os_trace_message_v2_s { - OS_ACTIVITY_STREAM_COMMON(); - const char *format; - const void *buffer; - size_t bufferLen; - xpc_object_t __unsafe_unretained payload; -} *os_trace_message_v2_t; + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const void *buffer; + size_t bufferLen; + xpc_object_t __unsafe_unretained payload; +} * os_trace_message_v2_t; typedef struct os_activity_useraction_s { - OS_ACTIVITY_STREAM_COMMON(); - const char *action; - bool persisted; -} *os_activity_useraction_t; + OS_ACTIVITY_STREAM_COMMON(); + const char *action; + bool persisted; +} * os_activity_useraction_t; typedef struct os_signpost_s { - OS_ACTIVITY_STREAM_COMMON(); - const char *format; - const uint8_t *buffer; - size_t buffer_sz; - const uint8_t *privdata; - size_t privdata_sz; - const char *subsystem; - const char *category; - uint64_t duration_nsec; - uint32_t callstack_depth; - uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK]; -} *os_signpost_t; + OS_ACTIVITY_STREAM_COMMON(); + const char *format; + const uint8_t *buffer; + size_t buffer_sz; + const uint8_t *privdata; + size_t privdata_sz; + const char *subsystem; + const char *category; + uint64_t duration_nsec; + uint32_t callstack_depth; + uint64_t callstack[OS_ACTIVITY_MAX_CALLSTACK]; +} * os_signpost_t; typedef struct os_activity_statedump_s { - OS_ACTIVITY_STREAM_COMMON(); - char *message; - size_t message_size; - char image_path_buffer[PATH_MAX]; -} *os_activity_statedump_t; + OS_ACTIVITY_STREAM_COMMON(); + char *message; + size_t message_size; + char image_path_buffer[PATH_MAX]; +} * os_activity_statedump_t; struct os_activity_stream_entry_s { - os_activity_stream_type_t type; - - // information about the process streaming the data - pid_t pid; - uint64_t proc_id; - const uint8_t *proc_imageuuid; - const char *proc_imagepath; - - // the activity associated with this streamed event - os_activity_id_t activity_id; - os_activity_id_t parent_id; - - union { - struct os_activity_stream_common_s common; - struct os_activity_create_s activity_create; - struct os_activity_transition_s activity_transition; - struct os_log_message_s log_message; - struct os_trace_message_v2_s trace_message; - struct os_activity_useraction_s useraction; - struct os_signpost_s signpost; - struct os_activity_statedump_s statedump; - }; + os_activity_stream_type_t type; + + // information about the process streaming the data + pid_t pid; + uint64_t proc_id; + const uint8_t *proc_imageuuid; + const char *proc_imagepath; + + // the activity associated with this streamed event + os_activity_id_t activity_id; + os_activity_id_t parent_id; + + union { + struct os_activity_stream_common_s common; + struct os_activity_create_s activity_create; + struct os_activity_transition_s activity_transition; + struct os_log_message_s log_message; + struct os_trace_message_v2_s trace_message; + struct os_activity_useraction_s useraction; + struct os_signpost_s signpost; + struct os_activity_statedump_s statedump; + }; }; // Blocks @@ -175,26 +171,21 @@ typedef bool (^os_activity_stream_block_t)(os_activity_stream_entry_t entry, int error); typedef void (^os_activity_stream_event_block_t)( - os_activity_stream_t stream, - os_activity_stream_event_t event); + os_activity_stream_t stream, os_activity_stream_event_t event); // SPI entry point prototypes -typedef os_activity_stream_t - (*os_activity_stream_for_pid_t)(pid_t pid, os_activity_stream_flag_t flags, - os_activity_stream_block_t stream_block); +typedef os_activity_stream_t (*os_activity_stream_for_pid_t)( + pid_t pid, os_activity_stream_flag_t flags, + os_activity_stream_block_t stream_block); -typedef void -(*os_activity_stream_resume_t)(os_activity_stream_t stream); +typedef void (*os_activity_stream_resume_t)(os_activity_stream_t stream); -typedef void - (*os_activity_stream_cancel_t)(os_activity_stream_t stream); +typedef void (*os_activity_stream_cancel_t)(os_activity_stream_t stream); -typedef char * - (*os_log_copy_formatted_message_t)(os_log_message_t log_message); +typedef char *(*os_log_copy_formatted_message_t)(os_log_message_t log_message); -typedef void - (*os_activity_stream_set_event_handler_t) - (os_activity_stream_t stream, os_activity_stream_event_block_t block); +typedef void (*os_activity_stream_set_event_handler_t)( + os_activity_stream_t stream, os_activity_stream_event_block_t block); #endif /* ActivityStreamSPI_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.cpp index 30f3e521669..982367092ed 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.cpp @@ -16,9 +16,9 @@ #include <mutex> #include <vector> -#include "DarwinLogTypes.h" #include "DNB.h" #include "DNBLog.h" +#include "DarwinLogTypes.h" #include "LogFilterChain.h" #include "LogFilterExactMatch.h" #include "LogFilterRegex.h" @@ -30,806 +30,668 @@ // Use an anonymous namespace for variables and methods that have no // reason to leak out through the interface. -namespace -{ - /// Specify max depth that the activity parent-child chain will search - /// back to get the full activity chain name. If we do more than this, - /// we assume either we hit a loop or it's just too long. - static const size_t MAX_ACTIVITY_CHAIN_DEPTH = 10; - - // Used to tap into and retrieve logs from target process. - // (Consumer of os_log). - static os_activity_stream_for_pid_t s_os_activity_stream_for_pid; - static os_activity_stream_resume_t s_os_activity_stream_resume; - static os_activity_stream_cancel_t s_os_activity_stream_cancel; - static os_log_copy_formatted_message_t s_os_log_copy_formatted_message; - static os_activity_stream_set_event_handler_t +namespace { +/// Specify max depth that the activity parent-child chain will search +/// back to get the full activity chain name. If we do more than this, +/// we assume either we hit a loop or it's just too long. +static const size_t MAX_ACTIVITY_CHAIN_DEPTH = 10; + +// Used to tap into and retrieve logs from target process. +// (Consumer of os_log). +static os_activity_stream_for_pid_t s_os_activity_stream_for_pid; +static os_activity_stream_resume_t s_os_activity_stream_resume; +static os_activity_stream_cancel_t s_os_activity_stream_cancel; +static os_log_copy_formatted_message_t s_os_log_copy_formatted_message; +static os_activity_stream_set_event_handler_t s_os_activity_stream_set_event_handler; - bool - LookupSPICalls() - { - static std::once_flag s_once_flag; - static bool s_has_spi; - - std::call_once(s_once_flag, [] { - s_os_activity_stream_for_pid = (os_activity_stream_for_pid_t) - dlsym(RTLD_DEFAULT, "os_activity_stream_for_pid"); - s_os_activity_stream_resume = (os_activity_stream_resume_t) - dlsym(RTLD_DEFAULT, "os_activity_stream_resume"); - s_os_activity_stream_cancel = (os_activity_stream_cancel_t) - dlsym(RTLD_DEFAULT, "os_activity_stream_cancel"); - s_os_log_copy_formatted_message = (os_log_copy_formatted_message_t) - dlsym(RTLD_DEFAULT, "os_log_copy_formatted_message"); - s_os_activity_stream_set_event_handler = - (os_activity_stream_set_event_handler_t) - dlsym(RTLD_DEFAULT, "os_activity_stream_set_event_handler"); - - // We'll indicate we're all set if every function entry point - // was found. - s_has_spi = - (s_os_activity_stream_for_pid != nullptr) && +bool LookupSPICalls() { + static std::once_flag s_once_flag; + static bool s_has_spi; + + std::call_once(s_once_flag, [] { + s_os_activity_stream_for_pid = (os_activity_stream_for_pid_t)dlsym( + RTLD_DEFAULT, "os_activity_stream_for_pid"); + s_os_activity_stream_resume = (os_activity_stream_resume_t)dlsym( + RTLD_DEFAULT, "os_activity_stream_resume"); + s_os_activity_stream_cancel = (os_activity_stream_cancel_t)dlsym( + RTLD_DEFAULT, "os_activity_stream_cancel"); + s_os_log_copy_formatted_message = (os_log_copy_formatted_message_t)dlsym( + RTLD_DEFAULT, "os_log_copy_formatted_message"); + s_os_activity_stream_set_event_handler = + (os_activity_stream_set_event_handler_t)dlsym( + RTLD_DEFAULT, "os_activity_stream_set_event_handler"); + + // We'll indicate we're all set if every function entry point + // was found. + s_has_spi = (s_os_activity_stream_for_pid != nullptr) && (s_os_activity_stream_resume != nullptr) && (s_os_activity_stream_cancel != nullptr) && (s_os_log_copy_formatted_message != nullptr) && (s_os_activity_stream_set_event_handler != nullptr); - if (s_has_spi) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "Found os_log SPI calls."); - // Tell LogMessageOsLog how to format messages when search - // criteria requires it. - LogMessageOsLog::SetFormatterFunction( - s_os_log_copy_formatted_message); - } - else - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "Failed to find os_log SPI " - "calls."); - } - }); - - return s_has_spi; + if (s_has_spi) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Found os_log SPI calls."); + // Tell LogMessageOsLog how to format messages when search + // criteria requires it. + LogMessageOsLog::SetFormatterFunction(s_os_log_copy_formatted_message); + } else { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Failed to find os_log SPI " + "calls."); } + }); - using Mutex = std::mutex; - static Mutex s_collector_mutex; - static std::vector<DarwinLogCollectorSP> s_collectors; + return s_has_spi; +} - static void - TrackCollector(const DarwinLogCollectorSP &collector_sp) - { - std::lock_guard<Mutex> locker(s_collector_mutex); - if (std::find(s_collectors.begin(), s_collectors.end(), collector_sp) - != s_collectors.end()) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "attempted to add same collector multiple times"); - return; - } - s_collectors.push_back(collector_sp); +using Mutex = std::mutex; +static Mutex s_collector_mutex; +static std::vector<DarwinLogCollectorSP> s_collectors; + +static void TrackCollector(const DarwinLogCollectorSP &collector_sp) { + std::lock_guard<Mutex> locker(s_collector_mutex); + if (std::find(s_collectors.begin(), s_collectors.end(), collector_sp) != + s_collectors.end()) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "attempted to add same collector multiple times"); + return; + } + s_collectors.push_back(collector_sp); +} + +static void StopTrackingCollector(const DarwinLogCollectorSP &collector_sp) { + std::lock_guard<Mutex> locker(s_collector_mutex); + s_collectors.erase( + std::remove(s_collectors.begin(), s_collectors.end(), collector_sp), + s_collectors.end()); +} + +static DarwinLogCollectorSP FindCollectorForProcess(pid_t pid) { + std::lock_guard<Mutex> locker(s_collector_mutex); + for (const auto &collector_sp : s_collectors) { + if (collector_sp && (collector_sp->GetProcessID() == pid)) + return collector_sp; + } + return DarwinLogCollectorSP(); +} + +static FilterTarget TargetStringToEnum(const std::string &filter_target_name) { + if (filter_target_name == "activity") + return eFilterTargetActivity; + else if (filter_target_name == "activity-chain") + return eFilterTargetActivityChain; + else if (filter_target_name == "category") + return eFilterTargetCategory; + else if (filter_target_name == "message") + return eFilterTargetMessage; + else if (filter_target_name == "subsystem") + return eFilterTargetSubsystem; + else + return eFilterTargetInvalid; +} + +class Configuration { +public: + Configuration(const JSONObject &config) + : m_is_valid(false), + m_activity_stream_flags(OS_ACTIVITY_STREAM_PROCESS_ONLY), + m_filter_chain_sp(nullptr) { + // Parse out activity stream flags + if (!ParseSourceFlags(config)) { + m_is_valid = false; + return; } - static void - StopTrackingCollector(const DarwinLogCollectorSP &collector_sp) - { - std::lock_guard<Mutex> locker(s_collector_mutex); - s_collectors.erase(std::remove(s_collectors.begin(), s_collectors.end(), - collector_sp), - s_collectors.end()); + // Parse filter rules + if (!ParseFilterRules(config)) { + m_is_valid = false; + return; } - static DarwinLogCollectorSP - FindCollectorForProcess(pid_t pid) - { - std::lock_guard<Mutex> locker(s_collector_mutex); - for (const auto &collector_sp : s_collectors) - { - if (collector_sp && (collector_sp->GetProcessID() == pid)) - return collector_sp; - } - return DarwinLogCollectorSP(); + // Everything worked. + m_is_valid = true; + } + + bool ParseSourceFlags(const JSONObject &config) { + // Get the source-flags dictionary. + auto source_flags_sp = config.GetObject("source-flags"); + if (!source_flags_sp) + return false; + if (!JSONObject::classof(source_flags_sp.get())) + return false; + + const JSONObject &source_flags = + *static_cast<JSONObject *>(source_flags_sp.get()); + + // Parse out the flags. + bool include_any_process = false; + bool include_callstacks = false; + bool include_info_level = false; + bool include_debug_level = false; + bool live_stream = false; + + if (!source_flags.GetObjectAsBool("any-process", include_any_process)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Source-flag 'any-process' missing from " + "configuration."); + return false; + } + if (!source_flags.GetObjectAsBool("callstacks", include_callstacks)) { + // We currently suppress the availability of this on the lldb + // side. We include here for devices when we enable in the + // future. + // DNBLogThreadedIf(LOG_DARWIN_LOG, + // "Source-flag 'callstacks' missing from " + // "configuration."); + + // OK. We just skip callstacks. + // return false; + } + if (!source_flags.GetObjectAsBool("info-level", include_info_level)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Source-flag 'info-level' missing from " + "configuration."); + return false; + } + if (!source_flags.GetObjectAsBool("debug-level", include_debug_level)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Source-flag 'debug-level' missing from " + "configuration."); + return false; + } + if (!source_flags.GetObjectAsBool("live-stream", live_stream)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Source-flag 'live-stream' missing from " + "configuration."); + return false; } - static FilterTarget - TargetStringToEnum(const std::string &filter_target_name) - { - if (filter_target_name == "activity") - return eFilterTargetActivity; - else if (filter_target_name == "activity-chain") - return eFilterTargetActivityChain; - else if (filter_target_name == "category") - return eFilterTargetCategory; - else if (filter_target_name == "message") - return eFilterTargetMessage; - else if (filter_target_name == "subsystem") - return eFilterTargetSubsystem; - else - return eFilterTargetInvalid; + // Setup the SPI flags based on this. + m_activity_stream_flags = 0; + if (!include_any_process) + m_activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY; + if (include_callstacks) + m_activity_stream_flags |= OS_ACTIVITY_STREAM_CALLSTACK; + if (include_info_level) + m_activity_stream_flags |= OS_ACTIVITY_STREAM_INFO; + if (include_debug_level) + m_activity_stream_flags |= OS_ACTIVITY_STREAM_DEBUG; + if (!live_stream) + m_activity_stream_flags |= OS_ACTIVITY_STREAM_BUFFERED; + + DNBLogThreadedIf(LOG_DARWIN_LOG, "m_activity_stream_flags = 0x%03x", + m_activity_stream_flags); + + return true; + } + + bool ParseFilterRules(const JSONObject &config) { + // Retrieve the default rule. + bool filter_default_accept = true; + if (!config.GetObjectAsBool("filter-fall-through-accepts", + filter_default_accept)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Setting 'filter-fall-through-accepts' " + "missing from configuration."); + return false; } + m_filter_chain_sp.reset(new LogFilterChain(filter_default_accept)); + DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLog no-match rule: %s.", + filter_default_accept ? "accept" : "reject"); + + // If we don't have the filter-rules array, we're done. + auto filter_rules_sp = config.GetObject("filter-rules"); + if (!filter_rules_sp) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "No 'filter-rules' config element, all log " + "entries will use the no-match action (%s).", + filter_default_accept ? "accept" : "reject"); + return true; + } + if (!JSONArray::classof(filter_rules_sp.get())) + return false; + const JSONArray &rules_config = + *static_cast<JSONArray *>(filter_rules_sp.get()); + + // Create the filters. + for (auto &rule_sp : rules_config.m_elements) { + if (!JSONObject::classof(rule_sp.get())) + return false; + const JSONObject &rule_config = *static_cast<JSONObject *>(rule_sp.get()); - class Configuration - { - public: + // Get whether this filter accepts or rejects. + bool filter_accepts = true; + if (!rule_config.GetObjectAsBool("accept", filter_accepts)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Filter 'accept' element missing."); + return false; + } - Configuration(const JSONObject &config) : - m_is_valid(false), - m_activity_stream_flags(OS_ACTIVITY_STREAM_PROCESS_ONLY), - m_filter_chain_sp(nullptr) - { - // Parse out activity stream flags - if (!ParseSourceFlags(config)) - { - m_is_valid = false; - return; - } - - // Parse filter rules - if (!ParseFilterRules(config)) - { - m_is_valid = false; - return; - } - - // Everything worked. - m_is_valid = true; - } + // Grab the target log field attribute for the match. + std::string target_attribute; + if (!rule_config.GetObjectAsString("attribute", target_attribute)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Filter 'attribute' element missing."); + return false; + } + auto target_enum = TargetStringToEnum(target_attribute); + if (target_enum == eFilterTargetInvalid) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Filter attribute '%s' unsupported.", + target_attribute.c_str()); + return false; + } - bool - ParseSourceFlags(const JSONObject &config) - { - // Get the source-flags dictionary. - auto source_flags_sp = config.GetObject("source-flags"); - if (!source_flags_sp) - return false; - if (!JSONObject::classof(source_flags_sp.get())) - return false; - - const JSONObject &source_flags = - *static_cast<JSONObject*>(source_flags_sp.get()); - - // Parse out the flags. - bool include_any_process = false; - bool include_callstacks = false; - bool include_info_level = false; - bool include_debug_level = false; - bool live_stream = false; - - if (!source_flags.GetObjectAsBool("any-process", - include_any_process)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Source-flag 'any-process' missing from " - "configuration."); - return false; - } - if (!source_flags.GetObjectAsBool("callstacks", - include_callstacks)) - { - // We currently suppress the availability of this on the lldb - // side. We include here for devices when we enable in the - // future. - // DNBLogThreadedIf(LOG_DARWIN_LOG, - // "Source-flag 'callstacks' missing from " - // "configuration."); - - // OK. We just skip callstacks. - // return false; - } - if (!source_flags.GetObjectAsBool("info-level", - include_info_level)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Source-flag 'info-level' missing from " - "configuration."); - return false; - } - if (!source_flags.GetObjectAsBool("debug-level", - include_debug_level)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Source-flag 'debug-level' missing from " - "configuration."); - return false; - } - if (!source_flags.GetObjectAsBool("live-stream", - live_stream)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Source-flag 'live-stream' missing from " - "configuration."); - return false; - } - - // Setup the SPI flags based on this. - m_activity_stream_flags = 0; - if (!include_any_process) - m_activity_stream_flags |= OS_ACTIVITY_STREAM_PROCESS_ONLY; - if (include_callstacks) - m_activity_stream_flags |= OS_ACTIVITY_STREAM_CALLSTACK; - if (include_info_level) - m_activity_stream_flags |= OS_ACTIVITY_STREAM_INFO; - if (include_debug_level) - m_activity_stream_flags |= OS_ACTIVITY_STREAM_DEBUG; - if (!live_stream) - m_activity_stream_flags |= OS_ACTIVITY_STREAM_BUFFERED; - - DNBLogThreadedIf(LOG_DARWIN_LOG, "m_activity_stream_flags = 0x%03x", - m_activity_stream_flags); - - return true; + // Handle operation-specific fields and filter creation. + std::string filter_type; + if (!rule_config.GetObjectAsString("type", filter_type)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "Filter 'type' element missing."); + return false; + } + DNBLogThreadedIf(LOG_DARWIN_LOG, "Reading filter of type '%s'", + filter_type.c_str()); + + LogFilterSP filter_sp; + if (filter_type == "regex") { + // Grab the regex for the match. + std::string regex; + if (!rule_config.GetObjectAsString("regex", regex)) { + DNBLogError("Regex filter missing 'regex' element."); + return false; } - - bool - ParseFilterRules(const JSONObject &config) - { - // Retrieve the default rule. - bool filter_default_accept = true; - if (!config.GetObjectAsBool("filter-fall-through-accepts", - filter_default_accept)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Setting 'filter-fall-through-accepts' " - "missing from configuration."); - return false; - } - m_filter_chain_sp.reset(new LogFilterChain(filter_default_accept)); - DNBLogThreadedIf(LOG_DARWIN_LOG, - "DarwinLog no-match rule: %s.", - filter_default_accept ? "accept" : "reject"); - - // If we don't have the filter-rules array, we're done. - auto filter_rules_sp = config.GetObject("filter-rules"); - if (!filter_rules_sp) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "No 'filter-rules' config element, all log " - "entries will use the no-match action (%s).", - filter_default_accept ? "accept" : "reject"); - return true; - } - if (!JSONArray::classof(filter_rules_sp.get())) - return false; - const JSONArray &rules_config = - *static_cast<JSONArray*>(filter_rules_sp.get()); - - // Create the filters. - for (auto &rule_sp : rules_config.m_elements) - { - if (!JSONObject::classof(rule_sp.get())) - return false; - const JSONObject &rule_config = *static_cast<JSONObject*> - (rule_sp.get()); - - // Get whether this filter accepts or rejects. - bool filter_accepts = true; - if (!rule_config.GetObjectAsBool("accept", filter_accepts)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Filter 'accept' element missing."); - return false; - } - - // Grab the target log field attribute for the match. - std::string target_attribute; - if (!rule_config.GetObjectAsString("attribute", - target_attribute)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Filter 'attribute' element missing."); - return false; - } - auto target_enum = TargetStringToEnum(target_attribute); - if (target_enum == eFilterTargetInvalid) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Filter attribute '%s' unsupported.", - target_attribute.c_str()); - return false; - } - - // Handle operation-specific fields and filter creation. - std::string filter_type; - if (!rule_config.GetObjectAsString("type", filter_type)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Filter 'type' element missing."); - return false; - } - DNBLogThreadedIf(LOG_DARWIN_LOG, - "Reading filter of type '%s'", filter_type - .c_str()); - - LogFilterSP filter_sp; - if (filter_type == "regex") - { - // Grab the regex for the match. - std::string regex; - if (!rule_config.GetObjectAsString("regex", - regex)) - { - DNBLogError("Regex filter missing 'regex' element."); - return false; - } - DNBLogThreadedIf(LOG_DARWIN_LOG, - "regex for filter: \"%s\"", regex.c_str()); - - // Create the regex filter. - auto regex_filter = - new LogFilterRegex(filter_accepts, target_enum, regex); - filter_sp.reset(regex_filter); - - // Validate that the filter is okay. - if (!regex_filter->IsValid()) - { - DNBLogError("Invalid regex in filter: " - "regex=\"%s\", error=%s", - regex.c_str(), - regex_filter->GetErrorAsCString()); - return false; - } - } - else if (filter_type == "match") - { - // Grab the regex for the match. - std::string exact_text; - if (!rule_config.GetObjectAsString("exact_text", - exact_text)) - { - DNBLogError("Exact match filter missing " - "'exact_text' element."); - return false; - } - - // Create the filter. - filter_sp.reset(new LogFilterExactMatch(filter_accepts, - target_enum, - exact_text)); - } - - // Add the filter to the chain. - m_filter_chain_sp->AppendFilter(filter_sp); - } - return true; + DNBLogThreadedIf(LOG_DARWIN_LOG, "regex for filter: \"%s\"", + regex.c_str()); + + // Create the regex filter. + auto regex_filter = + new LogFilterRegex(filter_accepts, target_enum, regex); + filter_sp.reset(regex_filter); + + // Validate that the filter is okay. + if (!regex_filter->IsValid()) { + DNBLogError("Invalid regex in filter: " + "regex=\"%s\", error=%s", + regex.c_str(), regex_filter->GetErrorAsCString()); + return false; } - - bool - IsValid() const - { - return m_is_valid; + } else if (filter_type == "match") { + // Grab the regex for the match. + std::string exact_text; + if (!rule_config.GetObjectAsString("exact_text", exact_text)) { + DNBLogError("Exact match filter missing " + "'exact_text' element."); + return false; } - os_activity_stream_flag_t - GetActivityStreamFlags() const - { - return m_activity_stream_flags; - } + // Create the filter. + filter_sp.reset( + new LogFilterExactMatch(filter_accepts, target_enum, exact_text)); + } - const LogFilterChainSP & - GetLogFilterChain() const - { - return m_filter_chain_sp; - } + // Add the filter to the chain. + m_filter_chain_sp->AppendFilter(filter_sp); + } + return true; + } + + bool IsValid() const { return m_is_valid; } - private: + os_activity_stream_flag_t GetActivityStreamFlags() const { + return m_activity_stream_flags; + } - bool m_is_valid; - os_activity_stream_flag_t m_activity_stream_flags; - LogFilterChainSP m_filter_chain_sp; + const LogFilterChainSP &GetLogFilterChain() const { + return m_filter_chain_sp; + } - }; +private: + bool m_is_valid; + os_activity_stream_flag_t m_activity_stream_flags; + LogFilterChainSP m_filter_chain_sp; +}; } -bool -DarwinLogCollector::IsSupported() -{ - // We're supported if we have successfully looked up the SPI entry points. - return LookupSPICalls(); +bool DarwinLogCollector::IsSupported() { + // We're supported if we have successfully looked up the SPI entry points. + return LookupSPICalls(); } -bool -DarwinLogCollector::StartCollectingForProcess(nub_process_t pid, - const JSONObject &config) -{ - // If we're currently collecting for this process, kill the existing - // collector. - if (CancelStreamForProcess(pid)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "%s() killed existing DarwinLog collector for pid %d.", - __FUNCTION__, pid); +bool DarwinLogCollector::StartCollectingForProcess(nub_process_t pid, + const JSONObject &config) { + // If we're currently collecting for this process, kill the existing + // collector. + if (CancelStreamForProcess(pid)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "%s() killed existing DarwinLog collector for pid %d.", + __FUNCTION__, pid); + } + + // If the process isn't alive, we're done. + if (!DNBProcessIsAlive(pid)) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "%s() cannot collect for pid %d: process not alive.", + __FUNCTION__, pid); + return false; + } + + // Validate the configuration. + auto spi_config = Configuration(config); + if (!spi_config.IsValid()) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "%s() invalid configuration, will not enable log " + "collection", + __FUNCTION__); + return false; + } + + // Create the stream collector that will manage collected data + // for this pid. + DarwinLogCollectorSP collector_sp( + new DarwinLogCollector(pid, spi_config.GetLogFilterChain())); + std::weak_ptr<DarwinLogCollector> collector_wp(collector_sp); + + // Setup the stream handling block. + os_activity_stream_block_t block = + ^bool(os_activity_stream_entry_t entry, int error) { + // Check if our collector is still alive. + DarwinLogCollectorSP inner_collector_sp = collector_wp.lock(); + if (!inner_collector_sp) + return false; + return inner_collector_sp->HandleStreamEntry(entry, error); + }; + + os_activity_stream_event_block_t stream_event_block = ^void( + os_activity_stream_t stream, os_activity_stream_event_t event) { + switch (event) { + case OS_ACTIVITY_STREAM_EVENT_STARTED: + DNBLogThreadedIf(LOG_DARWIN_LOG, + "received stream event: " + "OS_ACTIVITY_STREAM_EVENT_STARTED, stream %p.", + (void *)stream); + break; + case OS_ACTIVITY_STREAM_EVENT_STOPPED: + DNBLogThreadedIf(LOG_DARWIN_LOG, + "received stream event: " + "OS_ACTIVITY_STREAM_EVENT_STOPPED, stream %p.", + (void *)stream); + break; + case OS_ACTIVITY_STREAM_EVENT_FAILED: + DNBLogThreadedIf(LOG_DARWIN_LOG, + "received stream event: " + "OS_ACTIVITY_STREAM_EVENT_FAILED, stream %p.", + (void *)stream); + break; + case OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED: + DNBLogThreadedIf(LOG_DARWIN_LOG, + "received stream event: " + "OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED, stream %p.", + (void *)stream); + break; + case OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED: + DNBLogThreadedIf(LOG_DARWIN_LOG, + "received stream event: " + "OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED, stream %p.", + (void *)stream); + break; } + }; - // If the process isn't alive, we're done. - if (!DNBProcessIsAlive(pid)) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "%s() cannot collect for pid %d: process not alive.", - __FUNCTION__, pid); - return false; - } + // Create the stream. + os_activity_stream_t activity_stream = (*s_os_activity_stream_for_pid)( + pid, spi_config.GetActivityStreamFlags(), block); + collector_sp->SetActivityStream(activity_stream); - // Validate the configuration. - auto spi_config = Configuration(config); - if (!spi_config.IsValid()) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, - "%s() invalid configuration, will not enable log " - "collection", __FUNCTION__); - return false; - } + // Specify the stream-related event handler. + (*s_os_activity_stream_set_event_handler)(activity_stream, + stream_event_block); - // Create the stream collector that will manage collected data - // for this pid. - DarwinLogCollectorSP collector_sp(new DarwinLogCollector(pid, - spi_config.GetLogFilterChain())); - std::weak_ptr<DarwinLogCollector> collector_wp(collector_sp); + // Start the stream. + (*s_os_activity_stream_resume)(activity_stream); - // Setup the stream handling block. - os_activity_stream_block_t block = ^bool (os_activity_stream_entry_t entry, - int error) { - // Check if our collector is still alive. - DarwinLogCollectorSP inner_collector_sp = collector_wp.lock(); - if (!inner_collector_sp) - return false; - return inner_collector_sp->HandleStreamEntry(entry, error); - }; - - os_activity_stream_event_block_t stream_event_block = - ^void (os_activity_stream_t stream, os_activity_stream_event_t event) { - switch (event) - { - case OS_ACTIVITY_STREAM_EVENT_STARTED: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received stream event: " - "OS_ACTIVITY_STREAM_EVENT_STARTED, stream %p.", - (void*)stream); - break; - case OS_ACTIVITY_STREAM_EVENT_STOPPED: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received stream event: " - "OS_ACTIVITY_STREAM_EVENT_STOPPED, stream %p.", - (void*)stream); - break; - case OS_ACTIVITY_STREAM_EVENT_FAILED: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received stream event: " - "OS_ACTIVITY_STREAM_EVENT_FAILED, stream %p.", - (void*)stream); - break; - case OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received stream event: " - "OS_ACTIVITY_STREAM_EVENT_CHUNK_STARTED, stream %p.", - (void*)stream); - break; - case OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received stream event: " - "OS_ACTIVITY_STREAM_EVENT_CHUNK_FINISHED, stream %p.", - (void*)stream); - break; - } - }; - - // Create the stream. - os_activity_stream_t activity_stream = - (*s_os_activity_stream_for_pid)(pid, - spi_config.GetActivityStreamFlags(), - block); - collector_sp->SetActivityStream(activity_stream); - - // Specify the stream-related event handler. - (*s_os_activity_stream_set_event_handler)( - activity_stream, stream_event_block); - - // Start the stream. - (*s_os_activity_stream_resume)(activity_stream); - - TrackCollector(collector_sp); - return true; + TrackCollector(collector_sp); + return true; } DarwinLogEventVector -DarwinLogCollector::GetEventsForProcess(nub_process_t pid) -{ - auto collector_sp = FindCollectorForProcess(pid); - if (!collector_sp) - { - // We're not tracking a stream for this process. - return DarwinLogEventVector(); - } - - return collector_sp->RemoveEvents(); +DarwinLogCollector::GetEventsForProcess(nub_process_t pid) { + auto collector_sp = FindCollectorForProcess(pid); + if (!collector_sp) { + // We're not tracking a stream for this process. + return DarwinLogEventVector(); + } + + return collector_sp->RemoveEvents(); } -bool -DarwinLogCollector::CancelStreamForProcess(nub_process_t pid) -{ - auto collector_sp = FindCollectorForProcess(pid); - if (!collector_sp) - { - // We're not tracking a stream for this process. - return false; - } +bool DarwinLogCollector::CancelStreamForProcess(nub_process_t pid) { + auto collector_sp = FindCollectorForProcess(pid); + if (!collector_sp) { + // We're not tracking a stream for this process. + return false; + } - collector_sp->CancelActivityStream(); - StopTrackingCollector(collector_sp); + collector_sp->CancelActivityStream(); + StopTrackingCollector(collector_sp); - return true; + return true; } -const char* -DarwinLogCollector::GetActivityForID(os_activity_id_t activity_id) const -{ - auto find_it = m_activity_map.find(activity_id); - return (find_it != m_activity_map.end()) ? - find_it->second.m_name.c_str() : - nullptr; +const char * +DarwinLogCollector::GetActivityForID(os_activity_id_t activity_id) const { + auto find_it = m_activity_map.find(activity_id); + return (find_it != m_activity_map.end()) ? find_it->second.m_name.c_str() + : nullptr; } /// Retrieve the full parent-child chain for activity names. These /// can be arbitrarily deep. This method assumes the caller has already /// locked the activity mutex. -void -DarwinLogCollector::GetActivityChainForID_internal(os_activity_id_t activity_id, - std::string &result, - size_t depth) const -{ - if (depth > MAX_ACTIVITY_CHAIN_DEPTH) - { - // Terminating condition - too deeply nested. - return; - } - else if (activity_id == 0) - { - // Terminating condition - no activity. - return; - } - - auto find_it = m_activity_map.find(activity_id); - if (find_it == m_activity_map.end()) - { - //Terminating condition - no data for activity_id. - return; - } - - // Activity name becomes parent activity name chain + ':' + our activity - // name. - GetActivityChainForID_internal(find_it->second.m_parent_id, result, - depth + 1); - if (!result.empty()) - result += ':'; - result += find_it->second.m_name; +void DarwinLogCollector::GetActivityChainForID_internal( + os_activity_id_t activity_id, std::string &result, size_t depth) const { + if (depth > MAX_ACTIVITY_CHAIN_DEPTH) { + // Terminating condition - too deeply nested. + return; + } else if (activity_id == 0) { + // Terminating condition - no activity. + return; + } + + auto find_it = m_activity_map.find(activity_id); + if (find_it == m_activity_map.end()) { + // Terminating condition - no data for activity_id. + return; + } + + // Activity name becomes parent activity name chain + ':' + our activity + // name. + GetActivityChainForID_internal(find_it->second.m_parent_id, result, + depth + 1); + if (!result.empty()) + result += ':'; + result += find_it->second.m_name; } std::string -DarwinLogCollector::GetActivityChainForID(os_activity_id_t activity_id) const -{ - std::string result; - { - std::lock_guard<std::mutex> locker(m_activity_info_mutex); - GetActivityChainForID_internal(activity_id, result, 1); - } - return result; +DarwinLogCollector::GetActivityChainForID(os_activity_id_t activity_id) const { + std::string result; + { + std::lock_guard<std::mutex> locker(m_activity_info_mutex); + GetActivityChainForID_internal(activity_id, result, 1); + } + return result; } DarwinLogCollector::DarwinLogCollector(nub_process_t pid, - const LogFilterChainSP &filter_chain_sp): - ActivityStore(), - m_pid(pid), - m_activity_stream(0), - m_events(), - m_events_mutex(), - m_filter_chain_sp(filter_chain_sp), - m_activity_info_mutex(), - m_activity_map() -{ + const LogFilterChainSP &filter_chain_sp) + : ActivityStore(), m_pid(pid), m_activity_stream(0), m_events(), + m_events_mutex(), m_filter_chain_sp(filter_chain_sp), + m_activity_info_mutex(), m_activity_map() {} + +DarwinLogCollector::~DarwinLogCollector() { + // Cancel the stream. + if (m_activity_stream) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "tearing down activity stream " + "collector for %d", + m_pid); + (*s_os_activity_stream_cancel)(m_activity_stream); + m_activity_stream = 0; + } else { + DNBLogThreadedIf(LOG_DARWIN_LOG, "no stream to tear down for %d", m_pid); + } } -DarwinLogCollector::~DarwinLogCollector() -{ - // Cancel the stream. - if (m_activity_stream) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "tearing down activity stream " - "collector for %d", m_pid); - (*s_os_activity_stream_cancel)(m_activity_stream); - m_activity_stream = 0; - } - else - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "no stream to tear down for %d", - m_pid); - } +void DarwinLogCollector::SignalDataAvailable() { + RNBRemoteSP remoteSP(g_remoteSP); + if (!remoteSP) { + // We're done. This is unexpected. + StopTrackingCollector(shared_from_this()); + return; + } + + RNBContext &ctx = remoteSP->Context(); + ctx.Events().SetEvents(RNBContext::event_darwin_log_data_available); + // Wait for the main thread to consume this notification if it requested + // we wait for it. + ctx.Events().WaitForResetAck(RNBContext::event_darwin_log_data_available); +} + +void DarwinLogCollector::SetActivityStream( + os_activity_stream_t activity_stream) { + m_activity_stream = activity_stream; } -void -DarwinLogCollector::SignalDataAvailable() -{ - RNBRemoteSP remoteSP(g_remoteSP); - if (!remoteSP) - { - // We're done. This is unexpected. - StopTrackingCollector(shared_from_this()); - return; +bool DarwinLogCollector::HandleStreamEntry(os_activity_stream_entry_t entry, + int error) { + if ((error == 0) && (entry != nullptr)) { + if (entry->pid != m_pid) { + // For now, skip messages not originating from our process. + // Later we might want to keep all messages related to an event + // that we're tracking, even when it came from another process, + // possibly doing work on our behalf. + return true; } - RNBContext& ctx = remoteSP->Context(); - ctx.Events().SetEvents(RNBContext::event_darwin_log_data_available); - // Wait for the main thread to consume this notification if it requested - // we wait for it. - ctx.Events().WaitForResetAck(RNBContext::event_darwin_log_data_available); -} + switch (entry->type) { + case OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE: + DNBLogThreadedIf( + LOG_DARWIN_LOG, "received activity create: " + "%s, creator aid %" PRIu64 ", unique_pid %" PRIu64 + "(activity id=%" PRIu64 ", parent id=%" PRIu64 ")", + entry->activity_create.name, entry->activity_create.creator_aid, + entry->activity_create.unique_pid, entry->activity_id, + entry->parent_id); + { + std::lock_guard<std::mutex> locker(m_activity_info_mutex); + m_activity_map.insert( + std::make_pair(entry->activity_id, + ActivityInfo(entry->activity_create.name, + entry->activity_id, entry->parent_id))); + } + break; + + case OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION: + DNBLogThreadedIf( + LOG_DARWIN_LOG, "received activity transition:" + "new aid: %" PRIu64 "(activity id=%" PRIu64 + ", parent id=%" PRIu64 ", tid %" PRIu64 ")", + entry->activity_transition.transition_id, entry->activity_id, + entry->parent_id, entry->activity_transition.thread); + break; + + case OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE: { + DNBLogThreadedIf( + LOG_DARWIN_LOG, "received log message: " + "(activity id=%" PRIu64 ", parent id=%" PRIu64 ", " + "tid %" PRIu64 "): format %s", + entry->activity_id, entry->parent_id, entry->log_message.thread, + entry->log_message.format ? entry->log_message.format + : "<invalid-format>"); + + // Do the real work here. + { + // Ensure our process is still alive. If not, we can + // cancel the collection. + if (!DNBProcessIsAlive(m_pid)) { + // We're outta here. This is the manner in which we + // stop collecting for a process. + StopTrackingCollector(shared_from_this()); + return false; + } -void -DarwinLogCollector::SetActivityStream(os_activity_stream_t activity_stream) -{ - m_activity_stream = activity_stream; -} + LogMessageOsLog os_log_message(*this, *entry); + if (!m_filter_chain_sp || + !m_filter_chain_sp->GetAcceptMessage(os_log_message)) { + // This log message was rejected by the filter, + // so stop processing it now. + return true; + } -bool -DarwinLogCollector::HandleStreamEntry(os_activity_stream_entry_t entry, - int error) -{ - if ((error == 0) && (entry != nullptr)) - { - if (entry->pid != m_pid) - { - // For now, skip messages not originating from our process. - // Later we might want to keep all messages related to an event - // that we're tracking, even when it came from another process, - // possibly doing work on our behalf. - return true; + // Copy over the relevant bits from the message. + const struct os_log_message_s &log_message = entry->log_message; + + DarwinLogEventSP message_sp(new DarwinLogEvent()); + // Indicate this event is a log message event. + message_sp->AddStringItem("type", "log"); + + // Add the message contents (fully expanded). + // Consider expanding on the remote side. + // Then we don't pay for expansion until when it is + // used. + const char *message_text = os_log_message.GetMessage(); + if (message_text) + message_sp->AddStringItem("message", message_text); + + // Add some useful data fields. + message_sp->AddIntegerItem("timestamp", log_message.timestamp); + + // Do we want to do all activity name resolution on this + // side? Maybe. For now, send IDs and ID->name mappings + // and fix this up on that side. Later, when we add + // debugserver-side filtering, we'll want to get the + // activity names over here, so we should probably + // just send them as resolved strings. + message_sp->AddIntegerItem("activity_id", entry->activity_id); + message_sp->AddIntegerItem("parent_id", entry->parent_id); + message_sp->AddIntegerItem("thread_id", log_message.thread); + if (log_message.subsystem && strlen(log_message.subsystem) > 0) + message_sp->AddStringItem("subsystem", log_message.subsystem); + if (log_message.category && strlen(log_message.category) > 0) + message_sp->AddStringItem("category", log_message.category); + if (entry->activity_id != 0) { + std::string activity_chain = + GetActivityChainForID(entry->activity_id); + if (!activity_chain.empty()) + message_sp->AddStringItem("activity-chain", activity_chain); } - switch (entry->type) + // Add it to the list for later collection. { - case OS_ACTIVITY_STREAM_TYPE_ACTIVITY_CREATE: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received activity create: " - "%s, creator aid %" PRIu64 ", unique_pid %" PRIu64 - "(activity id=%" PRIu64 ", parent id=%" PRIu64 ")", - entry->activity_create.name, - entry->activity_create.creator_aid, - entry->activity_create.unique_pid, entry->activity_id, - entry->parent_id - ); - { - std::lock_guard<std::mutex> locker(m_activity_info_mutex); - m_activity_map.insert(std::make_pair( - entry->activity_id, - ActivityInfo( - entry->activity_create.name, - entry->activity_id, - entry->parent_id))); - } - break; - - case OS_ACTIVITY_STREAM_TYPE_ACTIVITY_TRANSITION: - DNBLogThreadedIf(LOG_DARWIN_LOG, "received activity transition:" - "new aid: %" PRIu64 "(activity id=%" PRIu64 - ", parent id=%" PRIu64 ", tid %" PRIu64 ")", - entry->activity_transition.transition_id, - entry->activity_id, entry->parent_id, - entry->activity_transition.thread); - break; - - case OS_ACTIVITY_STREAM_TYPE_LOG_MESSAGE: - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "received log message: " - "(activity id=%" PRIu64 ", parent id=%" PRIu64 ", " - "tid %" PRIu64 "): format %s", - entry->activity_id, entry->parent_id, - entry->log_message.thread, - entry->log_message.format ? entry->log_message.format : - "<invalid-format>"); - - // Do the real work here. - { - // Ensure our process is still alive. If not, we can - // cancel the collection. - if (!DNBProcessIsAlive(m_pid)) - { - // We're outta here. This is the manner in which we - // stop collecting for a process. - StopTrackingCollector(shared_from_this()); - return false; - } - - LogMessageOsLog os_log_message(*this, *entry); - if (!m_filter_chain_sp || - !m_filter_chain_sp->GetAcceptMessage(os_log_message)) - { - // This log message was rejected by the filter, - // so stop processing it now. - return true; - } - - // Copy over the relevant bits from the message. - const struct os_log_message_s &log_message = - entry->log_message; - - DarwinLogEventSP message_sp(new DarwinLogEvent()); - // Indicate this event is a log message event. - message_sp->AddStringItem("type", "log"); - - // Add the message contents (fully expanded). - // Consider expanding on the remote side. - // Then we don't pay for expansion until when it is - // used. - const char *message_text = os_log_message.GetMessage(); - if (message_text) - message_sp->AddStringItem("message", message_text); - - // Add some useful data fields. - message_sp->AddIntegerItem("timestamp", - log_message.timestamp); - - // Do we want to do all activity name resolution on this - // side? Maybe. For now, send IDs and ID->name mappings - // and fix this up on that side. Later, when we add - // debugserver-side filtering, we'll want to get the - // activity names over here, so we should probably - // just send them as resolved strings. - message_sp->AddIntegerItem("activity_id", - entry->activity_id); - message_sp->AddIntegerItem("parent_id", - entry->parent_id); - message_sp->AddIntegerItem("thread_id", - log_message.thread); - if (log_message.subsystem && strlen(log_message.subsystem) - > 0) - message_sp->AddStringItem("subsystem", - log_message.subsystem); - if (log_message.category && strlen(log_message.category) - > 0) - message_sp->AddStringItem("category", - log_message.category); - if (entry->activity_id != 0) - { - std::string activity_chain = - GetActivityChainForID(entry->activity_id); - if (!activity_chain.empty()) - message_sp->AddStringItem("activity-chain", - activity_chain); - } - - // Add it to the list for later collection. - { - std::lock_guard<std::mutex> locker(m_events_mutex); - m_events.push_back(message_sp); - } - SignalDataAvailable(); - } - break; - } + std::lock_guard<std::mutex> locker(m_events_mutex); + m_events.push_back(message_sp); } + SignalDataAvailable(); + } + break; } - else - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "HandleStreamEntry: final call, " - "error %d", error); } - return true; + } else { + DNBLogThreadedIf(LOG_DARWIN_LOG, "HandleStreamEntry: final call, " + "error %d", + error); + } + return true; } -DarwinLogEventVector -DarwinLogCollector::RemoveEvents() -{ - DarwinLogEventVector returned_events; - { - std::lock_guard<std::mutex> locker(m_events_mutex); - returned_events.swap(m_events); - } - DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLogCollector::%s(): removing %lu " - "queued log entries", __FUNCTION__, - returned_events.size()); - return returned_events; +DarwinLogEventVector DarwinLogCollector::RemoveEvents() { + DarwinLogEventVector returned_events; + { + std::lock_guard<std::mutex> locker(m_events_mutex); + returned_events.swap(m_events); + } + DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLogCollector::%s(): removing %lu " + "queued log entries", + __FUNCTION__, returned_events.size()); + return returned_events; } -void -DarwinLogCollector::CancelActivityStream() -{ - if (!m_activity_stream) - return; +void DarwinLogCollector::CancelActivityStream() { + if (!m_activity_stream) + return; - DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLogCollector::%s(): canceling " - "activity stream %p", __FUNCTION__, - m_activity_stream); - (*s_os_activity_stream_cancel)(m_activity_stream); - m_activity_stream = nullptr; + DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLogCollector::%s(): canceling " + "activity stream %p", + __FUNCTION__, m_activity_stream); + (*s_os_activity_stream_cancel)(m_activity_stream); + m_activity_stream = nullptr; } diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.h index 8263423fce1..a7d4e8a774c 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogCollector.h @@ -18,122 +18,97 @@ #include "ActivityStore.h" #include "ActivityStreamSPI.h" +#include "DNBDefs.h" #include "DarwinLogEvent.h" #include "DarwinLogInterfaces.h" -#include "DNBDefs.h" #include "JSON.h" class DarwinLogCollector; typedef std::shared_ptr<DarwinLogCollector> DarwinLogCollectorSP; -class DarwinLogCollector: - public std::enable_shared_from_this<DarwinLogCollector>, - public ActivityStore -{ +class DarwinLogCollector + : public std::enable_shared_from_this<DarwinLogCollector>, + public ActivityStore { public: + //------------------------------------------------------------------ + /// Return whether the os_log and activity tracing SPI is available. + /// + /// @return \b true if the activity stream support is available, + /// \b false otherwise. + //------------------------------------------------------------------ + static bool IsSupported(); - //------------------------------------------------------------------ - /// Return whether the os_log and activity tracing SPI is available. - /// - /// @return \b true if the activity stream support is available, - /// \b false otherwise. - //------------------------------------------------------------------ - static bool - IsSupported(); - - //------------------------------------------------------------------ - /// Return a log function suitable for DNBLog to use as the internal - /// logging function. - /// - /// @return a DNBLog-style logging function if IsSupported() returns - /// true; otherwise, returns nullptr. - //------------------------------------------------------------------ - static DNBCallbackLog - GetLogFunction(); + //------------------------------------------------------------------ + /// Return a log function suitable for DNBLog to use as the internal + /// logging function. + /// + /// @return a DNBLog-style logging function if IsSupported() returns + /// true; otherwise, returns nullptr. + //------------------------------------------------------------------ + static DNBCallbackLog GetLogFunction(); - static bool - StartCollectingForProcess(nub_process_t pid, const JSONObject &config); + static bool StartCollectingForProcess(nub_process_t pid, + const JSONObject &config); - static bool - CancelStreamForProcess(nub_process_t pid); + static bool CancelStreamForProcess(nub_process_t pid); - static DarwinLogEventVector - GetEventsForProcess(nub_process_t pid); + static DarwinLogEventVector GetEventsForProcess(nub_process_t pid); - ~DarwinLogCollector(); + ~DarwinLogCollector(); - pid_t - GetProcessID() const - { - return m_pid; - } + pid_t GetProcessID() const { return m_pid; } - //------------------------------------------------------------------ - // ActivityStore API - //------------------------------------------------------------------ - const char* - GetActivityForID(os_activity_id_t activity_id) const override; - - std::string - GetActivityChainForID(os_activity_id_t activity_id) const override; + //------------------------------------------------------------------ + // ActivityStore API + //------------------------------------------------------------------ + const char *GetActivityForID(os_activity_id_t activity_id) const override; + std::string + GetActivityChainForID(os_activity_id_t activity_id) const override; private: + DarwinLogCollector() = delete; + DarwinLogCollector(const DarwinLogCollector &) = delete; + DarwinLogCollector &operator=(const DarwinLogCollector &) = delete; - DarwinLogCollector() = delete; - DarwinLogCollector(const DarwinLogCollector&) = delete; - DarwinLogCollector &operator=(const DarwinLogCollector&) = delete; - - explicit - DarwinLogCollector(nub_process_t pid, - const LogFilterChainSP &filter_chain_sp); + explicit DarwinLogCollector(nub_process_t pid, + const LogFilterChainSP &filter_chain_sp); - void - SignalDataAvailable(); + void SignalDataAvailable(); - void - SetActivityStream(os_activity_stream_t activity_stream); + void SetActivityStream(os_activity_stream_t activity_stream); - bool - HandleStreamEntry(os_activity_stream_entry_t entry, int error); + bool HandleStreamEntry(os_activity_stream_entry_t entry, int error); - DarwinLogEventVector - RemoveEvents(); + DarwinLogEventVector RemoveEvents(); - void - CancelActivityStream(); + void CancelActivityStream(); - void - GetActivityChainForID_internal(os_activity_id_t activity_id, - std::string &result, size_t depth) const; + void GetActivityChainForID_internal(os_activity_id_t activity_id, + std::string &result, size_t depth) const; - struct ActivityInfo - { - ActivityInfo(const char *name, os_activity_id_t activity_id, - os_activity_id_t parent_activity_id) : - m_name(name), - m_id(activity_id), - m_parent_id(parent_activity_id) - { - } + struct ActivityInfo { + ActivityInfo(const char *name, os_activity_id_t activity_id, + os_activity_id_t parent_activity_id) + : m_name(name), m_id(activity_id), m_parent_id(parent_activity_id) {} - const std::string m_name; - const os_activity_id_t m_id; - const os_activity_id_t m_parent_id; - }; + const std::string m_name; + const os_activity_id_t m_id; + const os_activity_id_t m_parent_id; + }; - using ActivityMap = std::unordered_map<os_activity_id_t, ActivityInfo>; + using ActivityMap = std::unordered_map<os_activity_id_t, ActivityInfo>; - const nub_process_t m_pid; - os_activity_stream_t m_activity_stream; - DarwinLogEventVector m_events; - std::mutex m_events_mutex; - LogFilterChainSP m_filter_chain_sp; + const nub_process_t m_pid; + os_activity_stream_t m_activity_stream; + DarwinLogEventVector m_events; + std::mutex m_events_mutex; + LogFilterChainSP m_filter_chain_sp; - /// Mutex to protect activity info (activity name and parent structures) - mutable std::mutex m_activity_info_mutex; - /// Map of activity id to ActivityInfo - ActivityMap m_activity_map; + /// Mutex to protect activity info (activity name and parent structures) + mutable std::mutex m_activity_info_mutex; + /// Map of activity id to ActivityInfo + ActivityMap m_activity_map; }; #endif /* LogStreamCollector_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogTypes.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogTypes.h index a090fba0c14..e285e732e56 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogTypes.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/DarwinLogTypes.h @@ -10,14 +10,13 @@ #ifndef DarwinLogTypes_h #define DarwinLogTypes_h -enum FilterTarget -{ - eFilterTargetInvalid, - eFilterTargetActivity, - eFilterTargetActivityChain, - eFilterTargetCategory, - eFilterTargetMessage, - eFilterTargetSubsystem +enum FilterTarget { + eFilterTargetInvalid, + eFilterTargetActivity, + eFilterTargetActivityChain, + eFilterTargetCategory, + eFilterTargetMessage, + eFilterTargetSubsystem }; #endif /* DarwinLogTypes_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.cpp index 80af86ec505..d78419d4661 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.cpp @@ -9,6 +9,4 @@ #include "LogFilter.h" -LogFilter::~LogFilter() -{ -} +LogFilter::~LogFilter() {} diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.h index 4d54394cb32..92caac29725 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilter.h @@ -12,33 +12,19 @@ #include "DarwinLogInterfaces.h" -class LogFilter -{ +class LogFilter { public: + virtual ~LogFilter(); - virtual - ~LogFilter(); + virtual bool DoesMatch(const LogMessage &message) const = 0; - virtual bool - DoesMatch(const LogMessage &message) const = 0; - - bool - MatchesAreAccepted() const - { - return m_matches_accept; - } + bool MatchesAreAccepted() const { return m_matches_accept; } protected: - - LogFilter(bool matches_accept) : - m_matches_accept(matches_accept) - { - } + LogFilter(bool matches_accept) : m_matches_accept(matches_accept) {} private: - - bool m_matches_accept; - + bool m_matches_accept; }; #endif /* LogFilter_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.cpp index 888fbd9bfb1..12fbe77a906 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.cpp @@ -11,51 +11,32 @@ #include "LogFilter.h" -LogFilterChain::LogFilterChain(bool default_accept) : - m_filters(), - m_default_accept(default_accept) -{ -} +LogFilterChain::LogFilterChain(bool default_accept) + : m_filters(), m_default_accept(default_accept) {} -void -LogFilterChain::AppendFilter(const LogFilterSP &filter_sp) -{ - if (filter_sp) - m_filters.push_back(filter_sp); +void LogFilterChain::AppendFilter(const LogFilterSP &filter_sp) { + if (filter_sp) + m_filters.push_back(filter_sp); } -void -LogFilterChain::ClearFilterChain() -{ - m_filters.clear(); -} +void LogFilterChain::ClearFilterChain() { m_filters.clear(); } -bool -LogFilterChain::GetDefaultAccepts() const -{ - return m_default_accept; -} +bool LogFilterChain::GetDefaultAccepts() const { return m_default_accept; } -void -LogFilterChain::SetDefaultAccepts(bool default_accept) -{ - m_default_accept = default_accept; +void LogFilterChain::SetDefaultAccepts(bool default_accept) { + m_default_accept = default_accept; } -bool -LogFilterChain::GetAcceptMessage(const LogMessage &message) const -{ - for (auto filter_sp : m_filters) - { - if (filter_sp->DoesMatch(message)) - { - // This message matches this filter. If the filter accepts matches, - // this message matches; otherwise, it rejects matches. - return filter_sp->MatchesAreAccepted(); - } +bool LogFilterChain::GetAcceptMessage(const LogMessage &message) const { + for (auto filter_sp : m_filters) { + if (filter_sp->DoesMatch(message)) { + // This message matches this filter. If the filter accepts matches, + // this message matches; otherwise, it rejects matches. + return filter_sp->MatchesAreAccepted(); } + } - // None of the filters matched. Therefore, we do whatever the - // default fall-through rule says. - return m_default_accept; + // None of the filters matched. Therefore, we do whatever the + // default fall-through rule says. + return m_default_accept; } diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.h index 8774c15d98c..e4888361e71 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterChain.h @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #ifndef LogFilterChain_h #define LogFilterChain_h @@ -15,34 +14,25 @@ #include "DarwinLogInterfaces.h" -class LogFilterChain -{ +class LogFilterChain { public: + LogFilterChain(bool default_accept); - LogFilterChain(bool default_accept); - - void - AppendFilter(const LogFilterSP &filter_sp); + void AppendFilter(const LogFilterSP &filter_sp); - void - ClearFilterChain(); + void ClearFilterChain(); - bool - GetDefaultAccepts() const; + bool GetDefaultAccepts() const; - void - SetDefaultAccepts(bool default_accepts); + void SetDefaultAccepts(bool default_accepts); - bool - GetAcceptMessage(const LogMessage &message) const; + bool GetAcceptMessage(const LogMessage &message) const; private: + using FilterVector = std::vector<LogFilterSP>; - using FilterVector = std::vector<LogFilterSP>; - - FilterVector m_filters; - bool m_default_accept; - + FilterVector m_filters; + bool m_default_accept; }; #endif /* LogFilterChain_hpp */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.cpp index b85458618fd..c8034fe1f22 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.cpp @@ -12,46 +12,38 @@ LogFilterExactMatch::LogFilterExactMatch(bool match_accepts, FilterTarget filter_target, - const std::string &match_text) : - LogFilter(match_accepts), - m_filter_target(filter_target), - m_match_text(match_text) -{ -} + const std::string &match_text) + : LogFilter(match_accepts), m_filter_target(filter_target), + m_match_text(match_text) {} -bool -LogFilterExactMatch::DoesMatch(const LogMessage &message) const -{ - switch (m_filter_target) - { - case eFilterTargetActivity: - // Empty fields never match a condition. - if (!message.HasActivity()) - return false; - return m_match_text == message.GetActivity(); - case eFilterTargetActivityChain: - // Empty fields never match a condition. - if (!message.HasActivity()) - return false; - return m_match_text == message.GetActivityChain(); - case eFilterTargetCategory: - // Empty fields never match a condition. - if (!message.HasCategory()) - return false; - return m_match_text == message.GetCategory(); - case eFilterTargetMessage: - { - const char *message_text = message.GetMessage(); - return (message_text != nullptr) && - (m_match_text == message_text); - } - case eFilterTargetSubsystem: - // Empty fields never match a condition. - if (!message.HasSubsystem()) - return false; - return m_match_text == message.GetSubsystem(); - default: - // We don't know this type. - return false; - } +bool LogFilterExactMatch::DoesMatch(const LogMessage &message) const { + switch (m_filter_target) { + case eFilterTargetActivity: + // Empty fields never match a condition. + if (!message.HasActivity()) + return false; + return m_match_text == message.GetActivity(); + case eFilterTargetActivityChain: + // Empty fields never match a condition. + if (!message.HasActivity()) + return false; + return m_match_text == message.GetActivityChain(); + case eFilterTargetCategory: + // Empty fields never match a condition. + if (!message.HasCategory()) + return false; + return m_match_text == message.GetCategory(); + case eFilterTargetMessage: { + const char *message_text = message.GetMessage(); + return (message_text != nullptr) && (m_match_text == message_text); + } + case eFilterTargetSubsystem: + // Empty fields never match a condition. + if (!message.HasSubsystem()) + return false; + return m_match_text == message.GetSubsystem(); + default: + // We don't know this type. + return false; + } } diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.h index 131afaf234b..dd514bc8274 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterExactMatch.h @@ -16,21 +16,16 @@ #include "DarwinLogTypes.h" #include "LogFilter.h" -class LogFilterExactMatch : public LogFilter -{ +class LogFilterExactMatch : public LogFilter { public: + LogFilterExactMatch(bool match_accepts, FilterTarget filter_target, + const std::string &match_text); - LogFilterExactMatch(bool match_accepts, FilterTarget filter_target, - const std::string &match_text); - - bool - DoesMatch(const LogMessage &message) const override; + bool DoesMatch(const LogMessage &message) const override; private: - - const FilterTarget m_filter_target; - const std::string m_match_text; - + const FilterTarget m_filter_target; + const std::string m_match_text; }; #endif diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.cpp index 128c7514493..d21ce81c832 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.cpp @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #include "LogFilterRegex.h" #include "DNBLog.h" @@ -19,100 +18,80 @@ // everywhere. //---------------------------------------------------------------------- #if defined(REG_ENHANCED) -#define DEFAULT_COMPILE_FLAGS (REG_ENHANCED|REG_EXTENDED) +#define DEFAULT_COMPILE_FLAGS (REG_ENHANCED | REG_EXTENDED) #else #define DEFAULT_COMPILE_FLAGS (REG_EXTENDED) #endif -LogFilterRegex::LogFilterRegex(bool match_accepts, - FilterTarget filter_target, - const std::string ®ex) : - LogFilter(match_accepts), - m_filter_target(filter_target), - m_regex_text(regex), - m_regex(), - m_is_valid(false), - m_error_text() -{ - // Clear it. - memset(&m_regex, 0, sizeof(m_regex)); +LogFilterRegex::LogFilterRegex(bool match_accepts, FilterTarget filter_target, + const std::string ®ex) + : LogFilter(match_accepts), m_filter_target(filter_target), + m_regex_text(regex), m_regex(), m_is_valid(false), m_error_text() { + // Clear it. + memset(&m_regex, 0, sizeof(m_regex)); - // Compile it. - if (!regex.empty()) - { - auto comp_err = ::regcomp(&m_regex, regex.c_str(), - DEFAULT_COMPILE_FLAGS); - m_is_valid = (comp_err == 0); - if (!m_is_valid) - { - char buffer[256]; - buffer[0] = '\0'; - ::regerror(comp_err, &m_regex, buffer, sizeof(buffer)); - m_error_text = buffer; - } + // Compile it. + if (!regex.empty()) { + auto comp_err = ::regcomp(&m_regex, regex.c_str(), DEFAULT_COMPILE_FLAGS); + m_is_valid = (comp_err == 0); + if (!m_is_valid) { + char buffer[256]; + buffer[0] = '\0'; + ::regerror(comp_err, &m_regex, buffer, sizeof(buffer)); + m_error_text = buffer; } + } } -LogFilterRegex::~LogFilterRegex() -{ - if (m_is_valid) - { - // Free the regex internals. - regfree(&m_regex); - } +LogFilterRegex::~LogFilterRegex() { + if (m_is_valid) { + // Free the regex internals. + regfree(&m_regex); + } } -bool -LogFilterRegex::DoesMatch(const LogMessage &message) const -{ - switch (m_filter_target) - { - case eFilterTargetActivity: - // Empty fields never match a condition. - if (!message.HasActivity()) - return false; - return ::regexec(&m_regex, message.GetActivity(), 0, nullptr, 0) - == 0; - case eFilterTargetActivityChain: - // Empty fields never match a condition. - if (!message.HasActivity()) - return false; - return ::regexec(&m_regex, message.GetActivityChain().c_str(), 0, - nullptr, 0) == 0; - case eFilterTargetCategory: - // Empty fields never match a condition. - if (!message.HasCategory()) - return false; - return ::regexec(&m_regex, message.GetCategory(), 0, nullptr, - 0) == 0; - case eFilterTargetMessage: - { - const char *message_text = message.GetMessage(); - if (!message_text) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "LogFilterRegex: regex " - "\"%s\" no match due to nullptr message.", - m_regex_text.c_str()); - return false; - } - - bool match = ::regexec(&m_regex, message_text, 0, - nullptr, 0) == 0; - DNBLogThreadedIf(LOG_DARWIN_LOG, "LogFilterRegex: regex " - "\"%s\" %s message \"%s\".", - m_regex_text.c_str(), - match ? "matches" : "does not match", - message_text); - return match; - } - case eFilterTargetSubsystem: - // Empty fields never match a condition. - if (!message.HasSubsystem()) - return false; - return ::regexec(&m_regex, message.GetSubsystem(), 0, nullptr, - 0) == 0; - default: - // We don't know this type. - return false; +bool LogFilterRegex::DoesMatch(const LogMessage &message) const { + switch (m_filter_target) { + case eFilterTargetActivity: + // Empty fields never match a condition. + if (!message.HasActivity()) + return false; + return ::regexec(&m_regex, message.GetActivity(), 0, nullptr, 0) == 0; + case eFilterTargetActivityChain: + // Empty fields never match a condition. + if (!message.HasActivity()) + return false; + return ::regexec(&m_regex, message.GetActivityChain().c_str(), 0, nullptr, + 0) == 0; + case eFilterTargetCategory: + // Empty fields never match a condition. + if (!message.HasCategory()) + return false; + return ::regexec(&m_regex, message.GetCategory(), 0, nullptr, 0) == 0; + case eFilterTargetMessage: { + const char *message_text = message.GetMessage(); + if (!message_text) { + DNBLogThreadedIf(LOG_DARWIN_LOG, + "LogFilterRegex: regex " + "\"%s\" no match due to nullptr message.", + m_regex_text.c_str()); + return false; } + + bool match = ::regexec(&m_regex, message_text, 0, nullptr, 0) == 0; + DNBLogThreadedIf(LOG_DARWIN_LOG, "LogFilterRegex: regex " + "\"%s\" %s message \"%s\".", + m_regex_text.c_str(), match ? "matches" : "does not match", + message_text); + return match; + } + case eFilterTargetSubsystem: + // Empty fields never match a condition. + if (!message.HasSubsystem()) + return false; + return ::regexec(&m_regex, message.GetSubsystem(), 0, nullptr, 0) == 0; + default: + // We don't know this type. + return false; + } } diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.h index 796a62500ff..4a5939217f0 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogFilterRegex.h @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #ifndef LogFilterRegex_h #define LogFilterRegex_h @@ -21,38 +20,25 @@ #include "DarwinLogTypes.h" #include "LogFilter.h" -class LogFilterRegex : public LogFilter -{ +class LogFilterRegex : public LogFilter { public: + LogFilterRegex(bool match_accepts, FilterTarget filter_target, + const std::string ®ex); - LogFilterRegex(bool match_accepts, FilterTarget filter_target, - const std::string ®ex); - - virtual - ~LogFilterRegex(); + virtual ~LogFilterRegex(); - bool - IsValid() const - { - return m_is_valid; - } + bool IsValid() const { return m_is_valid; } - const char* - GetErrorAsCString() const - { - return m_error_text.c_str(); - } + const char *GetErrorAsCString() const { return m_error_text.c_str(); } - bool - DoesMatch(const LogMessage &message) const override; + bool DoesMatch(const LogMessage &message) const override; private: - - const FilterTarget m_filter_target; - const std::string m_regex_text; - regex_t m_regex; - bool m_is_valid; - std::string m_error_text; + const FilterTarget m_filter_target; + const std::string m_regex_text; + regex_t m_regex; + bool m_is_valid; + std::string m_error_text; }; #endif /* LogFilterSubsystemRegex_hpp */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.cpp index d98bb3de3c1..5a31087f231 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.cpp @@ -7,13 +7,8 @@ // //===----------------------------------------------------------------------===// - #include "LogMessage.h" -LogMessage::LogMessage() -{ -} +LogMessage::LogMessage() {} -LogMessage::~LogMessage() -{ -} +LogMessage::~LogMessage() {} diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.h index 0ec2b4277a4..bbc975133ec 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessage.h @@ -12,42 +12,29 @@ #include <string> -class LogMessage -{ +class LogMessage { public: + virtual ~LogMessage(); - virtual - ~LogMessage(); + virtual bool HasActivity() const = 0; - virtual bool - HasActivity() const = 0; + virtual const char *GetActivity() const = 0; - virtual const char* - GetActivity() const = 0; + virtual std::string GetActivityChain() const = 0; - virtual std::string - GetActivityChain() const = 0; + virtual bool HasCategory() const = 0; - virtual bool - HasCategory() const = 0; + virtual const char *GetCategory() const = 0; - virtual const char* - GetCategory() const = 0; + virtual bool HasSubsystem() const = 0; - virtual bool - HasSubsystem() const = 0; + virtual const char *GetSubsystem() const = 0; - virtual const char* - GetSubsystem() const = 0; - - // This can be expensive, so once we ask for it, we'll cache the result. - virtual const char* - GetMessage() const = 0; + // This can be expensive, so once we ask for it, we'll cache the result. + virtual const char *GetMessage() const = 0; protected: - - LogMessage(); - + LogMessage(); }; #endif /* LogMessage_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.cpp b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.cpp index f3b6e443918..91347eaf12c 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.cpp +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.cpp @@ -12,84 +12,57 @@ #include "ActivityStore.h" #include "ActivityStreamSPI.h" -namespace -{ - static os_log_copy_formatted_message_t s_log_copy_formatted_message; +namespace { +static os_log_copy_formatted_message_t s_log_copy_formatted_message; } -void -LogMessageOsLog::SetFormatterFunction(os_log_copy_formatted_message_t - format_func) -{ - s_log_copy_formatted_message = format_func; +void LogMessageOsLog::SetFormatterFunction( + os_log_copy_formatted_message_t format_func) { + s_log_copy_formatted_message = format_func; } LogMessageOsLog::LogMessageOsLog(const ActivityStore &activity_store, - ActivityStreamEntry &entry) : - LogMessage(), - m_activity_store(activity_store), - m_entry(entry), - m_message() -{ -} + ActivityStreamEntry &entry) + : LogMessage(), m_activity_store(activity_store), m_entry(entry), + m_message() {} -bool -LogMessageOsLog::HasActivity() const -{ - return m_entry.activity_id != 0; -} +bool LogMessageOsLog::HasActivity() const { return m_entry.activity_id != 0; } -const char* -LogMessageOsLog::GetActivity() const -{ - return m_activity_store.GetActivityForID(m_entry.activity_id); +const char *LogMessageOsLog::GetActivity() const { + return m_activity_store.GetActivityForID(m_entry.activity_id); } -std::string -LogMessageOsLog::GetActivityChain() const -{ - return m_activity_store.GetActivityChainForID(m_entry.activity_id); +std::string LogMessageOsLog::GetActivityChain() const { + return m_activity_store.GetActivityChainForID(m_entry.activity_id); } -bool -LogMessageOsLog::HasCategory() const -{ - return m_entry.log_message.category && - (m_entry.log_message.category[0] != 0); +bool LogMessageOsLog::HasCategory() const { + return m_entry.log_message.category && (m_entry.log_message.category[0] != 0); } -const char* -LogMessageOsLog::GetCategory() const -{ - return m_entry.log_message.category; +const char *LogMessageOsLog::GetCategory() const { + return m_entry.log_message.category; } -bool -LogMessageOsLog::HasSubsystem() const -{ - return m_entry.log_message.subsystem && - (m_entry.log_message.subsystem[0] != 0); +bool LogMessageOsLog::HasSubsystem() const { + return m_entry.log_message.subsystem && + (m_entry.log_message.subsystem[0] != 0); } -const char* -LogMessageOsLog::GetSubsystem() const -{ - return m_entry.log_message.subsystem; +const char *LogMessageOsLog::GetSubsystem() const { + return m_entry.log_message.subsystem; } -const char* -LogMessageOsLog::GetMessage() const -{ - if (m_message.empty()) - { - std::unique_ptr<char[]> formatted_message( - s_log_copy_formatted_message(&m_entry.log_message)); - if (formatted_message) - m_message = formatted_message.get(); - // else - // TODO log - } +const char *LogMessageOsLog::GetMessage() const { + if (m_message.empty()) { + std::unique_ptr<char[]> formatted_message( + s_log_copy_formatted_message(&m_entry.log_message)); + if (formatted_message) + m_message = formatted_message.get(); + // else + // TODO log + } - // This is safe to return as we're not modifying it once we've formatted it. - return m_message.c_str(); + // This is safe to return as we're not modifying it once we've formatted it. + return m_message.c_str(); } diff --git a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.h b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.h index 7c02059fc57..18103e03159 100644 --- a/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.h +++ b/lldb/tools/debugserver/source/MacOSX/DarwinLog/LogMessageOsLog.h @@ -7,7 +7,6 @@ // //===----------------------------------------------------------------------===// - #ifndef LogMessageOsLog_h #define LogMessageOsLog_h @@ -26,48 +25,35 @@ using ActivityStreamEntry = struct os_activity_stream_entry_s; /// outlive this LogMessageOsLog entry. // ----------------------------------------------------------------------------- -class LogMessageOsLog : public LogMessage -{ +class LogMessageOsLog : public LogMessage { public: + static void SetFormatterFunction(os_log_copy_formatted_message_t format_func); - static void - SetFormatterFunction(os_log_copy_formatted_message_t format_func); - - LogMessageOsLog(const ActivityStore &activity_store, - ActivityStreamEntry &entry); + LogMessageOsLog(const ActivityStore &activity_store, + ActivityStreamEntry &entry); - // API methods + // API methods - bool - HasActivity() const override; + bool HasActivity() const override; - const char* - GetActivity() const override; + const char *GetActivity() const override; - std::string - GetActivityChain() const override; + std::string GetActivityChain() const override; - bool - HasCategory() const override; + bool HasCategory() const override; - const char* - GetCategory() const override; + const char *GetCategory() const override; - bool - HasSubsystem() const override; + bool HasSubsystem() const override; - const char* - GetSubsystem() const override; + const char *GetSubsystem() const override; - const char* - GetMessage() const override; + const char *GetMessage() const override; private: - - const ActivityStore &m_activity_store; - ActivityStreamEntry &m_entry; - mutable std::string m_message; - + const ActivityStore &m_activity_store; + ActivityStreamEntry &m_entry; + mutable std::string m_message; }; #endif /* LogMessageOsLog_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp b/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp index a5ee097aa2a..22ff52abaa4 100644 --- a/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp +++ b/lldb/tools/debugserver/source/MacOSX/Genealogy.cpp @@ -8,8 +8,8 @@ //===----------------------------------------------------------------------===// #include <Availability.h> -#include <string> #include <dlfcn.h> +#include <string> #include <uuid/uuid.h> #include "DNBDefs.h" @@ -21,280 +21,299 @@ /// Constructor //--------------------------- -Genealogy::Genealogy () : - m_os_activity_diagnostic_for_pid (nullptr), - m_os_activity_iterate_processes (nullptr), - m_os_activity_iterate_breadcrumbs (nullptr), - m_os_activity_iterate_messages (nullptr), - m_os_activity_iterate_activities (nullptr), - m_os_trace_get_type (nullptr), - m_os_trace_copy_formatted_message (nullptr), - m_os_activity_for_thread (nullptr), - m_os_activity_for_task_thread (nullptr), - m_thread_activities(), - m_process_executable_infos(), - m_diagnosticd_call_timed_out(false) -{ - m_os_activity_diagnostic_for_pid = (bool (*)(pid_t, os_activity_t, uint32_t, os_diagnostic_block_t))dlsym (RTLD_DEFAULT, "os_activity_diagnostic_for_pid"); - m_os_activity_iterate_processes = (void (*)(os_activity_process_list_t, bool (^)(os_activity_process_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_processes"); - m_os_activity_iterate_breadcrumbs = (void (*)(os_activity_process_t, bool (^)(os_activity_breadcrumb_t))) dlsym (RTLD_DEFAULT, "os_activity_iterate_breadcrumbs"); - m_os_activity_iterate_messages = (void (*)(os_trace_message_list_t, os_activity_process_t, bool (^)(os_trace_message_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_messages"); - m_os_activity_iterate_activities = (void (*)(os_activity_list_t, os_activity_process_t, bool (^)(os_activity_entry_t)))dlsym (RTLD_DEFAULT, "os_activity_iterate_activities"); - m_os_trace_get_type = (uint8_t (*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_get_type"); - m_os_trace_copy_formatted_message = (char *(*)(os_trace_message_t)) dlsym (RTLD_DEFAULT, "os_trace_copy_formatted_message"); - m_os_activity_for_thread = (os_activity_t (*)(os_activity_process_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_thread"); - m_os_activity_for_task_thread = (os_activity_t (*)(task_t, uint64_t)) dlsym (RTLD_DEFAULT, "os_activity_for_task_thread"); - m_os_activity_messages_for_thread = (os_trace_message_list_t (*) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id)) dlsym (RTLD_DEFAULT, "os_activity_messages_for_thread"); +Genealogy::Genealogy() + : m_os_activity_diagnostic_for_pid(nullptr), + m_os_activity_iterate_processes(nullptr), + m_os_activity_iterate_breadcrumbs(nullptr), + m_os_activity_iterate_messages(nullptr), + m_os_activity_iterate_activities(nullptr), m_os_trace_get_type(nullptr), + m_os_trace_copy_formatted_message(nullptr), + m_os_activity_for_thread(nullptr), m_os_activity_for_task_thread(nullptr), + m_thread_activities(), m_process_executable_infos(), + m_diagnosticd_call_timed_out(false) { + m_os_activity_diagnostic_for_pid = + (bool (*)(pid_t, os_activity_t, uint32_t, os_diagnostic_block_t))dlsym( + RTLD_DEFAULT, "os_activity_diagnostic_for_pid"); + m_os_activity_iterate_processes = + (void (*)(os_activity_process_list_t, bool (^)(os_activity_process_t))) + dlsym(RTLD_DEFAULT, "os_activity_iterate_processes"); + m_os_activity_iterate_breadcrumbs = + (void (*)(os_activity_process_t, bool (^)(os_activity_breadcrumb_t))) + dlsym(RTLD_DEFAULT, "os_activity_iterate_breadcrumbs"); + m_os_activity_iterate_messages = (void (*)( + os_trace_message_list_t, os_activity_process_t, + bool (^)(os_trace_message_t)))dlsym(RTLD_DEFAULT, + "os_activity_iterate_messages"); + m_os_activity_iterate_activities = (void (*)( + os_activity_list_t, os_activity_process_t, + bool (^)(os_activity_entry_t)))dlsym(RTLD_DEFAULT, + "os_activity_iterate_activities"); + m_os_trace_get_type = + (uint8_t(*)(os_trace_message_t))dlsym(RTLD_DEFAULT, "os_trace_get_type"); + m_os_trace_copy_formatted_message = (char *(*)(os_trace_message_t))dlsym( + RTLD_DEFAULT, "os_trace_copy_formatted_message"); + m_os_activity_for_thread = + (os_activity_t(*)(os_activity_process_t, uint64_t))dlsym( + RTLD_DEFAULT, "os_activity_for_thread"); + m_os_activity_for_task_thread = (os_activity_t(*)(task_t, uint64_t))dlsym( + RTLD_DEFAULT, "os_activity_for_task_thread"); + m_os_activity_messages_for_thread = (os_trace_message_list_t(*)( + os_activity_process_t process, os_activity_t activity, + uint64_t thread_id))dlsym(RTLD_DEFAULT, + "os_activity_messages_for_thread"); } Genealogy::ThreadActivitySP -Genealogy::GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out) -{ - ThreadActivitySP activity; - // - // if we've timed out trying to get the activities, don't try again at this process stop. - // (else we'll need to hit the timeout for every thread we're asked about.) - // We'll try again at the next public stop. +Genealogy::GetGenealogyInfoForThread(pid_t pid, nub_thread_t tid, + const MachThreadList &thread_list, + task_t task, bool &timed_out) { + ThreadActivitySP activity; + // + // if we've timed out trying to get the activities, don't try again at this + // process stop. + // (else we'll need to hit the timeout for every thread we're asked about.) + // We'll try again at the next public stop. - if (m_thread_activities.size() == 0 && m_diagnosticd_call_timed_out == false) - { - GetActivities(pid, thread_list, task); - } - std::map<nub_thread_t, ThreadActivitySP>::const_iterator search; - search = m_thread_activities.find(tid); - if (search != m_thread_activities.end()) - { - activity = search->second; - } - timed_out = m_diagnosticd_call_timed_out; - return activity; + if (m_thread_activities.size() == 0 && + m_diagnosticd_call_timed_out == false) { + GetActivities(pid, thread_list, task); + } + std::map<nub_thread_t, ThreadActivitySP>::const_iterator search; + search = m_thread_activities.find(tid); + if (search != m_thread_activities.end()) { + activity = search->second; + } + timed_out = m_diagnosticd_call_timed_out; + return activity; } -void -Genealogy::Clear() -{ - m_thread_activities.clear(); - m_diagnosticd_call_timed_out = false; +void Genealogy::Clear() { + m_thread_activities.clear(); + m_diagnosticd_call_timed_out = false; } -void -Genealogy::GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task) -{ - if (m_os_activity_diagnostic_for_pid != nullptr - && m_os_activity_iterate_processes != nullptr - && m_os_activity_iterate_breadcrumbs != nullptr - && m_os_activity_iterate_messages != nullptr - && m_os_activity_iterate_activities != nullptr - && m_os_trace_get_type != nullptr - && m_os_trace_copy_formatted_message != nullptr - && (m_os_activity_for_thread != nullptr || m_os_activity_for_task_thread != nullptr) - ) - { - __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __block BreadcrumbList breadcrumbs; - __block ActivityList activities; - __block MessageList messages; - __block std::map<nub_thread_t, uint64_t> thread_activity_mapping; +void Genealogy::GetActivities(pid_t pid, const MachThreadList &thread_list, + task_t task) { + if (m_os_activity_diagnostic_for_pid != nullptr && + m_os_activity_iterate_processes != nullptr && + m_os_activity_iterate_breadcrumbs != nullptr && + m_os_activity_iterate_messages != nullptr && + m_os_activity_iterate_activities != nullptr && + m_os_trace_get_type != nullptr && + m_os_trace_copy_formatted_message != nullptr && + (m_os_activity_for_thread != nullptr || + m_os_activity_for_task_thread != nullptr)) { + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block BreadcrumbList breadcrumbs; + __block ActivityList activities; + __block MessageList messages; + __block std::map<nub_thread_t, uint64_t> thread_activity_mapping; - os_activity_diagnostic_flag_t flags = OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES | OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY; - if (m_os_activity_diagnostic_for_pid (pid, 0, flags, ^(os_activity_process_list_t processes, int error) - { - if (error == 0) - { - m_os_activity_iterate_processes (processes, ^bool(os_activity_process_t process_info) - { - if (pid == process_info->pid) - { - // Collect all the Breadcrumbs - m_os_activity_iterate_breadcrumbs (process_info, ^bool(os_activity_breadcrumb_t breadcrumb) - { - Breadcrumb bc; - bc.breadcrumb_id = breadcrumb->breadcrumb_id; - bc.activity_id = breadcrumb->activity_id; - bc.timestamp = breadcrumb->timestamp; - if (breadcrumb->name) - bc.name = breadcrumb->name; - breadcrumbs.push_back (bc); - return true; + os_activity_diagnostic_flag_t flags = + OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES | + OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY; + if (m_os_activity_diagnostic_for_pid( + pid, 0, flags, ^(os_activity_process_list_t processes, int error) { + if (error == 0) { + m_os_activity_iterate_processes(processes, ^bool( + os_activity_process_t + process_info) { + if (pid == process_info->pid) { + // Collect all the Breadcrumbs + m_os_activity_iterate_breadcrumbs( + process_info, + ^bool(os_activity_breadcrumb_t breadcrumb) { + Breadcrumb bc; + bc.breadcrumb_id = breadcrumb->breadcrumb_id; + bc.activity_id = breadcrumb->activity_id; + bc.timestamp = breadcrumb->timestamp; + if (breadcrumb->name) + bc.name = breadcrumb->name; + breadcrumbs.push_back(bc); + return true; }); - // Collect all the Activites - m_os_activity_iterate_activities (process_info->activities, process_info, ^bool(os_activity_entry_t activity) - { - Activity ac; - ac.activity_start = activity->activity_start; - ac.activity_id = activity->activity_id; - ac.parent_id = activity->parent_id; - if (activity->activity_name) - ac.activity_name = activity->activity_name; - if (activity->reason) - ac.reason = activity->reason; - activities.push_back (ac); - return true; + // Collect all the Activites + m_os_activity_iterate_activities( + process_info->activities, process_info, + ^bool(os_activity_entry_t activity) { + Activity ac; + ac.activity_start = activity->activity_start; + ac.activity_id = activity->activity_id; + ac.parent_id = activity->parent_id; + if (activity->activity_name) + ac.activity_name = activity->activity_name; + if (activity->reason) + ac.reason = activity->reason; + activities.push_back(ac); + return true; }); - - // Collect all the Messages -- messages not associated with any thread - m_os_activity_iterate_messages (process_info->messages, process_info, ^bool(os_trace_message_t trace_msg) - { - Message msg; - msg.timestamp = trace_msg->timestamp; - msg.trace_id = trace_msg->trace_id; - msg.thread = trace_msg->thread; - msg.type = m_os_trace_get_type (trace_msg); - msg.activity_id = 0; - if (trace_msg->image_uuid && trace_msg->image_path) - { - ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo()); - uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid); - process_info_sp->image_path = trace_msg->image_path; - msg.process_info_index = AddProcessExecutableInfo (process_info_sp); - } - const char *message_text = m_os_trace_copy_formatted_message (trace_msg); - if (message_text) - msg.message = message_text; - messages.push_back (msg); - return true; + // Collect all the Messages -- messages not associated with + // any thread + m_os_activity_iterate_messages( + process_info->messages, process_info, + ^bool(os_trace_message_t trace_msg) { + Message msg; + msg.timestamp = trace_msg->timestamp; + msg.trace_id = trace_msg->trace_id; + msg.thread = trace_msg->thread; + msg.type = m_os_trace_get_type(trace_msg); + msg.activity_id = 0; + if (trace_msg->image_uuid && trace_msg->image_path) { + ProcessExecutableInfoSP process_info_sp( + new ProcessExecutableInfo()); + uuid_copy(process_info_sp->image_uuid, + trace_msg->image_uuid); + process_info_sp->image_path = trace_msg->image_path; + msg.process_info_index = + AddProcessExecutableInfo(process_info_sp); + } + const char *message_text = + m_os_trace_copy_formatted_message(trace_msg); + if (message_text) + msg.message = message_text; + messages.push_back(msg); + return true; }); - // Discover which activities are said to be running on threads currently - const nub_size_t num_threads = thread_list.NumThreads(); - for (nub_size_t i = 0; i < num_threads; ++i) - { - nub_thread_t thread_id = thread_list.ThreadIDAtIndex(i); - os_activity_t act = 0; - if (m_os_activity_for_task_thread != nullptr) - { - act = m_os_activity_for_task_thread (task, thread_id); - } - else if (m_os_activity_for_thread != nullptr) - { - act = m_os_activity_for_thread (process_info, thread_id); - } - if (act != 0) - thread_activity_mapping[thread_id] = act; - } + // Discover which activities are said to be running on + // threads currently + const nub_size_t num_threads = thread_list.NumThreads(); + for (nub_size_t i = 0; i < num_threads; ++i) { + nub_thread_t thread_id = thread_list.ThreadIDAtIndex(i); + os_activity_t act = 0; + if (m_os_activity_for_task_thread != nullptr) { + act = m_os_activity_for_task_thread(task, thread_id); + } else if (m_os_activity_for_thread != nullptr) { + act = m_os_activity_for_thread(process_info, thread_id); + } + if (act != 0) + thread_activity_mapping[thread_id] = act; + } - // Collect all Messages -- messages associated with a thread + // Collect all Messages -- messages associated with a thread - // When there's no genealogy information, an early version of os_activity_messages_for_thread - // can crash in rare circumstances. Check to see if this process has any activities before - // making the call to get messages. - if (process_info->activities != nullptr && thread_activity_mapping.size() > 0) - { - std::map<nub_thread_t, uint64_t>::const_iterator iter; - for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter) - { - nub_thread_t thread_id = iter->first; - os_activity_t act = iter->second; - os_trace_message_list_t this_thread_messages = m_os_activity_messages_for_thread (process_info, act, thread_id); - m_os_activity_iterate_messages (this_thread_messages, process_info, ^bool(os_trace_message_t trace_msg) - { - Message msg; - msg.timestamp = trace_msg->timestamp; - msg.trace_id = trace_msg->trace_id; - msg.thread = trace_msg->thread; - msg.type = m_os_trace_get_type (trace_msg); - msg.activity_id = act; - if (trace_msg->image_uuid && trace_msg->image_path) - { - ProcessExecutableInfoSP process_info_sp (new ProcessExecutableInfo()); - uuid_copy (process_info_sp->image_uuid, trace_msg->image_uuid); - process_info_sp->image_path = trace_msg->image_path; - msg.process_info_index = AddProcessExecutableInfo (process_info_sp); - } - const char *message_text = m_os_trace_copy_formatted_message (trace_msg); - if (message_text) - msg.message = message_text; - messages.push_back (msg); - return true; - }); - } - } + // When there's no genealogy information, an early version + // of os_activity_messages_for_thread + // can crash in rare circumstances. Check to see if this + // process has any activities before + // making the call to get messages. + if (process_info->activities != nullptr && + thread_activity_mapping.size() > 0) { + std::map<nub_thread_t, uint64_t>::const_iterator iter; + for (iter = thread_activity_mapping.begin(); + iter != thread_activity_mapping.end(); ++iter) { + nub_thread_t thread_id = iter->first; + os_activity_t act = iter->second; + os_trace_message_list_t this_thread_messages = + m_os_activity_messages_for_thread(process_info, act, + thread_id); + m_os_activity_iterate_messages( + this_thread_messages, process_info, + ^bool(os_trace_message_t trace_msg) { + Message msg; + msg.timestamp = trace_msg->timestamp; + msg.trace_id = trace_msg->trace_id; + msg.thread = trace_msg->thread; + msg.type = m_os_trace_get_type(trace_msg); + msg.activity_id = act; + if (trace_msg->image_uuid && + trace_msg->image_path) { + ProcessExecutableInfoSP process_info_sp( + new ProcessExecutableInfo()); + uuid_copy(process_info_sp->image_uuid, + trace_msg->image_uuid); + process_info_sp->image_path = + trace_msg->image_path; + msg.process_info_index = + AddProcessExecutableInfo(process_info_sp); + } + const char *message_text = + m_os_trace_copy_formatted_message(trace_msg); + if (message_text) + msg.message = message_text; + messages.push_back(msg); + return true; + }); + } } - return true; + } + return true; }); - } - dispatch_semaphore_signal(semaphore); - }) == true) - { - // Wait for the diagnosticd xpc calls to all finish up -- or half a second to elapse. - dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2); - bool success = dispatch_semaphore_wait(semaphore, timeout) == 0; - if (!success) - { - m_diagnosticd_call_timed_out = true; - return; - } - } + } + dispatch_semaphore_signal(semaphore); + }) == true) { + // Wait for the diagnosticd xpc calls to all finish up -- or half a second + // to elapse. + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC / 2); + bool success = dispatch_semaphore_wait(semaphore, timeout) == 0; + if (!success) { + m_diagnosticd_call_timed_out = true; + return; + } + } - // breadcrumbs, activities, and messages have all now been filled in. + // breadcrumbs, activities, and messages have all now been filled in. - std::map<nub_thread_t, uint64_t>::const_iterator iter; - for (iter = thread_activity_mapping.begin(); iter != thread_activity_mapping.end(); ++iter) - { - nub_thread_t thread_id = iter->first; - uint64_t activity_id = iter->second; - ActivityList::const_iterator activity_search; - for (activity_search = activities.begin(); activity_search != activities.end(); ++activity_search) - { - if (activity_search->activity_id == activity_id) - { - ThreadActivitySP thread_activity_sp (new ThreadActivity()); - thread_activity_sp->current_activity = *activity_search; - - BreadcrumbList::const_iterator breadcrumb_search; - for (breadcrumb_search = breadcrumbs.begin(); breadcrumb_search != breadcrumbs.end(); ++breadcrumb_search) - { - if (breadcrumb_search->activity_id == activity_id) - { - thread_activity_sp->breadcrumbs.push_back (*breadcrumb_search); - } - } - MessageList::const_iterator message_search; - for (message_search = messages.begin(); message_search != messages.end(); ++message_search) - { - if (message_search->thread == thread_id) - { - thread_activity_sp->messages.push_back (*message_search); - } - } - - m_thread_activities[thread_id] = thread_activity_sp; - break; - } + std::map<nub_thread_t, uint64_t>::const_iterator iter; + for (iter = thread_activity_mapping.begin(); + iter != thread_activity_mapping.end(); ++iter) { + nub_thread_t thread_id = iter->first; + uint64_t activity_id = iter->second; + ActivityList::const_iterator activity_search; + for (activity_search = activities.begin(); + activity_search != activities.end(); ++activity_search) { + if (activity_search->activity_id == activity_id) { + ThreadActivitySP thread_activity_sp(new ThreadActivity()); + thread_activity_sp->current_activity = *activity_search; + + BreadcrumbList::const_iterator breadcrumb_search; + for (breadcrumb_search = breadcrumbs.begin(); + breadcrumb_search != breadcrumbs.end(); ++breadcrumb_search) { + if (breadcrumb_search->activity_id == activity_id) { + thread_activity_sp->breadcrumbs.push_back(*breadcrumb_search); } + } + MessageList::const_iterator message_search; + for (message_search = messages.begin(); + message_search != messages.end(); ++message_search) { + if (message_search->thread == thread_id) { + thread_activity_sp->messages.push_back(*message_search); + } + } + + m_thread_activities[thread_id] = thread_activity_sp; + break; } + } } + } } uint32_t -Genealogy::AddProcessExecutableInfo (ProcessExecutableInfoSP process_exe_info) -{ - const uint32_t info_size = static_cast<uint32_t>(m_process_executable_infos.size()); - for (uint32_t idx = 0; idx < info_size; ++idx) - { - if (uuid_compare (m_process_executable_infos[idx]->image_uuid, process_exe_info->image_uuid) == 0) - { - return idx + 1; - } +Genealogy::AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info) { + const uint32_t info_size = + static_cast<uint32_t>(m_process_executable_infos.size()); + for (uint32_t idx = 0; idx < info_size; ++idx) { + if (uuid_compare(m_process_executable_infos[idx]->image_uuid, + process_exe_info->image_uuid) == 0) { + return idx + 1; } - m_process_executable_infos.push_back (process_exe_info); - return info_size + 1; + } + m_process_executable_infos.push_back(process_exe_info); + return info_size + 1; } Genealogy::ProcessExecutableInfoSP -Genealogy::GetProcessExecutableInfosAtIndex(size_t idx) -{ - ProcessExecutableInfoSP info_sp; - if (idx > 0) - { - idx--; - if (idx <= m_process_executable_infos.size()) - { - info_sp = m_process_executable_infos[idx]; - } +Genealogy::GetProcessExecutableInfosAtIndex(size_t idx) { + ProcessExecutableInfoSP info_sp; + if (idx > 0) { + idx--; + if (idx <= m_process_executable_infos.size()) { + info_sp = m_process_executable_infos[idx]; } - return info_sp; + } + return info_sp; } - diff --git a/lldb/tools/debugserver/source/MacOSX/Genealogy.h b/lldb/tools/debugserver/source/MacOSX/Genealogy.h index d39145a06f2..f398b63c6d9 100644 --- a/lldb/tools/debugserver/source/MacOSX/Genealogy.h +++ b/lldb/tools/debugserver/source/MacOSX/Genealogy.h @@ -1,4 +1,5 @@ -//===-- Activity.h -----------------------------------------------*- C++ -*-===// +//===-- Activity.h -----------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -10,107 +11,110 @@ #ifndef __Genealogy_h__ #define __Genealogy_h__ -#include <string> -#include <vector> +#include <mach/task.h> #include <map> #include <pthread.h> -#include <mach/task.h> +#include <string> +#include <vector> #include "GenealogySPI.h" #include "MachThreadList.h" -class Genealogy -{ +class Genealogy { public: - - Genealogy (); - - ~Genealogy () - { - } - - void - Clear(); - - struct Breadcrumb - { - uint32_t breadcrumb_id; - uint64_t activity_id; - uint64_t timestamp; - std::string name; - }; - - struct Activity - { - uint64_t activity_start; - uint64_t activity_id; - uint64_t parent_id; - std::string activity_name; - std::string reason; - }; - - struct Message - { - uint64_t timestamp; - uint64_t activity_id; - uint64_t trace_id; - uint64_t thread; - uint8_t type; // OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_DEBUG, OS_TRACE_TYPE_ERROR, OS_TRACE_TYPE_FAULT - uint32_t process_info_index; // index # of the image uuid/file path, 0 means unknown - std::string message; - }; - - typedef std::vector<Message> MessageList; - typedef std::vector<Breadcrumb> BreadcrumbList; - typedef std::vector<Activity> ActivityList; - - struct ThreadActivity - { - Activity current_activity; - MessageList messages; - BreadcrumbList breadcrumbs; // should be 0 or 1 breadcrumbs; no more than 1 BC for any given activity - }; - - typedef std::shared_ptr<ThreadActivity> ThreadActivitySP; - - ThreadActivitySP - GetGenealogyInfoForThread (pid_t pid, nub_thread_t tid, const MachThreadList &thread_list, task_t task, bool &timed_out); - - struct ProcessExecutableInfo - { - std::string image_path; - uuid_t image_uuid; - }; - - typedef std::shared_ptr<ProcessExecutableInfo> ProcessExecutableInfoSP; - - ProcessExecutableInfoSP - GetProcessExecutableInfosAtIndex(size_t idx); - - uint32_t - AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info); + Genealogy(); + + ~Genealogy() {} + + void Clear(); + + struct Breadcrumb { + uint32_t breadcrumb_id; + uint64_t activity_id; + uint64_t timestamp; + std::string name; + }; + + struct Activity { + uint64_t activity_start; + uint64_t activity_id; + uint64_t parent_id; + std::string activity_name; + std::string reason; + }; + + struct Message { + uint64_t timestamp; + uint64_t activity_id; + uint64_t trace_id; + uint64_t thread; + uint8_t type; // OS_TRACE_TYPE_RELEASE, OS_TRACE_TYPE_DEBUG, + // OS_TRACE_TYPE_ERROR, OS_TRACE_TYPE_FAULT + uint32_t process_info_index; // index # of the image uuid/file path, 0 means + // unknown + std::string message; + }; + + typedef std::vector<Message> MessageList; + typedef std::vector<Breadcrumb> BreadcrumbList; + typedef std::vector<Activity> ActivityList; + + struct ThreadActivity { + Activity current_activity; + MessageList messages; + BreadcrumbList breadcrumbs; // should be 0 or 1 breadcrumbs; no more than 1 + // BC for any given activity + }; + + typedef std::shared_ptr<ThreadActivity> ThreadActivitySP; + + ThreadActivitySP GetGenealogyInfoForThread(pid_t pid, nub_thread_t tid, + const MachThreadList &thread_list, + task_t task, bool &timed_out); + + struct ProcessExecutableInfo { + std::string image_path; + uuid_t image_uuid; + }; + + typedef std::shared_ptr<ProcessExecutableInfo> ProcessExecutableInfoSP; + + ProcessExecutableInfoSP GetProcessExecutableInfosAtIndex(size_t idx); + + uint32_t AddProcessExecutableInfo(ProcessExecutableInfoSP process_exe_info); private: - - void - GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task); - - // the spi we need to call into libtrace - look them up via dlsym at runtime - bool (*m_os_activity_diagnostic_for_pid) (pid_t pid, os_activity_t activity, uint32_t flags, os_diagnostic_block_t block); - void (*m_os_activity_iterate_processes) (os_activity_process_list_t processes, bool (^iterator)(os_activity_process_t process_info)); - void (*m_os_activity_iterate_breadcrumbs) (os_activity_process_t process_info, bool (^iterator)(os_activity_breadcrumb_t breadcrumb)); - void (*m_os_activity_iterate_messages) (os_trace_message_list_t messages, os_activity_process_t process_info, bool (^iterator)(os_trace_message_t tracemsg)); - void (*m_os_activity_iterate_activities) (os_activity_list_t activities, os_activity_process_t process_info, bool (^iterator)(os_activity_entry_t activity)); - uint8_t (*m_os_trace_get_type) (os_trace_message_t trace_msg); - char * (*m_os_trace_copy_formatted_message) (os_trace_message_t trace_msg); - os_activity_t (*m_os_activity_for_thread) (os_activity_process_t process, uint64_t thread_id); - os_activity_t (*m_os_activity_for_task_thread) (task_t target, uint64_t thread_id); - os_trace_message_list_t (*m_os_activity_messages_for_thread) (os_activity_process_t process, os_activity_t activity, uint64_t thread_id); - - - std::map<nub_thread_t, ThreadActivitySP> m_thread_activities; - std::vector<ProcessExecutableInfoSP> m_process_executable_infos; - bool m_diagnosticd_call_timed_out; + void GetActivities(pid_t pid, const MachThreadList &thread_list, task_t task); + + // the spi we need to call into libtrace - look them up via dlsym at runtime + bool (*m_os_activity_diagnostic_for_pid)(pid_t pid, os_activity_t activity, + uint32_t flags, + os_diagnostic_block_t block); + void (*m_os_activity_iterate_processes)( + os_activity_process_list_t processes, + bool (^iterator)(os_activity_process_t process_info)); + void (*m_os_activity_iterate_breadcrumbs)( + os_activity_process_t process_info, + bool (^iterator)(os_activity_breadcrumb_t breadcrumb)); + void (*m_os_activity_iterate_messages)( + os_trace_message_list_t messages, os_activity_process_t process_info, + bool (^iterator)(os_trace_message_t tracemsg)); + void (*m_os_activity_iterate_activities)( + os_activity_list_t activities, os_activity_process_t process_info, + bool (^iterator)(os_activity_entry_t activity)); + uint8_t (*m_os_trace_get_type)(os_trace_message_t trace_msg); + char *(*m_os_trace_copy_formatted_message)(os_trace_message_t trace_msg); + os_activity_t (*m_os_activity_for_thread)(os_activity_process_t process, + uint64_t thread_id); + os_activity_t (*m_os_activity_for_task_thread)(task_t target, + uint64_t thread_id); + os_trace_message_list_t (*m_os_activity_messages_for_thread)( + os_activity_process_t process, os_activity_t activity, + uint64_t thread_id); + + std::map<nub_thread_t, ThreadActivitySP> m_thread_activities; + std::vector<ProcessExecutableInfoSP> m_process_executable_infos; + bool m_diagnosticd_call_timed_out; }; #endif // __Genealogy_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h b/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h index f84e930e872..de9db2d2e64 100644 --- a/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h +++ b/lldb/tools/debugserver/source/MacOSX/GenealogySPI.h @@ -18,67 +18,65 @@ typedef struct os_activity_watch_s *os_activity_watch_t; typedef uint64_t os_activity_t; struct os_activity_breadcrumb_s { - uint32_t breadcrumb_id; - uint64_t activity_id; - uint64_t timestamp; - const char *name; + uint32_t breadcrumb_id; + uint64_t activity_id; + uint64_t timestamp; + const char *name; }; typedef struct os_activity_breadcrumb_s *os_activity_breadcrumb_t; typedef struct os_trace_message_s { - uint64_t trace_id; - uint64_t thread; - uint64_t timestamp; - uint32_t offset; - xpc_object_t __unsafe_unretained payload; - const uint8_t *image_uuid; - const char *image_path; - const char *format; - const void *buffer; - size_t bufferLen; -} *os_trace_message_t; + uint64_t trace_id; + uint64_t thread; + uint64_t timestamp; + uint32_t offset; + xpc_object_t __unsafe_unretained payload; + const uint8_t *image_uuid; + const char *image_path; + const char *format; + const void *buffer; + size_t bufferLen; +} * os_trace_message_t; typedef struct os_activity_process_s { - os_activity_process_list_t child_procs; - os_trace_message_list_t messages; - os_activity_list_t activities; - void *breadcrumbs; - uint64_t proc_id; - const uint8_t *image_uuid; - const char *image_path; - pid_t pid; -} *os_activity_process_t; + os_activity_process_list_t child_procs; + os_trace_message_list_t messages; + os_activity_list_t activities; + void *breadcrumbs; + uint64_t proc_id; + const uint8_t *image_uuid; + const char *image_path; + pid_t pid; +} * os_activity_process_t; typedef struct os_activity_entry_s { - uint64_t activity_start; - os_activity_t activity_id; - os_activity_t parent_id; - const char *activity_name; - const char *reason; - os_trace_message_list_t messages; -} *os_activity_entry_t; + uint64_t activity_start; + os_activity_t activity_id; + os_activity_t parent_id; + const char *activity_name; + const char *reason; + os_trace_message_list_t messages; +} * os_activity_entry_t; -enum -{ - OS_ACTIVITY_DIAGNOSTIC_DEFAULT = 0x00000000, - OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY = 0x00000001, - OS_ACTIVITY_DIAGNOSTIC_SKIP_DECODE = 0x00000002, - OS_ACTIVITY_DIAGNOSTIC_FLATTENED = 0x00000004, - OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES = 0x00000008, - OS_ACTIVITY_DIAGNOSTIC_MAX = 0x0000000f +enum { + OS_ACTIVITY_DIAGNOSTIC_DEFAULT = 0x00000000, + OS_ACTIVITY_DIAGNOSTIC_PROCESS_ONLY = 0x00000001, + OS_ACTIVITY_DIAGNOSTIC_SKIP_DECODE = 0x00000002, + OS_ACTIVITY_DIAGNOSTIC_FLATTENED = 0x00000004, + OS_ACTIVITY_DIAGNOSTIC_ALL_ACTIVITIES = 0x00000008, + OS_ACTIVITY_DIAGNOSTIC_MAX = 0x0000000f }; typedef uint32_t os_activity_diagnostic_flag_t; -enum -{ - OS_ACTIVITY_WATCH_DEFAULT = 0x00000000, - OS_ACTIVITY_WATCH_PROCESS_ONLY = 0x00000001, - OS_ACTIVITY_WATCH_SKIP_DECODE = 0x00000002, - OS_ACTIVITY_WATCH_PAYLOAD = 0x00000004, - OS_ACTIVITY_WATCH_ERRORS = 0x00000008, - OS_ACTIVITY_WATCH_FAULTS = 0x00000010, - OS_ACTIVITY_WATCH_MAX = 0x0000001f +enum { + OS_ACTIVITY_WATCH_DEFAULT = 0x00000000, + OS_ACTIVITY_WATCH_PROCESS_ONLY = 0x00000001, + OS_ACTIVITY_WATCH_SKIP_DECODE = 0x00000002, + OS_ACTIVITY_WATCH_PAYLOAD = 0x00000004, + OS_ACTIVITY_WATCH_ERRORS = 0x00000008, + OS_ACTIVITY_WATCH_FAULTS = 0x00000010, + OS_ACTIVITY_WATCH_MAX = 0x0000001f }; typedef uint32_t os_activity_watch_flag_t; @@ -88,9 +86,10 @@ typedef uint32_t os_activity_watch_flag_t; #define OS_TRACE_TYPE_ERROR ((1u << 6) | (1u << 0)) #define OS_TRACE_TYPE_FAULT ((1u << 7) | (1u << 6) | (1u << 0)) - -typedef void (^os_activity_watch_block_t)(os_activity_watch_t watch, os_activity_process_t process_info, bool canceled); -typedef void (^os_diagnostic_block_t)(os_activity_process_list_t processes, int error); +typedef void (^os_activity_watch_block_t)(os_activity_watch_t watch, + os_activity_process_t process_info, + bool canceled); +typedef void (^os_diagnostic_block_t)(os_activity_process_list_t processes, + int error); #endif - diff --git a/lldb/tools/debugserver/source/MacOSX/HasAVX.h b/lldb/tools/debugserver/source/MacOSX/HasAVX.h index c7a50fa20b3..43fbd5e514e 100644 --- a/lldb/tools/debugserver/source/MacOSX/HasAVX.h +++ b/lldb/tools/debugserver/source/MacOSX/HasAVX.h @@ -10,18 +10,18 @@ #ifndef HasAVX_h #define HasAVX_h -#if defined (__i386__) || defined (__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #ifdef __cplusplus extern "C" { #endif -int HasAVX (); +int HasAVX(); #ifdef __cplusplus } #endif #endif - + #endif diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.cpp b/lldb/tools/debugserver/source/MacOSX/MachException.cpp index 0b5459e3a18..09849312fbb 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachException.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachException.cpp @@ -12,62 +12,40 @@ //===----------------------------------------------------------------------===// #include "MachException.h" -#include "MachProcess.h" #include "DNB.h" #include "DNBError.h" -#include <sys/types.h> #include "DNBLog.h" +#include "MachProcess.h" #include "PThreadMutex.h" #include "SysSignal.h" #include <errno.h> #include <sys/ptrace.h> +#include <sys/types.h> // Routine mach_exception_raise -extern "C" -kern_return_t catch_mach_exception_raise -( - mach_port_t exception_port, - mach_port_t thread, - mach_port_t task, - exception_type_t exception, - mach_exception_data_t code, - mach_msg_type_number_t codeCnt -); - -extern "C" -kern_return_t catch_mach_exception_raise_state -( - mach_port_t exception_port, - exception_type_t exception, - const mach_exception_data_t code, - mach_msg_type_number_t codeCnt, - int *flavor, - const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt -); +extern "C" kern_return_t +catch_mach_exception_raise(mach_port_t exception_port, mach_port_t thread, + mach_port_t task, exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt); + +extern "C" kern_return_t catch_mach_exception_raise_state( + mach_port_t exception_port, exception_type_t exception, + const mach_exception_data_t code, mach_msg_type_number_t codeCnt, + int *flavor, const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt); // Routine mach_exception_raise_state_identity -extern "C" -kern_return_t catch_mach_exception_raise_state_identity -( - mach_port_t exception_port, - mach_port_t thread, - mach_port_t task, - exception_type_t exception, - mach_exception_data_t code, - mach_msg_type_number_t codeCnt, - int *flavor, - thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt -); - -extern "C" boolean_t mach_exc_server( - mach_msg_header_t *InHeadP, - mach_msg_header_t *OutHeadP); +extern "C" kern_return_t catch_mach_exception_raise_state_identity( + mach_port_t exception_port, mach_port_t thread, mach_port_t task, + exception_type_t exception, mach_exception_data_t code, + mach_msg_type_number_t codeCnt, int *flavor, thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt); + +extern "C" boolean_t mach_exc_server(mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); // Any access to the g_message variable should be done by locking the // g_message_mutex first, using the g_message variable, then unlocking @@ -75,417 +53,339 @@ extern "C" boolean_t mach_exc_server( // for sample code. static MachException::Data *g_message = NULL; -//static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER; - - -extern "C" -kern_return_t -catch_mach_exception_raise_state -( - mach_port_t exc_port, - exception_type_t exc_type, - const mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count, - int * flavor, - const thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, - mach_msg_type_number_t * new_stateCnt -) -{ - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - { - DNBLogThreaded ("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data = 0x%llx, exc_data_count = %d)", - __FUNCTION__, - exc_port, - exc_type, MachException::Name(exc_type), - (uint64_t)exc_data, - exc_data_count); - } - return KERN_FAILURE; +// static pthread_mutex_t g_message_mutex = PTHREAD_MUTEX_INITIALIZER; + +extern "C" kern_return_t catch_mach_exception_raise_state( + mach_port_t exc_port, exception_type_t exc_type, + const mach_exception_data_t exc_data, mach_msg_type_number_t exc_data_count, + int *flavor, const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt) { + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { + DNBLogThreaded("::%s ( exc_port = 0x%4.4x, exc_type = %d ( %s ), exc_data " + "= 0x%llx, exc_data_count = %d)", + __FUNCTION__, exc_port, exc_type, + MachException::Name(exc_type), (uint64_t)exc_data, + exc_data_count); + } + return KERN_FAILURE; } -extern "C" -kern_return_t -catch_mach_exception_raise_state_identity -( - mach_port_t exc_port, - mach_port_t thread_port, - mach_port_t task_port, - exception_type_t exc_type, - mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count, - int * flavor, - thread_state_t old_state, - mach_msg_type_number_t old_stateCnt, - thread_state_t new_state, - mach_msg_type_number_t *new_stateCnt -) -{ - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - { - DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, 0x%llx })", - __FUNCTION__, - exc_port, - thread_port, - task_port, - exc_type, MachException::Name(exc_type), - exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - mach_port_deallocate (mach_task_self (), task_port); - mach_port_deallocate (mach_task_self (), thread_port); - - return KERN_FAILURE; +extern "C" kern_return_t catch_mach_exception_raise_state_identity( + mach_port_t exc_port, mach_port_t thread_port, mach_port_t task_port, + exception_type_t exc_type, mach_exception_data_t exc_data, + mach_msg_type_number_t exc_data_count, int *flavor, + thread_state_t old_state, mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, mach_msg_type_number_t *new_stateCnt) { + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { + DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = " + "0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, " + "0x%llx })", + __FUNCTION__, exc_port, thread_port, task_port, exc_type, + MachException::Name(exc_type), exc_data_count, + (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), + (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); + } + mach_port_deallocate(mach_task_self(), task_port); + mach_port_deallocate(mach_task_self(), thread_port); + + return KERN_FAILURE; } -extern "C" -kern_return_t -catch_mach_exception_raise -( - mach_port_t exc_port, - mach_port_t thread_port, - mach_port_t task_port, - exception_type_t exc_type, - mach_exception_data_t exc_data, - mach_msg_type_number_t exc_data_count) -{ - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - { - DNBLogThreaded ("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = 0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, 0x%llx })", - __FUNCTION__, - exc_port, - thread_port, - task_port, - exc_type, MachException::Name(exc_type), - exc_data_count, - (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), - (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); - } - - if (task_port == g_message->task_port) - { - g_message->task_port = task_port; - g_message->thread_port = thread_port; - g_message->exc_type = exc_type; - g_message->exc_data.resize(exc_data_count); - ::memcpy (&g_message->exc_data[0], exc_data, g_message->exc_data.size() * sizeof (mach_exception_data_type_t)); - return KERN_SUCCESS; - } - return KERN_FAILURE; +extern "C" kern_return_t +catch_mach_exception_raise(mach_port_t exc_port, mach_port_t thread_port, + mach_port_t task_port, exception_type_t exc_type, + mach_exception_data_t exc_data, + mach_msg_type_number_t exc_data_count) { + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { + DNBLogThreaded("::%s ( exc_port = 0x%4.4x, thd_port = 0x%4.4x, tsk_port = " + "0x%4.4x, exc_type = %d ( %s ), exc_data[%d] = { 0x%llx, " + "0x%llx })", + __FUNCTION__, exc_port, thread_port, task_port, exc_type, + MachException::Name(exc_type), exc_data_count, + (uint64_t)(exc_data_count > 0 ? exc_data[0] : 0xBADDBADD), + (uint64_t)(exc_data_count > 1 ? exc_data[1] : 0xBADDBADD)); + } + + if (task_port == g_message->task_port) { + g_message->task_port = task_port; + g_message->thread_port = thread_port; + g_message->exc_type = exc_type; + g_message->exc_data.resize(exc_data_count); + ::memcpy(&g_message->exc_data[0], exc_data, + g_message->exc_data.size() * sizeof(mach_exception_data_type_t)); + return KERN_SUCCESS; + } + return KERN_FAILURE; } - -void -MachException::Message::Dump() const -{ - DNBLogThreadedIf(LOG_EXCEPTIONS, - " exc_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = 0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = 0x%8.8x } ", - exc_msg.hdr.msgh_bits, - exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, - exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, - exc_msg.hdr.msgh_id); - - DNBLogThreadedIf(LOG_EXCEPTIONS, - "reply_msg { bits = 0x%8.8x size = 0x%8.8x remote-port = 0x%8.8x local-port = 0x%8.8x reserved = 0x%8.8x id = 0x%8.8x }", - reply_msg.hdr.msgh_bits, - reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, - reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, - reply_msg.hdr.msgh_id); - - state.Dump(); +void MachException::Message::Dump() const { + DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_msg { bits = 0x%8.8x size = 0x%8.8x " + "remote-port = 0x%8.8x local-port = 0x%8.8x " + "reserved = 0x%8.8x id = 0x%8.8x } ", + exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, + exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, + exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id); + + DNBLogThreadedIf(LOG_EXCEPTIONS, "reply_msg { bits = 0x%8.8x size = 0x%8.8x " + "remote-port = 0x%8.8x local-port = 0x%8.8x " + "reserved = 0x%8.8x id = 0x%8.8x }", + reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, + reply_msg.hdr.msgh_remote_port, + reply_msg.hdr.msgh_local_port, reply_msg.hdr.msgh_reserved, + reply_msg.hdr.msgh_id); + + state.Dump(); } -bool -MachException::Data::GetStopInfo(struct DNBThreadStopInfo *stop_info) const -{ - // Zero out the structure. - memset(stop_info, 0, sizeof(struct DNBThreadStopInfo)); - - if (exc_type == 0) - { - stop_info->reason = eStopTypeInvalid; - return true; - } +bool MachException::Data::GetStopInfo( + struct DNBThreadStopInfo *stop_info) const { + // Zero out the structure. + memset(stop_info, 0, sizeof(struct DNBThreadStopInfo)); - // We always stop with a mach exceptions - stop_info->reason = eStopTypeException; - // Save the EXC_XXXX exception type - stop_info->details.exception.type = exc_type; - - // Fill in a text description - const char * exc_name = MachException::Name(exc_type); - char *desc = stop_info->description; - const char *end_desc = desc + DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH; - if (exc_name) - desc += snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%s", exc_name); - else - desc += snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%i", exc_type); - - stop_info->details.exception.data_count = exc_data.size(); - - int soft_signal = SoftSignal(); - if (soft_signal) - { - if (desc < end_desc) - { - const char *sig_str = SysSignal::Name(soft_signal); - snprintf(desc, end_desc - desc, " EXC_SOFT_SIGNAL( %i ( %s ))", soft_signal, sig_str ? sig_str : "unknown signal"); - } + if (exc_type == 0) { + stop_info->reason = eStopTypeInvalid; + return true; + } + + // We always stop with a mach exceptions + stop_info->reason = eStopTypeException; + // Save the EXC_XXXX exception type + stop_info->details.exception.type = exc_type; + + // Fill in a text description + const char *exc_name = MachException::Name(exc_type); + char *desc = stop_info->description; + const char *end_desc = desc + DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH; + if (exc_name) + desc += + snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%s", exc_name); + else + desc += + snprintf(desc, DNB_THREAD_STOP_INFO_MAX_DESC_LENGTH, "%i", exc_type); + + stop_info->details.exception.data_count = exc_data.size(); + + int soft_signal = SoftSignal(); + if (soft_signal) { + if (desc < end_desc) { + const char *sig_str = SysSignal::Name(soft_signal); + snprintf(desc, end_desc - desc, " EXC_SOFT_SIGNAL( %i ( %s ))", + soft_signal, sig_str ? sig_str : "unknown signal"); } - else - { - // No special disassembly for exception data, just - size_t idx; - if (desc < end_desc) - { - desc += snprintf(desc, end_desc - desc, " data[%llu] = {", (uint64_t)stop_info->details.exception.data_count); - - for (idx = 0; desc < end_desc && idx < stop_info->details.exception.data_count; ++idx) - desc += snprintf(desc, end_desc - desc, "0x%llx%c", (uint64_t)exc_data[idx], ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); - } + } else { + // No special disassembly for exception data, just + size_t idx; + if (desc < end_desc) { + desc += snprintf(desc, end_desc - desc, " data[%llu] = {", + (uint64_t)stop_info->details.exception.data_count); + + for (idx = 0; + desc < end_desc && idx < stop_info->details.exception.data_count; + ++idx) + desc += snprintf( + desc, end_desc - desc, "0x%llx%c", (uint64_t)exc_data[idx], + ((idx + 1 == stop_info->details.exception.data_count) ? '}' : ',')); } + } - // Copy the exception data - size_t i; - for (i=0; i<stop_info->details.exception.data_count; i++) - stop_info->details.exception.data[i] = exc_data[i]; + // Copy the exception data + size_t i; + for (i = 0; i < stop_info->details.exception.data_count; i++) + stop_info->details.exception.data[i] = exc_data[i]; - return true; + return true; } - -void -MachException::Data::DumpStopReason() const -{ - int soft_signal = SoftSignal(); - if (soft_signal) - { - const char *signal_str = SysSignal::Name(soft_signal); - if (signal_str) - DNBLog("signal(%s)", signal_str); - else - DNBLog("signal(%i)", soft_signal); - return; - } - DNBLog("%s", Name(exc_type)); +void MachException::Data::DumpStopReason() const { + int soft_signal = SoftSignal(); + if (soft_signal) { + const char *signal_str = SysSignal::Name(soft_signal); + if (signal_str) + DNBLog("signal(%s)", signal_str); + else + DNBLog("signal(%i)", soft_signal); + return; + } + DNBLog("%s", Name(exc_type)); } -kern_return_t -MachException::Message::Receive(mach_port_t port, mach_msg_option_t options, mach_msg_timeout_t timeout, mach_port_t notify_port) -{ - DNBError err; - const bool log_exceptions = DNBLogCheckLogBit(LOG_EXCEPTIONS); - mach_msg_timeout_t mach_msg_timeout = options & MACH_RCV_TIMEOUT ? timeout : 0; - if (log_exceptions && ((options & MACH_RCV_TIMEOUT) == 0)) - { - // Dump this log message if we have no timeout in case it never returns - DNBLogThreaded ("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = 0, rcv_size = %llu, rcv_name = %#x, timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, - exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, - exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, - exc_msg.hdr.msgh_id, - options, - (uint64_t)sizeof (exc_msg.data), - port, - mach_msg_timeout, - notify_port); - } - - err = ::mach_msg (&exc_msg.hdr, - options, // options - 0, // Send size - sizeof (exc_msg.data), // Receive size - port, // exception port to watch for exception on - mach_msg_timeout, // timeout in msec (obeyed only if MACH_RCV_TIMEOUT is ORed into the options parameter) - notify_port); - - // Dump any errors we get - if (log_exceptions) - { - err.LogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)", - exc_msg.hdr.msgh_bits, - exc_msg.hdr.msgh_size, - exc_msg.hdr.msgh_remote_port, - exc_msg.hdr.msgh_local_port, - exc_msg.hdr.msgh_reserved, - exc_msg.hdr.msgh_id, - options, - 0, - sizeof (exc_msg.data), - port, - mach_msg_timeout, - notify_port); - } - return err.Error(); +kern_return_t MachException::Message::Receive(mach_port_t port, + mach_msg_option_t options, + mach_msg_timeout_t timeout, + mach_port_t notify_port) { + DNBError err; + const bool log_exceptions = DNBLogCheckLogBit(LOG_EXCEPTIONS); + mach_msg_timeout_t mach_msg_timeout = + options & MACH_RCV_TIMEOUT ? timeout : 0; + if (log_exceptions && ((options & MACH_RCV_TIMEOUT) == 0)) { + // Dump this log message if we have no timeout in case it never returns + DNBLogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = " + "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option " + "= %#x, send_size = 0, rcv_size = %llu, rcv_name = %#x, " + "timeout = %u, notify = %#x)", + exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, + exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, + exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, + (uint64_t)sizeof(exc_msg.data), port, mach_msg_timeout, + notify_port); + } + + err = ::mach_msg(&exc_msg.hdr, + options, // options + 0, // Send size + sizeof(exc_msg.data), // Receive size + port, // exception port to watch for exception on + mach_msg_timeout, // timeout in msec (obeyed only if + // MACH_RCV_TIMEOUT is ORed into the + // options parameter) + notify_port); + + // Dump any errors we get + if (log_exceptions) { + err.LogThreaded("::mach_msg ( msg->{bits = %#x, size = %u remote_port = " + "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " + "option = %#x, send_size = %u, rcv_size = %u, rcv_name = " + "%#x, timeout = %u, notify = %#x)", + exc_msg.hdr.msgh_bits, exc_msg.hdr.msgh_size, + exc_msg.hdr.msgh_remote_port, exc_msg.hdr.msgh_local_port, + exc_msg.hdr.msgh_reserved, exc_msg.hdr.msgh_id, options, 0, + sizeof(exc_msg.data), port, mach_msg_timeout, notify_port); + } + return err.Error(); } -bool -MachException::Message::CatchExceptionRaise(task_t task) -{ - bool success = false; - // locker will keep a mutex locked until it goes out of scope -// PThreadMutex::Locker locker(&g_message_mutex); - // DNBLogThreaded("calling mach_exc_server"); - state.task_port = task; - g_message = &state; - // The exc_server function is the MIG generated server handling function - // to handle messages from the kernel relating to the occurrence of an - // exception in a thread. Such messages are delivered to the exception port - // set via thread_set_exception_ports or task_set_exception_ports. When an - // exception occurs in a thread, the thread sends an exception message to - // its exception port, blocking in the kernel waiting for the receipt of a - // reply. The exc_server function performs all necessary argument handling - // for this kernel message and calls catch_exception_raise, - // catch_exception_raise_state or catch_exception_raise_state_identity, - // which should handle the exception. If the called routine returns - // KERN_SUCCESS, a reply message will be sent, allowing the thread to - // continue from the point of the exception; otherwise, no reply message - // is sent and the called routine must have dealt with the exception - // thread directly. - if (mach_exc_server (&exc_msg.hdr, &reply_msg.hdr)) - { - success = true; - } - else if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - { - DNBLogThreaded("mach_exc_server returned zero..."); - } - g_message = NULL; - return success; +bool MachException::Message::CatchExceptionRaise(task_t task) { + bool success = false; + // locker will keep a mutex locked until it goes out of scope + // PThreadMutex::Locker locker(&g_message_mutex); + // DNBLogThreaded("calling mach_exc_server"); + state.task_port = task; + g_message = &state; + // The exc_server function is the MIG generated server handling function + // to handle messages from the kernel relating to the occurrence of an + // exception in a thread. Such messages are delivered to the exception port + // set via thread_set_exception_ports or task_set_exception_ports. When an + // exception occurs in a thread, the thread sends an exception message to + // its exception port, blocking in the kernel waiting for the receipt of a + // reply. The exc_server function performs all necessary argument handling + // for this kernel message and calls catch_exception_raise, + // catch_exception_raise_state or catch_exception_raise_state_identity, + // which should handle the exception. If the called routine returns + // KERN_SUCCESS, a reply message will be sent, allowing the thread to + // continue from the point of the exception; otherwise, no reply message + // is sent and the called routine must have dealt with the exception + // thread directly. + if (mach_exc_server(&exc_msg.hdr, &reply_msg.hdr)) { + success = true; + } else if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) { + DNBLogThreaded("mach_exc_server returned zero..."); + } + g_message = NULL; + return success; } - - -kern_return_t -MachException::Message::Reply(MachProcess *process, int signal) -{ - // Reply to the exception... - DNBError err; - - // If we had a soft signal, we need to update the thread first so it can - // continue without signaling - int soft_signal = state.SoftSignal(); - if (soft_signal) - { - int state_pid = -1; - if (process->Task().TaskPort() == state.task_port) - { - // This is our task, so we can update the signal to send to it - state_pid = process->ProcessID(); - soft_signal = signal; - } - else - { - err = ::pid_for_task(state.task_port, &state_pid); - } - - assert (state_pid != -1); - if (state_pid != -1) - { - errno = 0; - if (::ptrace (PT_THUPDATE, state_pid, (caddr_t)((uintptr_t)state.thread_port), soft_signal) != 0) - err.SetError(errno, DNBError::POSIX); - else - err.Clear(); - - if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) - err.LogThreaded("::ptrace (request = PT_THUPDATE, pid = 0x%4.4x, tid = 0x%4.4x, signal = %i)", state_pid, state.thread_port, soft_signal); - } +kern_return_t MachException::Message::Reply(MachProcess *process, int signal) { + // Reply to the exception... + DNBError err; + + // If we had a soft signal, we need to update the thread first so it can + // continue without signaling + int soft_signal = state.SoftSignal(); + if (soft_signal) { + int state_pid = -1; + if (process->Task().TaskPort() == state.task_port) { + // This is our task, so we can update the signal to send to it + state_pid = process->ProcessID(); + soft_signal = signal; + } else { + err = ::pid_for_task(state.task_port, &state_pid); } - DNBLogThreadedIf(LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = %#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, option = %#x, send_size = %u, rcv_size = %u, rcv_name = %#x, timeout = %u, notify = %#x)", - reply_msg.hdr.msgh_bits, - reply_msg.hdr.msgh_size, - reply_msg.hdr.msgh_remote_port, - reply_msg.hdr.msgh_local_port, - reply_msg.hdr.msgh_reserved, - reply_msg.hdr.msgh_id, - MACH_SEND_MSG | MACH_SEND_INTERRUPT, - reply_msg.hdr.msgh_size, - 0, - MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - - err = ::mach_msg ( &reply_msg.hdr, - MACH_SEND_MSG | MACH_SEND_INTERRUPT, - reply_msg.hdr.msgh_size, - 0, - MACH_PORT_NULL, - MACH_MSG_TIMEOUT_NONE, - MACH_PORT_NULL); - - if (err.Fail()) - { - if (err.Error() == MACH_SEND_INTERRUPTED) - { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - err.LogThreaded("::mach_msg() - send interrupted"); - // TODO: keep retrying to reply??? - } - else - { - if (state.task_port == process->Task().TaskPort()) - { - DNBLogThreaded("error: mach_msg() returned an error when replying to a mach exception: error = %u", err.Error()); - } - else - { - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - err.LogThreaded("::mach_msg() - failed (child of task)"); - } - } + assert(state_pid != -1); + if (state_pid != -1) { + errno = 0; + if (::ptrace(PT_THUPDATE, state_pid, + (caddr_t)((uintptr_t)state.thread_port), soft_signal) != 0) + err.SetError(errno, DNBError::POSIX); + else + err.Clear(); + + if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) + err.LogThreaded("::ptrace (request = PT_THUPDATE, pid = 0x%4.4x, tid = " + "0x%4.4x, signal = %i)", + state_pid, state.thread_port, soft_signal); } + } + + DNBLogThreadedIf( + LOG_EXCEPTIONS, "::mach_msg ( msg->{bits = %#x, size = %u, remote_port = " + "%#x, local_port = %#x, reserved = 0x%x, id = 0x%x}, " + "option = %#x, send_size = %u, rcv_size = %u, rcv_name = " + "%#x, timeout = %u, notify = %#x)", + reply_msg.hdr.msgh_bits, reply_msg.hdr.msgh_size, + reply_msg.hdr.msgh_remote_port, reply_msg.hdr.msgh_local_port, + reply_msg.hdr.msgh_reserved, reply_msg.hdr.msgh_id, + MACH_SEND_MSG | MACH_SEND_INTERRUPT, reply_msg.hdr.msgh_size, 0, + MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + err = ::mach_msg(&reply_msg.hdr, MACH_SEND_MSG | MACH_SEND_INTERRUPT, + reply_msg.hdr.msgh_size, 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + if (err.Fail()) { + if (err.Error() == MACH_SEND_INTERRUPTED) { + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) + err.LogThreaded("::mach_msg() - send interrupted"); + // TODO: keep retrying to reply??? + } else { + if (state.task_port == process->Task().TaskPort()) { + DNBLogThreaded("error: mach_msg() returned an error when replying to a " + "mach exception: error = %u", + err.Error()); + } else { + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) + err.LogThreaded("::mach_msg() - failed (child of task)"); + } + } + } - return err.Error(); + return err.Error(); } - -void -MachException::Data::Dump() const -{ - const char *exc_type_name = MachException::Name(exc_type); - DNBLogThreadedIf(LOG_EXCEPTIONS, " state { task_port = 0x%4.4x, thread_port = 0x%4.4x, exc_type = %i (%s) ...", task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???"); - - const size_t exc_data_count = exc_data.size(); - // Dump any special exception data contents - int soft_signal = SoftSignal(); - if (soft_signal != 0) - { - const char *sig_str = SysSignal::Name(soft_signal); - DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data: EXC_SOFT_SIGNAL (%i (%s))", soft_signal, sig_str ? sig_str : "unknown signal"); - } - else - { - // No special disassembly for this data, just dump the data - size_t idx; - for (idx = 0; idx < exc_data_count; ++idx) - { - DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data[%llu]: 0x%llx", (uint64_t)idx, (uint64_t)exc_data[idx]); - } +void MachException::Data::Dump() const { + const char *exc_type_name = MachException::Name(exc_type); + DNBLogThreadedIf( + LOG_EXCEPTIONS, " state { task_port = 0x%4.4x, thread_port = " + "0x%4.4x, exc_type = %i (%s) ...", + task_port, thread_port, exc_type, exc_type_name ? exc_type_name : "???"); + + const size_t exc_data_count = exc_data.size(); + // Dump any special exception data contents + int soft_signal = SoftSignal(); + if (soft_signal != 0) { + const char *sig_str = SysSignal::Name(soft_signal); + DNBLogThreadedIf(LOG_EXCEPTIONS, + " exc_data: EXC_SOFT_SIGNAL (%i (%s))", + soft_signal, sig_str ? sig_str : "unknown signal"); + } else { + // No special disassembly for this data, just dump the data + size_t idx; + for (idx = 0; idx < exc_data_count; ++idx) { + DNBLogThreadedIf(LOG_EXCEPTIONS, " exc_data[%llu]: 0x%llx", + (uint64_t)idx, (uint64_t)exc_data[idx]); } + } } -#define PREV_EXC_MASK_ALL (EXC_MASK_BAD_ACCESS | \ - EXC_MASK_BAD_INSTRUCTION | \ - EXC_MASK_ARITHMETIC | \ - EXC_MASK_EMULATION | \ - EXC_MASK_SOFTWARE | \ - EXC_MASK_BREAKPOINT | \ - EXC_MASK_SYSCALL | \ - EXC_MASK_MACH_SYSCALL | \ - EXC_MASK_RPC_ALERT | \ - EXC_MASK_MACHINE) +#define PREV_EXC_MASK_ALL \ + (EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | \ + EXC_MASK_EMULATION | EXC_MASK_SOFTWARE | EXC_MASK_BREAKPOINT | \ + EXC_MASK_SYSCALL | EXC_MASK_MACH_SYSCALL | EXC_MASK_RPC_ALERT | \ + EXC_MASK_MACHINE) -// Don't listen for EXC_RESOURCE, it should really get handled by the system handler. +// Don't listen for EXC_RESOURCE, it should really get handled by the system +// handler. #ifndef EXC_RESOURCE #define EXC_RESOURCE 11 @@ -497,85 +397,92 @@ MachException::Data::Dump() const #define LLDB_EXC_MASK (EXC_MASK_ALL & ~EXC_MASK_RESOURCE) -kern_return_t -MachException::PortInfo::Save (task_t task) -{ - DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Save ( task = 0x%4.4x )", task); - // Be careful to be able to have debugserver built on a newer OS than what - // it is currently running on by being able to start with all exceptions - // and back off to just what is supported on the current system - DNBError err; - - mask = LLDB_EXC_MASK; - - count = (sizeof (ports) / sizeof (ports[0])); - err = ::task_get_exception_ports (task, mask, masks, &count, ports, behaviors, flavors); +kern_return_t MachException::PortInfo::Save(task_t task) { + DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, + "MachException::PortInfo::Save ( task = 0x%4.4x )", task); + // Be careful to be able to have debugserver built on a newer OS than what + // it is currently running on by being able to start with all exceptions + // and back off to just what is supported on the current system + DNBError err; + + mask = LLDB_EXC_MASK; + + count = (sizeof(ports) / sizeof(ports[0])); + err = ::task_get_exception_ports(task, mask, masks, &count, ports, behaviors, + flavors); + if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) + err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = 0x%x, " + "maskCnt => %u, ports, behaviors, flavors )", + task, mask, count); + + if (err.Error() == KERN_INVALID_ARGUMENT && mask != PREV_EXC_MASK_ALL) { + mask = PREV_EXC_MASK_ALL; + count = (sizeof(ports) / sizeof(ports[0])); + err = ::task_get_exception_ports(task, mask, masks, &count, ports, + behaviors, flavors); if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) - err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = 0x%x, maskCnt => %u, ports, behaviors, flavors )", task, mask, count); - - if (err.Error() == KERN_INVALID_ARGUMENT && mask != PREV_EXC_MASK_ALL) - { - mask = PREV_EXC_MASK_ALL; - count = (sizeof (ports) / sizeof (ports[0])); - err = ::task_get_exception_ports (task, mask, masks, &count, ports, behaviors, flavors); - if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) - err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = 0x%x, maskCnt => %u, ports, behaviors, flavors )", task, mask, count); - } - if (err.Fail()) - { - mask = 0; - count = 0; - } - return err.Error(); + err.LogThreaded("::task_get_exception_ports ( task = 0x%4.4x, mask = " + "0x%x, maskCnt => %u, ports, behaviors, flavors )", + task, mask, count); + } + if (err.Fail()) { + mask = 0; + count = 0; + } + return err.Error(); } -kern_return_t -MachException::PortInfo::Restore (task_t task) -{ - DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, "MachException::PortInfo::Restore( task = 0x%4.4x )", task); - uint32_t i = 0; - DNBError err; - if (count > 0) - { - for (i = 0; i < count; i++) - { - err = ::task_set_exception_ports (task, masks[i], ports[i], behaviors[i], flavors[i]); - if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) - { - err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", task, masks[i], ports[i], behaviors[i], flavors[i]); - // Bail if we encounter any errors - } - - if (err.Fail()) - break; - } +kern_return_t MachException::PortInfo::Restore(task_t task) { + DNBLogThreadedIf(LOG_EXCEPTIONS | LOG_VERBOSE, + "MachException::PortInfo::Restore( task = 0x%4.4x )", task); + uint32_t i = 0; + DNBError err; + if (count > 0) { + for (i = 0; i < count; i++) { + err = ::task_set_exception_ports(task, masks[i], ports[i], behaviors[i], + flavors[i]); + if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) { + err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, " + "exception_mask = 0x%8.8x, new_port = 0x%4.4x, " + "behavior = 0x%8.8x, new_flavor = 0x%8.8x )", + task, masks[i], ports[i], behaviors[i], flavors[i]); + // Bail if we encounter any errors + } + + if (err.Fail()) + break; } - count = 0; - return err.Error(); + } + count = 0; + return err.Error(); } -const char * -MachException::Name(exception_type_t exc_type) -{ - switch (exc_type) - { - case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS"; - case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION"; - case EXC_ARITHMETIC: return "EXC_ARITHMETIC"; - case EXC_EMULATION: return "EXC_EMULATION"; - case EXC_SOFTWARE: return "EXC_SOFTWARE"; - case EXC_BREAKPOINT: return "EXC_BREAKPOINT"; - case EXC_SYSCALL: return "EXC_SYSCALL"; - case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL"; - case EXC_RPC_ALERT: return "EXC_RPC_ALERT"; +const char *MachException::Name(exception_type_t exc_type) { + switch (exc_type) { + case EXC_BAD_ACCESS: + return "EXC_BAD_ACCESS"; + case EXC_BAD_INSTRUCTION: + return "EXC_BAD_INSTRUCTION"; + case EXC_ARITHMETIC: + return "EXC_ARITHMETIC"; + case EXC_EMULATION: + return "EXC_EMULATION"; + case EXC_SOFTWARE: + return "EXC_SOFTWARE"; + case EXC_BREAKPOINT: + return "EXC_BREAKPOINT"; + case EXC_SYSCALL: + return "EXC_SYSCALL"; + case EXC_MACH_SYSCALL: + return "EXC_MACH_SYSCALL"; + case EXC_RPC_ALERT: + return "EXC_RPC_ALERT"; #ifdef EXC_CRASH - case EXC_CRASH: return "EXC_CRASH"; + case EXC_CRASH: + return "EXC_CRASH"; #endif - default: - break; - } - return NULL; + default: + break; + } + return NULL; } - - - diff --git a/lldb/tools/debugserver/source/MacOSX/MachException.h b/lldb/tools/debugserver/source/MacOSX/MachException.h index c831479f2b6..a45a41e01f4 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachException.h +++ b/lldb/tools/debugserver/source/MacOSX/MachException.h @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// - #ifndef __MachException_h__ #define __MachException_h__ @@ -21,113 +20,105 @@ class MachProcess; class PThreadMutex; -typedef union MachMessageTag -{ - mach_msg_header_t hdr; - char data[1024]; +typedef union MachMessageTag { + mach_msg_header_t hdr; + char data[1024]; } MachMessage; - -class MachException -{ +class MachException { public: - - struct PortInfo - { - exception_mask_t mask; // the exception mask for this device which may be a subset of EXC_MASK_ALL... - exception_mask_t masks[EXC_TYPES_COUNT]; - mach_port_t ports[EXC_TYPES_COUNT]; - exception_behavior_t behaviors[EXC_TYPES_COUNT]; - thread_state_flavor_t flavors[EXC_TYPES_COUNT]; - mach_msg_type_number_t count; - - kern_return_t Save(task_t task); - kern_return_t Restore(task_t task); - }; - - struct Data - { - task_t task_port; - thread_t thread_port; - exception_type_t exc_type; - std::vector<mach_exception_data_type_t> exc_data; - Data() : - task_port(TASK_NULL), - thread_port(THREAD_NULL), - exc_type(0), - exc_data() - { - } - - void Clear() - { - task_port = TASK_NULL; - thread_port = THREAD_NULL; - exc_type = 0; - exc_data.clear(); - } - bool IsValid() const - { - return task_port != TASK_NULL && - thread_port != THREAD_NULL && - exc_type != 0; - } - // Return the SoftSignal for this MachException data, or zero if there is none - int SoftSignal() const - { - if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && exc_data[0] == EXC_SOFT_SIGNAL) - return static_cast<int>(exc_data[1]); - return 0; - } - bool IsBreakpoint() const - { - return (exc_type == EXC_BREAKPOINT || ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1)); - } - void Dump() const; - void DumpStopReason() const; - bool GetStopInfo(struct DNBThreadStopInfo *stop_info) const; - }; - - struct Message - { - MachMessage exc_msg; - MachMessage reply_msg; - Data state; - - Message() : - state() - { - memset(&exc_msg, 0, sizeof(exc_msg)); - memset(&reply_msg, 0, sizeof(reply_msg)); - } - bool CatchExceptionRaise(task_t task); - void Dump() const; - kern_return_t Reply (MachProcess *process, int signal); - kern_return_t Receive( mach_port_t receive_port, - mach_msg_option_t options, - mach_msg_timeout_t timeout, - mach_port_t notify_port = MACH_PORT_NULL); - - typedef std::vector<Message> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - }; - - enum - { - e_actionForward, // Forward signal to inferior process - e_actionStop, // Stop when this signal is received - }; - struct Action - { - task_t task_port; // Set to TASK_NULL for any TASK - thread_t thread_port; // Set to THREAD_NULL for any thread - exception_type_t exc_mask; // Mach exception mask to watch for - std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to exception data, or empty to ignore exc_data value for exception - std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare to exception data after masking, or empty to ignore exc_data value for exception - uint8_t flags; // Action flags describing what to do with the exception - }; - static const char *Name(exception_type_t exc_type); + struct PortInfo { + exception_mask_t mask; // the exception mask for this device which may be a + // subset of EXC_MASK_ALL... + exception_mask_t masks[EXC_TYPES_COUNT]; + mach_port_t ports[EXC_TYPES_COUNT]; + exception_behavior_t behaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t flavors[EXC_TYPES_COUNT]; + mach_msg_type_number_t count; + + kern_return_t Save(task_t task); + kern_return_t Restore(task_t task); + }; + + struct Data { + task_t task_port; + thread_t thread_port; + exception_type_t exc_type; + std::vector<mach_exception_data_type_t> exc_data; + Data() + : task_port(TASK_NULL), thread_port(THREAD_NULL), exc_type(0), + exc_data() {} + + void Clear() { + task_port = TASK_NULL; + thread_port = THREAD_NULL; + exc_type = 0; + exc_data.clear(); + } + bool IsValid() const { + return task_port != TASK_NULL && thread_port != THREAD_NULL && + exc_type != 0; + } + // Return the SoftSignal for this MachException data, or zero if there is + // none + int SoftSignal() const { + if (exc_type == EXC_SOFTWARE && exc_data.size() == 2 && + exc_data[0] == EXC_SOFT_SIGNAL) + return static_cast<int>(exc_data[1]); + return 0; + } + bool IsBreakpoint() const { + return (exc_type == EXC_BREAKPOINT || + ((exc_type == EXC_SOFTWARE) && exc_data[0] == 1)); + } + void Dump() const; + void DumpStopReason() const; + bool GetStopInfo(struct DNBThreadStopInfo *stop_info) const; + }; + + struct Message { + MachMessage exc_msg; + MachMessage reply_msg; + Data state; + + Message() : state() { + memset(&exc_msg, 0, sizeof(exc_msg)); + memset(&reply_msg, 0, sizeof(reply_msg)); + } + bool CatchExceptionRaise(task_t task); + void Dump() const; + kern_return_t Reply(MachProcess *process, int signal); + kern_return_t Receive(mach_port_t receive_port, mach_msg_option_t options, + mach_msg_timeout_t timeout, + mach_port_t notify_port = MACH_PORT_NULL); + + typedef std::vector<Message> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + }; + + enum { + e_actionForward, // Forward signal to inferior process + e_actionStop, // Stop when this signal is received + }; + struct Action { + task_t task_port; // Set to TASK_NULL for any TASK + thread_t thread_port; // Set to THREAD_NULL for any thread + exception_type_t exc_mask; // Mach exception mask to watch for + std::vector<mach_exception_data_type_t> exc_data_mask; // Mask to apply to + // exception data, or + // empty to ignore + // exc_data value for + // exception + std::vector<mach_exception_data_type_t> exc_data_value; // Value to compare + // to exception data + // after masking, or + // empty to ignore + // exc_data value + // for exception + uint8_t flags; // Action flags describing what to do with the exception + }; + static const char *Name(exception_type_t exc_type); }; #endif diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h index 094c13b8f0a..9ab06bcda9c 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h @@ -14,405 +14,432 @@ #ifndef __MachProcess_h__ #define __MachProcess_h__ -#include <mach/mach.h> +#include <CoreFoundation/CoreFoundation.h> #include <mach-o/loader.h> -#include <sys/signal.h> +#include <mach/mach.h> #include <pthread.h> +#include <sys/signal.h> #include <uuid/uuid.h> #include <vector> -#include <CoreFoundation/CoreFoundation.h> -#include "DNBDefs.h" #include "DNBBreakpoint.h" +#include "DNBDefs.h" #include "DNBError.h" #include "DNBThreadResumeActions.h" +#include "Genealogy.h" +#include "JSONGenerator.h" #include "MachException.h" -#include "MachVMMemory.h" #include "MachTask.h" #include "MachThreadList.h" +#include "MachVMMemory.h" #include "PThreadCondition.h" #include "PThreadEvent.h" #include "PThreadMutex.h" -#include "Genealogy.h" #include "ThreadInfo.h" -#include "JSONGenerator.h" class DNBThreadResumeActions; -class MachProcess -{ +class MachProcess { public: - //---------------------------------------------------------------------- - // Constructors and Destructors - //---------------------------------------------------------------------- - MachProcess (); - ~MachProcess (); - - // A structure that can hold everything debugserver needs to know from - // a binary's Mach-O header / load commands. - - struct mach_o_segment - { - std::string name; - uint64_t vmaddr; - uint64_t vmsize; - uint64_t fileoff; - uint64_t filesize; - uint64_t maxprot; - uint64_t initprot; - uint64_t nsects; - uint64_t flags; - }; - - struct mach_o_information - { - struct mach_header_64 mach_header; - std::vector<struct mach_o_segment> segments; - uuid_t uuid; - std::string min_version_os_name; - std::string min_version_os_version; - }; - - struct binary_image_information - { - std::string filename; - uint64_t load_address; - uint64_t mod_date; // may not be available - 0 if so - struct mach_o_information macho_info; - - binary_image_information () : - filename (), - load_address (INVALID_NUB_ADDRESS), - mod_date (0) - { } - }; - - //---------------------------------------------------------------------- - // Child process control - //---------------------------------------------------------------------- - pid_t AttachForDebug (pid_t pid, char *err_str, size_t err_len); - pid_t LaunchForDebug (const char *path, - char const *argv[], - char const *envp[], - const char *working_directory, - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - nub_launch_flavor_t launch_flavor, - int disable_aslr, - const char *event_data, - DNBError &err); - - static uint32_t GetCPUTypeForLocalProcess (pid_t pid); - static pid_t ForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], MachProcess* process, DNBError &err); - static pid_t PosixSpawnChildForPTraceDebugging (const char *path, - cpu_type_t cpu_type, - char const *argv[], - char const *envp[], - const char *working_directory, - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - MachProcess* process, - int disable_aslr, - DNBError& err); - nub_addr_t GetDYLDAllImageInfosAddress (); - static const void * PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &err_str); - static void CleanupAfterAttach (const void *attach_token, nub_launch_flavor_t launch_flavor, bool success, DNBError &err_str); - static nub_process_t CheckForProcess (const void *attach_token, nub_launch_flavor_t launch_flavor); + //---------------------------------------------------------------------- + // Constructors and Destructors + //---------------------------------------------------------------------- + MachProcess(); + ~MachProcess(); + + // A structure that can hold everything debugserver needs to know from + // a binary's Mach-O header / load commands. + + struct mach_o_segment { + std::string name; + uint64_t vmaddr; + uint64_t vmsize; + uint64_t fileoff; + uint64_t filesize; + uint64_t maxprot; + uint64_t initprot; + uint64_t nsects; + uint64_t flags; + }; + + struct mach_o_information { + struct mach_header_64 mach_header; + std::vector<struct mach_o_segment> segments; + uuid_t uuid; + std::string min_version_os_name; + std::string min_version_os_version; + }; + + struct binary_image_information { + std::string filename; + uint64_t load_address; + uint64_t mod_date; // may not be available - 0 if so + struct mach_o_information macho_info; + + binary_image_information() + : filename(), load_address(INVALID_NUB_ADDRESS), mod_date(0) {} + }; + + //---------------------------------------------------------------------- + // Child process control + //---------------------------------------------------------------------- + pid_t AttachForDebug(pid_t pid, char *err_str, size_t err_len); + pid_t LaunchForDebug(const char *path, char const *argv[], char const *envp[], + const char *working_directory, const char *stdin_path, + const char *stdout_path, const char *stderr_path, + bool no_stdio, nub_launch_flavor_t launch_flavor, + int disable_aslr, const char *event_data, DNBError &err); + + static uint32_t GetCPUTypeForLocalProcess(pid_t pid); + static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[], + char const *envp[], + MachProcess *process, DNBError &err); + static pid_t PosixSpawnChildForPTraceDebugging( + const char *path, cpu_type_t cpu_type, char const *argv[], + char const *envp[], const char *working_directory, const char *stdin_path, + const char *stdout_path, const char *stderr_path, bool no_stdio, + MachProcess *process, int disable_aslr, DNBError &err); + nub_addr_t GetDYLDAllImageInfosAddress(); + static const void *PrepareForAttach(const char *path, + nub_launch_flavor_t launch_flavor, + bool waitfor, DNBError &err_str); + static void CleanupAfterAttach(const void *attach_token, + nub_launch_flavor_t launch_flavor, + bool success, DNBError &err_str); + static nub_process_t CheckForProcess(const void *attach_token, + nub_launch_flavor_t launch_flavor); #if defined(WITH_BKS) || defined(WITH_FBS) - pid_t BoardServiceLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err); - pid_t BoardServiceForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err); - bool BoardServiceSendEvent (const char *event, DNBError &error); + pid_t BoardServiceLaunchForDebug(const char *app_bundle_path, + char const *argv[], char const *envp[], + bool no_stdio, bool disable_aslr, + const char *event_data, + DNBError &launch_err); + pid_t BoardServiceForkChildForPTraceDebugging( + const char *path, char const *argv[], char const *envp[], bool no_stdio, + bool disable_aslr, const char *event_data, DNBError &launch_err); + bool BoardServiceSendEvent(const char *event, DNBError &error); #endif - static bool GetOSVersionNumbers (uint64_t *major, uint64_t *minor, uint64_t *patch); + static bool GetOSVersionNumbers(uint64_t *major, uint64_t *minor, + uint64_t *patch); #ifdef WITH_BKS - static void BKSCleanupAfterAttach (const void *attach_token, DNBError &err_str); + static void BKSCleanupAfterAttach(const void *attach_token, + DNBError &err_str); #endif // WITH_BKS #ifdef WITH_FBS - static void FBSCleanupAfterAttach (const void *attach_token, DNBError &err_str); -#endif // WITH_FBS + static void FBSCleanupAfterAttach(const void *attach_token, + DNBError &err_str); +#endif // WITH_FBS #ifdef WITH_SPRINGBOARD - pid_t SBLaunchForDebug (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, DNBError &launch_err); - static pid_t SBForkChildForPTraceDebugging (const char *path, char const *argv[], char const *envp[], bool no_stdio, MachProcess* process, DNBError &launch_err); -#endif // WITH_SPRINGBOARD - nub_addr_t LookupSymbol (const char *name, const char *shlib); - void SetNameToAddressCallback (DNBCallbackNameToAddress callback, void *baton) - { - m_name_to_addr_callback = callback; - m_name_to_addr_baton = baton; - } - void SetSharedLibraryInfoCallback (DNBCallbackCopyExecutableImageInfos callback, void *baton) - { - m_image_infos_callback = callback; - m_image_infos_baton = baton; - } - - bool Resume (const DNBThreadResumeActions& thread_actions); - bool Signal (int signal, const struct timespec *timeout_abstime = NULL); - bool Interrupt(); - bool SendEvent (const char *event, DNBError &send_err); - bool Kill (const struct timespec *timeout_abstime = NULL); - bool Detach (); - nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf); - nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf); - - //---------------------------------------------------------------------- - // Path and arg accessors - //---------------------------------------------------------------------- - const char * Path () const { return m_path.c_str(); } - size_t ArgumentCount () const { return m_args.size(); } - const char * ArgumentAtIndex (size_t arg_idx) const - { - if (arg_idx < m_args.size()) - return m_args[arg_idx].c_str(); - return NULL; - } - - //---------------------------------------------------------------------- - // Breakpoint functions - //---------------------------------------------------------------------- - DNBBreakpoint * CreateBreakpoint (nub_addr_t addr, nub_size_t length, bool hardware); - bool DisableBreakpoint (nub_addr_t addr, bool remove); - void DisableAllBreakpoints (bool remove); - bool EnableBreakpoint (nub_addr_t addr); - DNBBreakpointList& Breakpoints() { return m_breakpoints; } - const DNBBreakpointList& Breakpoints() const { return m_breakpoints; } - - //---------------------------------------------------------------------- - // Watchpoint functions - //---------------------------------------------------------------------- - DNBBreakpoint * CreateWatchpoint (nub_addr_t addr, nub_size_t length, uint32_t watch_type, bool hardware); - bool DisableWatchpoint (nub_addr_t addr, bool remove); - void DisableAllWatchpoints (bool remove); - bool EnableWatchpoint (nub_addr_t addr); - uint32_t GetNumSupportedHardwareWatchpoints () const; - DNBBreakpointList& Watchpoints() { return m_watchpoints; } - const DNBBreakpointList& Watchpoints() const { return m_watchpoints; } - - //---------------------------------------------------------------------- - // Exception thread functions - //---------------------------------------------------------------------- - bool StartSTDIOThread (); - static void * STDIOThread (void *arg); - void ExceptionMessageReceived (const MachException::Message& exceptionMessage); - task_t ExceptionMessageBundleComplete (); - void SharedLibrariesUpdated (); - nub_size_t CopyImageInfos (struct DNBExecutableImageInfo **image_infos, bool only_changed); - - //---------------------------------------------------------------------- - // Profile functions - //---------------------------------------------------------------------- - void SetEnableAsyncProfiling (bool enable, uint64_t internal_usec, DNBProfileDataScanType scan_type); - bool IsProfilingEnabled () { return m_profile_enabled; } - useconds_t ProfileInterval () { return m_profile_interval_usec; } - bool StartProfileThread (); - static void * ProfileThread (void *arg); - void SignalAsyncProfileData (const char *info); - size_t GetAsyncProfileData (char *buf, size_t buf_size); - - //---------------------------------------------------------------------- - // Accessors - //---------------------------------------------------------------------- - pid_t ProcessID () const { return m_pid; } - bool ProcessIDIsValid () const { return m_pid > 0; } - pid_t SetProcessID (pid_t pid); - MachTask& Task() { return m_task; } - const MachTask& Task() const { return m_task; } - - PThreadEvent& Events() { return m_events; } - const DNBRegisterSetInfo * - GetRegisterSetInfo (nub_thread_t tid, nub_size_t *num_reg_sets) const; - bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const; - bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value) const; - nub_bool_t SyncThreadState (nub_thread_t tid); - const char * ThreadGetName (nub_thread_t tid); - nub_state_t ThreadGetState (nub_thread_t tid); - ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index); - nub_addr_t GetPThreadT (nub_thread_t tid); - nub_addr_t GetDispatchQueueT (nub_thread_t tid); - nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); - - - bool GetMachOInformationFromMemory (nub_addr_t mach_o_header_addr, int wordsize, struct mach_o_information &inf); - JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON (const std::vector<struct binary_image_information> &image_infos); - void GetAllLoadedBinariesViaDYLDSPI (std::vector<struct binary_image_information> &image_infos); - JSONGenerator::ObjectSP GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count); - JSONGenerator::ObjectSP GetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses); - JSONGenerator::ObjectSP GetAllLoadedLibrariesInfos (nub_process_t pid); - JSONGenerator::ObjectSP GetSharedCacheInfo (nub_process_t pid); - - nub_size_t GetNumThreads () const; - nub_thread_t GetThreadAtIndex (nub_size_t thread_idx) const; - nub_thread_t GetCurrentThread (); - nub_thread_t GetCurrentThreadMachPort (); - nub_thread_t SetCurrentThread (nub_thread_t tid); - MachThreadList & GetThreadList() { return m_thread_list; } - bool GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info); - void DumpThreadStoppedReason(nub_thread_t tid) const; - const char * GetThreadInfo (nub_thread_t tid) const; - - nub_thread_t GetThreadIDForMachPortNumber (thread_t mach_port_number) const; - - uint32_t GetCPUType (); - nub_state_t GetState (); - void SetState (nub_state_t state); - bool IsRunning (nub_state_t state) - { - return state == eStateRunning || IsStepping(state); - } - bool IsStepping (nub_state_t state) - { - return state == eStateStepping; - } - bool CanResume (nub_state_t state) - { - return state == eStateStopped; - } - - bool GetExitStatus(int* status) - { - if (GetState() == eStateExited) - { - if (status) - *status = m_exit_status; - return true; - } - return false; - } - void SetExitStatus(int status) - { - m_exit_status = status; - SetState(eStateExited); - } - const char * GetExitInfo () - { - return m_exit_info.c_str(); - } - - void SetExitInfo (const char *info); - - uint32_t StopCount() const { return m_stop_count; } - void SetChildFileDescriptors (int stdin_fileno, int stdout_fileno, int stderr_fileno) - { - m_child_stdin = stdin_fileno; - m_child_stdout = stdout_fileno; - m_child_stderr = stderr_fileno; - } - - int GetStdinFileDescriptor () const { return m_child_stdin; } - int GetStdoutFileDescriptor () const { return m_child_stdout; } - int GetStderrFileDescriptor () const { return m_child_stderr; } - void AppendSTDOUT (char* s, size_t len); - size_t GetAvailableSTDOUT (char *buf, size_t buf_size); - size_t GetAvailableSTDERR (char *buf, size_t buf_size); - void CloseChildFileDescriptors () - { - if (m_child_stdin >= 0) - { - ::close (m_child_stdin); - m_child_stdin = -1; - } - if (m_child_stdout >= 0) - { - ::close (m_child_stdout); - m_child_stdout = -1; - } - if (m_child_stderr >= 0) - { - ::close (m_child_stderr); - m_child_stderr = -1; - } - } - - bool ProcessUsingSpringBoard() const { return (m_flags & eMachProcessFlagsUsingSBS) != 0; } - bool ProcessUsingBackBoard() const { return (m_flags & eMachProcessFlagsUsingBKS) != 0; } - - Genealogy::ThreadActivitySP GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out); - - Genealogy::ProcessExecutableInfoSP GetGenealogyImageInfo (size_t idx); - - DNBProfileDataScanType GetProfileScanType () { return m_profile_scan_type; } + pid_t SBLaunchForDebug(const char *app_bundle_path, char const *argv[], + char const *envp[], bool no_stdio, bool disable_aslr, + DNBError &launch_err); + static pid_t SBForkChildForPTraceDebugging(const char *path, + char const *argv[], + char const *envp[], bool no_stdio, + MachProcess *process, + DNBError &launch_err); +#endif // WITH_SPRINGBOARD + nub_addr_t LookupSymbol(const char *name, const char *shlib); + void SetNameToAddressCallback(DNBCallbackNameToAddress callback, + void *baton) { + m_name_to_addr_callback = callback; + m_name_to_addr_baton = baton; + } + void + SetSharedLibraryInfoCallback(DNBCallbackCopyExecutableImageInfos callback, + void *baton) { + m_image_infos_callback = callback; + m_image_infos_baton = baton; + } + + bool Resume(const DNBThreadResumeActions &thread_actions); + bool Signal(int signal, const struct timespec *timeout_abstime = NULL); + bool Interrupt(); + bool SendEvent(const char *event, DNBError &send_err); + bool Kill(const struct timespec *timeout_abstime = NULL); + bool Detach(); + nub_size_t ReadMemory(nub_addr_t addr, nub_size_t size, void *buf); + nub_size_t WriteMemory(nub_addr_t addr, nub_size_t size, const void *buf); + + //---------------------------------------------------------------------- + // Path and arg accessors + //---------------------------------------------------------------------- + const char *Path() const { return m_path.c_str(); } + size_t ArgumentCount() const { return m_args.size(); } + const char *ArgumentAtIndex(size_t arg_idx) const { + if (arg_idx < m_args.size()) + return m_args[arg_idx].c_str(); + return NULL; + } + + //---------------------------------------------------------------------- + // Breakpoint functions + //---------------------------------------------------------------------- + DNBBreakpoint *CreateBreakpoint(nub_addr_t addr, nub_size_t length, + bool hardware); + bool DisableBreakpoint(nub_addr_t addr, bool remove); + void DisableAllBreakpoints(bool remove); + bool EnableBreakpoint(nub_addr_t addr); + DNBBreakpointList &Breakpoints() { return m_breakpoints; } + const DNBBreakpointList &Breakpoints() const { return m_breakpoints; } + + //---------------------------------------------------------------------- + // Watchpoint functions + //---------------------------------------------------------------------- + DNBBreakpoint *CreateWatchpoint(nub_addr_t addr, nub_size_t length, + uint32_t watch_type, bool hardware); + bool DisableWatchpoint(nub_addr_t addr, bool remove); + void DisableAllWatchpoints(bool remove); + bool EnableWatchpoint(nub_addr_t addr); + uint32_t GetNumSupportedHardwareWatchpoints() const; + DNBBreakpointList &Watchpoints() { return m_watchpoints; } + const DNBBreakpointList &Watchpoints() const { return m_watchpoints; } + + //---------------------------------------------------------------------- + // Exception thread functions + //---------------------------------------------------------------------- + bool StartSTDIOThread(); + static void *STDIOThread(void *arg); + void ExceptionMessageReceived(const MachException::Message &exceptionMessage); + task_t ExceptionMessageBundleComplete(); + void SharedLibrariesUpdated(); + nub_size_t CopyImageInfos(struct DNBExecutableImageInfo **image_infos, + bool only_changed); + + //---------------------------------------------------------------------- + // Profile functions + //---------------------------------------------------------------------- + void SetEnableAsyncProfiling(bool enable, uint64_t internal_usec, + DNBProfileDataScanType scan_type); + bool IsProfilingEnabled() { return m_profile_enabled; } + useconds_t ProfileInterval() { return m_profile_interval_usec; } + bool StartProfileThread(); + static void *ProfileThread(void *arg); + void SignalAsyncProfileData(const char *info); + size_t GetAsyncProfileData(char *buf, size_t buf_size); + + //---------------------------------------------------------------------- + // Accessors + //---------------------------------------------------------------------- + pid_t ProcessID() const { return m_pid; } + bool ProcessIDIsValid() const { return m_pid > 0; } + pid_t SetProcessID(pid_t pid); + MachTask &Task() { return m_task; } + const MachTask &Task() const { return m_task; } + + PThreadEvent &Events() { return m_events; } + const DNBRegisterSetInfo *GetRegisterSetInfo(nub_thread_t tid, + nub_size_t *num_reg_sets) const; + bool GetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + DNBRegisterValue *reg_value) const; + bool SetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + const DNBRegisterValue *value) const; + nub_bool_t SyncThreadState(nub_thread_t tid); + const char *ThreadGetName(nub_thread_t tid); + nub_state_t ThreadGetState(nub_thread_t tid); + ThreadInfo::QoS GetRequestedQoS(nub_thread_t tid, nub_addr_t tsd, + uint64_t dti_qos_class_index); + nub_addr_t GetPThreadT(nub_thread_t tid); + nub_addr_t GetDispatchQueueT(nub_thread_t tid); + nub_addr_t + GetTSDAddressForThread(nub_thread_t tid, + uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size); + + bool GetMachOInformationFromMemory(nub_addr_t mach_o_header_addr, + int wordsize, + struct mach_o_information &inf); + JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON( + const std::vector<struct binary_image_information> &image_infos); + void GetAllLoadedBinariesViaDYLDSPI( + std::vector<struct binary_image_information> &image_infos); + JSONGenerator::ObjectSP GetLoadedDynamicLibrariesInfos( + nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count); + JSONGenerator::ObjectSP + GetLibrariesInfoForAddresses(nub_process_t pid, + std::vector<uint64_t> &macho_addresses); + JSONGenerator::ObjectSP GetAllLoadedLibrariesInfos(nub_process_t pid); + JSONGenerator::ObjectSP GetSharedCacheInfo(nub_process_t pid); + + nub_size_t GetNumThreads() const; + nub_thread_t GetThreadAtIndex(nub_size_t thread_idx) const; + nub_thread_t GetCurrentThread(); + nub_thread_t GetCurrentThreadMachPort(); + nub_thread_t SetCurrentThread(nub_thread_t tid); + MachThreadList &GetThreadList() { return m_thread_list; } + bool GetThreadStoppedReason(nub_thread_t tid, + struct DNBThreadStopInfo *stop_info); + void DumpThreadStoppedReason(nub_thread_t tid) const; + const char *GetThreadInfo(nub_thread_t tid) const; + + nub_thread_t GetThreadIDForMachPortNumber(thread_t mach_port_number) const; + + uint32_t GetCPUType(); + nub_state_t GetState(); + void SetState(nub_state_t state); + bool IsRunning(nub_state_t state) { + return state == eStateRunning || IsStepping(state); + } + bool IsStepping(nub_state_t state) { return state == eStateStepping; } + bool CanResume(nub_state_t state) { return state == eStateStopped; } + + bool GetExitStatus(int *status) { + if (GetState() == eStateExited) { + if (status) + *status = m_exit_status; + return true; + } + return false; + } + void SetExitStatus(int status) { + m_exit_status = status; + SetState(eStateExited); + } + const char *GetExitInfo() { return m_exit_info.c_str(); } + + void SetExitInfo(const char *info); + + uint32_t StopCount() const { return m_stop_count; } + void SetChildFileDescriptors(int stdin_fileno, int stdout_fileno, + int stderr_fileno) { + m_child_stdin = stdin_fileno; + m_child_stdout = stdout_fileno; + m_child_stderr = stderr_fileno; + } + + int GetStdinFileDescriptor() const { return m_child_stdin; } + int GetStdoutFileDescriptor() const { return m_child_stdout; } + int GetStderrFileDescriptor() const { return m_child_stderr; } + void AppendSTDOUT(char *s, size_t len); + size_t GetAvailableSTDOUT(char *buf, size_t buf_size); + size_t GetAvailableSTDERR(char *buf, size_t buf_size); + void CloseChildFileDescriptors() { + if (m_child_stdin >= 0) { + ::close(m_child_stdin); + m_child_stdin = -1; + } + if (m_child_stdout >= 0) { + ::close(m_child_stdout); + m_child_stdout = -1; + } + if (m_child_stderr >= 0) { + ::close(m_child_stderr); + m_child_stderr = -1; + } + } + + bool ProcessUsingSpringBoard() const { + return (m_flags & eMachProcessFlagsUsingSBS) != 0; + } + bool ProcessUsingBackBoard() const { + return (m_flags & eMachProcessFlagsUsingBKS) != 0; + } + + Genealogy::ThreadActivitySP GetGenealogyInfoForThread(nub_thread_t tid, + bool &timed_out); + + Genealogy::ProcessExecutableInfoSP GetGenealogyImageInfo(size_t idx); + + DNBProfileDataScanType GetProfileScanType() { return m_profile_scan_type; } private: - enum - { - eMachProcessFlagsNone = 0, - eMachProcessFlagsAttached = (1 << 0), - eMachProcessFlagsUsingSBS = (1 << 1), - eMachProcessFlagsUsingBKS = (1 << 2), - eMachProcessFlagsUsingFBS = (1 << 3) - }; - void Clear (bool detaching = false); - void ReplyToAllExceptions (); - void PrivateResume (); - - uint32_t Flags () const { return m_flags; } - nub_state_t DoSIGSTOP (bool clear_bps_and_wps, bool allow_running, uint32_t *thread_idx_ptr); - - pid_t m_pid; // Process ID of child process - cpu_type_t m_cpu_type; // The CPU type of this process - int m_child_stdin; - int m_child_stdout; - int m_child_stderr; - std::string m_path; // A path to the executable if we have one - std::vector<std::string> m_args; // The arguments with which the process was lauched - int m_exit_status; // The exit status for the process - std::string m_exit_info; // Any extra info that we may have about the exit - MachTask m_task; // The mach task for this process - uint32_t m_flags; // Process specific flags (see eMachProcessFlags enums) - uint32_t m_stop_count; // A count of many times have we stopped - pthread_t m_stdio_thread; // Thread ID for the thread that watches for child process stdio - PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio - std::string m_stdout_data; - - bool m_profile_enabled; // A flag to indicate if profiling is enabled - useconds_t m_profile_interval_usec; // If enable, the profiling interval in microseconds - DNBProfileDataScanType m_profile_scan_type; // Indicates what needs to be profiled - pthread_t m_profile_thread; // Thread ID for the thread that profiles the inferior - PThreadMutex m_profile_data_mutex; // Multithreaded protection for profile info data - std::vector<std::string> m_profile_data; // Profile data, must be protected by m_profile_data_mutex - - DNBThreadResumeActions m_thread_actions; // The thread actions for the current MachProcess::Resume() call - MachException::Message::collection - m_exception_messages; // A collection of exception messages caught when listening to the exception port - PThreadMutex m_exception_messages_mutex; // Multithreaded protection for m_exception_messages - - MachThreadList m_thread_list; // A list of threads that is maintained/updated after each stop - Genealogy m_activities; // A list of activities that is updated after every stop lazily - nub_state_t m_state; // The state of our process - PThreadMutex m_state_mutex; // Multithreaded protection for m_state - PThreadEvent m_events; // Process related events in the child processes lifetime can be waited upon - PThreadEvent m_private_events; // Used to coordinate running and stopping the process without affecting m_events - DNBBreakpointList m_breakpoints; // Breakpoint list for this process - DNBBreakpointList m_watchpoints; // Watchpoint list for this process - DNBCallbackNameToAddress m_name_to_addr_callback; - void * m_name_to_addr_baton; - DNBCallbackCopyExecutableImageInfos - m_image_infos_callback; - void * m_image_infos_baton; - std::string m_bundle_id; // If we are a SB or BKS process, this will be our bundle ID. - int m_sent_interrupt_signo; // When we call MachProcess::Interrupt(), we want to send a single signal - // to the inferior and only send the signal if we aren't already stopped. - // If we end up sending a signal to stop the process we store it until we - // receive an exception with this signal. This helps us to verify we got - // the signal that interrupted the process. We might stop due to another - // reason after an interrupt signal is sent, so this helps us ensure that - // we don't report a spurious stop on the next resume. - int m_auto_resume_signo; // If we resume the process and still haven't received our interrupt signal - // acknownledgement, we will shortly after the next resume. We store the - // interrupt signal in this variable so when we get the interrupt signal - // as the sole reason for the process being stopped, we can auto resume - // the process. - bool m_did_exec; - - void * (*m_dyld_process_info_create) (task_t task, uint64_t timestamp, kern_return_t* kernelError); - void (*m_dyld_process_info_for_each_image) (void* info, void (^callback)(uint64_t machHeaderAddress, const uuid_t uuid, const char* path)); - void (*m_dyld_process_info_release) (void* info); - void (*m_dyld_process_info_get_cache) (void* info, void* cacheInfo); + enum { + eMachProcessFlagsNone = 0, + eMachProcessFlagsAttached = (1 << 0), + eMachProcessFlagsUsingSBS = (1 << 1), + eMachProcessFlagsUsingBKS = (1 << 2), + eMachProcessFlagsUsingFBS = (1 << 3) + }; + void Clear(bool detaching = false); + void ReplyToAllExceptions(); + void PrivateResume(); + + uint32_t Flags() const { return m_flags; } + nub_state_t DoSIGSTOP(bool clear_bps_and_wps, bool allow_running, + uint32_t *thread_idx_ptr); + + pid_t m_pid; // Process ID of child process + cpu_type_t m_cpu_type; // The CPU type of this process + int m_child_stdin; + int m_child_stdout; + int m_child_stderr; + std::string m_path; // A path to the executable if we have one + std::vector<std::string> + m_args; // The arguments with which the process was lauched + int m_exit_status; // The exit status for the process + std::string m_exit_info; // Any extra info that we may have about the exit + MachTask m_task; // The mach task for this process + uint32_t m_flags; // Process specific flags (see eMachProcessFlags enums) + uint32_t m_stop_count; // A count of many times have we stopped + pthread_t m_stdio_thread; // Thread ID for the thread that watches for child + // process stdio + PThreadMutex m_stdio_mutex; // Multithreaded protection for stdio + std::string m_stdout_data; + + bool m_profile_enabled; // A flag to indicate if profiling is enabled + useconds_t m_profile_interval_usec; // If enable, the profiling interval in + // microseconds + DNBProfileDataScanType + m_profile_scan_type; // Indicates what needs to be profiled + pthread_t + m_profile_thread; // Thread ID for the thread that profiles the inferior + PThreadMutex + m_profile_data_mutex; // Multithreaded protection for profile info data + std::vector<std::string> + m_profile_data; // Profile data, must be protected by m_profile_data_mutex + + DNBThreadResumeActions m_thread_actions; // The thread actions for the current + // MachProcess::Resume() call + MachException::Message::collection m_exception_messages; // A collection of + // exception messages + // caught when + // listening to the + // exception port + PThreadMutex m_exception_messages_mutex; // Multithreaded protection for + // m_exception_messages + + MachThreadList m_thread_list; // A list of threads that is maintained/updated + // after each stop + Genealogy m_activities; // A list of activities that is updated after every + // stop lazily + nub_state_t m_state; // The state of our process + PThreadMutex m_state_mutex; // Multithreaded protection for m_state + PThreadEvent m_events; // Process related events in the child processes + // lifetime can be waited upon + PThreadEvent m_private_events; // Used to coordinate running and stopping the + // process without affecting m_events + DNBBreakpointList m_breakpoints; // Breakpoint list for this process + DNBBreakpointList m_watchpoints; // Watchpoint list for this process + DNBCallbackNameToAddress m_name_to_addr_callback; + void *m_name_to_addr_baton; + DNBCallbackCopyExecutableImageInfos m_image_infos_callback; + void *m_image_infos_baton; + std::string + m_bundle_id; // If we are a SB or BKS process, this will be our bundle ID. + int m_sent_interrupt_signo; // When we call MachProcess::Interrupt(), we want + // to send a single signal + // to the inferior and only send the signal if we aren't already stopped. + // If we end up sending a signal to stop the process we store it until we + // receive an exception with this signal. This helps us to verify we got + // the signal that interrupted the process. We might stop due to another + // reason after an interrupt signal is sent, so this helps us ensure that + // we don't report a spurious stop on the next resume. + int m_auto_resume_signo; // If we resume the process and still haven't + // received our interrupt signal + // acknownledgement, we will shortly after the next resume. We store the + // interrupt signal in this variable so when we get the interrupt signal + // as the sole reason for the process being stopped, we can auto resume + // the process. + bool m_did_exec; + + void *(*m_dyld_process_info_create)(task_t task, uint64_t timestamp, + kern_return_t *kernelError); + void (*m_dyld_process_info_for_each_image)( + void *info, void (^callback)(uint64_t machHeaderAddress, + const uuid_t uuid, const char *path)); + void (*m_dyld_process_info_release)(void *info); + void (*m_dyld_process_info_get_cache)(void *info, void *cacheInfo); }; - #endif // __MachProcess_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm index cea1772d27d..e0f3290ff0d 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm @@ -12,23 +12,23 @@ //===----------------------------------------------------------------------===// #include "DNB.h" +#include "MacOSX/CFUtils.h" +#include "SysSignal.h" #include <dlfcn.h> #include <inttypes.h> +#include <mach-o/loader.h> #include <mach/mach.h> #include <mach/task.h> +#include <pthread.h> #include <signal.h> #include <spawn.h> #include <sys/fcntl.h> -#include <sys/types.h> #include <sys/ptrace.h> #include <sys/stat.h> #include <sys/sysctl.h> +#include <sys/types.h> #include <unistd.h> -#include <pthread.h> -#include <mach-o/loader.h> #include <uuid/uuid.h> -#include "MacOSX/CFUtils.h" -#include "SysSignal.h" #include <algorithm> #include <map> @@ -48,329 +48,359 @@ #ifdef WITH_SPRINGBOARD #include <CoreFoundation/CoreFoundation.h> -#include <SpringBoardServices/SpringBoardServer.h> #include <SpringBoardServices/SBSWatchdogAssertion.h> +#include <SpringBoardServices/SpringBoardServer.h> -static bool -IsSBProcess (nub_process_t pid) -{ - CFReleaser<CFArrayRef> appIdsForPID (::SBSCopyDisplayIdentifiersForProcessID(pid)); - return appIdsForPID.get() != NULL; +static bool IsSBProcess(nub_process_t pid) { + CFReleaser<CFArrayRef> appIdsForPID( + ::SBSCopyDisplayIdentifiersForProcessID(pid)); + return appIdsForPID.get() != NULL; } #endif // WITH_SPRINGBOARD -#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined (WITH_FBS) +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) // This returns a CFRetained pointer to the Bundle ID for app_bundle_path, // or NULL if there was some problem getting the bundle id. -static CFStringRef CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str); +static CFStringRef CopyBundleIDForPath(const char *app_bundle_path, + DNBError &err_str); #endif #if defined(WITH_BKS) || defined(WITH_FBS) #import <Foundation/Foundation.h> static const int OPEN_APPLICATION_TIMEOUT_ERROR = 111; -typedef void (*SetErrorFunction) (NSInteger, DNBError &); -typedef bool (*CallOpenApplicationFunction) (NSString *bundleIDNSStr, NSDictionary *options, DNBError &error, pid_t *return_pid); -// This function runs the BKSSystemService (or FBSSystemService) method openApplication:options:clientPort:withResult, +typedef void (*SetErrorFunction)(NSInteger, DNBError &); +typedef bool (*CallOpenApplicationFunction)(NSString *bundleIDNSStr, + NSDictionary *options, + DNBError &error, pid_t *return_pid); +// This function runs the BKSSystemService (or FBSSystemService) method +// openApplication:options:clientPort:withResult, // messaging the app passed in bundleIDNSStr. // The function should be run inside of an NSAutoReleasePool. // -// It will use the "options" dictionary passed in, and fill the error passed in if there is an error. -// If return_pid is not NULL, we'll fetch the pid that was made for the bundleID. +// It will use the "options" dictionary passed in, and fill the error passed in +// if there is an error. +// If return_pid is not NULL, we'll fetch the pid that was made for the +// bundleID. // If bundleIDNSStr is NULL, then the system application will be messaged. -template <typename OpenFlavor, typename ErrorFlavor, ErrorFlavor no_error_enum_value, SetErrorFunction error_function> -static bool -CallBoardSystemServiceOpenApplication (NSString *bundleIDNSStr, NSDictionary *options, DNBError &error, pid_t *return_pid) -{ - // Now make our systemService: - OpenFlavor *system_service = [[OpenFlavor alloc] init]; - - if (bundleIDNSStr == nil) - { - bundleIDNSStr = [system_service systemApplicationBundleIdentifier]; - if (bundleIDNSStr == nil) - { - // Okay, no system app... - error.SetErrorString("No system application to message."); - return false; - } - } - - mach_port_t client_port = [system_service createClientPort]; - __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __block ErrorFlavor open_app_error = no_error_enum_value; - bool wants_pid = (return_pid != NULL); - __block pid_t pid_in_block; - - const char *cstr = [bundleIDNSStr UTF8String]; - if (!cstr) - cstr = "<Unknown Bundle ID>"; - - DNBLog ("About to launch process for bundle ID: %s", cstr); - [system_service openApplication: bundleIDNSStr - options: options - clientPort: client_port - withResult: ^(NSError *bks_error) - { - // The system service will cleanup the client port we created for us. - if (bks_error) - open_app_error = (ErrorFlavor)[bks_error code]; - - if (open_app_error == no_error_enum_value) - { - if (wants_pid) - { - pid_in_block = [system_service pidForApplication: bundleIDNSStr]; - DNBLog("In completion handler, got pid for bundle id, pid: %d.", pid_in_block); - DNBLogThreadedIf(LOG_PROCESS, "In completion handler, got pid for bundle id, pid: %d.", pid_in_block); - } - else - DNBLogThreadedIf (LOG_PROCESS, "In completion handler: success."); - } - else - { - const char *error_str = [(NSString *)[bks_error localizedDescription] UTF8String]; - DNBLogThreadedIf(LOG_PROCESS, "In completion handler for send event, got error \"%s\"(%ld).", - error_str ? error_str : "<unknown error>", - open_app_error); - // REMOVE ME - DNBLogError ("In completion handler for send event, got error \"%s\"(%ld).", - error_str ? error_str : "<unknown error>", - open_app_error); - } - - [system_service release]; - dispatch_semaphore_signal(semaphore); - } - - ]; - - const uint32_t timeout_secs = 9; - - dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); - - long success = dispatch_semaphore_wait(semaphore, timeout) == 0; - - dispatch_release(semaphore); - - if (!success) -{ - DNBLogError("timed out trying to send openApplication to %s.", cstr); - error.SetError (OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); - error.SetErrorString ("timed out trying to launch app"); - } - else if (open_app_error != no_error_enum_value) - { - error_function (open_app_error, error); - DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %u", cstr, open_app_error); - success = false; - } - else if (wants_pid) - { - *return_pid = pid_in_block; - DNBLogThreadedIf (LOG_PROCESS, "Out of completion handler, pid from block %d and passing out: %d", pid_in_block, *return_pid); -} - - - return success; +template <typename OpenFlavor, typename ErrorFlavor, + ErrorFlavor no_error_enum_value, SetErrorFunction error_function> +static bool CallBoardSystemServiceOpenApplication(NSString *bundleIDNSStr, + NSDictionary *options, + DNBError &error, + pid_t *return_pid) { + // Now make our systemService: + OpenFlavor *system_service = [[OpenFlavor alloc] init]; + + if (bundleIDNSStr == nil) { + bundleIDNSStr = [system_service systemApplicationBundleIdentifier]; + if (bundleIDNSStr == nil) { + // Okay, no system app... + error.SetErrorString("No system application to message."); + return false; + } + } + + mach_port_t client_port = [system_service createClientPort]; + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block ErrorFlavor open_app_error = no_error_enum_value; + bool wants_pid = (return_pid != NULL); + __block pid_t pid_in_block; + + const char *cstr = [bundleIDNSStr UTF8String]; + if (!cstr) + cstr = "<Unknown Bundle ID>"; + + DNBLog("About to launch process for bundle ID: %s", cstr); + [system_service + openApplication:bundleIDNSStr + options:options + clientPort:client_port + withResult:^(NSError *bks_error) { + // The system service will cleanup the client port we created for + // us. + if (bks_error) + open_app_error = (ErrorFlavor)[bks_error code]; + + if (open_app_error == no_error_enum_value) { + if (wants_pid) { + pid_in_block = + [system_service pidForApplication:bundleIDNSStr]; + DNBLog( + "In completion handler, got pid for bundle id, pid: %d.", + pid_in_block); + DNBLogThreadedIf( + LOG_PROCESS, + "In completion handler, got pid for bundle id, pid: %d.", + pid_in_block); + } else + DNBLogThreadedIf(LOG_PROCESS, + "In completion handler: success."); + } else { + const char *error_str = + [(NSString *)[bks_error localizedDescription] UTF8String]; + DNBLogThreadedIf(LOG_PROCESS, "In completion handler for send " + "event, got error \"%s\"(%ld).", + error_str ? error_str : "<unknown error>", + open_app_error); + // REMOVE ME + DNBLogError("In completion handler for send event, got error " + "\"%s\"(%ld).", + error_str ? error_str : "<unknown error>", + open_app_error); + } + + [system_service release]; + dispatch_semaphore_signal(semaphore); + } + + ]; + + const uint32_t timeout_secs = 9; + + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); + + long success = dispatch_semaphore_wait(semaphore, timeout) == 0; + + dispatch_release(semaphore); + + if (!success) { + DNBLogError("timed out trying to send openApplication to %s.", cstr); + error.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); + error.SetErrorString("timed out trying to launch app"); + } else if (open_app_error != no_error_enum_value) { + error_function(open_app_error, error); + DNBLogError("unable to launch the application with CFBundleIdentifier '%s' " + "bks_error = %u", + cstr, open_app_error); + success = false; + } else if (wants_pid) { + *return_pid = pid_in_block; + DNBLogThreadedIf( + LOG_PROCESS, + "Out of completion handler, pid from block %d and passing out: %d", + pid_in_block, *return_pid); + } + + return success; } #endif #ifdef WITH_BKS #import <Foundation/Foundation.h> -extern "C" -{ -#import <BackBoardServices/BackBoardServices.h> -#import <BackBoardServices/BKSSystemService_LaunchServices.h> +extern "C" { #import <BackBoardServices/BKSOpenApplicationConstants_Private.h> +#import <BackBoardServices/BKSSystemService_LaunchServices.h> +#import <BackBoardServices/BackBoardServices.h> } -static bool -IsBKSProcess (nub_process_t pid) -{ - BKSApplicationStateMonitor *state_monitor = [[BKSApplicationStateMonitor alloc] init]; - BKSApplicationState app_state = [state_monitor mostElevatedApplicationStateForPID: pid]; - return app_state != BKSApplicationStateUnknown; -} - -static void -SetBKSError (NSInteger error_code, DNBError &error) -{ - error.SetError (error_code, DNBError::BackBoard); - NSString *err_nsstr = ::BKSOpenApplicationErrorCodeToString((BKSOpenApplicationErrorCode) error_code); - const char *err_str = NULL; - if (err_nsstr == NULL) - err_str = "unknown BKS error"; - else - { - err_str = [err_nsstr UTF8String]; - if (err_str == NULL) - err_str = "unknown BKS error"; - } - error.SetErrorString(err_str); -} - -static bool -BKSAddEventDataToOptions (NSMutableDictionary *options, const char *event_data, DNBError &option_error) -{ - if (strcmp (event_data, "BackgroundContentFetching") == 0) - { - DNBLog("Setting ActivateForEvent key in options dictionary."); - NSDictionary *event_details = [NSDictionary dictionary]; - NSDictionary *event_dictionary = [NSDictionary dictionaryWithObject:event_details forKey:BKSActivateForEventOptionTypeBackgroundContentFetching]; - [options setObject: event_dictionary forKey: BKSOpenApplicationOptionKeyActivateForEvent]; - return true; - } - else - { - DNBLogError ("Unrecognized event type: %s. Ignoring.", event_data); - option_error.SetErrorString("Unrecognized event data."); - return false; - } - -} - -static NSMutableDictionary * -BKSCreateOptionsDictionary(const char *app_bundle_path, NSMutableArray *launch_argv, NSMutableDictionary *launch_envp, NSString *stdio_path, bool disable_aslr, const char *event_data) -{ - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - if (launch_argv != nil) - [debug_options setObject: launch_argv forKey: BKSDebugOptionKeyArguments]; - if (launch_envp != nil) - [debug_options setObject: launch_envp forKey: BKSDebugOptionKeyEnvironment]; - - [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardOutPath]; - [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardErrorPath]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyWaitForDebugger]; - if (disable_aslr) - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyDisableASLR]; - - // That will go in the overall dictionary: - - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; - // And there are some other options at the top level in this dictionary: - [options setObject: [NSNumber numberWithBool: YES] forKey: BKSOpenApplicationOptionKeyUnlockDevice]; - - DNBError error; - BKSAddEventDataToOptions (options, event_data, error); - - return options; -} - -static CallOpenApplicationFunction BKSCallOpenApplicationFunction = CallBoardSystemServiceOpenApplication<BKSSystemService, BKSOpenApplicationErrorCode, BKSOpenApplicationErrorCodeNone, SetBKSError>; +static bool IsBKSProcess(nub_process_t pid) { + BKSApplicationStateMonitor *state_monitor = + [[BKSApplicationStateMonitor alloc] init]; + BKSApplicationState app_state = + [state_monitor mostElevatedApplicationStateForPID:pid]; + return app_state != BKSApplicationStateUnknown; +} + +static void SetBKSError(NSInteger error_code, DNBError &error) { + error.SetError(error_code, DNBError::BackBoard); + NSString *err_nsstr = ::BKSOpenApplicationErrorCodeToString( + (BKSOpenApplicationErrorCode)error_code); + const char *err_str = NULL; + if (err_nsstr == NULL) + err_str = "unknown BKS error"; + else { + err_str = [err_nsstr UTF8String]; + if (err_str == NULL) + err_str = "unknown BKS error"; + } + error.SetErrorString(err_str); +} + +static bool BKSAddEventDataToOptions(NSMutableDictionary *options, + const char *event_data, + DNBError &option_error) { + if (strcmp(event_data, "BackgroundContentFetching") == 0) { + DNBLog("Setting ActivateForEvent key in options dictionary."); + NSDictionary *event_details = [NSDictionary dictionary]; + NSDictionary *event_dictionary = [NSDictionary + dictionaryWithObject:event_details + forKey: + BKSActivateForEventOptionTypeBackgroundContentFetching]; + [options setObject:event_dictionary + forKey:BKSOpenApplicationOptionKeyActivateForEvent]; + return true; + } else { + DNBLogError("Unrecognized event type: %s. Ignoring.", event_data); + option_error.SetErrorString("Unrecognized event data."); + return false; + } +} + +static NSMutableDictionary *BKSCreateOptionsDictionary( + const char *app_bundle_path, NSMutableArray *launch_argv, + NSMutableDictionary *launch_envp, NSString *stdio_path, bool disable_aslr, + const char *event_data) { + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + if (launch_argv != nil) + [debug_options setObject:launch_argv forKey:BKSDebugOptionKeyArguments]; + if (launch_envp != nil) + [debug_options setObject:launch_envp forKey:BKSDebugOptionKeyEnvironment]; + + [debug_options setObject:stdio_path forKey:BKSDebugOptionKeyStandardOutPath]; + [debug_options setObject:stdio_path + forKey:BKSDebugOptionKeyStandardErrorPath]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:BKSDebugOptionKeyWaitForDebugger]; + if (disable_aslr) + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:BKSDebugOptionKeyDisableASLR]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject:debug_options + forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; + // And there are some other options at the top level in this dictionary: + [options setObject:[NSNumber numberWithBool:YES] + forKey:BKSOpenApplicationOptionKeyUnlockDevice]; + + DNBError error; + BKSAddEventDataToOptions(options, event_data, error); + + return options; +} + +static CallOpenApplicationFunction BKSCallOpenApplicationFunction = + CallBoardSystemServiceOpenApplication< + BKSSystemService, BKSOpenApplicationErrorCode, + BKSOpenApplicationErrorCodeNone, SetBKSError>; #endif // WITH_BKS #ifdef WITH_FBS #import <Foundation/Foundation.h> -extern "C" -{ -#import <FrontBoardServices/FrontBoardServices.h> -#import <FrontBoardServices/FBSSystemService_LaunchServices.h> +extern "C" { #import <FrontBoardServices/FBSOpenApplicationConstants_Private.h> -#import <MobileCoreServices/MobileCoreServices.h> +#import <FrontBoardServices/FBSSystemService_LaunchServices.h> +#import <FrontBoardServices/FrontBoardServices.h> #import <MobileCoreServices/LSResourceProxy.h> +#import <MobileCoreServices/MobileCoreServices.h> } #ifdef WITH_BKS -static bool -IsFBSProcess (nub_process_t pid) -{ - BKSApplicationStateMonitor *state_monitor = [[BKSApplicationStateMonitor alloc] init]; - BKSApplicationState app_state = [state_monitor mostElevatedApplicationStateForPID: pid]; - return app_state != BKSApplicationStateUnknown; +static bool IsFBSProcess(nub_process_t pid) { + BKSApplicationStateMonitor *state_monitor = + [[BKSApplicationStateMonitor alloc] init]; + BKSApplicationState app_state = + [state_monitor mostElevatedApplicationStateForPID:pid]; + return app_state != BKSApplicationStateUnknown; } #else -static bool -IsFBSProcess (nub_process_t pid) -{ - // FIXME: What is the FBS equivalent of BKSApplicationStateMonitor - return true; +static bool IsFBSProcess(nub_process_t pid) { + // FIXME: What is the FBS equivalent of BKSApplicationStateMonitor + return true; } #endif -static void -SetFBSError (NSInteger error_code, DNBError &error) -{ - error.SetError ((DNBError::ValueType) error_code, DNBError::FrontBoard); - NSString *err_nsstr = ::FBSOpenApplicationErrorCodeToString((FBSOpenApplicationErrorCode) error_code); - const char *err_str = NULL; - if (err_nsstr == NULL) - err_str = "unknown FBS error"; - else - { - err_str = [err_nsstr UTF8String]; - if (err_str == NULL) - err_str = "unknown FBS error"; - } - error.SetErrorString(err_str); -} - -static bool -FBSAddEventDataToOptions (NSMutableDictionary *options, const char *event_data, DNBError &option_error) -{ - if (strcmp (event_data, "BackgroundContentFetching") == 0) - { - DNBLog("Setting ActivateForEvent key in options dictionary."); - NSDictionary *event_details = [NSDictionary dictionary]; - NSDictionary *event_dictionary = [NSDictionary dictionaryWithObject:event_details forKey:FBSActivateForEventOptionTypeBackgroundContentFetching]; - [options setObject: event_dictionary forKey: FBSOpenApplicationOptionKeyActivateForEvent]; - return true; - } - else - { - DNBLogError ("Unrecognized event type: %s. Ignoring.", event_data); - option_error.SetErrorString("Unrecognized event data."); - return false; - } - +static void SetFBSError(NSInteger error_code, DNBError &error) { + error.SetError((DNBError::ValueType)error_code, DNBError::FrontBoard); + NSString *err_nsstr = ::FBSOpenApplicationErrorCodeToString( + (FBSOpenApplicationErrorCode)error_code); + const char *err_str = NULL; + if (err_nsstr == NULL) + err_str = "unknown FBS error"; + else { + err_str = [err_nsstr UTF8String]; + if (err_str == NULL) + err_str = "unknown FBS error"; + } + error.SetErrorString(err_str); +} + +static bool FBSAddEventDataToOptions(NSMutableDictionary *options, + const char *event_data, + DNBError &option_error) { + if (strcmp(event_data, "BackgroundContentFetching") == 0) { + DNBLog("Setting ActivateForEvent key in options dictionary."); + NSDictionary *event_details = [NSDictionary dictionary]; + NSDictionary *event_dictionary = [NSDictionary + dictionaryWithObject:event_details + forKey: + FBSActivateForEventOptionTypeBackgroundContentFetching]; + [options setObject:event_dictionary + forKey:FBSOpenApplicationOptionKeyActivateForEvent]; + return true; + } else { + DNBLogError("Unrecognized event type: %s. Ignoring.", event_data); + option_error.SetErrorString("Unrecognized event data."); + return false; + } } static NSMutableDictionary * -FBSCreateOptionsDictionary(const char *app_bundle_path, NSMutableArray *launch_argv, NSDictionary *launch_envp, NSString *stdio_path, bool disable_aslr, const char *event_data) -{ - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - - if (launch_argv != nil) - [debug_options setObject: launch_argv forKey: FBSDebugOptionKeyArguments]; - if (launch_envp != nil) - [debug_options setObject: launch_envp forKey: FBSDebugOptionKeyEnvironment]; - - [debug_options setObject: stdio_path forKey: FBSDebugOptionKeyStandardOutPath]; - [debug_options setObject: stdio_path forKey: FBSDebugOptionKeyStandardErrorPath]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: FBSDebugOptionKeyWaitForDebugger]; - if (disable_aslr) - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: FBSDebugOptionKeyDisableASLR]; - - // That will go in the overall dictionary: - - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - [options setObject: debug_options forKey: FBSOpenApplicationOptionKeyDebuggingOptions]; - // And there are some other options at the top level in this dictionary: - [options setObject: [NSNumber numberWithBool: YES] forKey: FBSOpenApplicationOptionKeyUnlockDevice]; - - // We have to get the "sequence ID & UUID" for this app bundle path and send them to FBS: - - NSURL *app_bundle_url = [NSURL fileURLWithPath: [NSString stringWithUTF8String: app_bundle_path] isDirectory: YES]; - LSApplicationProxy *app_proxy = [LSApplicationProxy applicationProxyForBundleURL: app_bundle_url]; - if (app_proxy) - { - DNBLog("Sending AppProxy info: sequence no: %lu, GUID: %s.", app_proxy.sequenceNumber, [app_proxy.cacheGUID.UUIDString UTF8String]); - [options setObject: [NSNumber numberWithUnsignedInteger: app_proxy.sequenceNumber] forKey: FBSOpenApplicationOptionKeyLSSequenceNumber]; - [options setObject: app_proxy.cacheGUID.UUIDString forKey: FBSOpenApplicationOptionKeyLSCacheGUID]; - } - - DNBError error; - FBSAddEventDataToOptions (options, event_data, error); - - return options; -} -static CallOpenApplicationFunction FBSCallOpenApplicationFunction = CallBoardSystemServiceOpenApplication<FBSSystemService, FBSOpenApplicationErrorCode, FBSOpenApplicationErrorCodeNone, SetFBSError>; +FBSCreateOptionsDictionary(const char *app_bundle_path, + NSMutableArray *launch_argv, + NSDictionary *launch_envp, NSString *stdio_path, + bool disable_aslr, const char *event_data) { + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + + if (launch_argv != nil) + [debug_options setObject:launch_argv forKey:FBSDebugOptionKeyArguments]; + if (launch_envp != nil) + [debug_options setObject:launch_envp forKey:FBSDebugOptionKeyEnvironment]; + + [debug_options setObject:stdio_path forKey:FBSDebugOptionKeyStandardOutPath]; + [debug_options setObject:stdio_path + forKey:FBSDebugOptionKeyStandardErrorPath]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:FBSDebugOptionKeyWaitForDebugger]; + if (disable_aslr) + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:FBSDebugOptionKeyDisableASLR]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject:debug_options + forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; + // And there are some other options at the top level in this dictionary: + [options setObject:[NSNumber numberWithBool:YES] + forKey:FBSOpenApplicationOptionKeyUnlockDevice]; + + // We have to get the "sequence ID & UUID" for this app bundle path and send + // them to FBS: + + NSURL *app_bundle_url = + [NSURL fileURLWithPath:[NSString stringWithUTF8String:app_bundle_path] + isDirectory:YES]; + LSApplicationProxy *app_proxy = + [LSApplicationProxy applicationProxyForBundleURL:app_bundle_url]; + if (app_proxy) { + DNBLog("Sending AppProxy info: sequence no: %lu, GUID: %s.", + app_proxy.sequenceNumber, + [app_proxy.cacheGUID.UUIDString UTF8String]); + [options + setObject:[NSNumber numberWithUnsignedInteger:app_proxy.sequenceNumber] + forKey:FBSOpenApplicationOptionKeyLSSequenceNumber]; + [options setObject:app_proxy.cacheGUID.UUIDString + forKey:FBSOpenApplicationOptionKeyLSCacheGUID]; + } + + DNBError error; + FBSAddEventDataToOptions(options, event_data, error); + + return options; +} +static CallOpenApplicationFunction FBSCallOpenApplicationFunction = + CallBoardSystemServiceOpenApplication< + FBSSystemService, FBSOpenApplicationErrorCode, + FBSOpenApplicationErrorCodeNone, SetFBSError>; #endif // WITH_FBS #if 0 -#define DEBUG_LOG(fmt, ...) printf(fmt, ## __VA_ARGS__) +#define DEBUG_LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) #else #define DEBUG_LOG(fmt, ...) #endif @@ -380,1055 +410,1015 @@ static CallOpenApplicationFunction FBSCallOpenApplicationFunction = CallBoardSys #endif #ifndef _POSIX_SPAWN_DISABLE_ASLR -#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 +#define _POSIX_SPAWN_DISABLE_ASLR 0x0100 #endif -MachProcess::MachProcess() : - m_pid (0), - m_cpu_type (0), - m_child_stdin (-1), - m_child_stdout (-1), - m_child_stderr (-1), - m_path (), - m_args (), - m_task (this), - m_flags (eMachProcessFlagsNone), - m_stdio_thread (0), - m_stdio_mutex (PTHREAD_MUTEX_RECURSIVE), - m_stdout_data (), - m_profile_enabled (false), - m_profile_interval_usec (0), - m_profile_thread (0), - m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE), - m_profile_data (), - m_thread_actions (), - m_exception_messages (), - m_exception_messages_mutex (PTHREAD_MUTEX_RECURSIVE), - m_thread_list (), - m_activities (), - m_state (eStateUnloaded), - m_state_mutex (PTHREAD_MUTEX_RECURSIVE), - m_events (0, kAllEventsMask), - m_private_events (0, kAllEventsMask), - m_breakpoints (), - m_watchpoints (), - m_name_to_addr_callback(NULL), - m_name_to_addr_baton(NULL), - m_image_infos_callback(NULL), - m_image_infos_baton(NULL), - m_sent_interrupt_signo (0), - m_auto_resume_signo (0), - m_did_exec (false), - m_dyld_process_info_create (nullptr), - m_dyld_process_info_for_each_image (nullptr), - m_dyld_process_info_release (nullptr), - m_dyld_process_info_get_cache (nullptr) -{ - m_dyld_process_info_create = (void * (*) (task_t task, uint64_t timestamp, kern_return_t* kernelError)) dlsym (RTLD_DEFAULT, "_dyld_process_info_create"); - m_dyld_process_info_for_each_image = (void (*)(void *info, void (^)(uint64_t machHeaderAddress, const uuid_t uuid, const char* path))) dlsym (RTLD_DEFAULT, "_dyld_process_info_for_each_image"); - m_dyld_process_info_release = (void (*) (void* info)) dlsym (RTLD_DEFAULT, "_dyld_process_info_release"); - m_dyld_process_info_get_cache = (void (*) (void* info, void* cacheInfo)) dlsym (RTLD_DEFAULT, "_dyld_process_info_get_cache"); - - DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); -} - -MachProcess::~MachProcess() -{ - DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); - Clear(); -} - -pid_t -MachProcess::SetProcessID(pid_t pid) -{ - // Free any previous process specific data or resources - Clear(); - // Set the current PID appropriately - if (pid == 0) - m_pid = ::getpid (); - else - m_pid = pid; - return m_pid; // Return actually PID in case a zero pid was passed in +MachProcess::MachProcess() + : m_pid(0), m_cpu_type(0), m_child_stdin(-1), m_child_stdout(-1), + m_child_stderr(-1), m_path(), m_args(), m_task(this), + m_flags(eMachProcessFlagsNone), m_stdio_thread(0), + m_stdio_mutex(PTHREAD_MUTEX_RECURSIVE), m_stdout_data(), + m_profile_enabled(false), m_profile_interval_usec(0), m_profile_thread(0), + m_profile_data_mutex(PTHREAD_MUTEX_RECURSIVE), m_profile_data(), + m_thread_actions(), m_exception_messages(), + m_exception_messages_mutex(PTHREAD_MUTEX_RECURSIVE), m_thread_list(), + m_activities(), m_state(eStateUnloaded), + m_state_mutex(PTHREAD_MUTEX_RECURSIVE), m_events(0, kAllEventsMask), + m_private_events(0, kAllEventsMask), m_breakpoints(), m_watchpoints(), + m_name_to_addr_callback(NULL), m_name_to_addr_baton(NULL), + m_image_infos_callback(NULL), m_image_infos_baton(NULL), + m_sent_interrupt_signo(0), m_auto_resume_signo(0), m_did_exec(false), + m_dyld_process_info_create(nullptr), + m_dyld_process_info_for_each_image(nullptr), + m_dyld_process_info_release(nullptr), + m_dyld_process_info_get_cache(nullptr) { + m_dyld_process_info_create = + (void *(*)(task_t task, uint64_t timestamp, kern_return_t * kernelError)) + dlsym(RTLD_DEFAULT, "_dyld_process_info_create"); + m_dyld_process_info_for_each_image = + (void (*)(void *info, void (^)(uint64_t machHeaderAddress, + const uuid_t uuid, const char *path))) + dlsym(RTLD_DEFAULT, "_dyld_process_info_for_each_image"); + m_dyld_process_info_release = + (void (*)(void *info))dlsym(RTLD_DEFAULT, "_dyld_process_info_release"); + m_dyld_process_info_get_cache = (void (*)(void *info, void *cacheInfo))dlsym( + RTLD_DEFAULT, "_dyld_process_info_get_cache"); + + DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); } -nub_state_t -MachProcess::GetState() -{ - // If any other threads access this we will need a mutex for it - PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); - return m_state; +MachProcess::~MachProcess() { + DNBLogThreadedIf(LOG_PROCESS | LOG_VERBOSE, "%s", __PRETTY_FUNCTION__); + Clear(); } -const char * -MachProcess::ThreadGetName(nub_thread_t tid) -{ - return m_thread_list.GetName(tid); +pid_t MachProcess::SetProcessID(pid_t pid) { + // Free any previous process specific data or resources + Clear(); + // Set the current PID appropriately + if (pid == 0) + m_pid = ::getpid(); + else + m_pid = pid; + return m_pid; // Return actually PID in case a zero pid was passed in } -nub_state_t -MachProcess::ThreadGetState(nub_thread_t tid) -{ - return m_thread_list.GetState(tid); +nub_state_t MachProcess::GetState() { + // If any other threads access this we will need a mutex for it + PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); + return m_state; } +const char *MachProcess::ThreadGetName(nub_thread_t tid) { + return m_thread_list.GetName(tid); +} -nub_size_t -MachProcess::GetNumThreads () const -{ - return m_thread_list.NumThreads(); +nub_state_t MachProcess::ThreadGetState(nub_thread_t tid) { + return m_thread_list.GetState(tid); } -nub_thread_t -MachProcess::GetThreadAtIndex (nub_size_t thread_idx) const -{ - return m_thread_list.ThreadIDAtIndex(thread_idx); +nub_size_t MachProcess::GetNumThreads() const { + return m_thread_list.NumThreads(); } -nub_thread_t -MachProcess::GetThreadIDForMachPortNumber (thread_t mach_port_number) const -{ - return m_thread_list.GetThreadIDByMachPortNumber (mach_port_number); +nub_thread_t MachProcess::GetThreadAtIndex(nub_size_t thread_idx) const { + return m_thread_list.ThreadIDAtIndex(thread_idx); } -nub_bool_t -MachProcess::SyncThreadState (nub_thread_t tid) -{ - MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid)); - if (!thread_sp) - return false; - kern_return_t kret = ::thread_abort_safely(thread_sp->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%8.8" PRIx32 " calling thread_abort_safely (tid) => %u (GetGPRState() for stop_count = %u)", thread_sp->MachPortNumber(), kret, thread_sp->Process()->StopCount()); +nub_thread_t +MachProcess::GetThreadIDForMachPortNumber(thread_t mach_port_number) const { + return m_thread_list.GetThreadIDByMachPortNumber(mach_port_number); +} - if (kret == KERN_SUCCESS) - return true; - else - return false; - +nub_bool_t MachProcess::SyncThreadState(nub_thread_t tid) { + MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid)); + if (!thread_sp) + return false; + kern_return_t kret = ::thread_abort_safely(thread_sp->MachPortNumber()); + DNBLogThreadedIf(LOG_THREAD, "thread = 0x%8.8" PRIx32 + " calling thread_abort_safely (tid) => %u " + "(GetGPRState() for stop_count = %u)", + thread_sp->MachPortNumber(), kret, + thread_sp->Process()->StopCount()); + + if (kret == KERN_SUCCESS) + return true; + else + return false; } -ThreadInfo::QoS -MachProcess::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) -{ - return m_thread_list.GetRequestedQoS (tid, tsd, dti_qos_class_index); +ThreadInfo::QoS MachProcess::GetRequestedQoS(nub_thread_t tid, nub_addr_t tsd, + uint64_t dti_qos_class_index) { + return m_thread_list.GetRequestedQoS(tid, tsd, dti_qos_class_index); } -nub_addr_t -MachProcess::GetPThreadT (nub_thread_t tid) -{ - return m_thread_list.GetPThreadT (tid); +nub_addr_t MachProcess::GetPThreadT(nub_thread_t tid) { + return m_thread_list.GetPThreadT(tid); } -nub_addr_t -MachProcess::GetDispatchQueueT (nub_thread_t tid) -{ - return m_thread_list.GetDispatchQueueT (tid); +nub_addr_t MachProcess::GetDispatchQueueT(nub_thread_t tid) { + return m_thread_list.GetDispatchQueueT(tid); } -nub_addr_t -MachProcess::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) -{ - return m_thread_list.GetTSDAddressForThread (tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); +nub_addr_t MachProcess::GetTSDAddressForThread( + nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) { + return m_thread_list.GetTSDAddressForThread( + tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, + plo_pthread_tsd_entry_size); } -// Given an address, read the mach-o header and load commands out of memory to fill in +// Given an address, read the mach-o header and load commands out of memory to +// fill in // the mach_o_information "inf" object. // -// Returns false if there was an error in reading this mach-o file header/load commands. - -bool -MachProcess::GetMachOInformationFromMemory (nub_addr_t mach_o_header_addr, int wordsize, struct mach_o_information &inf) -{ - uint64_t load_cmds_p; - if (wordsize == 4) - { - struct mach_header header; - if (ReadMemory (mach_o_header_addr, sizeof (struct mach_header), &header) != sizeof (struct mach_header)) - { - return false; - } - load_cmds_p = mach_o_header_addr + sizeof (struct mach_header); - inf.mach_header.magic = header.magic; - inf.mach_header.cputype = header.cputype; - // high byte of cpusubtype is used for "capability bits", v. CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h - inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; - inf.mach_header.filetype = header.filetype; - inf.mach_header.ncmds = header.ncmds; - inf.mach_header.sizeofcmds = header.sizeofcmds; - inf.mach_header.flags = header.flags; - } - else - { - struct mach_header_64 header; - if (ReadMemory (mach_o_header_addr, sizeof (struct mach_header_64), &header) != sizeof (struct mach_header_64)) - { - return false; - } - load_cmds_p = mach_o_header_addr + sizeof (struct mach_header_64); - inf.mach_header.magic = header.magic; - inf.mach_header.cputype = header.cputype; - // high byte of cpusubtype is used for "capability bits", v. CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h - inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; - inf.mach_header.filetype = header.filetype; - inf.mach_header.ncmds = header.ncmds; - inf.mach_header.sizeofcmds = header.sizeofcmds; - inf.mach_header.flags = header.flags; - } - for (uint32_t j = 0; j < inf.mach_header.ncmds; j++) - { - struct load_command lc; - if (ReadMemory (load_cmds_p, sizeof (struct load_command), &lc) != sizeof (struct load_command)) - { - return false; - } - if (lc.cmd == LC_SEGMENT) - { - struct segment_command seg; - if (ReadMemory (load_cmds_p, sizeof (struct segment_command), &seg) != sizeof (struct segment_command)) - { - return false; - } - struct mach_o_segment this_seg; - char name[17]; - ::memset (name, 0, sizeof (name)); - memcpy (name, seg.segname, sizeof (seg.segname)); - this_seg.name = name; - this_seg.vmaddr = seg.vmaddr; - this_seg.vmsize = seg.vmsize; - this_seg.fileoff = seg.fileoff; - this_seg.filesize = seg.filesize; - this_seg.maxprot = seg.maxprot; - this_seg.initprot = seg.initprot; - this_seg.nsects = seg.nsects; - this_seg.flags = seg.flags; - inf.segments.push_back(this_seg); - } - if (lc.cmd == LC_SEGMENT_64) - { - struct segment_command_64 seg; - if (ReadMemory (load_cmds_p, sizeof (struct segment_command_64), &seg) != sizeof (struct segment_command_64)) - { - return false; - } - struct mach_o_segment this_seg; - char name[17]; - ::memset (name, 0, sizeof (name)); - memcpy (name, seg.segname, sizeof (seg.segname)); - this_seg.name = name; - this_seg.vmaddr = seg.vmaddr; - this_seg.vmsize = seg.vmsize; - this_seg.fileoff = seg.fileoff; - this_seg.filesize = seg.filesize; - this_seg.maxprot = seg.maxprot; - this_seg.initprot = seg.initprot; - this_seg.nsects = seg.nsects; - this_seg.flags = seg.flags; - inf.segments.push_back(this_seg); - } - if (lc.cmd == LC_UUID) - { - struct uuid_command uuidcmd; - if (ReadMemory (load_cmds_p, sizeof (struct uuid_command), &uuidcmd) == sizeof (struct uuid_command)) - uuid_copy (inf.uuid, uuidcmd.uuid); - } - bool lc_cmd_known = lc.cmd == LC_VERSION_MIN_IPHONEOS || lc.cmd == LC_VERSION_MIN_MACOSX; +// Returns false if there was an error in reading this mach-o file header/load +// commands. + +bool MachProcess::GetMachOInformationFromMemory( + nub_addr_t mach_o_header_addr, int wordsize, + struct mach_o_information &inf) { + uint64_t load_cmds_p; + if (wordsize == 4) { + struct mach_header header; + if (ReadMemory(mach_o_header_addr, sizeof(struct mach_header), &header) != + sizeof(struct mach_header)) { + return false; + } + load_cmds_p = mach_o_header_addr + sizeof(struct mach_header); + inf.mach_header.magic = header.magic; + inf.mach_header.cputype = header.cputype; + // high byte of cpusubtype is used for "capability bits", v. + // CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h + inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; + inf.mach_header.filetype = header.filetype; + inf.mach_header.ncmds = header.ncmds; + inf.mach_header.sizeofcmds = header.sizeofcmds; + inf.mach_header.flags = header.flags; + } else { + struct mach_header_64 header; + if (ReadMemory(mach_o_header_addr, sizeof(struct mach_header_64), + &header) != sizeof(struct mach_header_64)) { + return false; + } + load_cmds_p = mach_o_header_addr + sizeof(struct mach_header_64); + inf.mach_header.magic = header.magic; + inf.mach_header.cputype = header.cputype; + // high byte of cpusubtype is used for "capability bits", v. + // CPU_SUBTYPE_MASK, CPU_SUBTYPE_LIB64 in machine.h + inf.mach_header.cpusubtype = header.cpusubtype & 0x00ffffff; + inf.mach_header.filetype = header.filetype; + inf.mach_header.ncmds = header.ncmds; + inf.mach_header.sizeofcmds = header.sizeofcmds; + inf.mach_header.flags = header.flags; + } + for (uint32_t j = 0; j < inf.mach_header.ncmds; j++) { + struct load_command lc; + if (ReadMemory(load_cmds_p, sizeof(struct load_command), &lc) != + sizeof(struct load_command)) { + return false; + } + if (lc.cmd == LC_SEGMENT) { + struct segment_command seg; + if (ReadMemory(load_cmds_p, sizeof(struct segment_command), &seg) != + sizeof(struct segment_command)) { + return false; + } + struct mach_o_segment this_seg; + char name[17]; + ::memset(name, 0, sizeof(name)); + memcpy(name, seg.segname, sizeof(seg.segname)); + this_seg.name = name; + this_seg.vmaddr = seg.vmaddr; + this_seg.vmsize = seg.vmsize; + this_seg.fileoff = seg.fileoff; + this_seg.filesize = seg.filesize; + this_seg.maxprot = seg.maxprot; + this_seg.initprot = seg.initprot; + this_seg.nsects = seg.nsects; + this_seg.flags = seg.flags; + inf.segments.push_back(this_seg); + } + if (lc.cmd == LC_SEGMENT_64) { + struct segment_command_64 seg; + if (ReadMemory(load_cmds_p, sizeof(struct segment_command_64), &seg) != + sizeof(struct segment_command_64)) { + return false; + } + struct mach_o_segment this_seg; + char name[17]; + ::memset(name, 0, sizeof(name)); + memcpy(name, seg.segname, sizeof(seg.segname)); + this_seg.name = name; + this_seg.vmaddr = seg.vmaddr; + this_seg.vmsize = seg.vmsize; + this_seg.fileoff = seg.fileoff; + this_seg.filesize = seg.filesize; + this_seg.maxprot = seg.maxprot; + this_seg.initprot = seg.initprot; + this_seg.nsects = seg.nsects; + this_seg.flags = seg.flags; + inf.segments.push_back(this_seg); + } + if (lc.cmd == LC_UUID) { + struct uuid_command uuidcmd; + if (ReadMemory(load_cmds_p, sizeof(struct uuid_command), &uuidcmd) == + sizeof(struct uuid_command)) + uuid_copy(inf.uuid, uuidcmd.uuid); + } + bool lc_cmd_known = + lc.cmd == LC_VERSION_MIN_IPHONEOS || lc.cmd == LC_VERSION_MIN_MACOSX; #if defined(LC_VERSION_MIN_TVOS) - lc_cmd_known |= lc.cmd == LC_VERSION_MIN_TVOS; + lc_cmd_known |= lc.cmd == LC_VERSION_MIN_TVOS; #endif #if defined(LC_VERSION_MIN_WATCHOS) - lc_cmd_known |= lc.cmd == LC_VERSION_MIN_WATCHOS; + lc_cmd_known |= lc.cmd == LC_VERSION_MIN_WATCHOS; #endif - if (lc_cmd_known) - { - struct version_min_command vers_cmd; - if (ReadMemory (load_cmds_p, sizeof (struct version_min_command), &vers_cmd) != sizeof (struct version_min_command)) - { - return false; - } - switch (lc.cmd) - { - case LC_VERSION_MIN_IPHONEOS: - inf.min_version_os_name = "iphoneos"; - break; - case LC_VERSION_MIN_MACOSX: - inf.min_version_os_name = "macosx"; - break; + if (lc_cmd_known) { + struct version_min_command vers_cmd; + if (ReadMemory(load_cmds_p, sizeof(struct version_min_command), + &vers_cmd) != sizeof(struct version_min_command)) { + return false; + } + switch (lc.cmd) { + case LC_VERSION_MIN_IPHONEOS: + inf.min_version_os_name = "iphoneos"; + break; + case LC_VERSION_MIN_MACOSX: + inf.min_version_os_name = "macosx"; + break; #if defined(LC_VERSION_MIN_TVOS) - case LC_VERSION_MIN_TVOS: - inf.min_version_os_name = "tvos"; - break; + case LC_VERSION_MIN_TVOS: + inf.min_version_os_name = "tvos"; + break; #endif #if defined(LC_VERSION_MIN_WATCHOS) - case LC_VERSION_MIN_WATCHOS: - inf.min_version_os_name = "watchos"; - break; + case LC_VERSION_MIN_WATCHOS: + inf.min_version_os_name = "watchos"; + break; #endif - default: - return false; - } - uint32_t xxxx = vers_cmd.sdk >> 16; - uint32_t yy = (vers_cmd.sdk >> 8) & 0xffu; - uint32_t zz = vers_cmd.sdk & 0xffu; - inf.min_version_os_version = ""; - inf.min_version_os_version += std::to_string(xxxx); - inf.min_version_os_version += "."; - inf.min_version_os_version += std::to_string(yy); - if (zz != 0) - { - inf.min_version_os_version += "."; - inf.min_version_os_version += std::to_string(zz); - } - } - load_cmds_p += lc.cmdsize; - } - return true; -} - -// Given completely filled in array of binary_image_information structures, create a JSONGenerator object + default: + return false; + } + uint32_t xxxx = vers_cmd.sdk >> 16; + uint32_t yy = (vers_cmd.sdk >> 8) & 0xffu; + uint32_t zz = vers_cmd.sdk & 0xffu; + inf.min_version_os_version = ""; + inf.min_version_os_version += std::to_string(xxxx); + inf.min_version_os_version += "."; + inf.min_version_os_version += std::to_string(yy); + if (zz != 0) { + inf.min_version_os_version += "."; + inf.min_version_os_version += std::to_string(zz); + } + } + load_cmds_p += lc.cmdsize; + } + return true; +} + +// Given completely filled in array of binary_image_information structures, +// create a JSONGenerator object // with all the details we want to send to lldb. -JSONGenerator::ObjectSP -MachProcess::FormatDynamicLibrariesIntoJSON (const std::vector<struct binary_image_information> &image_infos) -{ - - JSONGenerator::ArraySP image_infos_array_sp (new JSONGenerator::Array()); - - const size_t image_count = image_infos.size(); - - for (size_t i = 0; i < image_count; i++) - { - JSONGenerator::DictionarySP image_info_dict_sp (new JSONGenerator::Dictionary()); - image_info_dict_sp->AddIntegerItem ("load_address", image_infos[i].load_address); - image_info_dict_sp->AddIntegerItem ("mod_date", image_infos[i].mod_date); - image_info_dict_sp->AddStringItem ("pathname", image_infos[i].filename); - - uuid_string_t uuidstr; - uuid_unparse_upper (image_infos[i].macho_info.uuid, uuidstr); - image_info_dict_sp->AddStringItem ("uuid", uuidstr); - - if (image_infos[i].macho_info.min_version_os_name.empty() == false - && image_infos[i].macho_info.min_version_os_version.empty() == false) - { - image_info_dict_sp->AddStringItem ("min_version_os_name", image_infos[i].macho_info.min_version_os_name); - image_info_dict_sp->AddStringItem ("min_version_os_sdk", image_infos[i].macho_info.min_version_os_version); - } - - JSONGenerator::DictionarySP mach_header_dict_sp (new JSONGenerator::Dictionary()); - mach_header_dict_sp->AddIntegerItem ("magic", image_infos[i].macho_info.mach_header.magic); - mach_header_dict_sp->AddIntegerItem ("cputype", (uint32_t) image_infos[i].macho_info.mach_header.cputype); - mach_header_dict_sp->AddIntegerItem ("cpusubtype", (uint32_t) image_infos[i].macho_info.mach_header.cpusubtype); - mach_header_dict_sp->AddIntegerItem ("filetype", image_infos[i].macho_info.mach_header.filetype); - -// DynamicLoaderMacOSX doesn't currently need these fields, so don't send them. -// mach_header_dict_sp->AddIntegerItem ("ncmds", image_infos[i].macho_info.mach_header.ncmds); -// mach_header_dict_sp->AddIntegerItem ("sizeofcmds", image_infos[i].macho_info.mach_header.sizeofcmds); -// mach_header_dict_sp->AddIntegerItem ("flags", image_infos[i].macho_info.mach_header.flags); - image_info_dict_sp->AddItem ("mach_header", mach_header_dict_sp); - - JSONGenerator::ArraySP segments_sp (new JSONGenerator::Array()); - for (size_t j = 0; j < image_infos[i].macho_info.segments.size(); j++) - { - JSONGenerator::DictionarySP segment_sp (new JSONGenerator::Dictionary()); - segment_sp->AddStringItem ("name", image_infos[i].macho_info.segments[j].name); - segment_sp->AddIntegerItem ("vmaddr", image_infos[i].macho_info.segments[j].vmaddr); - segment_sp->AddIntegerItem ("vmsize", image_infos[i].macho_info.segments[j].vmsize); - segment_sp->AddIntegerItem ("fileoff", image_infos[i].macho_info.segments[j].fileoff); - segment_sp->AddIntegerItem ("filesize", image_infos[i].macho_info.segments[j].filesize); - segment_sp->AddIntegerItem ("maxprot", image_infos[i].macho_info.segments[j].maxprot); - -// DynamicLoaderMacOSX doesn't currently need these fields, so don't send them. -// segment_sp->AddIntegerItem ("initprot", image_infos[i].macho_info.segments[j].initprot); -// segment_sp->AddIntegerItem ("nsects", image_infos[i].macho_info.segments[j].nsects); -// segment_sp->AddIntegerItem ("flags", image_infos[i].macho_info.segments[j].flags); - segments_sp->AddItem (segment_sp); - } - image_info_dict_sp->AddItem ("segments", segments_sp); - - image_infos_array_sp->AddItem (image_info_dict_sp); - } - - JSONGenerator::DictionarySP reply_sp (new JSONGenerator::Dictionary());; - reply_sp->AddItem ("images", image_infos_array_sp); - - return reply_sp; -} - -// Get the shared library information using the old (pre-macOS 10.12, pre-iOS 10, pre-tvOS 10, pre-watchOS 3) +JSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON( + const std::vector<struct binary_image_information> &image_infos) { + + JSONGenerator::ArraySP image_infos_array_sp(new JSONGenerator::Array()); + + const size_t image_count = image_infos.size(); + + for (size_t i = 0; i < image_count; i++) { + JSONGenerator::DictionarySP image_info_dict_sp( + new JSONGenerator::Dictionary()); + image_info_dict_sp->AddIntegerItem("load_address", + image_infos[i].load_address); + image_info_dict_sp->AddIntegerItem("mod_date", image_infos[i].mod_date); + image_info_dict_sp->AddStringItem("pathname", image_infos[i].filename); + + uuid_string_t uuidstr; + uuid_unparse_upper(image_infos[i].macho_info.uuid, uuidstr); + image_info_dict_sp->AddStringItem("uuid", uuidstr); + + if (image_infos[i].macho_info.min_version_os_name.empty() == false && + image_infos[i].macho_info.min_version_os_version.empty() == false) { + image_info_dict_sp->AddStringItem( + "min_version_os_name", image_infos[i].macho_info.min_version_os_name); + image_info_dict_sp->AddStringItem( + "min_version_os_sdk", + image_infos[i].macho_info.min_version_os_version); + } + + JSONGenerator::DictionarySP mach_header_dict_sp( + new JSONGenerator::Dictionary()); + mach_header_dict_sp->AddIntegerItem( + "magic", image_infos[i].macho_info.mach_header.magic); + mach_header_dict_sp->AddIntegerItem( + "cputype", (uint32_t)image_infos[i].macho_info.mach_header.cputype); + mach_header_dict_sp->AddIntegerItem( + "cpusubtype", + (uint32_t)image_infos[i].macho_info.mach_header.cpusubtype); + mach_header_dict_sp->AddIntegerItem( + "filetype", image_infos[i].macho_info.mach_header.filetype); + + // DynamicLoaderMacOSX doesn't currently need these fields, so + // don't send them. + // mach_header_dict_sp->AddIntegerItem ("ncmds", + // image_infos[i].macho_info.mach_header.ncmds); + // mach_header_dict_sp->AddIntegerItem ("sizeofcmds", + // image_infos[i].macho_info.mach_header.sizeofcmds); + // mach_header_dict_sp->AddIntegerItem ("flags", + // image_infos[i].macho_info.mach_header.flags); + image_info_dict_sp->AddItem("mach_header", mach_header_dict_sp); + + JSONGenerator::ArraySP segments_sp(new JSONGenerator::Array()); + for (size_t j = 0; j < image_infos[i].macho_info.segments.size(); j++) { + JSONGenerator::DictionarySP segment_sp(new JSONGenerator::Dictionary()); + segment_sp->AddStringItem("name", + image_infos[i].macho_info.segments[j].name); + segment_sp->AddIntegerItem("vmaddr", + image_infos[i].macho_info.segments[j].vmaddr); + segment_sp->AddIntegerItem("vmsize", + image_infos[i].macho_info.segments[j].vmsize); + segment_sp->AddIntegerItem("fileoff", + image_infos[i].macho_info.segments[j].fileoff); + segment_sp->AddIntegerItem( + "filesize", image_infos[i].macho_info.segments[j].filesize); + segment_sp->AddIntegerItem("maxprot", + image_infos[i].macho_info.segments[j].maxprot); + + // DynamicLoaderMacOSX doesn't currently need these fields, + // so don't send them. + // segment_sp->AddIntegerItem ("initprot", + // image_infos[i].macho_info.segments[j].initprot); + // segment_sp->AddIntegerItem ("nsects", + // image_infos[i].macho_info.segments[j].nsects); + // segment_sp->AddIntegerItem ("flags", + // image_infos[i].macho_info.segments[j].flags); + segments_sp->AddItem(segment_sp); + } + image_info_dict_sp->AddItem("segments", segments_sp); + + image_infos_array_sp->AddItem(image_info_dict_sp); + } + + JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary()); + ; + reply_sp->AddItem("images", image_infos_array_sp); + + return reply_sp; +} + +// Get the shared library information using the old (pre-macOS 10.12, pre-iOS +// 10, pre-tvOS 10, pre-watchOS 3) // code path. We'll be given the address of an array of structures in the form -// {void* load_addr, void* mod_date, void* pathname} +// {void* load_addr, void* mod_date, void* pathname} // -// In macOS 10.12 etc and newer, we'll use SPI calls into dyld to gather this information. -JSONGenerator::ObjectSP -MachProcess::GetLoadedDynamicLibrariesInfos (nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) -{ - JSONGenerator::DictionarySP reply_sp; - - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0) - { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; - - std::vector<struct binary_image_information> image_infos; - size_t image_infos_size = image_count * 3 * pointer_size; - - uint8_t *image_info_buf = (uint8_t *) malloc (image_infos_size); - if (image_info_buf == NULL) - { - return reply_sp; - } - if (ReadMemory (image_list_address, image_infos_size, image_info_buf) != image_infos_size) - { - return reply_sp; - } - - - //// First the image_infos array with (load addr, pathname, mod date) tuples - - - for (size_t i = 0; i < image_count; i++) - { - struct binary_image_information info; - nub_addr_t pathname_address; - if (pointer_size == 4) - { - uint32_t load_address_32; - uint32_t pathname_address_32; - uint32_t mod_date_32; - ::memcpy (&load_address_32, image_info_buf + (i * 3 * pointer_size), 4); - ::memcpy (&pathname_address_32, image_info_buf + (i * 3 * pointer_size) + pointer_size, 4); - ::memcpy (&mod_date_32, image_info_buf + (i * 3 * pointer_size) + pointer_size + pointer_size, 4); - info.load_address = load_address_32; - info.mod_date = mod_date_32; - pathname_address = pathname_address_32; - } - else - { - uint64_t load_address_64; - uint64_t pathname_address_64; - uint64_t mod_date_64; - ::memcpy (&load_address_64, image_info_buf + (i * 3 * pointer_size), 8); - ::memcpy (&pathname_address_64, image_info_buf + (i * 3 * pointer_size) + pointer_size, 8); - ::memcpy (&mod_date_64, image_info_buf + (i * 3 * pointer_size) + pointer_size + pointer_size, 8); - info.load_address = load_address_64; - info.mod_date = mod_date_64; - pathname_address = pathname_address_64; - } - char strbuf[17]; - info.filename = ""; - uint64_t pathname_ptr = pathname_address; - bool still_reading = true; - while (still_reading && ReadMemory (pathname_ptr, sizeof (strbuf) - 1, strbuf) == sizeof (strbuf) - 1) - { - strbuf[sizeof(strbuf) - 1] = '\0'; - info.filename += strbuf; - pathname_ptr += sizeof (strbuf) - 1; - // Stop if we found nul byte indicating the end of the string - for (size_t i = 0; i < sizeof(strbuf) - 1; i++) - { - if (strbuf[i] == '\0') - { - still_reading = false; - break; - } - } - } - uuid_clear (info.macho_info.uuid); - image_infos.push_back (info); - } - if (image_infos.size() == 0) - { - return reply_sp; +// In macOS 10.12 etc and newer, we'll use SPI calls into dyld to gather this +// information. +JSONGenerator::ObjectSP MachProcess::GetLoadedDynamicLibrariesInfos( + nub_process_t pid, nub_addr_t image_list_address, nub_addr_t image_count) { + JSONGenerator::DictionarySP reply_sp; + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, + NULL, 0) == 0 && + bufsize > 0) { + uint32_t pointer_size = 4; + if (processInfo.kp_proc.p_flag & P_LP64) + pointer_size = 8; + + std::vector<struct binary_image_information> image_infos; + size_t image_infos_size = image_count * 3 * pointer_size; + + uint8_t *image_info_buf = (uint8_t *)malloc(image_infos_size); + if (image_info_buf == NULL) { + return reply_sp; + } + if (ReadMemory(image_list_address, image_infos_size, image_info_buf) != + image_infos_size) { + return reply_sp; + } + + //// First the image_infos array with (load addr, pathname, mod date) + ///tuples + + for (size_t i = 0; i < image_count; i++) { + struct binary_image_information info; + nub_addr_t pathname_address; + if (pointer_size == 4) { + uint32_t load_address_32; + uint32_t pathname_address_32; + uint32_t mod_date_32; + ::memcpy(&load_address_32, image_info_buf + (i * 3 * pointer_size), 4); + ::memcpy(&pathname_address_32, + image_info_buf + (i * 3 * pointer_size) + pointer_size, 4); + ::memcpy(&mod_date_32, image_info_buf + (i * 3 * pointer_size) + + pointer_size + pointer_size, + 4); + info.load_address = load_address_32; + info.mod_date = mod_date_32; + pathname_address = pathname_address_32; + } else { + uint64_t load_address_64; + uint64_t pathname_address_64; + uint64_t mod_date_64; + ::memcpy(&load_address_64, image_info_buf + (i * 3 * pointer_size), 8); + ::memcpy(&pathname_address_64, + image_info_buf + (i * 3 * pointer_size) + pointer_size, 8); + ::memcpy(&mod_date_64, image_info_buf + (i * 3 * pointer_size) + + pointer_size + pointer_size, + 8); + info.load_address = load_address_64; + info.mod_date = mod_date_64; + pathname_address = pathname_address_64; + } + char strbuf[17]; + info.filename = ""; + uint64_t pathname_ptr = pathname_address; + bool still_reading = true; + while (still_reading && + ReadMemory(pathname_ptr, sizeof(strbuf) - 1, strbuf) == + sizeof(strbuf) - 1) { + strbuf[sizeof(strbuf) - 1] = '\0'; + info.filename += strbuf; + pathname_ptr += sizeof(strbuf) - 1; + // Stop if we found nul byte indicating the end of the string + for (size_t i = 0; i < sizeof(strbuf) - 1; i++) { + if (strbuf[i] == '\0') { + still_reading = false; + break; + } } + } + uuid_clear(info.macho_info.uuid); + image_infos.push_back(info); + } + if (image_infos.size() == 0) { + return reply_sp; + } - free (image_info_buf); - - //// Second, read the mach header / load commands for all the dylibs + free(image_info_buf); - for (size_t i = 0; i < image_count; i++) - { - if (!GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info)) - { - return reply_sp; - } - } + //// Second, read the mach header / load commands for all the dylibs + for (size_t i = 0; i < image_count; i++) { + if (!GetMachOInformationFromMemory(image_infos[i].load_address, + pointer_size, + image_infos[i].macho_info)) { + return reply_sp; + } + } - //// Third, format all of the above in the JSONGenerator object. + //// Third, format all of the above in the JSONGenerator object. + return FormatDynamicLibrariesIntoJSON(image_infos); + } - return FormatDynamicLibrariesIntoJSON (image_infos); - } - - return reply_sp; + return reply_sp; } // From dyld SPI header dyld_process_info.h -typedef void* dyld_process_info; -struct dyld_process_cache_info -{ - uuid_t cacheUUID; // UUID of cache used by process - uint64_t cacheBaseAddress; // load address of dyld shared cache - bool noCache; // process is running without a dyld cache - bool privateCache; // process is using a private copy of its dyld cache +typedef void *dyld_process_info; +struct dyld_process_cache_info { + uuid_t cacheUUID; // UUID of cache used by process + uint64_t cacheBaseAddress; // load address of dyld shared cache + bool noCache; // process is running without a dyld cache + bool privateCache; // process is using a private copy of its dyld cache }; - -// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer to get +// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer +// to get // the load address, uuid, and filenames of all the libraries. -// This only fills in those three fields in the 'struct binary_image_information' - call -// GetMachOInformationFromMemory to fill in the mach-o header/load command details. -void -MachProcess::GetAllLoadedBinariesViaDYLDSPI (std::vector<struct binary_image_information> &image_infos) -{ - kern_return_t kern_ret; - if (m_dyld_process_info_create) - { - dyld_process_info info = m_dyld_process_info_create (m_task.TaskPort(), 0, &kern_ret); - if (info) - { - m_dyld_process_info_for_each_image (info, ^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) { - struct binary_image_information image; - image.filename = path; - uuid_copy (image.macho_info.uuid, uuid); - image.load_address = mach_header_addr; - image_infos.push_back (image); - }); - m_dyld_process_info_release (info); - } - } -} - -// Fetch information about all shared libraries using the dyld SPIs that exist in +// This only fills in those three fields in the 'struct +// binary_image_information' - call +// GetMachOInformationFromMemory to fill in the mach-o header/load command +// details. +void MachProcess::GetAllLoadedBinariesViaDYLDSPI( + std::vector<struct binary_image_information> &image_infos) { + kern_return_t kern_ret; + if (m_dyld_process_info_create) { + dyld_process_info info = + m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); + if (info) { + m_dyld_process_info_for_each_image( + info, + ^(uint64_t mach_header_addr, const uuid_t uuid, const char *path) { + struct binary_image_information image; + image.filename = path; + uuid_copy(image.macho_info.uuid, uuid); + image.load_address = mach_header_addr; + image_infos.push_back(image); + }); + m_dyld_process_info_release(info); + } + } +} + +// Fetch information about all shared libraries using the dyld SPIs that exist +// in // macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer. -JSONGenerator::ObjectSP -MachProcess::GetAllLoadedLibrariesInfos (nub_process_t pid) -{ - JSONGenerator::DictionarySP reply_sp; - - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0) - { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; - - std::vector<struct binary_image_information> image_infos; - GetAllLoadedBinariesViaDYLDSPI (image_infos); - const size_t image_count = image_infos.size(); - for (size_t i = 0; i < image_count; i++) - { - GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info); - } - return FormatDynamicLibrariesIntoJSON (image_infos); +JSONGenerator::ObjectSP +MachProcess::GetAllLoadedLibrariesInfos(nub_process_t pid) { + JSONGenerator::DictionarySP reply_sp; + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, + NULL, 0) == 0 && + bufsize > 0) { + uint32_t pointer_size = 4; + if (processInfo.kp_proc.p_flag & P_LP64) + pointer_size = 8; + + std::vector<struct binary_image_information> image_infos; + GetAllLoadedBinariesViaDYLDSPI(image_infos); + const size_t image_count = image_infos.size(); + for (size_t i = 0; i < image_count; i++) { + GetMachOInformationFromMemory(image_infos[i].load_address, pointer_size, + image_infos[i].macho_info); } - return reply_sp; + return FormatDynamicLibrariesIntoJSON(image_infos); + } + return reply_sp; } -// Fetch information about the shared libraries at the given load addresses using the +// Fetch information about the shared libraries at the given load addresses +// using the // dyld SPIs that exist in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer. -JSONGenerator::ObjectSP -MachProcess::GetLibrariesInfoForAddresses (nub_process_t pid, std::vector<uint64_t> &macho_addresses) -{ - JSONGenerator::DictionarySP reply_sp; - - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid }; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0) - { - uint32_t pointer_size = 4; - if (processInfo.kp_proc.p_flag & P_LP64) - pointer_size = 8; - - std::vector<struct binary_image_information> all_image_infos; - GetAllLoadedBinariesViaDYLDSPI (all_image_infos); - - std::vector<struct binary_image_information> image_infos; - const size_t macho_addresses_count = macho_addresses.size(); - const size_t all_image_infos_count = all_image_infos.size(); - for (size_t i = 0; i < macho_addresses_count; i++) - { - for (size_t j = 0; j < all_image_infos_count; j++) - { - if (all_image_infos[j].load_address == macho_addresses[i]) - { - image_infos.push_back (all_image_infos[j]); - } - } - } +JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses( + nub_process_t pid, std::vector<uint64_t> &macho_addresses) { + JSONGenerator::DictionarySP reply_sp; + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, &bufsize, + NULL, 0) == 0 && + bufsize > 0) { + uint32_t pointer_size = 4; + if (processInfo.kp_proc.p_flag & P_LP64) + pointer_size = 8; + + std::vector<struct binary_image_information> all_image_infos; + GetAllLoadedBinariesViaDYLDSPI(all_image_infos); - const size_t image_infos_count = image_infos.size(); - for (size_t i = 0; i < image_infos_count; i++) - { - GetMachOInformationFromMemory (image_infos[i].load_address, pointer_size, image_infos[i].macho_info); + std::vector<struct binary_image_information> image_infos; + const size_t macho_addresses_count = macho_addresses.size(); + const size_t all_image_infos_count = all_image_infos.size(); + for (size_t i = 0; i < macho_addresses_count; i++) { + for (size_t j = 0; j < all_image_infos_count; j++) { + if (all_image_infos[j].load_address == macho_addresses[i]) { + image_infos.push_back(all_image_infos[j]); } - return FormatDynamicLibrariesIntoJSON (image_infos); + } + } + + const size_t image_infos_count = image_infos.size(); + for (size_t i = 0; i < image_infos_count; i++) { + GetMachOInformationFromMemory(image_infos[i].load_address, pointer_size, + image_infos[i].macho_info); } - return reply_sp; + return FormatDynamicLibrariesIntoJSON(image_infos); + } + return reply_sp; } // From dyld's internal podyld_process_info.h: -JSONGenerator::ObjectSP -MachProcess::GetSharedCacheInfo (nub_process_t pid) -{ - JSONGenerator::DictionarySP reply_sp (new JSONGenerator::Dictionary());; - kern_return_t kern_ret; - if (m_dyld_process_info_create && m_dyld_process_info_get_cache) - { - dyld_process_info info = m_dyld_process_info_create (m_task.TaskPort(), 0, &kern_ret); - if (info) - { - struct dyld_process_cache_info shared_cache_info; - m_dyld_process_info_get_cache (info, &shared_cache_info); - - reply_sp->AddIntegerItem ("shared_cache_base_address", shared_cache_info.cacheBaseAddress); - - uuid_string_t uuidstr; - uuid_unparse_upper (shared_cache_info.cacheUUID, uuidstr); - reply_sp->AddStringItem ("shared_cache_uuid", uuidstr); - - reply_sp->AddBooleanItem ("no_shared_cache", shared_cache_info.noCache); - reply_sp->AddBooleanItem ("shared_cache_private_cache", shared_cache_info.privateCache); - - m_dyld_process_info_release (info); - } - } - return reply_sp; -} +JSONGenerator::ObjectSP MachProcess::GetSharedCacheInfo(nub_process_t pid) { + JSONGenerator::DictionarySP reply_sp(new JSONGenerator::Dictionary()); + ; + kern_return_t kern_ret; + if (m_dyld_process_info_create && m_dyld_process_info_get_cache) { + dyld_process_info info = + m_dyld_process_info_create(m_task.TaskPort(), 0, &kern_ret); + if (info) { + struct dyld_process_cache_info shared_cache_info; + m_dyld_process_info_get_cache(info, &shared_cache_info); -nub_thread_t -MachProcess::GetCurrentThread () -{ - return m_thread_list.CurrentThreadID(); -} + reply_sp->AddIntegerItem("shared_cache_base_address", + shared_cache_info.cacheBaseAddress); -nub_thread_t -MachProcess::GetCurrentThreadMachPort () -{ - return m_thread_list.GetMachPortNumberByThreadID(m_thread_list.CurrentThreadID()); -} + uuid_string_t uuidstr; + uuid_unparse_upper(shared_cache_info.cacheUUID, uuidstr); + reply_sp->AddStringItem("shared_cache_uuid", uuidstr); -nub_thread_t -MachProcess::SetCurrentThread(nub_thread_t tid) -{ - return m_thread_list.SetCurrentThread(tid); -} - -bool -MachProcess::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) -{ - if (m_thread_list.GetThreadStoppedReason(tid, stop_info)) - { - if (m_did_exec) - stop_info->reason = eStopTypeExec; - return true; + reply_sp->AddBooleanItem("no_shared_cache", shared_cache_info.noCache); + reply_sp->AddBooleanItem("shared_cache_private_cache", + shared_cache_info.privateCache); + + m_dyld_process_info_release(info); } - return false; + } + return reply_sp; } -void -MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const -{ - return m_thread_list.DumpThreadStoppedReason(tid); +nub_thread_t MachProcess::GetCurrentThread() { + return m_thread_list.CurrentThreadID(); } -const char * -MachProcess::GetThreadInfo(nub_thread_t tid) const -{ - return m_thread_list.GetThreadInfo(tid); +nub_thread_t MachProcess::GetCurrentThreadMachPort() { + return m_thread_list.GetMachPortNumberByThreadID( + m_thread_list.CurrentThreadID()); } -uint32_t -MachProcess::GetCPUType () -{ - if (m_cpu_type == 0 && m_pid != 0) - m_cpu_type = MachProcess::GetCPUTypeForLocalProcess (m_pid); - return m_cpu_type; +nub_thread_t MachProcess::SetCurrentThread(nub_thread_t tid) { + return m_thread_list.SetCurrentThread(tid); } -const DNBRegisterSetInfo * -MachProcess::GetRegisterSetInfo (nub_thread_t tid, nub_size_t *num_reg_sets) const -{ - MachThreadSP thread_sp (m_thread_list.GetThreadByID (tid)); - if (thread_sp) - { - DNBArchProtocol *arch = thread_sp->GetArchProtocol(); - if (arch) - return arch->GetRegisterSetInfo (num_reg_sets); - } - *num_reg_sets = 0; - return NULL; +bool MachProcess::GetThreadStoppedReason(nub_thread_t tid, + struct DNBThreadStopInfo *stop_info) { + if (m_thread_list.GetThreadStoppedReason(tid, stop_info)) { + if (m_did_exec) + stop_info->reason = eStopTypeExec; + return true; + } + return false; } -bool -MachProcess::GetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *value ) const -{ - return m_thread_list.GetRegisterValue(tid, set, reg, value); +void MachProcess::DumpThreadStoppedReason(nub_thread_t tid) const { + return m_thread_list.DumpThreadStoppedReason(tid); } -bool -MachProcess::SetRegisterValue ( nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *value ) const -{ - return m_thread_list.SetRegisterValue(tid, set, reg, value); +const char *MachProcess::GetThreadInfo(nub_thread_t tid) const { + return m_thread_list.GetThreadInfo(tid); } -void -MachProcess::SetState(nub_state_t new_state) -{ - // If any other threads access this we will need a mutex for it - uint32_t event_mask = 0; - - // Scope for mutex locker - { - PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); - const nub_state_t old_state = m_state; - - if (old_state == eStateExited) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState(%s) ignoring new state since current state is exited", DNBStateAsString(new_state)); - } - else if (old_state == new_state) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState(%s) ignoring redundant state change...", DNBStateAsString(new_state)); - } - else - { - if (NUB_STATE_IS_STOPPED(new_state)) - event_mask = eEventProcessStoppedStateChanged; - else - event_mask = eEventProcessRunningStateChanged; - - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState(%s) upating state (previous state was %s), event_mask = 0x%8.8x", DNBStateAsString(new_state), DNBStateAsString(old_state), event_mask); - - m_state = new_state; - if (new_state == eStateStopped) - m_stop_count++; - } - } - - if (event_mask != 0) - { - m_events.SetEvents (event_mask); - m_private_events.SetEvents (event_mask); - if (event_mask == eEventProcessStoppedStateChanged) - m_private_events.ResetEvents (eEventProcessRunningStateChanged); - else - m_private_events.ResetEvents (eEventProcessStoppedStateChanged); - - // Wait for the event bit to reset if a reset ACK is requested - m_events.WaitForResetAck(event_mask); - } +uint32_t MachProcess::GetCPUType() { + if (m_cpu_type == 0 && m_pid != 0) + m_cpu_type = MachProcess::GetCPUTypeForLocalProcess(m_pid); + return m_cpu_type; +} +const DNBRegisterSetInfo * +MachProcess::GetRegisterSetInfo(nub_thread_t tid, + nub_size_t *num_reg_sets) const { + MachThreadSP thread_sp(m_thread_list.GetThreadByID(tid)); + if (thread_sp) { + DNBArchProtocol *arch = thread_sp->GetArchProtocol(); + if (arch) + return arch->GetRegisterSetInfo(num_reg_sets); + } + *num_reg_sets = 0; + return NULL; } -void -MachProcess::Clear(bool detaching) -{ - // Clear any cached thread list while the pid and task are still valid +bool MachProcess::GetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + DNBRegisterValue *value) const { + return m_thread_list.GetRegisterValue(tid, set, reg, value); +} - m_task.Clear(); - // Now clear out all member variables - m_pid = INVALID_NUB_PROCESS; - if (!detaching) - CloseChildFileDescriptors(); - - m_path.clear(); - m_args.clear(); - SetState(eStateUnloaded); - m_flags = eMachProcessFlagsNone; - m_stop_count = 0; - m_thread_list.Clear(); - { - PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); - m_exception_messages.clear(); - } - m_activities.Clear(); - if (m_profile_thread) - { - pthread_join(m_profile_thread, NULL); - m_profile_thread = NULL; - } +bool MachProcess::SetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + const DNBRegisterValue *value) const { + return m_thread_list.SetRegisterValue(tid, set, reg, value); } +void MachProcess::SetState(nub_state_t new_state) { + // If any other threads access this we will need a mutex for it + uint32_t event_mask = 0; -bool -MachProcess::StartSTDIOThread() -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); - // Create the thread that watches for the child STDIO - return ::pthread_create (&m_stdio_thread, NULL, MachProcess::STDIOThread, this) == 0; -} + // Scope for mutex locker + { + PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); + const nub_state_t old_state = m_state; + + if (old_state == eStateExited) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SetState(%s) ignoring new " + "state since current state is exited", + DNBStateAsString(new_state)); + } else if (old_state == new_state) { + DNBLogThreadedIf( + LOG_PROCESS, + "MachProcess::SetState(%s) ignoring redundant state change...", + DNBStateAsString(new_state)); + } else { + if (NUB_STATE_IS_STOPPED(new_state)) + event_mask = eEventProcessStoppedStateChanged; + else + event_mask = eEventProcessRunningStateChanged; + + DNBLogThreadedIf( + LOG_PROCESS, "MachProcess::SetState(%s) upating state (previous " + "state was %s), event_mask = 0x%8.8x", + DNBStateAsString(new_state), DNBStateAsString(old_state), event_mask); + + m_state = new_state; + if (new_state == eStateStopped) + m_stop_count++; + } + } + + if (event_mask != 0) { + m_events.SetEvents(event_mask); + m_private_events.SetEvents(event_mask); + if (event_mask == eEventProcessStoppedStateChanged) + m_private_events.ResetEvents(eEventProcessRunningStateChanged); + else + m_private_events.ResetEvents(eEventProcessStoppedStateChanged); -void -MachProcess::SetEnableAsyncProfiling(bool enable, uint64_t interval_usec, DNBProfileDataScanType scan_type) -{ - m_profile_enabled = enable; - m_profile_interval_usec = static_cast<useconds_t>(interval_usec); - m_profile_scan_type = scan_type; - - if (m_profile_enabled && (m_profile_thread == NULL)) - { - StartProfileThread(); - } - else if (!m_profile_enabled && m_profile_thread) - { - pthread_join(m_profile_thread, NULL); - m_profile_thread = NULL; - } + // Wait for the event bit to reset if a reset ACK is requested + m_events.WaitForResetAck(event_mask); + } +} + +void MachProcess::Clear(bool detaching) { + // Clear any cached thread list while the pid and task are still valid + + m_task.Clear(); + // Now clear out all member variables + m_pid = INVALID_NUB_PROCESS; + if (!detaching) + CloseChildFileDescriptors(); + + m_path.clear(); + m_args.clear(); + SetState(eStateUnloaded); + m_flags = eMachProcessFlagsNone; + m_stop_count = 0; + m_thread_list.Clear(); + { + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); + m_exception_messages.clear(); + } + m_activities.Clear(); + if (m_profile_thread) { + pthread_join(m_profile_thread, NULL); + m_profile_thread = NULL; + } } -bool -MachProcess::StartProfileThread() -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); - // Create the thread that profiles the inferior and reports back if enabled - return ::pthread_create (&m_profile_thread, NULL, MachProcess::ProfileThread, this) == 0; +bool MachProcess::StartSTDIOThread() { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); + // Create the thread that watches for the child STDIO + return ::pthread_create(&m_stdio_thread, NULL, MachProcess::STDIOThread, + this) == 0; } +void MachProcess::SetEnableAsyncProfiling(bool enable, uint64_t interval_usec, + DNBProfileDataScanType scan_type) { + m_profile_enabled = enable; + m_profile_interval_usec = static_cast<useconds_t>(interval_usec); + m_profile_scan_type = scan_type; -nub_addr_t -MachProcess::LookupSymbol(const char *name, const char *shlib) -{ - if (m_name_to_addr_callback != NULL && name && name[0]) - return m_name_to_addr_callback(ProcessID(), name, shlib, m_name_to_addr_baton); - return INVALID_NUB_ADDRESS; + if (m_profile_enabled && (m_profile_thread == NULL)) { + StartProfileThread(); + } else if (!m_profile_enabled && m_profile_thread) { + pthread_join(m_profile_thread, NULL); + m_profile_thread = NULL; + } } -bool -MachProcess::Resume (const DNBThreadResumeActions& thread_actions) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()"); - nub_state_t state = GetState(); - - if (CanResume(state)) - { - m_thread_actions = thread_actions; - PrivateResume(); - return true; - } - else if (state == eStateRunning) - { - DNBLog("Resume() - task 0x%x is already running, ignoring...", m_task.TaskPort()); - return true; - } - DNBLog("Resume() - task 0x%x has state %s, can't continue...", m_task.TaskPort(), DNBStateAsString(state)); - return false; +bool MachProcess::StartProfileThread() { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( )", __FUNCTION__); + // Create the thread that profiles the inferior and reports back if enabled + return ::pthread_create(&m_profile_thread, NULL, MachProcess::ProfileThread, + this) == 0; } -bool -MachProcess::Kill (const struct timespec *timeout_abstime) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()"); - nub_state_t state = DoSIGSTOP(true, false, NULL); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", DNBStateAsString(state)); - errno = 0; - DNBLog ("Sending ptrace PT_KILL to terminate inferior process."); - ::ptrace (PT_KILL, m_pid, 0, 0); - DNBError err; - err.SetErrorToErrno(); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace (PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", m_pid, err.Error(), err.AsString()); - m_thread_actions = DNBThreadResumeActions (eStateRunning, 0); - PrivateResume (); - - // Try and reap the process without touching our m_events since - // we want the code above this to still get the eStateExited event - const uint32_t reap_timeout_usec = 1000000; // Wait 1 second and try to reap the process - const uint32_t reap_interval_usec = 10000; // - uint32_t reap_time_elapsed; - for (reap_time_elapsed = 0; - reap_time_elapsed < reap_timeout_usec; - reap_time_elapsed += reap_interval_usec) - { - if (GetState() == eStateExited) - break; - usleep(reap_interval_usec); - } - DNBLog ("Waited %u ms for process to be reaped (state = %s)", reap_time_elapsed/1000, DNBStateAsString(GetState())); - return true; +nub_addr_t MachProcess::LookupSymbol(const char *name, const char *shlib) { + if (m_name_to_addr_callback != NULL && name && name[0]) + return m_name_to_addr_callback(ProcessID(), name, shlib, + m_name_to_addr_baton); + return INVALID_NUB_ADDRESS; } -bool -MachProcess::Interrupt() -{ - nub_state_t state = GetState(); - if (IsRunning(state)) - { - if (m_sent_interrupt_signo == 0) - { - m_sent_interrupt_signo = SIGSTOP; - if (Signal (m_sent_interrupt_signo)) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - sent %i signal to interrupt process", m_sent_interrupt_signo); - return true; - } - else - { - m_sent_interrupt_signo = 0; - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - failed to send %i signal to interrupt process", m_sent_interrupt_signo); - } - } - else - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - previously sent an interrupt signal %i that hasn't been received yet, interrupt aborted", m_sent_interrupt_signo); - } - } - else - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - process already stopped, no interrupt sent"); - } - return false; -} +bool MachProcess::Resume(const DNBThreadResumeActions &thread_actions) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Resume ()"); + nub_state_t state = GetState(); -bool -MachProcess::Signal (int signal, const struct timespec *timeout_abstime) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p)", signal, timeout_abstime); - nub_state_t state = GetState(); - if (::kill (ProcessID(), signal) == 0) - { - // If we were running and we have a timeout, wait for the signal to stop - if (IsRunning(state) && timeout_abstime) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) waiting for signal to stop process...", signal, timeout_abstime); - m_private_events.WaitForSetEvents(eEventProcessStoppedStateChanged, timeout_abstime); - state = GetState(); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, timeout_abstime, DNBStateAsString(state)); - return !IsRunning (state); - } - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", signal, timeout_abstime); + if (CanResume(state)) { + m_thread_actions = thread_actions; + PrivateResume(); + return true; + } else if (state == eStateRunning) { + DNBLog("Resume() - task 0x%x is already running, ignoring...", + m_task.TaskPort()); + return true; + } + DNBLog("Resume() - task 0x%x has state %s, can't continue...", + m_task.TaskPort(), DNBStateAsString(state)); + return false; +} + +bool MachProcess::Kill(const struct timespec *timeout_abstime) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill ()"); + nub_state_t state = DoSIGSTOP(true, false, NULL); + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() state = %s", + DNBStateAsString(state)); + errno = 0; + DNBLog("Sending ptrace PT_KILL to terminate inferior process."); + ::ptrace(PT_KILL, m_pid, 0, 0); + DNBError err; + err.SetErrorToErrno(); + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Kill() DoSIGSTOP() ::ptrace " + "(PT_KILL, pid=%u, 0, 0) => 0x%8.8x (%s)", + m_pid, err.Error(), err.AsString()); + m_thread_actions = DNBThreadResumeActions(eStateRunning, 0); + PrivateResume(); + + // Try and reap the process without touching our m_events since + // we want the code above this to still get the eStateExited event + const uint32_t reap_timeout_usec = + 1000000; // Wait 1 second and try to reap the process + const uint32_t reap_interval_usec = 10000; // + uint32_t reap_time_elapsed; + for (reap_time_elapsed = 0; reap_time_elapsed < reap_timeout_usec; + reap_time_elapsed += reap_interval_usec) { + if (GetState() == eStateExited) + break; + usleep(reap_interval_usec); + } + DNBLog("Waited %u ms for process to be reaped (state = %s)", + reap_time_elapsed / 1000, DNBStateAsString(GetState())); + return true; +} + +bool MachProcess::Interrupt() { + nub_state_t state = GetState(); + if (IsRunning(state)) { + if (m_sent_interrupt_signo == 0) { + m_sent_interrupt_signo = SIGSTOP; + if (Signal(m_sent_interrupt_signo)) { + DNBLogThreadedIf( + LOG_PROCESS, + "MachProcess::Interrupt() - sent %i signal to interrupt process", + m_sent_interrupt_signo); return true; - } - DNBError err(errno, DNBError::POSIX); - err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal); - return false; - + } else { + m_sent_interrupt_signo = 0; + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - failed to " + "send %i signal to interrupt process", + m_sent_interrupt_signo); + } + } else { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - previously " + "sent an interrupt signal %i that hasn't " + "been received yet, interrupt aborted", + m_sent_interrupt_signo); + } + } else { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Interrupt() - process already " + "stopped, no interrupt sent"); + } + return false; +} + +bool MachProcess::Signal(int signal, const struct timespec *timeout_abstime) { + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::Signal (signal = %d, timeout = %p)", signal, + timeout_abstime); + nub_state_t state = GetState(); + if (::kill(ProcessID(), signal) == 0) { + // If we were running and we have a timeout, wait for the signal to stop + if (IsRunning(state) && timeout_abstime) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Signal (signal = %d, timeout " + "= %p) waiting for signal to stop " + "process...", + signal, timeout_abstime); + m_private_events.WaitForSetEvents(eEventProcessStoppedStateChanged, + timeout_abstime); + state = GetState(); + DNBLogThreadedIf( + LOG_PROCESS, + "MachProcess::Signal (signal = %d, timeout = %p) state = %s", signal, + timeout_abstime, DNBStateAsString(state)); + return !IsRunning(state); + } + DNBLogThreadedIf( + LOG_PROCESS, + "MachProcess::Signal (signal = %d, timeout = %p) not waiting...", + signal, timeout_abstime); + return true; + } + DNBError err(errno, DNBError::POSIX); + err.LogThreadedIfError("kill (pid = %d, signo = %i)", ProcessID(), signal); + return false; } -bool -MachProcess::SendEvent (const char *event, DNBError &send_err) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::SendEvent (event = %s) to pid: %d", event, m_pid); - if (m_pid == INVALID_NUB_PROCESS) - return false; - // FIXME: Shouldn't we use the launch flavor we were started with? +bool MachProcess::SendEvent(const char *event, DNBError &send_err) { + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::SendEvent (event = %s) to pid: %d", event, + m_pid); + if (m_pid == INVALID_NUB_PROCESS) + return false; +// FIXME: Shouldn't we use the launch flavor we were started with? #if defined(WITH_FBS) || defined(WITH_BKS) - return BoardServiceSendEvent (event, send_err); + return BoardServiceSendEvent(event, send_err); #endif - return true; + return true; } -nub_state_t -MachProcess::DoSIGSTOP (bool clear_bps_and_wps, bool allow_running, uint32_t *thread_idx_ptr) -{ - nub_state_t state = GetState(); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", DNBStateAsString (state)); +nub_state_t MachProcess::DoSIGSTOP(bool clear_bps_and_wps, bool allow_running, + uint32_t *thread_idx_ptr) { + nub_state_t state = GetState(); + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s", + DNBStateAsString(state)); - if (!IsRunning(state)) - { - if (clear_bps_and_wps) - { - DisableAllBreakpoints (true); - DisableAllWatchpoints (true); - clear_bps_and_wps = false; - } + if (!IsRunning(state)) { + if (clear_bps_and_wps) { + DisableAllBreakpoints(true); + DisableAllWatchpoints(true); + clear_bps_and_wps = false; + } - // If we already have a thread stopped due to a SIGSTOP, we don't have - // to do anything... - uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP); - if (thread_idx_ptr) - *thread_idx_ptr = thread_idx; - if (thread_idx != UINT32_MAX) - return GetState(); - - // No threads were stopped with a SIGSTOP, we need to run and halt the - // process with a signal - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- resuming process", DNBStateAsString (state)); - if (allow_running) - m_thread_actions = DNBThreadResumeActions (eStateRunning, 0); - else - m_thread_actions = DNBThreadResumeActions (eStateSuspended, 0); - - PrivateResume (); - - // Reset the event that says we were indeed running - m_events.ResetEvents(eEventProcessRunningStateChanged); - state = GetState(); - } - - // We need to be stopped in order to be able to detach, so we need - // to send ourselves a SIGSTOP - - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", DNBStateAsString (state)); - struct timespec sigstop_timeout; - DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0); - Signal (SIGSTOP, &sigstop_timeout); - if (clear_bps_and_wps) - { - DisableAllBreakpoints (true); - DisableAllWatchpoints (true); - //clear_bps_and_wps = false; - } - uint32_t thread_idx = m_thread_list.GetThreadIndexForThreadStoppedWithSignal (SIGSTOP); + // If we already have a thread stopped due to a SIGSTOP, we don't have + // to do anything... + uint32_t thread_idx = + m_thread_list.GetThreadIndexForThreadStoppedWithSignal(SIGSTOP); if (thread_idx_ptr) - *thread_idx_ptr = thread_idx; - return GetState(); -} - -bool -MachProcess::Detach() -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()"); + *thread_idx_ptr = thread_idx; + if (thread_idx != UINT32_MAX) + return GetState(); - uint32_t thread_idx = UINT32_MAX; - nub_state_t state = DoSIGSTOP(true, true, &thread_idx); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", DNBStateAsString(state)); + // No threads were stopped with a SIGSTOP, we need to run and halt the + // process with a signal + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::DoSIGSTOP() state = %s -- resuming process", + DNBStateAsString(state)); + if (allow_running) + m_thread_actions = DNBThreadResumeActions(eStateRunning, 0); + else + m_thread_actions = DNBThreadResumeActions(eStateSuspended, 0); + + PrivateResume(); + + // Reset the event that says we were indeed running + m_events.ResetEvents(eEventProcessRunningStateChanged); + state = GetState(); + } + + // We need to be stopped in order to be able to detach, so we need + // to send ourselves a SIGSTOP + + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::DoSIGSTOP() state = %s -- sending SIGSTOP", + DNBStateAsString(state)); + struct timespec sigstop_timeout; + DNBTimer::OffsetTimeOfDay(&sigstop_timeout, 2, 0); + Signal(SIGSTOP, &sigstop_timeout); + if (clear_bps_and_wps) { + DisableAllBreakpoints(true); + DisableAllWatchpoints(true); + // clear_bps_and_wps = false; + } + uint32_t thread_idx = + m_thread_list.GetThreadIndexForThreadStoppedWithSignal(SIGSTOP); + if (thread_idx_ptr) + *thread_idx_ptr = thread_idx; + return GetState(); +} + +bool MachProcess::Detach() { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach()"); + + uint32_t thread_idx = UINT32_MAX; + nub_state_t state = DoSIGSTOP(true, true, &thread_idx); + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::Detach() DoSIGSTOP() returned %s", + DNBStateAsString(state)); + + { + m_thread_actions.Clear(); + m_activities.Clear(); + DNBThreadResumeAction thread_action; + thread_action.tid = m_thread_list.ThreadIDAtIndex(thread_idx); + thread_action.state = eStateRunning; + thread_action.signal = -1; + thread_action.addr = INVALID_NUB_ADDRESS; - { - m_thread_actions.Clear(); - m_activities.Clear(); - DNBThreadResumeAction thread_action; - thread_action.tid = m_thread_list.ThreadIDAtIndex (thread_idx); - thread_action.state = eStateRunning; - thread_action.signal = -1; - thread_action.addr = INVALID_NUB_ADDRESS; - - m_thread_actions.Append (thread_action); - m_thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, 0); - - PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); + m_thread_actions.Append(thread_action); + m_thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); - ReplyToAllExceptions (); + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); - } + ReplyToAllExceptions(); + } - m_task.ShutDownExcecptionThread(); + m_task.ShutDownExcecptionThread(); - // Detach from our process - errno = 0; - nub_process_t pid = m_pid; - int ret = ::ptrace (PT_DETACH, pid, (caddr_t)1, 0); - DNBError err(errno, DNBError::POSIX); - if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail() || (ret != 0)) - err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid); + // Detach from our process + errno = 0; + nub_process_t pid = m_pid; + int ret = ::ptrace(PT_DETACH, pid, (caddr_t)1, 0); + DNBError err(errno, DNBError::POSIX); + if (DNBLogCheckLogBit(LOG_PROCESS) || err.Fail() || (ret != 0)) + err.LogThreaded("::ptrace (PT_DETACH, %u, (caddr_t)1, 0)", pid); - // Resume our task - m_task.Resume(); + // Resume our task + m_task.Resume(); - // NULL our task out as we have already retored all exception ports - m_task.Clear(); + // NULL our task out as we have already retored all exception ports + m_task.Clear(); - // Clear out any notion of the process we once were - const bool detaching = true; - Clear(detaching); + // Clear out any notion of the process we once were + const bool detaching = true; + Clear(detaching); - SetState(eStateDetached); + SetState(eStateDetached); - return true; + return true; } //---------------------------------------------------------------------- @@ -1438,20 +1428,19 @@ MachProcess::Detach() // (m_task.ReadMemory()) as that version will give you what is actually // in inferior memory. //---------------------------------------------------------------------- -nub_size_t -MachProcess::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf) -{ - // We need to remove any current software traps (enabled software - // breakpoints) that we may have placed in our tasks memory. +nub_size_t MachProcess::ReadMemory(nub_addr_t addr, nub_size_t size, + void *buf) { + // We need to remove any current software traps (enabled software + // breakpoints) that we may have placed in our tasks memory. - // First just read the memory as is - nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf); + // First just read the memory as is + nub_size_t bytes_read = m_task.ReadMemory(addr, size, buf); - // Then place any opcodes that fall into this range back into the buffer - // before we return this to callers. - if (bytes_read > 0) - m_breakpoints.RemoveTrapsFromBuffer (addr, bytes_read, buf); - return bytes_read; + // Then place any opcodes that fall into this range back into the buffer + // before we return this to callers. + if (bytes_read > 0) + m_breakpoints.RemoveTrapsFromBuffer(addr, bytes_read, buf); + return bytes_read; } //---------------------------------------------------------------------- @@ -1463,1288 +1452,1275 @@ MachProcess::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf) // (m_task.WriteMemory()) as that version will always modify inferior // memory. //---------------------------------------------------------------------- -nub_size_t -MachProcess::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf) -{ - // We need to write any data that would go where any current software traps - // (enabled software breakpoints) any software traps (breakpoints) that we - // may have placed in our tasks memory. - - std::vector<DNBBreakpoint *> bps; - - const size_t num_bps = m_breakpoints.FindBreakpointsThatOverlapRange(addr, size, bps); - if (num_bps == 0) - return m_task.WriteMemory(addr, size, buf); - - nub_size_t bytes_written = 0; - nub_addr_t intersect_addr; - nub_size_t intersect_size; - nub_size_t opcode_offset; - const uint8_t *ubuf = (const uint8_t *)buf; - - for (size_t i=0; i<num_bps; ++i) - { - DNBBreakpoint *bp = bps[i]; - - const bool intersects = bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset); - UNUSED_IF_ASSERT_DISABLED(intersects); - assert(intersects); - assert(addr <= intersect_addr && intersect_addr < addr + size); - assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size); - assert(opcode_offset + intersect_size <= bp->ByteSize()); - - // Check for bytes before this breakpoint - const nub_addr_t curr_addr = addr + bytes_written; - if (intersect_addr > curr_addr) - { - // There are some bytes before this breakpoint that we need to - // just write to memory - nub_size_t curr_size = intersect_addr - curr_addr; - nub_size_t curr_bytes_written = m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written); - bytes_written += curr_bytes_written; - if (curr_bytes_written != curr_size) - { - // We weren't able to write all of the requested bytes, we - // are done looping and will return the number of bytes that - // we have written so far. - break; - } - } - - // Now write any bytes that would cover up any software breakpoints - // directly into the breakpoint opcode buffer - ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size); - bytes_written += intersect_size; - } - - // Write any remaining bytes after the last breakpoint if we have any left - if (bytes_written < size) - bytes_written += m_task.WriteMemory(addr + bytes_written, size - bytes_written, ubuf + bytes_written); - - return bytes_written; -} - -void -MachProcess::ReplyToAllExceptions () -{ - PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); - if (m_exception_messages.empty() == false) - { - MachException::Message::iterator pos; - MachException::Message::iterator begin = m_exception_messages.begin(); - MachException::Message::iterator end = m_exception_messages.end(); - for (pos = begin; pos != end; ++pos) - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %u...", (uint32_t)std::distance(begin, pos)); - int thread_reply_signal = 0; - - nub_thread_t tid = m_thread_list.GetThreadIDByMachPortNumber (pos->state.thread_port); - const DNBThreadResumeAction *action = NULL; - if (tid != INVALID_NUB_THREAD) - { - action = m_thread_actions.GetActionForThread (tid, false); - } - - if (action) - { - thread_reply_signal = action->signal; - if (thread_reply_signal) - m_thread_actions.SetSignalHandledForThread (tid); - } - - DNBError err (pos->Reply(this, thread_reply_signal)); - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - err.LogThreadedIfError("Error replying to exception"); - } - - // Erase all exception message as we should have used and replied - // to them all already. - m_exception_messages.clear(); - } +nub_size_t MachProcess::WriteMemory(nub_addr_t addr, nub_size_t size, + const void *buf) { + // We need to write any data that would go where any current software traps + // (enabled software breakpoints) any software traps (breakpoints) that we + // may have placed in our tasks memory. + + std::vector<DNBBreakpoint *> bps; + + const size_t num_bps = + m_breakpoints.FindBreakpointsThatOverlapRange(addr, size, bps); + if (num_bps == 0) + return m_task.WriteMemory(addr, size, buf); + + nub_size_t bytes_written = 0; + nub_addr_t intersect_addr; + nub_size_t intersect_size; + nub_size_t opcode_offset; + const uint8_t *ubuf = (const uint8_t *)buf; + + for (size_t i = 0; i < num_bps; ++i) { + DNBBreakpoint *bp = bps[i]; + + const bool intersects = bp->IntersectsRange( + addr, size, &intersect_addr, &intersect_size, &opcode_offset); + UNUSED_IF_ASSERT_DISABLED(intersects); + assert(intersects); + assert(addr <= intersect_addr && intersect_addr < addr + size); + assert(addr < intersect_addr + intersect_size && + intersect_addr + intersect_size <= addr + size); + assert(opcode_offset + intersect_size <= bp->ByteSize()); + + // Check for bytes before this breakpoint + const nub_addr_t curr_addr = addr + bytes_written; + if (intersect_addr > curr_addr) { + // There are some bytes before this breakpoint that we need to + // just write to memory + nub_size_t curr_size = intersect_addr - curr_addr; + nub_size_t curr_bytes_written = + m_task.WriteMemory(curr_addr, curr_size, ubuf + bytes_written); + bytes_written += curr_bytes_written; + if (curr_bytes_written != curr_size) { + // We weren't able to write all of the requested bytes, we + // are done looping and will return the number of bytes that + // we have written so far. + break; + } + } + + // Now write any bytes that would cover up any software breakpoints + // directly into the breakpoint opcode buffer + ::memcpy(bp->SavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, + intersect_size); + bytes_written += intersect_size; + } + + // Write any remaining bytes after the last breakpoint if we have any left + if (bytes_written < size) + bytes_written += m_task.WriteMemory( + addr + bytes_written, size - bytes_written, ubuf + bytes_written); + + return bytes_written; +} + +void MachProcess::ReplyToAllExceptions() { + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); + if (m_exception_messages.empty() == false) { + MachException::Message::iterator pos; + MachException::Message::iterator begin = m_exception_messages.begin(); + MachException::Message::iterator end = m_exception_messages.end(); + for (pos = begin; pos != end; ++pos) { + DNBLogThreadedIf(LOG_EXCEPTIONS, "Replying to exception %u...", + (uint32_t)std::distance(begin, pos)); + int thread_reply_signal = 0; + + nub_thread_t tid = + m_thread_list.GetThreadIDByMachPortNumber(pos->state.thread_port); + const DNBThreadResumeAction *action = NULL; + if (tid != INVALID_NUB_THREAD) { + action = m_thread_actions.GetActionForThread(tid, false); + } + + if (action) { + thread_reply_signal = action->signal; + if (thread_reply_signal) + m_thread_actions.SetSignalHandledForThread(tid); + } + + DNBError err(pos->Reply(this, thread_reply_signal)); + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) + err.LogThreadedIfError("Error replying to exception"); + } + + // Erase all exception message as we should have used and replied + // to them all already. + m_exception_messages.clear(); + } +} +void MachProcess::PrivateResume() { + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); + + m_auto_resume_signo = m_sent_interrupt_signo; + if (m_auto_resume_signo) + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrivateResume() - task 0x%x " + "resuming (with unhandled interrupt signal " + "%i)...", + m_task.TaskPort(), m_auto_resume_signo); + else + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::PrivateResume() - task 0x%x resuming...", + m_task.TaskPort()); + + ReplyToAllExceptions(); + // bool stepOverBreakInstruction = step; + + // Let the thread prepare to resume and see if any threads want us to + // step over a breakpoint instruction (ProcessWillResume will modify + // the value of stepOverBreakInstruction). + m_thread_list.ProcessWillResume(this, m_thread_actions); + + // Set our state accordingly + if (m_thread_actions.NumActionsWithState(eStateStepping)) + SetState(eStateStepping); + else + SetState(eStateRunning); + + // Now resume our task. + m_task.Resume(); +} + +DNBBreakpoint *MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, + bool hardware) { + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = " + "0x%8.8llx, length = %llu, hardware = %i)", + (uint64_t)addr, (uint64_t)length, hardware); + + DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); + if (bp) + bp->Retain(); + else + bp = m_breakpoints.Add(addr, length, hardware); + + if (EnableBreakpoint(addr)) { + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = " + "0x%8.8llx, length = %llu) => %p", + (uint64_t)addr, (uint64_t)length, bp); + return bp; + } else if (bp->Release() == 0) { + m_breakpoints.Remove(addr); + } + // We failed to enable the breakpoint + return NULL; } -void -MachProcess::PrivateResume () -{ - PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); - - m_auto_resume_signo = m_sent_interrupt_signo; - if (m_auto_resume_signo) - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrivateResume() - task 0x%x resuming (with unhandled interrupt signal %i)...", m_task.TaskPort(), m_auto_resume_signo); - else - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrivateResume() - task 0x%x resuming...", m_task.TaskPort()); - - ReplyToAllExceptions (); -// bool stepOverBreakInstruction = step; - - // Let the thread prepare to resume and see if any threads want us to - // step over a breakpoint instruction (ProcessWillResume will modify - // the value of stepOverBreakInstruction). - m_thread_list.ProcessWillResume (this, m_thread_actions); - - // Set our state accordingly - if (m_thread_actions.NumActionsWithState(eStateStepping)) - SetState (eStateStepping); - else - SetState (eStateRunning); - // Now resume our task. - m_task.Resume(); +DNBBreakpoint *MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, + uint32_t watch_flags, + bool hardware) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = " + "0x%8.8llx, length = %llu, flags = " + "0x%8.8x, hardware = %i)", + (uint64_t)addr, (uint64_t)length, watch_flags, hardware); + + DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); + // since the Z packets only send an address, we can only have one watchpoint + // at + // an address. If there is already one, we must refuse to create another + // watchpoint + if (wp) + return NULL; + + wp = m_watchpoints.Add(addr, length, hardware); + wp->SetIsWatchpoint(watch_flags); + + if (EnableWatchpoint(addr)) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = " + "0x%8.8llx, length = %llu) => %p", + (uint64_t)addr, (uint64_t)length, wp); + return wp; + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = " + "0x%8.8llx, length = %llu) => FAILED", + (uint64_t)addr, (uint64_t)length); + m_watchpoints.Remove(addr); + } + // We failed to enable the watchpoint + return NULL; } -DNBBreakpoint * -MachProcess::CreateBreakpoint(nub_addr_t addr, nub_size_t length, bool hardware) -{ - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %llu, hardware = %i)", (uint64_t)addr, (uint64_t)length, hardware); +void MachProcess::DisableAllBreakpoints(bool remove) { + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", + __FUNCTION__, remove); - DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); - if (bp) - bp->Retain(); - else - bp = m_breakpoints.Add(addr, length, hardware); + m_breakpoints.DisableAllBreakpoints(this); - if (EnableBreakpoint(addr)) - { - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::CreateBreakpoint ( addr = 0x%8.8llx, length = %llu) => %p", (uint64_t)addr, (uint64_t)length, bp); - return bp; - } - else if (bp->Release() == 0) - { - m_breakpoints.Remove(addr); - } - // We failed to enable the breakpoint - return NULL; + if (remove) + m_breakpoints.RemoveDisabled(); } -DNBBreakpoint * -MachProcess::CreateWatchpoint(nub_addr_t addr, nub_size_t length, uint32_t watch_flags, bool hardware) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %llu, flags = 0x%8.8x, hardware = %i)", (uint64_t)addr, (uint64_t)length, watch_flags, hardware); +void MachProcess::DisableAllWatchpoints(bool remove) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", + __FUNCTION__, remove); - DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); - // since the Z packets only send an address, we can only have one watchpoint at - // an address. If there is already one, we must refuse to create another watchpoint - if (wp) - return NULL; - - wp = m_watchpoints.Add(addr, length, hardware); - wp->SetIsWatchpoint(watch_flags); + m_watchpoints.DisableAllWatchpoints(this); - if (EnableWatchpoint(addr)) - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %llu) => %p", (uint64_t)addr, (uint64_t)length, wp); - return wp; - } - else - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::CreateWatchpoint ( addr = 0x%8.8llx, length = %llu) => FAILED", (uint64_t)addr, (uint64_t)length); - m_watchpoints.Remove(addr); - } - // We failed to enable the watchpoint - return NULL; + if (remove) + m_watchpoints.RemoveDisabled(); } -void -MachProcess::DisableAllBreakpoints (bool remove) -{ - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove); - - m_breakpoints.DisableAllBreakpoints (this); - - if (remove) - m_breakpoints.RemoveDisabled(); -} - -void -MachProcess::DisableAllWatchpoints(bool remove) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s (remove = %d )", __FUNCTION__, remove); - - m_watchpoints.DisableAllWatchpoints(this); - - if (remove) - m_watchpoints.RemoveDisabled(); -} - -bool -MachProcess::DisableBreakpoint(nub_addr_t addr, bool remove) -{ - DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); - if (bp) - { - // After "exec" we might end up with a bunch of breakpoints that were disabled - // manually, just ignore them - if (!bp->IsEnabled()) - { - // Breakpoint might have been disabled by an exec - if (remove && bp->Release() == 0) - { +bool MachProcess::DisableBreakpoint(nub_addr_t addr, bool remove) { + DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); + if (bp) { + // After "exec" we might end up with a bunch of breakpoints that were + // disabled + // manually, just ignore them + if (!bp->IsEnabled()) { + // Breakpoint might have been disabled by an exec + if (remove && bp->Release() == 0) { + m_thread_list.NotifyBreakpointChanged(bp); + m_breakpoints.Remove(addr); + } + return true; + } + + // We have multiple references to this breakpoint, decrement the ref count + // and if it isn't zero, then return true; + if (remove && bp->Release() > 0) + return true; + + DNBLogThreadedIf( + LOG_BREAKPOINTS | LOG_VERBOSE, + "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d )", + (uint64_t)addr, remove); + + if (bp->IsHardware()) { + bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint(bp); + + if (hw_disable_result == true) { + bp->SetEnabled(false); + // Let the thread list know that a breakpoint has been modified + if (remove) { + m_thread_list.NotifyBreakpointChanged(bp); + m_breakpoints.Remove(addr); + } + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( " + "addr = 0x%8.8llx, remove = %d ) " + "(hardware) => success", + (uint64_t)addr, remove); + return true; + } + + return false; + } + + const nub_size_t break_op_size = bp->ByteSize(); + assert(break_op_size > 0); + const uint8_t *const break_op = + DNBArchProtocol::GetBreakpointOpcode(bp->ByteSize()); + if (break_op_size > 0) { + // Clear a software breakpoint instruction + uint8_t curr_break_op[break_op_size]; + bool break_op_found = false; + + // Read the breakpoint opcode + if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == + break_op_size) { + bool verify = false; + if (bp->IsEnabled()) { + // Make sure we have the a breakpoint opcode exists at this address + if (memcmp(curr_break_op, break_op, break_op_size) == 0) { + break_op_found = true; + // We found a valid breakpoint opcode at this address, now restore + // the saved opcode. + if (m_task.WriteMemory(addr, break_op_size, + bp->SavedOpcodeBytes()) == break_op_size) { + verify = true; + } else { + DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " + "remove = %d ) memory write failed when restoring " + "original opcode", + (uint64_t)addr, remove); + } + } else { + DNBLogWarning("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " + "remove = %d ) expected a breakpoint opcode but " + "didn't find one.", + (uint64_t)addr, remove); + // Set verify to true and so we can check if the original opcode has + // already been restored + verify = true; + } + } else { + DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, + "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, " + "remove = %d ) is not enabled", + (uint64_t)addr, remove); + // Set verify to true and so we can check if the original opcode is + // there + verify = true; + } + + if (verify) { + uint8_t verify_opcode[break_op_size]; + // Verify that our original opcode made it back to the inferior + if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == + break_op_size) { + // compare the memory we just read with the original opcode + if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == + 0) { + // SUCCESS + bp->SetEnabled(false); + // Let the thread list know that a breakpoint has been modified + if (remove && bp->Release() == 0) { m_thread_list.NotifyBreakpointChanged(bp); m_breakpoints.Remove(addr); + } + DNBLogThreadedIf(LOG_BREAKPOINTS, + "MachProcess::DisableBreakpoint ( addr = " + "0x%8.8llx, remove = %d ) => success", + (uint64_t)addr, remove); + return true; + } else { + if (break_op_found) + DNBLogError("MachProcess::DisableBreakpoint ( addr = " + "0x%8.8llx, remove = %d ) : failed to restore " + "original opcode", + (uint64_t)addr, remove); + else + DNBLogError("MachProcess::DisableBreakpoint ( addr = " + "0x%8.8llx, remove = %d ) : opcode changed", + (uint64_t)addr, remove); } - return true; - } - - // We have multiple references to this breakpoint, decrement the ref count - // and if it isn't zero, then return true; - if (remove && bp->Release() > 0) - return true; - - DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d )", (uint64_t)addr, remove); - - if (bp->IsHardware()) - { - bool hw_disable_result = m_thread_list.DisableHardwareBreakpoint (bp); - - if (hw_disable_result == true) - { - bp->SetEnabled(false); + } else { + DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable " + "breakpoint 0x%8.8llx", + (uint64_t)addr); + } + } + } else { + DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory " + "at 0x%8.8llx", + (uint64_t)addr); + } + } + } else { + DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = " + "%d ) invalid breakpoint address", + (uint64_t)addr, remove); + } + return false; +} + +bool MachProcess::DisableWatchpoint(nub_addr_t addr, bool remove) { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "MachProcess::%s(addr = 0x%8.8llx, remove = %d)", + __FUNCTION__, (uint64_t)addr, remove); + DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); + if (wp) { + // If we have multiple references to a watchpoint, removing the watchpoint + // shouldn't clear it + if (remove && wp->Release() > 0) + return true; + + nub_addr_t addr = wp->Address(); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = %d )", + (uint64_t)addr, remove); + + if (wp->IsHardware()) { + bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint(wp); + + if (hw_disable_result == true) { + wp->SetEnabled(false); + if (remove) + m_watchpoints.Remove(addr); + DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( " + "addr = 0x%8.8llx, remove = %d ) " + "(hardware) => success", + (uint64_t)addr, remove); + return true; + } + } + + // TODO: clear software watchpoints if we implement them + } else { + DNBLogError("MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = " + "%d ) invalid watchpoint ID", + (uint64_t)addr, remove); + } + return false; +} + +uint32_t MachProcess::GetNumSupportedHardwareWatchpoints() const { + return m_thread_list.NumSupportedHardwareWatchpoints(); +} + +bool MachProcess::EnableBreakpoint(nub_addr_t addr) { + DNBLogThreadedIf(LOG_BREAKPOINTS, + "MachProcess::EnableBreakpoint ( addr = 0x%8.8llx )", + (uint64_t)addr); + DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); + if (bp) { + if (bp->IsEnabled()) { + DNBLogWarning("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " + "breakpoint already enabled.", + (uint64_t)addr); + return true; + } else { + if (bp->HardwarePreferred()) { + bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp)); + if (bp->IsHardware()) { + bp->SetEnabled(true); + return true; + } + } + + const nub_size_t break_op_size = bp->ByteSize(); + assert(break_op_size != 0); + const uint8_t *const break_op = + DNBArchProtocol::GetBreakpointOpcode(break_op_size); + if (break_op_size > 0) { + // Save the original opcode by reading it + if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == + break_op_size) { + // Write a software breakpoint in place of the original opcode + if (m_task.WriteMemory(addr, break_op_size, break_op) == + break_op_size) { + uint8_t verify_break_op[4]; + if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == + break_op_size) { + if (memcmp(break_op, verify_break_op, break_op_size) == 0) { + bp->SetEnabled(true); // Let the thread list know that a breakpoint has been modified - if (remove) - { - m_thread_list.NotifyBreakpointChanged(bp); - m_breakpoints.Remove(addr); - } - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) (hardware) => success", (uint64_t)addr, remove); + m_thread_list.NotifyBreakpointChanged(bp); + DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::" + "EnableBreakpoint ( addr = " + "0x%8.8llx ) : SUCCESS.", + (uint64_t)addr); return true; + } else { + DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx " + "): breakpoint opcode verification failed.", + (uint64_t)addr); + } + } else { + DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " + "unable to read memory to verify breakpoint opcode.", + (uint64_t)addr); } + } else { + DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " + "unable to write breakpoint opcode to memory.", + (uint64_t)addr); + } + } else { + DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): " + "unable to read memory at breakpoint address.", + (uint64_t)addr); + } + } else { + DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ) no " + "software breakpoint opcode for current architecture.", + (uint64_t)addr); + } + } + } + return false; +} + +bool MachProcess::EnableWatchpoint(nub_addr_t addr) { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "MachProcess::EnableWatchpoint(addr = 0x%8.8llx)", + (uint64_t)addr); + DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); + if (wp) { + nub_addr_t addr = wp->Address(); + if (wp->IsEnabled()) { + DNBLogWarning("MachProcess::EnableWatchpoint(addr = 0x%8.8llx): " + "watchpoint already enabled.", + (uint64_t)addr); + return true; + } else { + // Currently only try and set hardware watchpoints. + wp->SetHardwareIndex(m_thread_list.EnableHardwareWatchpoint(wp)); + if (wp->IsHardware()) { + wp->SetEnabled(true); + return true; + } + // TODO: Add software watchpoints by doing page protection tricks. + } + } + return false; +} - return false; - } - - const nub_size_t break_op_size = bp->ByteSize(); - assert (break_op_size > 0); - const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (bp->ByteSize()); - if (break_op_size > 0) - { - // Clear a software breakpoint instruction - uint8_t curr_break_op[break_op_size]; - bool break_op_found = false; - - // Read the breakpoint opcode - if (m_task.ReadMemory(addr, break_op_size, curr_break_op) == break_op_size) - { - bool verify = false; - if (bp->IsEnabled()) - { - // Make sure we have the a breakpoint opcode exists at this address - if (memcmp(curr_break_op, break_op, break_op_size) == 0) - { - break_op_found = true; - // We found a valid breakpoint opcode at this address, now restore - // the saved opcode. - if (m_task.WriteMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size) - { - verify = true; - } - else - { - DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) memory write failed when restoring original opcode", (uint64_t)addr, remove); - } - } - else - { - DNBLogWarning("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) expected a breakpoint opcode but didn't find one.", (uint64_t)addr, remove); - // Set verify to true and so we can check if the original opcode has already been restored - verify = true; - } - } - else - { - DNBLogThreadedIf(LOG_BREAKPOINTS | LOG_VERBOSE, "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) is not enabled", (uint64_t)addr, remove); - // Set verify to true and so we can check if the original opcode is there - verify = true; - } - - if (verify) - { - uint8_t verify_opcode[break_op_size]; - // Verify that our original opcode made it back to the inferior - if (m_task.ReadMemory(addr, break_op_size, verify_opcode) == break_op_size) - { - // compare the memory we just read with the original opcode - if (memcmp(bp->SavedOpcodeBytes(), verify_opcode, break_op_size) == 0) - { - // SUCCESS - bp->SetEnabled(false); - // Let the thread list know that a breakpoint has been modified - if (remove && bp->Release() == 0) - { - m_thread_list.NotifyBreakpointChanged(bp); - m_breakpoints.Remove(addr); - } - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) => success", (uint64_t)addr, remove); - return true; - } - else - { - if (break_op_found) - DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) : failed to restore original opcode", (uint64_t)addr, remove); - else - DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) : opcode changed", (uint64_t)addr, remove); - } - } - else - { - DNBLogWarning("MachProcess::DisableBreakpoint: unable to disable breakpoint 0x%8.8llx", (uint64_t)addr); - } +// Called by the exception thread when an exception has been received from +// our process. The exception message is completely filled and the exception +// data has already been copied. +void MachProcess::ExceptionMessageReceived( + const MachException::Message &exceptionMessage) { + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); + + if (m_exception_messages.empty()) + m_task.Suspend(); + + DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )"); + + // Use a locker to automatically unlock our mutex in case of exceptions + // Add the exception to our internal exception stack + m_exception_messages.push_back(exceptionMessage); +} + +task_t MachProcess::ExceptionMessageBundleComplete() { + // We have a complete bundle of exceptions for our child process. + PTHREAD_MUTEX_LOCKER(locker, m_exception_messages_mutex); + DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %llu exception messages.", + __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); + bool auto_resume = false; + if (!m_exception_messages.empty()) { + m_did_exec = false; + // First check for any SIGTRAP and make sure we didn't exec + const task_t task = m_task.TaskPort(); + size_t i; + if (m_pid != 0) { + bool received_interrupt = false; + uint32_t num_task_exceptions = 0; + for (i = 0; i < m_exception_messages.size(); ++i) { + if (m_exception_messages[i].state.task_port == task) { + ++num_task_exceptions; + const int signo = m_exception_messages[i].state.SoftSignal(); + if (signo == SIGTRAP) { + // SIGTRAP could mean that we exec'ed. We need to check the + // dyld all_image_infos.infoArray to see if it is NULL and if + // so, say that we exec'ed. + const nub_addr_t aii_addr = GetDYLDAllImageInfosAddress(); + if (aii_addr != INVALID_NUB_ADDRESS) { + const nub_addr_t info_array_count_addr = aii_addr + 4; + uint32_t info_array_count = 0; + if (m_task.ReadMemory(info_array_count_addr, 4, + &info_array_count) == 4) { + if (info_array_count == 0) { + m_did_exec = true; + // Force the task port to update itself in case the task port + // changed after exec + DNBError err; + const task_t old_task = m_task.TaskPort(); + const task_t new_task = + m_task.TaskPortForProcessID(err, true); + if (old_task != new_task) + DNBLogThreadedIf( + LOG_PROCESS, + "exec: task changed from 0x%4.4x to 0x%4.4x", old_task, + new_task); } + } else { + DNBLog("error: failed to read all_image_infos.infoArrayCount " + "from 0x%8.8llx", + (uint64_t)info_array_count_addr); + } } - else - { - DNBLogWarning("MachProcess::DisableBreakpoint: unable to read memory at 0x%8.8llx", (uint64_t)addr); + break; + } else if (m_sent_interrupt_signo != 0 && + signo == m_sent_interrupt_signo) { + received_interrupt = true; + } + } + } + + if (m_did_exec) { + cpu_type_t process_cpu_type = + MachProcess::GetCPUTypeForLocalProcess(m_pid); + if (m_cpu_type != process_cpu_type) { + DNBLog("arch changed from 0x%8.8x to 0x%8.8x", m_cpu_type, + process_cpu_type); + m_cpu_type = process_cpu_type; + DNBArchProtocol::SetArchitecture(process_cpu_type); + } + m_thread_list.Clear(); + m_activities.Clear(); + m_breakpoints.DisableAll(); + } + + if (m_sent_interrupt_signo != 0) { + if (received_interrupt) { + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::ExceptionMessageBundleComplete(): " + "process successfully interrupted with signal %i", + m_sent_interrupt_signo); + + // Mark that we received the interrupt signal + m_sent_interrupt_signo = 0; + // Not check if we had a case where: + // 1 - We called MachProcess::Interrupt() but we stopped for another + // reason + // 2 - We called MachProcess::Resume() (but still haven't gotten the + // interrupt signal) + // 3 - We are now incorrectly stopped because we are handling the + // interrupt signal we missed + // 4 - We might need to resume if we stopped only with the interrupt + // signal that we never handled + if (m_auto_resume_signo != 0) { + // Only auto_resume if we stopped with _only_ the interrupt signal + if (num_task_exceptions == 1) { + auto_resume = true; + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::" + "ExceptionMessageBundleComplete(): " + "auto resuming due to unhandled " + "interrupt signal %i", + m_auto_resume_signo); } + m_auto_resume_signo = 0; + } + } else { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::" + "ExceptionMessageBundleComplete(): " + "didn't get signal %i after " + "MachProcess::Interrupt()", + m_sent_interrupt_signo); } + } } - else - { - DNBLogError("MachProcess::DisableBreakpoint ( addr = 0x%8.8llx, remove = %d ) invalid breakpoint address", (uint64_t)addr, remove); - } - return false; -} -bool -MachProcess::DisableWatchpoint(nub_addr_t addr, bool remove) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::%s(addr = 0x%8.8llx, remove = %d)", __FUNCTION__, (uint64_t)addr, remove); - DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); - if (wp) - { - // If we have multiple references to a watchpoint, removing the watchpoint shouldn't clear it - if (remove && wp->Release() > 0) - return true; - - nub_addr_t addr = wp->Address(); - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = %d )", (uint64_t)addr, remove); - - if (wp->IsHardware()) - { - bool hw_disable_result = m_thread_list.DisableHardwareWatchpoint (wp); - - if (hw_disable_result == true) - { - wp->SetEnabled(false); - if (remove) - m_watchpoints.Remove(addr); - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::Disablewatchpoint ( addr = 0x%8.8llx, remove = %d ) (hardware) => success", (uint64_t)addr, remove); - return true; - } - } + // Let all threads recover from stopping and do any clean up based + // on the previous thread state (if any). + m_thread_list.ProcessDidStop(this); + m_activities.Clear(); - // TODO: clear software watchpoints if we implement them - } - else - { - DNBLogError("MachProcess::DisableWatchpoint ( addr = 0x%8.8llx, remove = %d ) invalid watchpoint ID", (uint64_t)addr, remove); - } - return false; + // Let each thread know of any exceptions + for (i = 0; i < m_exception_messages.size(); ++i) { + // Let the thread list figure use the MachProcess to forward all + // exceptions + // on down to each thread. + if (m_exception_messages[i].state.task_port == task) + m_thread_list.NotifyException(m_exception_messages[i].state); + if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) + m_exception_messages[i].Dump(); + } + + if (DNBLogCheckLogBit(LOG_THREAD)) + m_thread_list.Dump(); + + bool step_more = false; + if (m_thread_list.ShouldStop(step_more) && auto_resume == false) { + // Wait for the eEventProcessRunningStateChanged event to be reset + // before changing state to stopped to avoid race condition with + // very fast start/stops + struct timespec timeout; + // DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 + // ms + DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms + m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout); + SetState(eStateStopped); + } else { + // Resume without checking our current state. + PrivateResume(); + } + } else { + DNBLogThreadedIf( + LOG_EXCEPTIONS, "%s empty exception messages bundle (%llu exceptions).", + __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); + } + return m_task.TaskPort(); } +nub_size_t +MachProcess::CopyImageInfos(struct DNBExecutableImageInfo **image_infos, + bool only_changed) { + if (m_image_infos_callback != NULL) + return m_image_infos_callback(ProcessID(), image_infos, only_changed, + m_image_infos_baton); + return 0; +} + +void MachProcess::SharedLibrariesUpdated() { + uint32_t event_bits = eEventSharedLibsStateChange; + // Set the shared library event bit to let clients know of shared library + // changes + m_events.SetEvents(event_bits); + // Wait for the event bit to reset if a reset ACK is requested + m_events.WaitForResetAck(event_bits); +} + +void MachProcess::SetExitInfo(const char *info) { + if (info && info[0]) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(\"%s\")", __FUNCTION__, + info); + m_exit_info.assign(info); + } else { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(NULL)", __FUNCTION__); + m_exit_info.clear(); + } +} + +void MachProcess::AppendSTDOUT(char *s, size_t len) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%llu> %s) ...", __FUNCTION__, + (uint64_t)len, s); + PTHREAD_MUTEX_LOCKER(locker, m_stdio_mutex); + m_stdout_data.append(s, len); + m_events.SetEvents(eEventStdioAvailable); + + // Wait for the event bit to reset if a reset ACK is requested + m_events.WaitForResetAck(eEventStdioAvailable); +} + +size_t MachProcess::GetAvailableSTDOUT(char *buf, size_t buf_size) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, + buf, (uint64_t)buf_size); + PTHREAD_MUTEX_LOCKER(locker, m_stdio_mutex); + size_t bytes_available = m_stdout_data.size(); + if (bytes_available > 0) { + if (bytes_available > buf_size) { + memcpy(buf, m_stdout_data.data(), buf_size); + m_stdout_data.erase(0, buf_size); + bytes_available = buf_size; + } else { + memcpy(buf, m_stdout_data.data(), bytes_available); + m_stdout_data.clear(); + } + } + return bytes_available; +} + +nub_addr_t MachProcess::GetDYLDAllImageInfosAddress() { + DNBError err; + return m_task.GetDYLDAllImageInfosAddress(err); +} + +size_t MachProcess::GetAvailableSTDERR(char *buf, size_t buf_size) { return 0; } + +void *MachProcess::STDIOThread(void *arg) { + MachProcess *proc = (MachProcess *)arg; + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::%s ( arg = %p ) thread starting...", + __FUNCTION__, arg); + +#if defined(__APPLE__) + pthread_setname_np("stdio monitoring thread"); +#endif -uint32_t -MachProcess::GetNumSupportedHardwareWatchpoints () const -{ - return m_thread_list.NumSupportedHardwareWatchpoints(); + // We start use a base and more options so we can control if we + // are currently using a timeout on the mach_msg. We do this to get a + // bunch of related exceptions on our exception port so we can process + // then together. When we have multiple threads, we can get an exception + // per thread and they will come in consecutively. The main thread loop + // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT + // flag set in the options, so we will wait forever for an exception on + // our exception port. After we get one exception, we then will use the + // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current + // exceptions for our process. After we have received the last pending + // exception, we will get a timeout which enables us to then notify + // our main thread that we have an exception bundle available. We then wait + // for the main thread to tell this exception thread to start trying to get + // exceptions messages again and we start again with a mach_msg read with + // infinite timeout. + DNBError err; + int stdout_fd = proc->GetStdoutFileDescriptor(); + int stderr_fd = proc->GetStderrFileDescriptor(); + if (stdout_fd == stderr_fd) + stderr_fd = -1; + + while (stdout_fd >= 0 || stderr_fd >= 0) { + ::pthread_testcancel(); + + fd_set read_fds; + FD_ZERO(&read_fds); + if (stdout_fd >= 0) + FD_SET(stdout_fd, &read_fds); + if (stderr_fd >= 0) + FD_SET(stderr_fd, &read_fds); + int nfds = std::max<int>(stdout_fd, stderr_fd) + 1; + + int num_set_fds = select(nfds, &read_fds, NULL, NULL, NULL); + DNBLogThreadedIf(LOG_PROCESS, + "select (nfds, &read_fds, NULL, NULL, NULL) => %d", + num_set_fds); + + if (num_set_fds < 0) { + int select_errno = errno; + if (DNBLogCheckLogBit(LOG_PROCESS)) { + err.SetError(select_errno, DNBError::POSIX); + err.LogThreadedIfError( + "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds); + } + + switch (select_errno) { + case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate + // the requested number of file descriptors, or we have + // non-blocking IO + break; + case EBADF: // One of the descriptor sets specified an invalid descriptor. + return NULL; + break; + case EINTR: // A signal was delivered before the time limit expired and + // before any of the selected events occurred. + case EINVAL: // The specified time limit is invalid. One of its components + // is negative or too large. + default: // Other unknown error + break; + } + } else if (num_set_fds == 0) { + } else { + char s[1024]; + s[sizeof(s) - 1] = '\0'; // Ensure we have NULL termination + ssize_t bytes_read = 0; + if (stdout_fd >= 0 && FD_ISSET(stdout_fd, &read_fds)) { + do { + bytes_read = ::read(stdout_fd, s, sizeof(s) - 1); + if (bytes_read < 0) { + int read_errno = errno; + DNBLogThreadedIf(LOG_PROCESS, + "read (stdout_fd, ) => %zd errno: %d (%s)", + bytes_read, read_errno, strerror(read_errno)); + } else if (bytes_read == 0) { + // EOF... + DNBLogThreadedIf( + LOG_PROCESS, + "read (stdout_fd, ) => %zd (reached EOF for child STDOUT)", + bytes_read); + stdout_fd = -1; + } else if (bytes_read > 0) { + proc->AppendSTDOUT(s, bytes_read); + } + + } while (bytes_read > 0); + } + + if (stderr_fd >= 0 && FD_ISSET(stderr_fd, &read_fds)) { + do { + bytes_read = ::read(stderr_fd, s, sizeof(s) - 1); + if (bytes_read < 0) { + int read_errno = errno; + DNBLogThreadedIf(LOG_PROCESS, + "read (stderr_fd, ) => %zd errno: %d (%s)", + bytes_read, read_errno, strerror(read_errno)); + } else if (bytes_read == 0) { + // EOF... + DNBLogThreadedIf( + LOG_PROCESS, + "read (stderr_fd, ) => %zd (reached EOF for child STDERR)", + bytes_read); + stderr_fd = -1; + } else if (bytes_read > 0) { + proc->AppendSTDOUT(s, bytes_read); + } + + } while (bytes_read > 0); + } + } + } + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", + __FUNCTION__, arg); + return NULL; } -bool -MachProcess::EnableBreakpoint(nub_addr_t addr) -{ - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( addr = 0x%8.8llx )", (uint64_t)addr); - DNBBreakpoint *bp = m_breakpoints.FindByAddress(addr); - if (bp) - { - if (bp->IsEnabled()) - { - DNBLogWarning("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): breakpoint already enabled.", (uint64_t)addr); - return true; - } - else - { - if (bp->HardwarePreferred()) - { - bp->SetHardwareIndex(m_thread_list.EnableHardwareBreakpoint(bp)); - if (bp->IsHardware()) - { - bp->SetEnabled(true); - return true; - } - } +void MachProcess::SignalAsyncProfileData(const char *info) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%s) ...", __FUNCTION__, info); + PTHREAD_MUTEX_LOCKER(locker, m_profile_data_mutex); + m_profile_data.push_back(info); + m_events.SetEvents(eEventProfileDataAvailable); - const nub_size_t break_op_size = bp->ByteSize(); - assert (break_op_size != 0); - const uint8_t * const break_op = DNBArchProtocol::GetBreakpointOpcode (break_op_size); - if (break_op_size > 0) - { - // Save the original opcode by reading it - if (m_task.ReadMemory(addr, break_op_size, bp->SavedOpcodeBytes()) == break_op_size) - { - // Write a software breakpoint in place of the original opcode - if (m_task.WriteMemory(addr, break_op_size, break_op) == break_op_size) - { - uint8_t verify_break_op[4]; - if (m_task.ReadMemory(addr, break_op_size, verify_break_op) == break_op_size) - { - if (memcmp(break_op, verify_break_op, break_op_size) == 0) - { - bp->SetEnabled(true); - // Let the thread list know that a breakpoint has been modified - m_thread_list.NotifyBreakpointChanged(bp); - DNBLogThreadedIf(LOG_BREAKPOINTS, "MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ) : SUCCESS.", (uint64_t)addr); - return true; - } - else - { - DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): breakpoint opcode verification failed.", (uint64_t)addr); - } - } - else - { - DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): unable to read memory to verify breakpoint opcode.", (uint64_t)addr); - } - } - else - { - DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): unable to write breakpoint opcode to memory.", (uint64_t)addr); - } - } - else - { - DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ): unable to read memory at breakpoint address.", (uint64_t)addr); - } - } - else - { - DNBLogError("MachProcess::EnableBreakpoint ( addr = 0x%8.8llx ) no software breakpoint opcode for current architecture.", (uint64_t)addr); - } - } - } - return false; + // Wait for the event bit to reset if a reset ACK is requested + m_events.WaitForResetAck(eEventProfileDataAvailable); } -bool -MachProcess::EnableWatchpoint(nub_addr_t addr) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "MachProcess::EnableWatchpoint(addr = 0x%8.8llx)", (uint64_t)addr); - DNBBreakpoint *wp = m_watchpoints.FindByAddress(addr); - if (wp) - { - nub_addr_t addr = wp->Address(); - if (wp->IsEnabled()) - { - DNBLogWarning("MachProcess::EnableWatchpoint(addr = 0x%8.8llx): watchpoint already enabled.", (uint64_t)addr); - return true; - } - else - { - // Currently only try and set hardware watchpoints. - wp->SetHardwareIndex(m_thread_list.EnableHardwareWatchpoint(wp)); - if (wp->IsHardware()) - { - wp->SetEnabled(true); - return true; - } - // TODO: Add software watchpoints by doing page protection tricks. - } +size_t MachProcess::GetAsyncProfileData(char *buf, size_t buf_size) { + DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, + buf, (uint64_t)buf_size); + PTHREAD_MUTEX_LOCKER(locker, m_profile_data_mutex); + if (m_profile_data.empty()) + return 0; + + size_t bytes_available = m_profile_data.front().size(); + if (bytes_available > 0) { + if (bytes_available > buf_size) { + memcpy(buf, m_profile_data.front().data(), buf_size); + m_profile_data.front().erase(0, buf_size); + bytes_available = buf_size; + } else { + memcpy(buf, m_profile_data.front().data(), bytes_available); + m_profile_data.erase(m_profile_data.begin()); } - return false; + } + return bytes_available; } -// Called by the exception thread when an exception has been received from -// our process. The exception message is completely filled and the exception -// data has already been copied. -void -MachProcess::ExceptionMessageReceived (const MachException::Message& exceptionMessage) -{ - PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); - - if (m_exception_messages.empty()) - m_task.Suspend(); - - DNBLogThreadedIf(LOG_EXCEPTIONS, "MachProcess::ExceptionMessageReceived ( )"); - - // Use a locker to automatically unlock our mutex in case of exceptions - // Add the exception to our internal exception stack - m_exception_messages.push_back(exceptionMessage); -} - -task_t -MachProcess::ExceptionMessageBundleComplete() -{ - // We have a complete bundle of exceptions for our child process. - PTHREAD_MUTEX_LOCKER (locker, m_exception_messages_mutex); - DNBLogThreadedIf(LOG_EXCEPTIONS, "%s: %llu exception messages.", __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); - bool auto_resume = false; - if (!m_exception_messages.empty()) - { - m_did_exec = false; - // First check for any SIGTRAP and make sure we didn't exec - const task_t task = m_task.TaskPort(); - size_t i; - if (m_pid != 0) - { - bool received_interrupt = false; - uint32_t num_task_exceptions = 0; - for (i=0; i<m_exception_messages.size(); ++i) - { - if (m_exception_messages[i].state.task_port == task) - { - ++num_task_exceptions; - const int signo = m_exception_messages[i].state.SoftSignal(); - if (signo == SIGTRAP) - { - // SIGTRAP could mean that we exec'ed. We need to check the - // dyld all_image_infos.infoArray to see if it is NULL and if - // so, say that we exec'ed. - const nub_addr_t aii_addr = GetDYLDAllImageInfosAddress(); - if (aii_addr != INVALID_NUB_ADDRESS) - { - const nub_addr_t info_array_count_addr = aii_addr + 4; - uint32_t info_array_count = 0; - if (m_task.ReadMemory(info_array_count_addr, 4, &info_array_count) == 4) - { - if (info_array_count == 0) - { - m_did_exec = true; - // Force the task port to update itself in case the task port changed after exec - DNBError err; - const task_t old_task = m_task.TaskPort(); - const task_t new_task = m_task.TaskPortForProcessID (err, true); - if (old_task != new_task) - DNBLogThreadedIf(LOG_PROCESS, "exec: task changed from 0x%4.4x to 0x%4.4x", old_task, new_task); - } - } - else - { - DNBLog ("error: failed to read all_image_infos.infoArrayCount from 0x%8.8llx", (uint64_t)info_array_count_addr); - } - } - break; - } - else if (m_sent_interrupt_signo != 0 && signo == m_sent_interrupt_signo) - { - received_interrupt = true; - } - } - } - - if (m_did_exec) - { - cpu_type_t process_cpu_type = MachProcess::GetCPUTypeForLocalProcess (m_pid); - if (m_cpu_type != process_cpu_type) - { - DNBLog ("arch changed from 0x%8.8x to 0x%8.8x", m_cpu_type, process_cpu_type); - m_cpu_type = process_cpu_type; - DNBArchProtocol::SetArchitecture (process_cpu_type); - } - m_thread_list.Clear(); - m_activities.Clear(); - m_breakpoints.DisableAll(); - } - - if (m_sent_interrupt_signo != 0) - { - if (received_interrupt) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::ExceptionMessageBundleComplete(): process successfully interrupted with signal %i", m_sent_interrupt_signo); - - // Mark that we received the interrupt signal - m_sent_interrupt_signo = 0; - // Not check if we had a case where: - // 1 - We called MachProcess::Interrupt() but we stopped for another reason - // 2 - We called MachProcess::Resume() (but still haven't gotten the interrupt signal) - // 3 - We are now incorrectly stopped because we are handling the interrupt signal we missed - // 4 - We might need to resume if we stopped only with the interrupt signal that we never handled - if (m_auto_resume_signo != 0) - { - // Only auto_resume if we stopped with _only_ the interrupt signal - if (num_task_exceptions == 1) - { - auto_resume = true; - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::ExceptionMessageBundleComplete(): auto resuming due to unhandled interrupt signal %i", m_auto_resume_signo); - } - m_auto_resume_signo = 0; - } - } - else - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::ExceptionMessageBundleComplete(): didn't get signal %i after MachProcess::Interrupt()", - m_sent_interrupt_signo); - } - } - } +void *MachProcess::ProfileThread(void *arg) { + MachProcess *proc = (MachProcess *)arg; + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::%s ( arg = %p ) thread starting...", + __FUNCTION__, arg); - // Let all threads recover from stopping and do any clean up based - // on the previous thread state (if any). - m_thread_list.ProcessDidStop(this); - m_activities.Clear(); +#if defined(__APPLE__) + pthread_setname_np("performance profiling thread"); +#endif - // Let each thread know of any exceptions - for (i=0; i<m_exception_messages.size(); ++i) - { - // Let the thread list figure use the MachProcess to forward all exceptions - // on down to each thread. - if (m_exception_messages[i].state.task_port == task) - m_thread_list.NotifyException(m_exception_messages[i].state); - if (DNBLogCheckLogBit(LOG_EXCEPTIONS)) - m_exception_messages[i].Dump(); - } + while (proc->IsProfilingEnabled()) { + nub_state_t state = proc->GetState(); + if (state == eStateRunning) { + std::string data = + proc->Task().GetProfileData(proc->GetProfileScanType()); + if (!data.empty()) { + proc->SignalAsyncProfileData(data.c_str()); + } + } else if ((state == eStateUnloaded) || (state == eStateDetached) || + (state == eStateUnloaded)) { + // Done. Get out of this thread. + break; + } + + // A simple way to set up the profile interval. We can also use select() or + // dispatch timer source if necessary. + usleep(proc->ProfileInterval()); + } + return NULL; +} - if (DNBLogCheckLogBit(LOG_THREAD)) - m_thread_list.Dump(); - - bool step_more = false; - if (m_thread_list.ShouldStop(step_more) && auto_resume == false) - { - // Wait for the eEventProcessRunningStateChanged event to be reset - // before changing state to stopped to avoid race condition with - // very fast start/stops - struct timespec timeout; - //DNBTimer::OffsetTimeOfDay(&timeout, 0, 250 * 1000); // Wait for 250 ms - DNBTimer::OffsetTimeOfDay(&timeout, 1, 0); // Wait for 250 ms - m_events.WaitForEventsToReset(eEventProcessRunningStateChanged, &timeout); - SetState(eStateStopped); - } - else - { - // Resume without checking our current state. - PrivateResume (); - } +pid_t MachProcess::AttachForDebug(pid_t pid, char *err_str, size_t err_len) { + // Clear out and clean up from any current state + Clear(); + if (pid != 0) { + DNBError err; + // Make sure the process exists... + if (::getpgid(pid) < 0) { + err.SetErrorToErrno(); + const char *err_cstr = err.AsString(); + ::snprintf(err_str, err_len, "%s", + err_cstr ? err_cstr : "No such process"); + return INVALID_NUB_PROCESS; + } + + SetState(eStateAttaching); + m_pid = pid; +// Let ourselves know we are going to be using SBS or BKS if the correct flag +// bit is set... +#if defined(WITH_FBS) || defined(WITH_BKS) + bool found_app_flavor = false; +#endif + +#if defined(WITH_FBS) + if (!found_app_flavor && IsFBSProcess(pid)) { + found_app_flavor = true; + m_flags |= eMachProcessFlagsUsingFBS; + } +#elif defined(WITH_BKS) + if (!found_app_flavor && IsBKSProcess(pid)) { + found_app_flavor = true; + m_flags |= eMachProcessFlagsUsingBKS; } +#elif defined(WITH_SPRINGBOARD) + if (IsSBProcess(pid)) + m_flags |= eMachProcessFlagsUsingSBS; +#endif + if (!m_task.StartExceptionThread(err)) { + const char *err_cstr = err.AsString(); + ::snprintf(err_str, err_len, "%s", + err_cstr ? err_cstr : "unable to start the exception thread"); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); + m_pid = INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; + } + + errno = 0; + if (::ptrace(PT_ATTACHEXC, pid, 0, 0)) + err.SetError(errno); else - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "%s empty exception messages bundle (%llu exceptions).", __PRETTY_FUNCTION__, (uint64_t)m_exception_messages.size()); + err.Clear(); + + if (err.Success()) { + m_flags |= eMachProcessFlagsAttached; + // Sleep a bit to let the exception get received and set our process + // status + // to stopped. + ::usleep(250000); + DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid); + return m_pid; + } else { + ::snprintf(err_str, err_len, "%s", err.AsString()); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); } - return m_task.TaskPort(); + } + return INVALID_NUB_PROCESS; } -nub_size_t -MachProcess::CopyImageInfos ( struct DNBExecutableImageInfo **image_infos, bool only_changed) -{ - if (m_image_infos_callback != NULL) - return m_image_infos_callback(ProcessID(), image_infos, only_changed, m_image_infos_baton); - return 0; +Genealogy::ThreadActivitySP +MachProcess::GetGenealogyInfoForThread(nub_thread_t tid, bool &timed_out) { + return m_activities.GetGenealogyInfoForThread(m_pid, tid, m_thread_list, + m_task.TaskPort(), timed_out); } -void -MachProcess::SharedLibrariesUpdated ( ) -{ - uint32_t event_bits = eEventSharedLibsStateChange; - // Set the shared library event bit to let clients know of shared library - // changes - m_events.SetEvents(event_bits); - // Wait for the event bit to reset if a reset ACK is requested - m_events.WaitForResetAck(event_bits); +Genealogy::ProcessExecutableInfoSP +MachProcess::GetGenealogyImageInfo(size_t idx) { + return m_activities.GetProcessExecutableInfosAtIndex(idx); } -void -MachProcess::SetExitInfo (const char *info) -{ - if (info && info[0]) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(\"%s\")", __FUNCTION__, info); - m_exit_info.assign(info); - } - else - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s(NULL)", __FUNCTION__); - m_exit_info.clear(); - } -} +bool MachProcess::GetOSVersionNumbers(uint64_t *major, uint64_t *minor, + uint64_t *patch) { +#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000) + return false; +#else + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -void -MachProcess::AppendSTDOUT (char* s, size_t len) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (<%llu> %s) ...", __FUNCTION__, (uint64_t)len, s); - PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex); - m_stdout_data.append(s, len); - m_events.SetEvents(eEventStdioAvailable); + NSOperatingSystemVersion vers = + [[NSProcessInfo processInfo] operatingSystemVersion]; + if (major) + *major = vers.majorVersion; + if (minor) + *minor = vers.minorVersion; + if (patch) + *patch = vers.patchVersion; - // Wait for the event bit to reset if a reset ACK is requested - m_events.WaitForResetAck(eEventStdioAvailable); -} - -size_t -MachProcess::GetAvailableSTDOUT (char *buf, size_t buf_size) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, buf, (uint64_t)buf_size); - PTHREAD_MUTEX_LOCKER (locker, m_stdio_mutex); - size_t bytes_available = m_stdout_data.size(); - if (bytes_available > 0) - { - if (bytes_available > buf_size) - { - memcpy(buf, m_stdout_data.data(), buf_size); - m_stdout_data.erase(0, buf_size); - bytes_available = buf_size; - } - else - { - memcpy(buf, m_stdout_data.data(), bytes_available); - m_stdout_data.clear(); - } - } - return bytes_available; -} + [pool drain]; -nub_addr_t -MachProcess::GetDYLDAllImageInfosAddress () -{ - DNBError err; - return m_task.GetDYLDAllImageInfosAddress(err); + return true; +#endif } -size_t -MachProcess::GetAvailableSTDERR (char *buf, size_t buf_size) -{ - return 0; -} +// Do the process specific setup for attach. If this returns NULL, then there's +// no +// platform specific stuff to be done to wait for the attach. If you get +// non-null, +// pass that token to the CheckForProcess method, and then to +// CleanupAfterAttach. -void * -MachProcess::STDIOThread(void *arg) -{ - MachProcess *proc = (MachProcess*) arg; - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg); +// Call PrepareForAttach before attaching to a process that has not yet +// launched +// This returns a token that can be passed to CheckForProcess, and to +// CleanupAfterAttach. +// You should call CleanupAfterAttach to free the token, and do whatever other +// cleanup seems good. -#if defined (__APPLE__) - pthread_setname_np ("stdio monitoring thread"); +const void *MachProcess::PrepareForAttach(const char *path, + nub_launch_flavor_t launch_flavor, + bool waitfor, DNBError &attach_err) { +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) + // Tell SpringBoard to halt the next launch of this application on startup. + + if (!waitfor) + return NULL; + + const char *app_ext = strstr(path, ".app"); + const bool is_app = + app_ext != NULL && (app_ext[4] == '\0' || app_ext[4] == '/'); + if (!is_app) { + DNBLogThreadedIf( + LOG_PROCESS, + "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, " + "we can't tell springboard to wait for launch...", + path); + return NULL; + } + +#if defined(WITH_FBS) + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = eLaunchFlavorFBS; + if (launch_flavor != eLaunchFlavorFBS) + return NULL; +#elif defined(WITH_BKS) + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = eLaunchFlavorBKS; + if (launch_flavor != eLaunchFlavorBKS) + return NULL; +#elif defined(WITH_SPRINGBOARD) + if (launch_flavor == eLaunchFlavorDefault) + launch_flavor = eLaunchFlavorSpringBoard; + if (launch_flavor != eLaunchFlavorSpringBoard) + return NULL; #endif - // We start use a base and more options so we can control if we - // are currently using a timeout on the mach_msg. We do this to get a - // bunch of related exceptions on our exception port so we can process - // then together. When we have multiple threads, we can get an exception - // per thread and they will come in consecutively. The main thread loop - // will start by calling mach_msg to without having the MACH_RCV_TIMEOUT - // flag set in the options, so we will wait forever for an exception on - // our exception port. After we get one exception, we then will use the - // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current - // exceptions for our process. After we have received the last pending - // exception, we will get a timeout which enables us to then notify - // our main thread that we have an exception bundle available. We then wait - // for the main thread to tell this exception thread to start trying to get - // exceptions messages again and we start again with a mach_msg read with - // infinite timeout. - DNBError err; - int stdout_fd = proc->GetStdoutFileDescriptor(); - int stderr_fd = proc->GetStderrFileDescriptor(); - if (stdout_fd == stderr_fd) - stderr_fd = -1; - - while (stdout_fd >= 0 || stderr_fd >= 0) - { - ::pthread_testcancel (); - - fd_set read_fds; - FD_ZERO (&read_fds); - if (stdout_fd >= 0) - FD_SET (stdout_fd, &read_fds); - if (stderr_fd >= 0) - FD_SET (stderr_fd, &read_fds); - int nfds = std::max<int>(stdout_fd, stderr_fd) + 1; - - int num_set_fds = select (nfds, &read_fds, NULL, NULL, NULL); - DNBLogThreadedIf(LOG_PROCESS, "select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds); - - if (num_set_fds < 0) - { - int select_errno = errno; - if (DNBLogCheckLogBit(LOG_PROCESS)) - { - err.SetError (select_errno, DNBError::POSIX); - err.LogThreadedIfError("select (nfds, &read_fds, NULL, NULL, NULL) => %d", num_set_fds); - } + std::string app_bundle_path(path, app_ext + strlen(".app")); - switch (select_errno) - { - case EAGAIN: // The kernel was (perhaps temporarily) unable to allocate the requested number of file descriptors, or we have non-blocking IO - break; - case EBADF: // One of the descriptor sets specified an invalid descriptor. - return NULL; - break; - case EINTR: // A signal was delivered before the time limit expired and before any of the selected events occurred. - case EINVAL: // The specified time limit is invalid. One of its components is negative or too large. - default: // Other unknown error - break; - } - } - else if (num_set_fds == 0) - { - } - else - { - char s[1024]; - s[sizeof(s)-1] = '\0'; // Ensure we have NULL termination - ssize_t bytes_read = 0; - if (stdout_fd >= 0 && FD_ISSET (stdout_fd, &read_fds)) - { - do - { - bytes_read = ::read (stdout_fd, s, sizeof(s)-1); - if (bytes_read < 0) - { - int read_errno = errno; - DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %zd errno: %d (%s)", bytes_read, read_errno, strerror(read_errno)); - } - else if (bytes_read == 0) - { - // EOF... - DNBLogThreadedIf(LOG_PROCESS, "read (stdout_fd, ) => %zd (reached EOF for child STDOUT)", bytes_read); - stdout_fd = -1; - } - else if (bytes_read > 0) - { - proc->AppendSTDOUT(s, bytes_read); - } - - } while (bytes_read > 0); - } + CFStringRef bundleIDCFStr = + CopyBundleIDForPath(app_bundle_path.c_str(), attach_err); + std::string bundleIDStr; + CFString::UTF8(bundleIDCFStr, bundleIDStr); + DNBLogThreadedIf(LOG_PROCESS, + "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", + app_bundle_path.c_str(), bundleIDStr.c_str()); - if (stderr_fd >= 0 && FD_ISSET (stderr_fd, &read_fds)) - { - do - { - bytes_read = ::read (stderr_fd, s, sizeof(s)-1); - if (bytes_read < 0) - { - int read_errno = errno; - DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %zd errno: %d (%s)", bytes_read, read_errno, strerror(read_errno)); - } - else if (bytes_read == 0) - { - // EOF... - DNBLogThreadedIf(LOG_PROCESS, "read (stderr_fd, ) => %zd (reached EOF for child STDERR)", bytes_read); - stderr_fd = -1; - } - else if (bytes_read > 0) - { - proc->AppendSTDOUT(s, bytes_read); - } - - } while (bytes_read > 0); - } - } - } - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%p): thread exiting...", __FUNCTION__, arg); + if (bundleIDCFStr == NULL) { return NULL; -} + } +#if defined(WITH_FBS) + if (launch_flavor == eLaunchFlavorFBS) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -void -MachProcess::SignalAsyncProfileData (const char *info) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (%s) ...", __FUNCTION__, info); - PTHREAD_MUTEX_LOCKER (locker, m_profile_data_mutex); - m_profile_data.push_back(info); - m_events.SetEvents(eEventProfileDataAvailable); - - // Wait for the event bit to reset if a reset ACK is requested - m_events.WaitForResetAck(eEventProfileDataAvailable); -} - - -size_t -MachProcess::GetAsyncProfileData (char *buf, size_t buf_size) -{ - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s (&%p[%llu]) ...", __FUNCTION__, buf, (uint64_t)buf_size); - PTHREAD_MUTEX_LOCKER (locker, m_profile_data_mutex); - if (m_profile_data.empty()) - return 0; - - size_t bytes_available = m_profile_data.front().size(); - if (bytes_available > 0) - { - if (bytes_available > buf_size) - { - memcpy(buf, m_profile_data.front().data(), buf_size); - m_profile_data.front().erase(0, buf_size); - bytes_available = buf_size; - } - else - { - memcpy(buf, m_profile_data.front().data(), bytes_available); - m_profile_data.erase(m_profile_data.begin()); - } - } - return bytes_available; -} + NSString *stdio_path = nil; + NSFileManager *file_manager = [NSFileManager defaultManager]; + const char *null_path = "/dev/null"; + stdio_path = + [file_manager stringWithFileSystemRepresentation:null_path + length:strlen(null_path)]; + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + NSMutableDictionary *options = [NSMutableDictionary dictionary]; -void * -MachProcess::ProfileThread(void *arg) -{ - MachProcess *proc = (MachProcess*) arg; - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( arg = %p ) thread starting...", __FUNCTION__, arg); + DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: " + "@\"%s\",options include stdio path: \"%s\", " + "BKSDebugOptionKeyDebugOnNextLaunch & " + "BKSDebugOptionKeyWaitForDebugger )", + bundleIDStr.c_str(), null_path); -#if defined (__APPLE__) - pthread_setname_np ("performance profiling thread"); -#endif + [debug_options setObject:stdio_path + forKey:FBSDebugOptionKeyStandardOutPath]; + [debug_options setObject:stdio_path + forKey:FBSDebugOptionKeyStandardErrorPath]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:FBSDebugOptionKeyWaitForDebugger]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:FBSDebugOptionKeyDebugOnNextLaunch]; - while (proc->IsProfilingEnabled()) - { - nub_state_t state = proc->GetState(); - if (state == eStateRunning) - { - std::string data = proc->Task().GetProfileData(proc->GetProfileScanType()); - if (!data.empty()) - { - proc->SignalAsyncProfileData(data.c_str()); - } - } - else if ((state == eStateUnloaded) || (state == eStateDetached) || (state == eStateUnloaded)) - { - // Done. Get out of this thread. - break; - } - - // A simple way to set up the profile interval. We can also use select() or dispatch timer source if necessary. - usleep(proc->ProfileInterval()); - } - return NULL; -} + [options setObject:debug_options + forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; + FBSSystemService *system_service = [[FBSSystemService alloc] init]; -pid_t -MachProcess::AttachForDebug (pid_t pid, char *err_str, size_t err_len) -{ - // Clear out and clean up from any current state - Clear(); - if (pid != 0) - { - DNBError err; - // Make sure the process exists... - if (::getpgid (pid) < 0) - { - err.SetErrorToErrno(); - const char *err_cstr = err.AsString(); - ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "No such process"); - return INVALID_NUB_PROCESS; - } + mach_port_t client_port = [system_service createClientPort]; + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block FBSOpenApplicationErrorCode attach_error_code = + FBSOpenApplicationErrorCodeNone; - SetState(eStateAttaching); - m_pid = pid; - // Let ourselves know we are going to be using SBS or BKS if the correct flag bit is set... -#if defined (WITH_FBS) || defined (WITH_BKS) - bool found_app_flavor = false; -#endif - -#if defined (WITH_FBS) - if (!found_app_flavor && IsFBSProcess (pid)) - { - found_app_flavor = true; - m_flags |= eMachProcessFlagsUsingFBS; - } -#elif defined (WITH_BKS) - if (!found_app_flavor && IsBKSProcess (pid)) - { - found_app_flavor = true; - m_flags |= eMachProcessFlagsUsingBKS; - } -#elif defined (WITH_SPRINGBOARD) - if (IsSBProcess(pid)) - m_flags |= eMachProcessFlagsUsingSBS; -#endif - if (!m_task.StartExceptionThread(err)) - { - const char *err_cstr = err.AsString(); - ::snprintf (err_str, err_len, "%s", err_cstr ? err_cstr : "unable to start the exception thread"); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); - m_pid = INVALID_NUB_PROCESS; - return INVALID_NUB_PROCESS; - } + NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; - errno = 0; - if (::ptrace (PT_ATTACHEXC, pid, 0, 0)) - err.SetError(errno); - else - err.Clear(); - - if (err.Success()) - { - m_flags |= eMachProcessFlagsAttached; - // Sleep a bit to let the exception get received and set our process status - // to stopped. - ::usleep(250000); - DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", pid); - return m_pid; - } - else - { - ::snprintf (err_str, err_len, "%s", err.AsString()); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", pid); - } - } - return INVALID_NUB_PROCESS; -} + [system_service openApplication:bundleIDNSStr + options:options + clientPort:client_port + withResult:^(NSError *error) { + // The system service will cleanup the client port we + // created for us. + if (error) + attach_error_code = + (FBSOpenApplicationErrorCode)[error code]; -Genealogy::ThreadActivitySP -MachProcess::GetGenealogyInfoForThread (nub_thread_t tid, bool &timed_out) -{ - return m_activities.GetGenealogyInfoForThread (m_pid, tid, m_thread_list, m_task.TaskPort(), timed_out); -} + [system_service release]; + dispatch_semaphore_signal(semaphore); + }]; -Genealogy::ProcessExecutableInfoSP -MachProcess::GetGenealogyImageInfo (size_t idx) -{ - return m_activities.GetProcessExecutableInfosAtIndex (idx); -} + const uint32_t timeout_secs = 9; -bool -MachProcess::GetOSVersionNumbers (uint64_t *major, uint64_t *minor, uint64_t *patch) -{ -#if defined (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000) - return false; -#else - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); - NSOperatingSystemVersion vers = [[NSProcessInfo processInfo] operatingSystemVersion]; - if (major) - *major = vers.majorVersion; - if (minor) - *minor = vers.minorVersion; - if (patch) - *patch = vers.patchVersion; + long success = dispatch_semaphore_wait(semaphore, timeout) == 0; + if (!success) { + DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); + attach_err.SetErrorString( + "debugserver timed out waiting for openApplication to complete."); + attach_err.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); + } else if (attach_error_code != FBSOpenApplicationErrorCodeNone) { + SetFBSError(attach_error_code, attach_err); + DNBLogError("unable to launch the application with CFBundleIdentifier " + "'%s' bks_error = %ld", + bundleIDStr.c_str(), (NSInteger)attach_error_code); + } + dispatch_release(semaphore); [pool drain]; - - return true; + } #endif -} +#if defined(WITH_BKS) + if (launch_flavor == eLaunchFlavorBKS) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; -// Do the process specific setup for attach. If this returns NULL, then there's no -// platform specific stuff to be done to wait for the attach. If you get non-null, -// pass that token to the CheckForProcess method, and then to CleanupAfterAttach. + NSString *stdio_path = nil; + NSFileManager *file_manager = [NSFileManager defaultManager]; + const char *null_path = "/dev/null"; + stdio_path = + [file_manager stringWithFileSystemRepresentation:null_path + length:strlen(null_path)]; -// Call PrepareForAttach before attaching to a process that has not yet launched -// This returns a token that can be passed to CheckForProcess, and to CleanupAfterAttach. -// You should call CleanupAfterAttach to free the token, and do whatever other -// cleanup seems good. + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + NSMutableDictionary *options = [NSMutableDictionary dictionary]; -const void * -MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flavor, bool waitfor, DNBError &attach_err) -{ -#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined (WITH_FBS) - // Tell SpringBoard to halt the next launch of this application on startup. + DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: " + "@\"%s\",options include stdio path: \"%s\", " + "BKSDebugOptionKeyDebugOnNextLaunch & " + "BKSDebugOptionKeyWaitForDebugger )", + bundleIDStr.c_str(), null_path); - if (!waitfor) - return NULL; + [debug_options setObject:stdio_path + forKey:BKSDebugOptionKeyStandardOutPath]; + [debug_options setObject:stdio_path + forKey:BKSDebugOptionKeyStandardErrorPath]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:BKSDebugOptionKeyWaitForDebugger]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:BKSDebugOptionKeyDebugOnNextLaunch]; - const char *app_ext = strstr(path, ".app"); - const bool is_app = app_ext != NULL && (app_ext[4] == '\0' || app_ext[4] == '/'); - if (!is_app) - { - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::PrepareForAttach(): path '%s' doesn't contain .app, " - "we can't tell springboard to wait for launch...", - path); - return NULL; - } + [options setObject:debug_options + forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; -#if defined (WITH_FBS) - if (launch_flavor == eLaunchFlavorDefault) - launch_flavor = eLaunchFlavorFBS; - if (launch_flavor != eLaunchFlavorFBS) - return NULL; -#elif defined (WITH_BKS) - if (launch_flavor == eLaunchFlavorDefault) - launch_flavor = eLaunchFlavorBKS; - if (launch_flavor != eLaunchFlavorBKS) - return NULL; -#elif defined (WITH_SPRINGBOARD) - if (launch_flavor == eLaunchFlavorDefault) - launch_flavor = eLaunchFlavorSpringBoard; - if (launch_flavor != eLaunchFlavorSpringBoard) - return NULL; -#endif + BKSSystemService *system_service = [[BKSSystemService alloc] init]; - std::string app_bundle_path(path, app_ext + strlen(".app")); + mach_port_t client_port = [system_service createClientPort]; + __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + __block BKSOpenApplicationErrorCode attach_error_code = + BKSOpenApplicationErrorCodeNone; - CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path.c_str (), attach_err); - std::string bundleIDStr; - CFString::UTF8(bundleIDCFStr, bundleIDStr); - DNBLogThreadedIf(LOG_PROCESS, - "CopyBundleIDForPath (%s, err_str) returned @\"%s\"", - app_bundle_path.c_str (), - bundleIDStr.c_str()); + NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; - if (bundleIDCFStr == NULL) - { - return NULL; - } + [system_service openApplication:bundleIDNSStr + options:options + clientPort:client_port + withResult:^(NSError *error) { + // The system service will cleanup the client port we + // created for us. + if (error) + attach_error_code = + (BKSOpenApplicationErrorCode)[error code]; -#if defined (WITH_FBS) - if (launch_flavor == eLaunchFlavorFBS) - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSString *stdio_path = nil; - NSFileManager *file_manager = [NSFileManager defaultManager]; - const char *null_path = "/dev/null"; - stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)]; - - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - - DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: @\"%s\",options include stdio path: \"%s\", " - "BKSDebugOptionKeyDebugOnNextLaunch & BKSDebugOptionKeyWaitForDebugger )", - bundleIDStr.c_str(), - null_path); - - [debug_options setObject: stdio_path forKey: FBSDebugOptionKeyStandardOutPath]; - [debug_options setObject: stdio_path forKey: FBSDebugOptionKeyStandardErrorPath]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: FBSDebugOptionKeyWaitForDebugger]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: FBSDebugOptionKeyDebugOnNextLaunch]; - - [options setObject: debug_options forKey: FBSOpenApplicationOptionKeyDebuggingOptions]; - - FBSSystemService *system_service = [[FBSSystemService alloc] init]; - - mach_port_t client_port = [system_service createClientPort]; - __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __block FBSOpenApplicationErrorCode attach_error_code = FBSOpenApplicationErrorCodeNone; - - NSString *bundleIDNSStr = (NSString *) bundleIDCFStr; - - [system_service openApplication: bundleIDNSStr - options: options - clientPort: client_port - withResult: ^(NSError *error) - { - // The system service will cleanup the client port we created for us. - if (error) - attach_error_code = (FBSOpenApplicationErrorCode)[error code]; - - [system_service release]; - dispatch_semaphore_signal(semaphore); - } - ]; - - const uint32_t timeout_secs = 9; - - dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); - - long success = dispatch_semaphore_wait(semaphore, timeout) == 0; - - if (!success) - { - DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); - attach_err.SetErrorString("debugserver timed out waiting for openApplication to complete."); - attach_err.SetError (OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); - } - else if (attach_error_code != FBSOpenApplicationErrorCodeNone) - { - SetFBSError (attach_error_code, attach_err); - DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %ld", - bundleIDStr.c_str(), - (NSInteger) attach_error_code); - } - dispatch_release(semaphore); - [pool drain]; - } -#endif -#if defined (WITH_BKS) - if (launch_flavor == eLaunchFlavorBKS) - { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - NSString *stdio_path = nil; - NSFileManager *file_manager = [NSFileManager defaultManager]; - const char *null_path = "/dev/null"; - stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)]; - - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - - DNBLogThreadedIf(LOG_PROCESS, "Calling BKSSystemService openApplication: @\"%s\",options include stdio path: \"%s\", " - "BKSDebugOptionKeyDebugOnNextLaunch & BKSDebugOptionKeyWaitForDebugger )", - bundleIDStr.c_str(), - null_path); - - [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardOutPath]; - [debug_options setObject: stdio_path forKey: BKSDebugOptionKeyStandardErrorPath]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyWaitForDebugger]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyDebugOnNextLaunch]; - - [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; - - BKSSystemService *system_service = [[BKSSystemService alloc] init]; - - mach_port_t client_port = [system_service createClientPort]; - __block dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - __block BKSOpenApplicationErrorCode attach_error_code = BKSOpenApplicationErrorCodeNone; - - NSString *bundleIDNSStr = (NSString *) bundleIDCFStr; - - [system_service openApplication: bundleIDNSStr - options: options - clientPort: client_port - withResult: ^(NSError *error) - { - // The system service will cleanup the client port we created for us. - if (error) - attach_error_code = (BKSOpenApplicationErrorCode)[error code]; - - [system_service release]; - dispatch_semaphore_signal(semaphore); - } - ]; - - const uint32_t timeout_secs = 9; - - dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); - - long success = dispatch_semaphore_wait(semaphore, timeout) == 0; - - if (!success) - { - DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); - attach_err.SetErrorString("debugserver timed out waiting for openApplication to complete."); - attach_err.SetError (OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); - } - else if (attach_error_code != BKSOpenApplicationErrorCodeNone) - { - SetBKSError (attach_error_code, attach_err); - DNBLogError("unable to launch the application with CFBundleIdentifier '%s' bks_error = %ld", - bundleIDStr.c_str(), - attach_error_code); - } - dispatch_release(semaphore); - [pool drain]; + [system_service release]; + dispatch_semaphore_signal(semaphore); + }]; + + const uint32_t timeout_secs = 9; + + dispatch_time_t timeout = + dispatch_time(DISPATCH_TIME_NOW, timeout_secs * NSEC_PER_SEC); + + long success = dispatch_semaphore_wait(semaphore, timeout) == 0; + + if (!success) { + DNBLogError("timed out trying to launch %s.", bundleIDStr.c_str()); + attach_err.SetErrorString( + "debugserver timed out waiting for openApplication to complete."); + attach_err.SetError(OPEN_APPLICATION_TIMEOUT_ERROR, DNBError::Generic); + } else if (attach_error_code != BKSOpenApplicationErrorCodeNone) { + SetBKSError(attach_error_code, attach_err); + DNBLogError("unable to launch the application with CFBundleIdentifier " + "'%s' bks_error = %ld", + bundleIDStr.c_str(), attach_error_code); } + dispatch_release(semaphore); + [pool drain]; + } #endif -#if defined (WITH_SPRINGBOARD) - if (launch_flavor == eLaunchFlavorSpringBoard) - { - SBSApplicationLaunchError sbs_error = 0; - - const char *stdout_err = "/dev/null"; - CFString stdio_path; - stdio_path.SetFileSystemRepresentation (stdout_err); - - DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" , NULL, NULL, NULL, @\"%s\", @\"%s\", " - "SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger )", - bundleIDStr.c_str(), - stdout_err, - stdout_err); - - sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, - (CFURLRef)NULL, // openURL - NULL, // launch_argv.get(), - NULL, // launch_envp.get(), // CFDictionaryRef environment - stdio_path.get(), - stdio_path.get(), - SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger); - - if (sbs_error != SBSApplicationLaunchErrorSuccess) - { - attach_err.SetError(sbs_error, DNBError::SpringBoard); - return NULL; - } - } +#if defined(WITH_SPRINGBOARD) + if (launch_flavor == eLaunchFlavorSpringBoard) { + SBSApplicationLaunchError sbs_error = 0; + + const char *stdout_err = "/dev/null"; + CFString stdio_path; + stdio_path.SetFileSystemRepresentation(stdout_err); + + DNBLogThreadedIf(LOG_PROCESS, "SBSLaunchApplicationForDebugging ( @\"%s\" " + ", NULL, NULL, NULL, @\"%s\", @\"%s\", " + "SBSApplicationDebugOnNextLaunch | " + "SBSApplicationLaunchWaitForDebugger )", + bundleIDStr.c_str(), stdout_err, stdout_err); + + sbs_error = SBSLaunchApplicationForDebugging( + bundleIDCFStr, + (CFURLRef)NULL, // openURL + NULL, // launch_argv.get(), + NULL, // launch_envp.get(), // CFDictionaryRef environment + stdio_path.get(), stdio_path.get(), + SBSApplicationDebugOnNextLaunch | SBSApplicationLaunchWaitForDebugger); + + if (sbs_error != SBSApplicationLaunchErrorSuccess) { + attach_err.SetError(sbs_error, DNBError::SpringBoard); + return NULL; + } + } #endif // WITH_SPRINGBOARD - DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch."); - return bundleIDCFStr; -# else // !(defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined (WITH_FBS)) + DNBLogThreadedIf(LOG_PROCESS, "Successfully set DebugOnNextLaunch."); + return bundleIDCFStr; +#else // !(defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined + // (WITH_FBS)) return NULL; #endif } @@ -2753,1148 +2729,1097 @@ MachProcess::PrepareForAttach (const char *path, nub_launch_flavor_t launch_flav // for that token, then the pid will be returned, otherwise INVALID_NUB_PROCESS // will be returned. -nub_process_t -MachProcess::CheckForProcess (const void *attach_token, nub_launch_flavor_t launch_flavor) -{ - if (attach_token == NULL) - return INVALID_NUB_PROCESS; - -#if defined (WITH_FBS) - if (launch_flavor == eLaunchFlavorFBS) - { - NSString *bundleIDNSStr = (NSString *) attach_token; - FBSSystemService *systemService = [[FBSSystemService alloc] init]; - pid_t pid = [systemService pidForApplication: bundleIDNSStr]; - [systemService release]; - if (pid == 0) - return INVALID_NUB_PROCESS; - else - return pid; - } +nub_process_t MachProcess::CheckForProcess(const void *attach_token, + nub_launch_flavor_t launch_flavor) { + if (attach_token == NULL) + return INVALID_NUB_PROCESS; + +#if defined(WITH_FBS) + if (launch_flavor == eLaunchFlavorFBS) { + NSString *bundleIDNSStr = (NSString *)attach_token; + FBSSystemService *systemService = [[FBSSystemService alloc] init]; + pid_t pid = [systemService pidForApplication:bundleIDNSStr]; + [systemService release]; + if (pid == 0) + return INVALID_NUB_PROCESS; + else + return pid; + } #endif -#if defined (WITH_BKS) - if (launch_flavor == eLaunchFlavorBKS) - { - NSString *bundleIDNSStr = (NSString *) attach_token; +#if defined(WITH_BKS) + if (launch_flavor == eLaunchFlavorBKS) { + NSString *bundleIDNSStr = (NSString *)attach_token; BKSSystemService *systemService = [[BKSSystemService alloc] init]; - pid_t pid = [systemService pidForApplication: bundleIDNSStr]; + pid_t pid = [systemService pidForApplication:bundleIDNSStr]; [systemService release]; if (pid == 0) - return INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; else - return pid; - } + return pid; + } #endif -#if defined (WITH_SPRINGBOARD) - if (launch_flavor == eLaunchFlavorSpringBoard) - { - CFStringRef bundleIDCFStr = (CFStringRef) attach_token; +#if defined(WITH_SPRINGBOARD) + if (launch_flavor == eLaunchFlavorSpringBoard) { + CFStringRef bundleIDCFStr = (CFStringRef)attach_token; Boolean got_it; nub_process_t attach_pid; got_it = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &attach_pid); if (got_it) - return attach_pid; + return attach_pid; else - return INVALID_NUB_PROCESS; - } + return INVALID_NUB_PROCESS; + } #endif - return INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; } -// Call this to clean up after you have either attached or given up on the attach. +// Call this to clean up after you have either attached or given up on the +// attach. // Pass true for success if you have attached, false if you have not. // The token will also be freed at this point, so you can't use it after calling // this method. -void -MachProcess::CleanupAfterAttach (const void *attach_token, nub_launch_flavor_t launch_flavor, bool success, DNBError &err_str) -{ - if (attach_token == NULL) - return; +void MachProcess::CleanupAfterAttach(const void *attach_token, + nub_launch_flavor_t launch_flavor, + bool success, DNBError &err_str) { + if (attach_token == NULL) + return; -#if defined (WITH_FBS) - if (launch_flavor == eLaunchFlavorFBS) - { - if (!success) - { - FBSCleanupAfterAttach (attach_token, err_str); - } - CFRelease((CFStringRef) attach_token); +#if defined(WITH_FBS) + if (launch_flavor == eLaunchFlavorFBS) { + if (!success) { + FBSCleanupAfterAttach(attach_token, err_str); } + CFRelease((CFStringRef)attach_token); + } #endif -#if defined (WITH_BKS) +#if defined(WITH_BKS) - if (launch_flavor == eLaunchFlavorBKS) - { - if (!success) - { - BKSCleanupAfterAttach (attach_token, err_str); - } - CFRelease((CFStringRef) attach_token); + if (launch_flavor == eLaunchFlavorBKS) { + if (!success) { + BKSCleanupAfterAttach(attach_token, err_str); } + CFRelease((CFStringRef)attach_token); + } #endif - -#if defined (WITH_SPRINGBOARD) - // Tell SpringBoard to cancel the debug on next launch of this application - // if we failed to attach - if (launch_flavor == eMachProcessFlagsUsingSpringBoard) - { - if (!success) - { - SBSApplicationLaunchError sbs_error = 0; - CFStringRef bundleIDCFStr = (CFStringRef) attach_token; - - sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, - (CFURLRef)NULL, - NULL, - NULL, - NULL, - NULL, - SBSApplicationCancelDebugOnNextLaunch); - - if (sbs_error != SBSApplicationLaunchErrorSuccess) - { - err_str.SetError(sbs_error, DNBError::SpringBoard); - return; - } - } - CFRelease((CFStringRef) attach_token); +#if defined(WITH_SPRINGBOARD) + // Tell SpringBoard to cancel the debug on next launch of this application + // if we failed to attach + if (launch_flavor == eMachProcessFlagsUsingSpringBoard) { + if (!success) { + SBSApplicationLaunchError sbs_error = 0; + CFStringRef bundleIDCFStr = (CFStringRef)attach_token; + + sbs_error = SBSLaunchApplicationForDebugging( + bundleIDCFStr, (CFURLRef)NULL, NULL, NULL, NULL, NULL, + SBSApplicationCancelDebugOnNextLaunch); + + if (sbs_error != SBSApplicationLaunchErrorSuccess) { + err_str.SetError(sbs_error, DNBError::SpringBoard); + return; + } } + + CFRelease((CFStringRef)attach_token); + } #endif } -pid_t -MachProcess::LaunchForDebug -( - const char *path, - char const *argv[], - char const *envp[], - const char *working_directory, // NULL => don't change, non-NULL => set working directory for inferior to this - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - nub_launch_flavor_t launch_flavor, - int disable_aslr, - const char *event_data, - DNBError &launch_err -) -{ - // Clear out and clean up from any current state - Clear(); - - DNBLogThreadedIf(LOG_PROCESS, "%s( path = '%s', argv = %p, envp = %p, launch_flavor = %u, disable_aslr = %d )", __FUNCTION__, path, argv, envp, launch_flavor, disable_aslr); - - // Fork a child process for debugging - SetState(eStateLaunching); - - switch (launch_flavor) - { - case eLaunchFlavorForkExec: - m_pid = MachProcess::ForkChildForPTraceDebugging (path, argv, envp, this, launch_err); - break; +pid_t MachProcess::LaunchForDebug( + const char *path, char const *argv[], char const *envp[], + const char *working_directory, // NULL => don't change, non-NULL => set + // working directory for inferior to this + const char *stdin_path, const char *stdout_path, const char *stderr_path, + bool no_stdio, nub_launch_flavor_t launch_flavor, int disable_aslr, + const char *event_data, DNBError &launch_err) { + // Clear out and clean up from any current state + Clear(); + + DNBLogThreadedIf(LOG_PROCESS, "%s( path = '%s', argv = %p, envp = %p, " + "launch_flavor = %u, disable_aslr = %d )", + __FUNCTION__, path, argv, envp, launch_flavor, disable_aslr); + + // Fork a child process for debugging + SetState(eStateLaunching); + + switch (launch_flavor) { + case eLaunchFlavorForkExec: + m_pid = MachProcess::ForkChildForPTraceDebugging(path, argv, envp, this, + launch_err); + break; #ifdef WITH_FBS - case eLaunchFlavorFBS: - { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingFBS; - if (BoardServiceLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a FBS launch, but didn't succeed lets get out - } - } - break; + case eLaunchFlavorFBS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingFBS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a FBS launch, but didn't succeed lets get out + } + } break; #endif #ifdef WITH_BKS - case eLaunchFlavorBKS: - { - const char *app_ext = strstr(path, ".app"); - if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - m_flags |= eMachProcessFlagsUsingBKS; - if (BoardServiceLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, event_data, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a BKS launch, but didn't succeed lets get out - } - } - break; + case eLaunchFlavorBKS: { + const char *app_ext = strstr(path, ".app"); + if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + m_flags |= eMachProcessFlagsUsingBKS; + if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp, + no_stdio, disable_aslr, event_data, + launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a BKS launch, but didn't succeed lets get out + } + } break; #endif #ifdef WITH_SPRINGBOARD - case eLaunchFlavorSpringBoard: - { - // .../whatever.app/whatever ? - // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in "com.apple.whatever" here - const char *app_ext = strstr (path, ".app/"); - if (app_ext == NULL) - { - // .../whatever.app ? - int len = strlen (path); - if (len > 5) - { - if (strcmp (path + len - 4, ".app") == 0) - { - app_ext = path + len - 4; - } - } - } - if (app_ext) - { - std::string app_bundle_path(path, app_ext + strlen(".app")); - if (SBLaunchForDebug (app_bundle_path.c_str(), argv, envp, no_stdio, disable_aslr, launch_err) != 0) - return m_pid; // A successful SBLaunchForDebug() returns and assigns a non-zero m_pid. - else - break; // We tried a springboard launch, but didn't succeed lets get out - } - } - break; + case eLaunchFlavorSpringBoard: { + // .../whatever.app/whatever ? + // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in + // "com.apple.whatever" here + const char *app_ext = strstr(path, ".app/"); + if (app_ext == NULL) { + // .../whatever.app ? + int len = strlen(path); + if (len > 5) { + if (strcmp(path + len - 4, ".app") == 0) { + app_ext = path + len - 4; + } + } + } + if (app_ext) { + std::string app_bundle_path(path, app_ext + strlen(".app")); + if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio, + disable_aslr, launch_err) != 0) + return m_pid; // A successful SBLaunchForDebug() returns and assigns a + // non-zero m_pid. + else + break; // We tried a springboard launch, but didn't succeed lets get out + } + } break; #endif - case eLaunchFlavorPosixSpawn: - m_pid = MachProcess::PosixSpawnChildForPTraceDebugging (path, - DNBArchProtocol::GetArchitecture (), - argv, - envp, - working_directory, - stdin_path, - stdout_path, - stderr_path, - no_stdio, - this, - disable_aslr, - launch_err); - break; + case eLaunchFlavorPosixSpawn: + m_pid = MachProcess::PosixSpawnChildForPTraceDebugging( + path, DNBArchProtocol::GetArchitecture(), argv, envp, working_directory, + stdin_path, stdout_path, stderr_path, no_stdio, this, disable_aslr, + launch_err); + break; - default: - // Invalid launch + default: + // Invalid launch + launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); + return INVALID_NUB_PROCESS; + } + + if (m_pid == INVALID_NUB_PROCESS) { + // If we don't have a valid process ID and no one has set the error, + // then return a generic error + if (launch_err.Success()) + launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); + } else { + m_path = path; + size_t i; + char const *arg; + for (i = 0; (arg = argv[i]) != NULL; i++) + m_args.push_back(arg); + + m_task.StartExceptionThread(launch_err); + if (launch_err.Fail()) { + if (launch_err.AsString() == NULL) + launch_err.SetErrorString("unable to start the exception thread"); + DNBLog("Could not get inferior's Mach exception port, sending ptrace " + "PT_KILL and exiting."); + ::ptrace(PT_KILL, m_pid, 0, 0); + m_pid = INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; + } + + StartSTDIOThread(); + + if (launch_flavor == eLaunchFlavorPosixSpawn) { + + SetState(eStateAttaching); + errno = 0; + int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + if (err == 0) { + m_flags |= eMachProcessFlagsAttached; + DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid); + launch_err.Clear(); + } else { + SetState(eStateExited); + DNBError ptrace_err(errno, DNBError::POSIX); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid " + "%d (err = %i, errno = %i (%s))", + m_pid, err, ptrace_err.Error(), ptrace_err.AsString()); launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); - return INVALID_NUB_PROCESS; - } + } + } else { + launch_err.Clear(); + } + } + return m_pid; +} + +pid_t MachProcess::PosixSpawnChildForPTraceDebugging( + const char *path, cpu_type_t cpu_type, char const *argv[], + char const *envp[], const char *working_directory, const char *stdin_path, + const char *stdout_path, const char *stderr_path, bool no_stdio, + MachProcess *process, int disable_aslr, DNBError &err) { + posix_spawnattr_t attr; + short flags; + DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv=%p, envp=%p, " + "working_dir=%s, stdin=%s, stdout=%s " + "stderr=%s, no-stdio=%i)", + __FUNCTION__, path, argv, envp, working_directory, + stdin_path, stdout_path, stderr_path, no_stdio); + + err.SetError(::posix_spawnattr_init(&attr), DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawnattr_init ( &attr )"); + if (err.Fail()) + return INVALID_NUB_PROCESS; - if (m_pid == INVALID_NUB_PROCESS) - { - // If we don't have a valid process ID and no one has set the error, - // then return a generic error - if (launch_err.Success()) - launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); - } - else - { - m_path = path; - size_t i; - char const *arg; - for (i=0; (arg = argv[i]) != NULL; i++) - m_args.push_back(arg); - - m_task.StartExceptionThread(launch_err); - if (launch_err.Fail()) - { - if (launch_err.AsString() == NULL) - launch_err.SetErrorString("unable to start the exception thread"); - DNBLog ("Could not get inferior's Mach exception port, sending ptrace PT_KILL and exiting."); - ::ptrace (PT_KILL, m_pid, 0, 0); - m_pid = INVALID_NUB_PROCESS; - return INVALID_NUB_PROCESS; - } + flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | + POSIX_SPAWN_SETSIGMASK; + if (disable_aslr) + flags |= _POSIX_SPAWN_DISABLE_ASLR; + + sigset_t no_signals; + sigset_t all_signals; + sigemptyset(&no_signals); + sigfillset(&all_signals); + ::posix_spawnattr_setsigmask(&attr, &no_signals); + ::posix_spawnattr_setsigdefault(&attr, &all_signals); + + err.SetError(::posix_spawnattr_setflags(&attr, flags), DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded( + "::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED%s )", + flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" + : ""); + if (err.Fail()) + return INVALID_NUB_PROCESS; - StartSTDIOThread(); +// Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail +// and we will fail to continue with our process... - if (launch_flavor == eLaunchFlavorPosixSpawn) - { +// On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment.... - SetState (eStateAttaching); - errno = 0; - int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0); - if (err == 0) - { - m_flags |= eMachProcessFlagsAttached; - DNBLogThreadedIf(LOG_PROCESS, "successfully spawned pid %d", m_pid); - launch_err.Clear(); - } - else - { - SetState (eStateExited); - DNBError ptrace_err(errno, DNBError::POSIX); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to spawned pid %d (err = %i, errno = %i (%s))", m_pid, err, ptrace_err.Error(), ptrace_err.AsString()); - launch_err.SetError(NUB_GENERIC_ERROR, DNBError::Generic); - } - } - else - { - launch_err.Clear(); - } - } - return m_pid; -} - -pid_t -MachProcess::PosixSpawnChildForPTraceDebugging -( - const char *path, - cpu_type_t cpu_type, - char const *argv[], - char const *envp[], - const char *working_directory, - const char *stdin_path, - const char *stdout_path, - const char *stderr_path, - bool no_stdio, - MachProcess* process, - int disable_aslr, - DNBError& err -) -{ - posix_spawnattr_t attr; - short flags; - DNBLogThreadedIf(LOG_PROCESS, "%s ( path='%s', argv=%p, envp=%p, working_dir=%s, stdin=%s, stdout=%s stderr=%s, no-stdio=%i)", - __FUNCTION__, - path, - argv, - envp, - working_directory, - stdin_path, - stdout_path, - stderr_path, - no_stdio); - - err.SetError( ::posix_spawnattr_init (&attr), DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnattr_init ( &attr )"); - if (err.Fail()) - return INVALID_NUB_PROCESS; - - flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK; - if (disable_aslr) - flags |= _POSIX_SPAWN_DISABLE_ASLR; - - sigset_t no_signals; - sigset_t all_signals; - sigemptyset (&no_signals); - sigfillset (&all_signals); - ::posix_spawnattr_setsigmask(&attr, &no_signals); - ::posix_spawnattr_setsigdefault(&attr, &all_signals); - - err.SetError( ::posix_spawnattr_setflags (&attr, flags), DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnattr_setflags ( &attr, POSIX_SPAWN_START_SUSPENDED%s )", flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR" : ""); - if (err.Fail()) - return INVALID_NUB_PROCESS; - - // Don't do this on SnowLeopard, _sometimes_ the TASK_BASIC_INFO will fail - // and we will fail to continue with our process... - - // On SnowLeopard we should set "DYLD_NO_PIE" in the inferior environment.... - #if !defined(__arm__) - // We don't need to do this for ARM, and we really shouldn't now that we - // have multiple CPU subtypes and no posix_spawnattr call that allows us - // to set which CPU subtype to launch... - if (cpu_type != 0) - { - size_t ocount = 0; - err.SetError( ::posix_spawnattr_setbinpref_np (&attr, 1, &cpu_type, &ocount), DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = 0x%8.8x, count => %llu )", cpu_type, (uint64_t)ocount); + // We don't need to do this for ARM, and we really shouldn't now that we + // have multiple CPU subtypes and no posix_spawnattr call that allows us + // to set which CPU subtype to launch... + if (cpu_type != 0) { + size_t ocount = 0; + err.SetError(::posix_spawnattr_setbinpref_np(&attr, 1, &cpu_type, &ocount), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawnattr_setbinpref_np ( &attr, 1, cpu_type = " + "0x%8.8x, count => %llu )", + cpu_type, (uint64_t)ocount); - if (err.Fail() != 0 || ocount != 1) - return INVALID_NUB_PROCESS; - } + if (err.Fail() != 0 || ocount != 1) + return INVALID_NUB_PROCESS; + } #endif - PseudoTerminal pty; - - posix_spawn_file_actions_t file_actions; - err.SetError( ::posix_spawn_file_actions_init (&file_actions), DNBError::POSIX); - int file_actions_valid = err.Success(); - if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )"); - int pty_error = -1; - pid_t pid = INVALID_NUB_PROCESS; - if (file_actions_valid) - { - if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && !no_stdio) - { - pty_error = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY); - if (pty_error == PseudoTerminal::success) - { - stdin_path = stdout_path = stderr_path = pty.SlaveName(); - } - } - - // if no_stdio or std paths not supplied, then route to "/dev/null". - if (no_stdio || stdin_path == NULL || stdin_path[0] == '\0') - stdin_path = "/dev/null"; - if (no_stdio || stdout_path == NULL || stdout_path[0] == '\0') - stdout_path = "/dev/null"; - if (no_stdio || stderr_path == NULL || stderr_path[0] == '\0') - stderr_path = "/dev/null"; - - err.SetError( ::posix_spawn_file_actions_addopen (&file_actions, - STDIN_FILENO, - stdin_path, - O_RDONLY | O_NOCTTY, - 0), - DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS)) - err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDIN_FILENO, path='%s')", stdin_path); - - err.SetError( ::posix_spawn_file_actions_addopen (&file_actions, - STDOUT_FILENO, - stdout_path, - O_WRONLY | O_NOCTTY | O_CREAT, - 0640), - DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS)) - err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDOUT_FILENO, path='%s')", stdout_path); - - err.SetError( ::posix_spawn_file_actions_addopen (&file_actions, - STDERR_FILENO, - stderr_path, - O_WRONLY | O_NOCTTY | O_CREAT, - 0640), - DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit (LOG_PROCESS)) - err.LogThreaded ("::posix_spawn_file_actions_addopen (&file_actions, filedes=STDERR_FILENO, path='%s')", stderr_path); - - // TODO: Verify if we can set the working directory back immediately - // after the posix_spawnp call without creating a race condition??? - if (working_directory) - ::chdir (working_directory); - - err.SetError( ::posix_spawnp (&pid, path, &file_actions, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, &file_actions, &attr, argv, envp); - } - else - { - // TODO: Verify if we can set the working directory back immediately - // after the posix_spawnp call without creating a race condition??? - if (working_directory) - ::chdir (working_directory); - - err.SetError( ::posix_spawnp (&pid, path, NULL, &attr, (char * const*)argv, (char * const*)envp), DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = %p, attr = %p, argv = %p, envp = %p )", pid, path, NULL, &attr, argv, envp); - } - - // We have seen some cases where posix_spawnp was returning a valid - // looking pid even when an error was returned, so clear it out - if (err.Fail()) - pid = INVALID_NUB_PROCESS; - - if (pty_error == 0) - { - if (process != NULL) - { - int master_fd = pty.ReleaseMasterFD(); - process->SetChildFileDescriptors(master_fd, master_fd, master_fd); - } - } - ::posix_spawnattr_destroy (&attr); - - if (pid != INVALID_NUB_PROCESS) - { - cpu_type_t pid_cpu_type = MachProcess::GetCPUTypeForLocalProcess (pid); - DNBLogThreadedIf(LOG_PROCESS, "MachProcess::%s ( ) pid=%i, cpu_type=0x%8.8x", __FUNCTION__, pid, pid_cpu_type); - if (pid_cpu_type) - DNBArchProtocol::SetArchitecture (pid_cpu_type); - } - - if (file_actions_valid) - { - DNBError err2; - err2.SetError( ::posix_spawn_file_actions_destroy (&file_actions), DNBError::POSIX); - if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) - err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )"); - } - - return pid; -} + PseudoTerminal pty; + + posix_spawn_file_actions_t file_actions; + err.SetError(::posix_spawn_file_actions_init(&file_actions), DNBError::POSIX); + int file_actions_valid = err.Success(); + if (!file_actions_valid || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawn_file_actions_init ( &file_actions )"); + int pty_error = -1; + pid_t pid = INVALID_NUB_PROCESS; + if (file_actions_valid) { + if (stdin_path == NULL && stdout_path == NULL && stderr_path == NULL && + !no_stdio) { + pty_error = pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY); + if (pty_error == PseudoTerminal::success) { + stdin_path = stdout_path = stderr_path = pty.SlaveName(); + } + } + + // if no_stdio or std paths not supplied, then route to "/dev/null". + if (no_stdio || stdin_path == NULL || stdin_path[0] == '\0') + stdin_path = "/dev/null"; + if (no_stdio || stdout_path == NULL || stdout_path[0] == '\0') + stdout_path = "/dev/null"; + if (no_stdio || stderr_path == NULL || stderr_path[0] == '\0') + stderr_path = "/dev/null"; + + err.SetError(::posix_spawn_file_actions_addopen(&file_actions, STDIN_FILENO, + stdin_path, + O_RDONLY | O_NOCTTY, 0), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " + "filedes=STDIN_FILENO, path='%s')", + stdin_path); + + err.SetError(::posix_spawn_file_actions_addopen( + &file_actions, STDOUT_FILENO, stdout_path, + O_WRONLY | O_NOCTTY | O_CREAT, 0640), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " + "filedes=STDOUT_FILENO, path='%s')", + stdout_path); + + err.SetError(::posix_spawn_file_actions_addopen( + &file_actions, STDERR_FILENO, stderr_path, + O_WRONLY | O_NOCTTY | O_CREAT, 0640), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawn_file_actions_addopen (&file_actions, " + "filedes=STDERR_FILENO, path='%s')", + stderr_path); + + // TODO: Verify if we can set the working directory back immediately + // after the posix_spawnp call without creating a race condition??? + if (working_directory) + ::chdir(working_directory); + + err.SetError(::posix_spawnp(&pid, path, &file_actions, &attr, + (char *const *)argv, (char *const *)envp), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = " + "%p, attr = %p, argv = %p, envp = %p )", + pid, path, &file_actions, &attr, argv, envp); + } else { + // TODO: Verify if we can set the working directory back immediately + // after the posix_spawnp call without creating a race condition??? + if (working_directory) + ::chdir(working_directory); + + err.SetError(::posix_spawnp(&pid, path, NULL, &attr, (char *const *)argv, + (char *const *)envp), + DNBError::POSIX); + if (err.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err.LogThreaded("::posix_spawnp ( pid => %i, path = '%s', file_actions = " + "%p, attr = %p, argv = %p, envp = %p )", + pid, path, NULL, &attr, argv, envp); + } + + // We have seen some cases where posix_spawnp was returning a valid + // looking pid even when an error was returned, so clear it out + if (err.Fail()) + pid = INVALID_NUB_PROCESS; + + if (pty_error == 0) { + if (process != NULL) { + int master_fd = pty.ReleaseMasterFD(); + process->SetChildFileDescriptors(master_fd, master_fd, master_fd); + } + } + ::posix_spawnattr_destroy(&attr); + + if (pid != INVALID_NUB_PROCESS) { + cpu_type_t pid_cpu_type = MachProcess::GetCPUTypeForLocalProcess(pid); + DNBLogThreadedIf(LOG_PROCESS, + "MachProcess::%s ( ) pid=%i, cpu_type=0x%8.8x", + __FUNCTION__, pid, pid_cpu_type); + if (pid_cpu_type) + DNBArchProtocol::SetArchitecture(pid_cpu_type); + } + + if (file_actions_valid) { + DNBError err2; + err2.SetError(::posix_spawn_file_actions_destroy(&file_actions), + DNBError::POSIX); + if (err2.Fail() || DNBLogCheckLogBit(LOG_PROCESS)) + err2.LogThreaded("::posix_spawn_file_actions_destroy ( &file_actions )"); + } + + return pid; +} + +uint32_t MachProcess::GetCPUTypeForLocalProcess(pid_t pid) { + int mib[CTL_MAXNAME] = { + 0, + }; + size_t len = CTL_MAXNAME; + if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) + return 0; -uint32_t -MachProcess::GetCPUTypeForLocalProcess (pid_t pid) -{ - int mib[CTL_MAXNAME]={0,}; - size_t len = CTL_MAXNAME; - if (::sysctlnametomib("sysctl.proc_cputype", mib, &len)) - return 0; - - mib[len] = pid; - len++; - - cpu_type_t cpu; - size_t cpu_len = sizeof(cpu); - if (::sysctl (mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) - cpu = 0; - return cpu; -} - -pid_t -MachProcess::ForkChildForPTraceDebugging -( - const char *path, - char const *argv[], - char const *envp[], - MachProcess* process, - DNBError& launch_err -) -{ - PseudoTerminal::Error pty_error = PseudoTerminal::success; - - // Use a fork that ties the child process's stdin/out/err to a pseudo - // terminal so we can read it in our MachProcess::STDIOThread - // as unbuffered io. - PseudoTerminal pty; - pid_t pid = pty.Fork(pty_error); - - if (pid < 0) - { - //-------------------------------------------------------------- - // Error during fork. - //-------------------------------------------------------------- - return pid; - } - else if (pid == 0) - { - //-------------------------------------------------------------- - // Child process - //-------------------------------------------------------------- - ::ptrace (PT_TRACE_ME, 0, 0, 0); // Debug this process - ::ptrace (PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions - - // If our parent is setgid, lets make sure we don't inherit those - // extra powers due to nepotism. - if (::setgid (getgid ()) == 0) - { - - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race condition - // between the two processes. - ::setpgid (0, 0); // Set the child process group to match its pid - - // Sleep a bit to before the exec call - ::sleep (1); - - // Turn this process into - ::execv (path, (char * const *)argv); - } - // Exit with error code. Child process should have taken - // over in above exec call and if the exec fails it will - // exit the child process below. - ::exit (127); - } - else - { - //-------------------------------------------------------------- - // Parent process - //-------------------------------------------------------------- - // Let the child have its own process group. We need to execute - // this call in both the child and parent to avoid a race condition - // between the two processes. - ::setpgid (pid, pid); // Set the child process group to match its pid - - if (process != NULL) - { - // Release our master pty file descriptor so the pty class doesn't - // close it and so we can continue to use it in our STDIO thread - int master_fd = pty.ReleaseMasterFD(); - process->SetChildFileDescriptors(master_fd, master_fd, master_fd); - } - } + mib[len] = pid; + len++; + + cpu_type_t cpu; + size_t cpu_len = sizeof(cpu); + if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0)) + cpu = 0; + return cpu; +} + +pid_t MachProcess::ForkChildForPTraceDebugging(const char *path, + char const *argv[], + char const *envp[], + MachProcess *process, + DNBError &launch_err) { + PseudoTerminal::Error pty_error = PseudoTerminal::success; + + // Use a fork that ties the child process's stdin/out/err to a pseudo + // terminal so we can read it in our MachProcess::STDIOThread + // as unbuffered io. + PseudoTerminal pty; + pid_t pid = pty.Fork(pty_error); + + if (pid < 0) { + //-------------------------------------------------------------- + // Error during fork. + //-------------------------------------------------------------- return pid; -} - -#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined (WITH_FBS) + } else if (pid == 0) { + //-------------------------------------------------------------- + // Child process + //-------------------------------------------------------------- + ::ptrace(PT_TRACE_ME, 0, 0, 0); // Debug this process + ::ptrace(PT_SIGEXC, 0, 0, 0); // Get BSD signals as mach exceptions + + // If our parent is setgid, lets make sure we don't inherit those + // extra powers due to nepotism. + if (::setgid(getgid()) == 0) { + + // Let the child have its own process group. We need to execute + // this call in both the child and parent to avoid a race condition + // between the two processes. + ::setpgid(0, 0); // Set the child process group to match its pid + + // Sleep a bit to before the exec call + ::sleep(1); + + // Turn this process into + ::execv(path, (char *const *)argv); + } + // Exit with error code. Child process should have taken + // over in above exec call and if the exec fails it will + // exit the child process below. + ::exit(127); + } else { + //-------------------------------------------------------------- + // Parent process + //-------------------------------------------------------------- + // Let the child have its own process group. We need to execute + // this call in both the child and parent to avoid a race condition + // between the two processes. + ::setpgid(pid, pid); // Set the child process group to match its pid + + if (process != NULL) { + // Release our master pty file descriptor so the pty class doesn't + // close it and so we can continue to use it in our STDIO thread + int master_fd = pty.ReleaseMasterFD(); + process->SetChildFileDescriptors(master_fd, master_fd, master_fd); + } + } + return pid; +} + +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) || defined(WITH_FBS) // This returns a CFRetained pointer to the Bundle ID for app_bundle_path, // or NULL if there was some problem getting the bundle id. -static CFStringRef -CopyBundleIDForPath (const char *app_bundle_path, DNBError &err_str) -{ - CFBundle bundle(app_bundle_path); - CFStringRef bundleIDCFStr = bundle.GetIdentifier(); - std::string bundleID; - if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL) - { - struct stat app_bundle_stat; - char err_msg[PATH_MAX]; - - if (::stat (app_bundle_path, &app_bundle_stat) < 0) - { - err_str.SetError(errno, DNBError::POSIX); - snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), app_bundle_path); - err_str.SetErrorString(err_msg); - DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg); - } - else - { - err_str.SetError(-1, DNBError::Generic); - snprintf(err_msg, sizeof(err_msg), "failed to extract CFBundleIdentifier from %s", app_bundle_path); - err_str.SetErrorString(err_msg); - DNBLogThreadedIf(LOG_PROCESS, "%s() error: failed to extract CFBundleIdentifier from '%s'", __FUNCTION__, app_bundle_path); - } - return NULL; +static CFStringRef CopyBundleIDForPath(const char *app_bundle_path, + DNBError &err_str) { + CFBundle bundle(app_bundle_path); + CFStringRef bundleIDCFStr = bundle.GetIdentifier(); + std::string bundleID; + if (CFString::UTF8(bundleIDCFStr, bundleID) == NULL) { + struct stat app_bundle_stat; + char err_msg[PATH_MAX]; + + if (::stat(app_bundle_path, &app_bundle_stat) < 0) { + err_str.SetError(errno, DNBError::POSIX); + snprintf(err_msg, sizeof(err_msg), "%s: \"%s\"", err_str.AsString(), + app_bundle_path); + err_str.SetErrorString(err_msg); + DNBLogThreadedIf(LOG_PROCESS, "%s() error: %s", __FUNCTION__, err_msg); + } else { + err_str.SetError(-1, DNBError::Generic); + snprintf(err_msg, sizeof(err_msg), + "failed to extract CFBundleIdentifier from %s", app_bundle_path); + err_str.SetErrorString(err_msg); + DNBLogThreadedIf( + LOG_PROCESS, + "%s() error: failed to extract CFBundleIdentifier from '%s'", + __FUNCTION__, app_bundle_path); } + return NULL; + } - DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", __FUNCTION__, bundleID.c_str()); - CFRetain (bundleIDCFStr); + DNBLogThreadedIf(LOG_PROCESS, "%s() extracted CFBundleIdentifier: %s", + __FUNCTION__, bundleID.c_str()); + CFRetain(bundleIDCFStr); - return bundleIDCFStr; + return bundleIDCFStr; } -#endif // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined (WITH_FBS) +#endif // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) || defined + // (WITH_FBS) #ifdef WITH_SPRINGBOARD -pid_t -MachProcess::SBLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, DNBError &launch_err) -{ - // Clear out and clean up from any current state - Clear(); - - DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); - - // Fork a child process for debugging - SetState(eStateLaunching); - m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, no_stdio, this, launch_err); - if (m_pid != 0) - { - m_flags |= eMachProcessFlagsUsingSBS; - m_path = path; - size_t i; - char const *arg; - for (i=0; (arg = argv[i]) != NULL; i++) - m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); - - if (launch_err.Fail()) - { - if (launch_err.AsString() == NULL) - launch_err.SetErrorString("unable to start the exception thread"); - DNBLog ("Could not get inferior's Mach exception port, sending ptrace PT_KILL and exiting."); - ::ptrace (PT_KILL, m_pid, 0, 0); - m_pid = INVALID_NUB_PROCESS; - return INVALID_NUB_PROCESS; - } - - StartSTDIOThread(); - SetState (eStateAttaching); - int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0); - if (err == 0) - { - m_flags |= eMachProcessFlagsAttached; - DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); - } - else - { - SetState (eStateExited); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); - } - } - return m_pid; +pid_t MachProcess::SBLaunchForDebug(const char *path, char const *argv[], + char const *envp[], bool no_stdio, + bool disable_aslr, DNBError &launch_err) { + // Clear out and clean up from any current state + Clear(); + + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); + + // Fork a child process for debugging + SetState(eStateLaunching); + m_pid = MachProcess::SBForkChildForPTraceDebugging(path, argv, envp, no_stdio, + this, launch_err); + if (m_pid != 0) { + m_flags |= eMachProcessFlagsUsingSBS; + m_path = path; + size_t i; + char const *arg; + for (i = 0; (arg = argv[i]) != NULL; i++) + m_args.push_back(arg); + m_task.StartExceptionThread(launch_err); + + if (launch_err.Fail()) { + if (launch_err.AsString() == NULL) + launch_err.SetErrorString("unable to start the exception thread"); + DNBLog("Could not get inferior's Mach exception port, sending ptrace " + "PT_KILL and exiting."); + ::ptrace(PT_KILL, m_pid, 0, 0); + m_pid = INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; + } + + StartSTDIOThread(); + SetState(eStateAttaching); + int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + if (err == 0) { + m_flags |= eMachProcessFlagsAttached; + DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); + } else { + SetState(eStateExited); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); + } + } + return m_pid; } #include <servers/bootstrap.h> -pid_t -MachProcess::SBForkChildForPTraceDebugging (const char *app_bundle_path, char const *argv[], char const *envp[], bool no_stdio, MachProcess* process, DNBError &launch_err) -{ - DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, process); - CFAllocatorRef alloc = kCFAllocatorDefault; - - if (argv[0] == NULL) - return INVALID_NUB_PROCESS; - - size_t argc = 0; - // Count the number of arguments - while (argv[argc] != NULL) - argc++; - - // Enumerate the arguments - size_t first_launch_arg_idx = 1; - CFReleaser<CFMutableArrayRef> launch_argv; - - if (argv[first_launch_arg_idx]) - { - size_t launch_argc = argc > 0 ? argc - 1 : 0; - launch_argv.reset (::CFArrayCreateMutable (alloc, launch_argc, &kCFTypeArrayCallBacks)); - size_t i; - char const *arg; - CFString launch_arg; - for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++) - { - launch_arg.reset(::CFStringCreateWithCString (alloc, arg, kCFStringEncodingUTF8)); - if (launch_arg.get() != NULL) - CFArrayAppendValue(launch_argv.get(), launch_arg.get()); - else - break; - } - } - - // Next fill in the arguments dictionary. Note, the envp array is of the form - // Variable=value but SpringBoard wants a CF dictionary. So we have to convert - // this here. - - CFReleaser<CFMutableDictionaryRef> launch_envp; - - if (envp[0]) - { - launch_envp.reset(::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - const char *value; - int name_len; - CFString name_string, value_string; - - for (int i = 0; envp[i] != NULL; i++) - { - value = strstr (envp[i], "="); - - // If the name field is empty or there's no =, skip it. Somebody's messing with us. - if (value == NULL || value == envp[i]) - continue; - - name_len = value - envp[i]; +pid_t MachProcess::SBForkChildForPTraceDebugging( + const char *app_bundle_path, char const *argv[], char const *envp[], + bool no_stdio, MachProcess *process, DNBError &launch_err) { + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, + app_bundle_path, process); + CFAllocatorRef alloc = kCFAllocatorDefault; - // Now move value over the "=" - value++; - - name_string.reset(::CFStringCreateWithBytes(alloc, (const UInt8 *) envp[i], name_len, kCFStringEncodingUTF8, false)); - value_string.reset(::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8)); - CFDictionarySetValue (launch_envp.get(), name_string.get(), value_string.get()); - } - } - - CFString stdio_path; + if (argv[0] == NULL) + return INVALID_NUB_PROCESS; - PseudoTerminal pty; - if (!no_stdio) - { - PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY); - if (pty_err == PseudoTerminal::success) - { - const char* slave_name = pty.SlaveName(); - DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name); - if (slave_name && slave_name[0]) - { - ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO); - stdio_path.SetFileSystemRepresentation (slave_name); - } - } - } - - if (stdio_path.get() == NULL) - { - stdio_path.SetFileSystemRepresentation ("/dev/null"); + size_t argc = 0; + // Count the number of arguments + while (argv[argc] != NULL) + argc++; + + // Enumerate the arguments + size_t first_launch_arg_idx = 1; + CFReleaser<CFMutableArrayRef> launch_argv; + + if (argv[first_launch_arg_idx]) { + size_t launch_argc = argc > 0 ? argc - 1 : 0; + launch_argv.reset( + ::CFArrayCreateMutable(alloc, launch_argc, &kCFTypeArrayCallBacks)); + size_t i; + char const *arg; + CFString launch_arg; + for (i = first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); + i++) { + launch_arg.reset( + ::CFStringCreateWithCString(alloc, arg, kCFStringEncodingUTF8)); + if (launch_arg.get() != NULL) + CFArrayAppendValue(launch_argv.get(), launch_arg.get()); + else + break; } + } + + // Next fill in the arguments dictionary. Note, the envp array is of the form + // Variable=value but SpringBoard wants a CF dictionary. So we have to + // convert + // this here. + + CFReleaser<CFMutableDictionaryRef> launch_envp; + + if (envp[0]) { + launch_envp.reset( + ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + const char *value; + int name_len; + CFString name_string, value_string; + + for (int i = 0; envp[i] != NULL; i++) { + value = strstr(envp[i], "="); + + // If the name field is empty or there's no =, skip it. Somebody's + // messing with us. + if (value == NULL || value == envp[i]) + continue; + + name_len = value - envp[i]; + + // Now move value over the "=" + value++; + + name_string.reset( + ::CFStringCreateWithBytes(alloc, (const UInt8 *)envp[i], name_len, + kCFStringEncodingUTF8, false)); + value_string.reset( + ::CFStringCreateWithCString(alloc, value, kCFStringEncodingUTF8)); + CFDictionarySetValue(launch_envp.get(), name_string.get(), + value_string.get()); + } + } + + CFString stdio_path; + + PseudoTerminal pty; + if (!no_stdio) { + PseudoTerminal::Error pty_err = + pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY); + if (pty_err == PseudoTerminal::success) { + const char *slave_name = pty.SlaveName(); + DNBLogThreadedIf(LOG_PROCESS, + "%s() successfully opened master pty, slave is %s", + __FUNCTION__, slave_name); + if (slave_name && slave_name[0]) { + ::chmod(slave_name, S_IRWXU | S_IRWXG | S_IRWXO); + stdio_path.SetFileSystemRepresentation(slave_name); + } + } + } + + if (stdio_path.get() == NULL) { + stdio_path.SetFileSystemRepresentation("/dev/null"); + } + + CFStringRef bundleIDCFStr = CopyBundleIDForPath(app_bundle_path, launch_err); + if (bundleIDCFStr == NULL) + return INVALID_NUB_PROCESS; - CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err); - if (bundleIDCFStr == NULL) - return INVALID_NUB_PROCESS; - - // This is just for logging: - std::string bundleID; - CFString::UTF8(bundleIDCFStr, bundleID); - - DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", __FUNCTION__); - - // Find SpringBoard - SBSApplicationLaunchError sbs_error = 0; - sbs_error = SBSLaunchApplicationForDebugging (bundleIDCFStr, - (CFURLRef)NULL, // openURL - launch_argv.get(), - launch_envp.get(), // CFDictionaryRef environment - stdio_path.get(), - stdio_path.get(), - SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice); - - - launch_err.SetError(sbs_error, DNBError::SpringBoard); - - if (sbs_error == SBSApplicationLaunchErrorSuccess) - { - static const useconds_t pid_poll_interval = 200000; - static const useconds_t pid_poll_timeout = 30000000; - - useconds_t pid_poll_total = 0; - - nub_process_t pid = INVALID_NUB_PROCESS; - Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); - // Poll until the process is running, as long as we are getting valid responses and the timeout hasn't expired - // A return PID of 0 means the process is not running, which may be because it hasn't been (asynchronously) started - // yet, or that it died very quickly (if you weren't using waitForDebugger). - while (!pid_found && pid_poll_total < pid_poll_timeout) - { - usleep (pid_poll_interval); - pid_poll_total += pid_poll_interval; - DNBLogThreadedIf(LOG_PROCESS, "%s() polling Springboard for pid for %s...", __FUNCTION__, bundleID.c_str()); - pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); - } - - CFRelease (bundleIDCFStr); - if (pid_found) - { - if (process != NULL) - { - // Release our master pty file descriptor so the pty class doesn't - // close it and so we can continue to use it in our STDIO thread - int master_fd = pty.ReleaseMasterFD(); - process->SetChildFileDescriptors(master_fd, master_fd, master_fd); - } - DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid); - } - else - { - DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", bundleID.c_str()); - } - return pid; + // This is just for logging: + std::string bundleID; + CFString::UTF8(bundleIDCFStr, bundleID); + + DNBLogThreadedIf(LOG_PROCESS, "%s() serialized launch arg array", + __FUNCTION__); + + // Find SpringBoard + SBSApplicationLaunchError sbs_error = 0; + sbs_error = SBSLaunchApplicationForDebugging( + bundleIDCFStr, + (CFURLRef)NULL, // openURL + launch_argv.get(), + launch_envp.get(), // CFDictionaryRef environment + stdio_path.get(), stdio_path.get(), + SBSApplicationLaunchWaitForDebugger | SBSApplicationLaunchUnlockDevice); + + launch_err.SetError(sbs_error, DNBError::SpringBoard); + + if (sbs_error == SBSApplicationLaunchErrorSuccess) { + static const useconds_t pid_poll_interval = 200000; + static const useconds_t pid_poll_timeout = 30000000; + + useconds_t pid_poll_total = 0; + + nub_process_t pid = INVALID_NUB_PROCESS; + Boolean pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); + // Poll until the process is running, as long as we are getting valid + // responses and the timeout hasn't expired + // A return PID of 0 means the process is not running, which may be because + // it hasn't been (asynchronously) started + // yet, or that it died very quickly (if you weren't using waitForDebugger). + while (!pid_found && pid_poll_total < pid_poll_timeout) { + usleep(pid_poll_interval); + pid_poll_total += pid_poll_interval; + DNBLogThreadedIf(LOG_PROCESS, + "%s() polling Springboard for pid for %s...", + __FUNCTION__, bundleID.c_str()); + pid_found = SBSProcessIDForDisplayIdentifier(bundleIDCFStr, &pid); + } + + CFRelease(bundleIDCFStr); + if (pid_found) { + if (process != NULL) { + // Release our master pty file descriptor so the pty class doesn't + // close it and so we can continue to use it in our STDIO thread + int master_fd = pty.ReleaseMasterFD(); + process->SetChildFileDescriptors(master_fd, master_fd, master_fd); + } + DNBLogThreadedIf(LOG_PROCESS, "%s() => pid = %4.4x", __FUNCTION__, pid); + } else { + DNBLogError("failed to lookup the process ID for CFBundleIdentifier %s.", + bundleID.c_str()); } + return pid; + } - DNBLogError("unable to launch the application with CFBundleIdentifier '%s' sbs_error = %u", bundleID.c_str(), sbs_error); - return INVALID_NUB_PROCESS; + DNBLogError("unable to launch the application with CFBundleIdentifier '%s' " + "sbs_error = %u", + bundleID.c_str(), sbs_error); + return INVALID_NUB_PROCESS; } #endif // #ifdef WITH_SPRINGBOARD - - -#if defined (WITH_BKS) || defined (WITH_FBS) -pid_t -MachProcess::BoardServiceLaunchForDebug (const char *path, char const *argv[], char const *envp[], bool no_stdio, bool disable_aslr, const char *event_data, DNBError &launch_err) -{ - DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); - - // Fork a child process for debugging - SetState(eStateLaunching); - m_pid = BoardServiceForkChildForPTraceDebugging(path, argv, envp, no_stdio, disable_aslr, event_data, launch_err); - if (m_pid != 0) - { - m_path = path; - size_t i; - char const *arg; - for (i=0; (arg = argv[i]) != NULL; i++) - m_args.push_back(arg); - m_task.StartExceptionThread(launch_err); - - if (launch_err.Fail()) - { - if (launch_err.AsString() == NULL) - launch_err.SetErrorString("unable to start the exception thread"); - DNBLog ("Could not get inferior's Mach exception port, sending ptrace PT_KILL and exiting."); - ::ptrace (PT_KILL, m_pid, 0, 0); - m_pid = INVALID_NUB_PROCESS; - return INVALID_NUB_PROCESS; - } +#if defined(WITH_BKS) || defined(WITH_FBS) +pid_t MachProcess::BoardServiceLaunchForDebug( + const char *path, char const *argv[], char const *envp[], bool no_stdio, + bool disable_aslr, const char *event_data, DNBError &launch_err) { + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv)", __FUNCTION__, path); + + // Fork a child process for debugging + SetState(eStateLaunching); + m_pid = BoardServiceForkChildForPTraceDebugging( + path, argv, envp, no_stdio, disable_aslr, event_data, launch_err); + if (m_pid != 0) { + m_path = path; + size_t i; + char const *arg; + for (i = 0; (arg = argv[i]) != NULL; i++) + m_args.push_back(arg); + m_task.StartExceptionThread(launch_err); + + if (launch_err.Fail()) { + if (launch_err.AsString() == NULL) + launch_err.SetErrorString("unable to start the exception thread"); + DNBLog("Could not get inferior's Mach exception port, sending ptrace " + "PT_KILL and exiting."); + ::ptrace(PT_KILL, m_pid, 0, 0); + m_pid = INVALID_NUB_PROCESS; + return INVALID_NUB_PROCESS; + } + + StartSTDIOThread(); + SetState(eStateAttaching); + int err = ::ptrace(PT_ATTACHEXC, m_pid, 0, 0); + if (err == 0) { + m_flags |= eMachProcessFlagsAttached; + DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); + } else { + SetState(eStateExited); + DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); + } + } + return m_pid; +} + +pid_t MachProcess::BoardServiceForkChildForPTraceDebugging( + const char *app_bundle_path, char const *argv[], char const *envp[], + bool no_stdio, bool disable_aslr, const char *event_data, + DNBError &launch_err) { + if (argv[0] == NULL) + return INVALID_NUB_PROCESS; - StartSTDIOThread(); - SetState (eStateAttaching); - int err = ::ptrace (PT_ATTACHEXC, m_pid, 0, 0); - if (err == 0) - { - m_flags |= eMachProcessFlagsAttached; - DNBLogThreadedIf(LOG_PROCESS, "successfully attached to pid %d", m_pid); - } - else - { - SetState (eStateExited); - DNBLogThreadedIf(LOG_PROCESS, "error: failed to attach to pid %d", m_pid); - } + DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, + app_bundle_path, this); + + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + size_t argc = 0; + // Count the number of arguments + while (argv[argc] != NULL) + argc++; + + // Enumerate the arguments + size_t first_launch_arg_idx = 1; + + NSMutableArray *launch_argv = nil; + + if (argv[first_launch_arg_idx]) { + size_t launch_argc = argc > 0 ? argc - 1 : 0; + launch_argv = [NSMutableArray arrayWithCapacity:launch_argc]; + size_t i; + char const *arg; + NSString *launch_arg; + for (i = first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); + i++) { + launch_arg = [NSString stringWithUTF8String:arg]; + // FIXME: Should we silently eat an argument that we can't convert into a + // UTF8 string? + if (launch_arg != nil) + [launch_argv addObject:launch_arg]; + else + break; } - return m_pid; -} - -pid_t -MachProcess::BoardServiceForkChildForPTraceDebugging (const char *app_bundle_path, - char const *argv[], - char const *envp[], - bool no_stdio, - bool disable_aslr, - const char *event_data, - DNBError &launch_err) -{ - if (argv[0] == NULL) - return INVALID_NUB_PROCESS; - - DNBLogThreadedIf(LOG_PROCESS, "%s( '%s', argv, %p)", __FUNCTION__, app_bundle_path, this); - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + } + + NSMutableDictionary *launch_envp = nil; + if (envp[0]) { + launch_envp = [[NSMutableDictionary alloc] init]; + const char *value; + int name_len; + NSString *name_string, *value_string; + + for (int i = 0; envp[i] != NULL; i++) { + value = strstr(envp[i], "="); + + // If the name field is empty or there's no =, skip it. Somebody's + // messing with us. + if (value == NULL || value == envp[i]) + continue; + + name_len = value - envp[i]; + + // Now move value over the "=" + value++; + name_string = [[NSString alloc] initWithBytes:envp[i] + length:name_len + encoding:NSUTF8StringEncoding]; + value_string = [NSString stringWithUTF8String:value]; + [launch_envp setObject:value_string forKey:name_string]; + } + } + + NSString *stdio_path = nil; + NSFileManager *file_manager = [NSFileManager defaultManager]; + + PseudoTerminal pty; + if (!no_stdio) { + PseudoTerminal::Error pty_err = + pty.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY); + if (pty_err == PseudoTerminal::success) { + const char *slave_name = pty.SlaveName(); + DNBLogThreadedIf(LOG_PROCESS, + "%s() successfully opened master pty, slave is %s", + __FUNCTION__, slave_name); + if (slave_name && slave_name[0]) { + ::chmod(slave_name, S_IRWXU | S_IRWXG | S_IRWXO); + stdio_path = [file_manager + stringWithFileSystemRepresentation:slave_name + length:strlen(slave_name)]; + } + } + } + + if (stdio_path == nil) { + const char *null_path = "/dev/null"; + stdio_path = + [file_manager stringWithFileSystemRepresentation:null_path + length:strlen(null_path)]; + } + + CFStringRef bundleIDCFStr = CopyBundleIDForPath(app_bundle_path, launch_err); + if (bundleIDCFStr == NULL) { + [pool drain]; + return INVALID_NUB_PROCESS; + } - size_t argc = 0; - // Count the number of arguments - while (argv[argc] != NULL) - argc++; - - // Enumerate the arguments - size_t first_launch_arg_idx = 1; - - NSMutableArray *launch_argv = nil; - - if (argv[first_launch_arg_idx]) - { - size_t launch_argc = argc > 0 ? argc - 1 : 0; - launch_argv = [NSMutableArray arrayWithCapacity: launch_argc]; - size_t i; - char const *arg; - NSString *launch_arg; - for (i=first_launch_arg_idx; (i < argc) && ((arg = argv[i]) != NULL); i++) - { - launch_arg = [NSString stringWithUTF8String: arg]; - // FIXME: Should we silently eat an argument that we can't convert into a UTF8 string? - if (launch_arg != nil) - [launch_argv addObject: launch_arg]; - else - break; - } - } + // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use + // toll-free bridging here: + NSString *bundleIDNSStr = (NSString *)bundleIDCFStr; - NSMutableDictionary *launch_envp = nil; - if (envp[0]) - { - launch_envp = [[NSMutableDictionary alloc] init]; - const char *value; - int name_len; - NSString *name_string, *value_string; + // Okay, now let's assemble all these goodies into the BackBoardServices + // options mega-dictionary: - for (int i = 0; envp[i] != NULL; i++) - { - value = strstr (envp[i], "="); + NSMutableDictionary *options = nullptr; + pid_t return_pid = INVALID_NUB_PROCESS; + bool success = false; - // If the name field is empty or there's no =, skip it. Somebody's messing with us. - if (value == NULL || value == envp[i]) - continue; +#ifdef WITH_BKS + if (m_flags & eMachProcessFlagsUsingBKS) { + options = + BKSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, + stdio_path, disable_aslr, event_data); + success = BKSCallOpenApplicationFunction(bundleIDNSStr, options, launch_err, + &return_pid); + } +#endif +#ifdef WITH_FBS + if (m_flags & eMachProcessFlagsUsingFBS) { + options = + FBSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, + stdio_path, disable_aslr, event_data); + success = FBSCallOpenApplicationFunction(bundleIDNSStr, options, launch_err, + &return_pid); + } +#endif - name_len = value - envp[i]; + if (success) { + int master_fd = pty.ReleaseMasterFD(); + SetChildFileDescriptors(master_fd, master_fd, master_fd); + CFString::UTF8(bundleIDCFStr, m_bundle_id); + } - // Now move value over the "=" - value++; - name_string = [[NSString alloc] initWithBytes: envp[i] length: name_len encoding: NSUTF8StringEncoding]; - value_string = [NSString stringWithUTF8String: value]; - [launch_envp setObject: value_string forKey: name_string]; - } - } + [pool drain]; - NSString *stdio_path = nil; - NSFileManager *file_manager = [NSFileManager defaultManager]; + return return_pid; +} - PseudoTerminal pty; - if (!no_stdio) - { - PseudoTerminal::Error pty_err = pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY); - if (pty_err == PseudoTerminal::success) - { - const char* slave_name = pty.SlaveName(); - DNBLogThreadedIf(LOG_PROCESS, "%s() successfully opened master pty, slave is %s", __FUNCTION__, slave_name); - if (slave_name && slave_name[0]) - { - ::chmod (slave_name, S_IRWXU | S_IRWXG | S_IRWXO); - stdio_path = [file_manager stringWithFileSystemRepresentation: slave_name length: strlen(slave_name)]; - } - } - } - - if (stdio_path == nil) - { - const char *null_path = "/dev/null"; - stdio_path = [file_manager stringWithFileSystemRepresentation: null_path length: strlen(null_path)]; - } - - CFStringRef bundleIDCFStr = CopyBundleIDForPath (app_bundle_path, launch_err); - if (bundleIDCFStr == NULL) - { - [pool drain]; - return INVALID_NUB_PROCESS; - } +bool MachProcess::BoardServiceSendEvent(const char *event_data, + DNBError &send_err) { + bool return_value = true; - // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use toll-free bridging here: - NSString *bundleIDNSStr = (NSString *) bundleIDCFStr; + if (event_data == NULL || *event_data == '\0') { + DNBLogError("SendEvent called with NULL event data."); + send_err.SetErrorString("SendEvent called with empty event data"); + return false; + } - // Okay, now let's assemble all these goodies into the BackBoardServices options mega-dictionary: - - NSMutableDictionary *options = nullptr; - pid_t return_pid = INVALID_NUB_PROCESS; - bool success = false; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + if (strcmp(event_data, "BackgroundApplication") == 0) { +// This is an event I cooked up. What you actually do is foreground the system +// app, so: #ifdef WITH_BKS - if (m_flags & eMachProcessFlagsUsingBKS) - { - options = BKSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, stdio_path, disable_aslr, event_data); - success = BKSCallOpenApplicationFunction (bundleIDNSStr, options, launch_err, &return_pid); - } + if (m_flags & eMachProcessFlagsUsingBKS) { + return_value = BKSCallOpenApplicationFunction(nil, nil, send_err, NULL); + } #endif #ifdef WITH_FBS - if (m_flags & eMachProcessFlagsUsingFBS) - { - options = FBSCreateOptionsDictionary(app_bundle_path, launch_argv, launch_envp, stdio_path, disable_aslr, event_data); - success = FBSCallOpenApplicationFunction (bundleIDNSStr, options, launch_err, &return_pid); + if (m_flags & eMachProcessFlagsUsingFBS) { + return_value = FBSCallOpenApplicationFunction(nil, nil, send_err, NULL); } #endif - - if (success) - { - int master_fd = pty.ReleaseMasterFD(); - SetChildFileDescriptors(master_fd, master_fd, master_fd); - CFString::UTF8(bundleIDCFStr, m_bundle_id); + if (!return_value) { + DNBLogError("Failed to background application, error: %s.", + send_err.AsString()); } - - [pool drain]; + } else { + if (m_bundle_id.empty()) { + // See if we can figure out the bundle ID for this PID: - return return_pid; -} + DNBLogError( + "Tried to send event \"%s\" to a process that has no bundle ID.", + event_data); + return false; + } + + NSString *bundleIDNSStr = + [NSString stringWithUTF8String:m_bundle_id.c_str()]; -bool -MachProcess::BoardServiceSendEvent (const char *event_data, DNBError &send_err) -{ - bool return_value = true; - - if (event_data == NULL || *event_data == '\0') - { - DNBLogError ("SendEvent called with NULL event data."); - send_err.SetErrorString("SendEvent called with empty event data"); + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + +#ifdef WITH_BKS + if (m_flags & eMachProcessFlagsUsingBKS) { + if (!BKSAddEventDataToOptions(options, event_data, send_err)) { + [pool drain]; return false; + } + return_value = BKSCallOpenApplicationFunction(bundleIDNSStr, options, + send_err, NULL); + DNBLogThreadedIf(LOG_PROCESS, + "Called BKSCallOpenApplicationFunction to send event."); } - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - if (strcmp (event_data, "BackgroundApplication") == 0) - { - // This is an event I cooked up. What you actually do is foreground the system app, so: -#ifdef WITH_BKS - if (m_flags & eMachProcessFlagsUsingBKS) - { - return_value = BKSCallOpenApplicationFunction(nil, nil, send_err, NULL); - } #endif #ifdef WITH_FBS - if (m_flags & eMachProcessFlagsUsingFBS) - { - return_value = FBSCallOpenApplicationFunction(nil, nil, send_err, NULL); - } -#endif - if (!return_value) - { - DNBLogError ("Failed to background application, error: %s.", send_err.AsString()); - } + if (m_flags & eMachProcessFlagsUsingFBS) { + if (!FBSAddEventDataToOptions(options, event_data, send_err)) { + [pool drain]; + return false; + } + return_value = FBSCallOpenApplicationFunction(bundleIDNSStr, options, + send_err, NULL); + DNBLogThreadedIf(LOG_PROCESS, + "Called FBSCallOpenApplicationFunction to send event."); } - else - { - if (m_bundle_id.empty()) - { - // See if we can figure out the bundle ID for this PID: - - DNBLogError ("Tried to send event \"%s\" to a process that has no bundle ID.", event_data); - return false; - } - - NSString *bundleIDNSStr = [NSString stringWithUTF8String:m_bundle_id.c_str()]; - - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - -#ifdef WITH_BKS - if (m_flags & eMachProcessFlagsUsingBKS) - { - if (!BKSAddEventDataToOptions(options, event_data, send_err)) - { - [pool drain]; - return false; - } - return_value = BKSCallOpenApplicationFunction (bundleIDNSStr, options, send_err, NULL); - DNBLogThreadedIf (LOG_PROCESS, "Called BKSCallOpenApplicationFunction to send event."); - - } #endif -#ifdef WITH_FBS - if (m_flags & eMachProcessFlagsUsingFBS) - { - if (!FBSAddEventDataToOptions(options, event_data, send_err)) - { - [pool drain]; - return false; - } - return_value = FBSCallOpenApplicationFunction (bundleIDNSStr, options, send_err, NULL); - DNBLogThreadedIf (LOG_PROCESS, "Called FBSCallOpenApplicationFunction to send event."); - } -#endif - - if (!return_value) - { - DNBLogError ("Failed to send event: %s, error: %s.", event_data, send_err.AsString()); - } + + if (!return_value) { + DNBLogError("Failed to send event: %s, error: %s.", event_data, + send_err.AsString()); } - - [pool drain]; - return return_value; + } + + [pool drain]; + return return_value; } #endif // defined(WITH_BKS) || defined (WITH_FBS) #ifdef WITH_BKS -void -MachProcess::BKSCleanupAfterAttach (const void *attach_token, DNBError &err_str) -{ - bool success; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use toll-free bridging here: - NSString *bundleIDNSStr = (NSString *) attach_token; +void MachProcess::BKSCleanupAfterAttach(const void *attach_token, + DNBError &err_str) { + bool success; - // Okay, now let's assemble all these goodies into the BackBoardServices options mega-dictionary: - - // First we have the debug sub-dictionary: - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: BKSDebugOptionKeyCancelDebugOnNextLaunch]; - - // That will go in the overall dictionary: - - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - [options setObject: debug_options forKey: BKSOpenApplicationOptionKeyDebuggingOptions]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - success = BKSCallOpenApplicationFunction (bundleIDNSStr, options, err_str, NULL); - - if (!success) - { - DNBLogError ("error trying to cancel debug on next launch for %s: %s", [bundleIDNSStr UTF8String], err_str.AsString()); - } + // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use + // toll-free bridging here: + NSString *bundleIDNSStr = (NSString *)attach_token; - [pool drain]; + // Okay, now let's assemble all these goodies into the BackBoardServices + // options mega-dictionary: + + // First we have the debug sub-dictionary: + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:BKSDebugOptionKeyCancelDebugOnNextLaunch]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject:debug_options + forKey:BKSOpenApplicationOptionKeyDebuggingOptions]; + + success = + BKSCallOpenApplicationFunction(bundleIDNSStr, options, err_str, NULL); + + if (!success) { + DNBLogError("error trying to cancel debug on next launch for %s: %s", + [bundleIDNSStr UTF8String], err_str.AsString()); + } + + [pool drain]; } #endif // WITH_BKS #ifdef WITH_FBS -void -MachProcess::FBSCleanupAfterAttach (const void *attach_token, DNBError &err_str) -{ - bool success; - - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use toll-free bridging here: - NSString *bundleIDNSStr = (NSString *) attach_token; +void MachProcess::FBSCleanupAfterAttach(const void *attach_token, + DNBError &err_str) { + bool success; - // Okay, now let's assemble all these goodies into the BackBoardServices options mega-dictionary: - - // First we have the debug sub-dictionary: - NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; - [debug_options setObject: [NSNumber numberWithBool: YES] forKey: FBSDebugOptionKeyCancelDebugOnNextLaunch]; - - // That will go in the overall dictionary: - - NSMutableDictionary *options = [NSMutableDictionary dictionary]; - [options setObject: debug_options forKey: FBSOpenApplicationOptionKeyDebuggingOptions]; + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - success = FBSCallOpenApplicationFunction (bundleIDNSStr, options, err_str, NULL); + // Instead of rewriting CopyBundleIDForPath for NSStrings, we'll just use + // toll-free bridging here: + NSString *bundleIDNSStr = (NSString *)attach_token; - if (!success) - { - DNBLogError ("error trying to cancel debug on next launch for %s: %s", [bundleIDNSStr UTF8String], err_str.AsString()); - } + // Okay, now let's assemble all these goodies into the BackBoardServices + // options mega-dictionary: - [pool drain]; + // First we have the debug sub-dictionary: + NSMutableDictionary *debug_options = [NSMutableDictionary dictionary]; + [debug_options setObject:[NSNumber numberWithBool:YES] + forKey:FBSDebugOptionKeyCancelDebugOnNextLaunch]; + + // That will go in the overall dictionary: + + NSMutableDictionary *options = [NSMutableDictionary dictionary]; + [options setObject:debug_options + forKey:FBSOpenApplicationOptionKeyDebuggingOptions]; + + success = + FBSCallOpenApplicationFunction(bundleIDNSStr, options, err_str, NULL); + + if (!success) { + DNBLogError("error trying to cancel debug on next launch for %s: %s", + [bundleIDNSStr UTF8String], err_str.AsString()); + } + + [pool drain]; } #endif // WITH_FBS diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.h b/lldb/tools/debugserver/source/MacOSX/MachTask.h index d8021e8f7fe..2fdb22f8e56 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachTask.h +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.h @@ -35,80 +35,82 @@ class MachProcess; typedef uint64_t MachMallocEventId; -enum MachMallocEventType -{ - eMachMallocEventTypeAlloc = 2, - eMachMallocEventTypeDealloc = 4, - eMachMallocEventTypeOther = 1 +enum MachMallocEventType { + eMachMallocEventTypeAlloc = 2, + eMachMallocEventTypeDealloc = 4, + eMachMallocEventTypeOther = 1 }; -struct MachMallocEvent -{ - mach_vm_address_t m_base_address; - uint64_t m_size; - MachMallocEventType m_event_type; - MachMallocEventId m_event_id; +struct MachMallocEvent { + mach_vm_address_t m_base_address; + uint64_t m_size; + MachMallocEventType m_event_type; + MachMallocEventId m_event_id; }; -class MachTask -{ +class MachTask { public: - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - MachTask (MachProcess *process); - virtual ~MachTask (); - - void Clear (); - - kern_return_t Suspend (); - kern_return_t Resume (); - - nub_size_t ReadMemory (nub_addr_t addr, nub_size_t size, void *buf); - nub_size_t WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf); - int GetMemoryRegionInfo (nub_addr_t addr, DNBRegionInfo *region_info); - std::string GetProfileData (DNBProfileDataScanType scanType); - - nub_addr_t AllocateMemory (nub_size_t size, uint32_t permissions); - nub_bool_t DeallocateMemory (nub_addr_t addr); - - mach_port_t ExceptionPort () const; - bool ExceptionPortIsValid () const; - kern_return_t SaveExceptionPortInfo (); - kern_return_t RestoreExceptionPortInfo (); - kern_return_t ShutDownExcecptionThread (); - - bool StartExceptionThread (DNBError &err); - nub_addr_t GetDYLDAllImageInfosAddress (DNBError& err); - kern_return_t BasicInfo (struct task_basic_info *info); - static kern_return_t BasicInfo (task_t task, struct task_basic_info *info); - bool IsValid () const; - static bool IsValid (task_t task); - static void * ExceptionThread (void *arg); - task_t TaskPort () const { return m_task; } - task_t TaskPortForProcessID (DNBError &err, bool force = false); - static task_t TaskPortForProcessID (pid_t pid, DNBError &err, uint32_t num_retries = 10, uint32_t usec_interval = 10000); - - MachProcess * Process () { return m_process; } - const MachProcess * Process () const { return m_process; } - - nub_size_t PageSize (); + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + MachTask(MachProcess *process); + virtual ~MachTask(); + + void Clear(); + + kern_return_t Suspend(); + kern_return_t Resume(); + + nub_size_t ReadMemory(nub_addr_t addr, nub_size_t size, void *buf); + nub_size_t WriteMemory(nub_addr_t addr, nub_size_t size, const void *buf); + int GetMemoryRegionInfo(nub_addr_t addr, DNBRegionInfo *region_info); + std::string GetProfileData(DNBProfileDataScanType scanType); + + nub_addr_t AllocateMemory(nub_size_t size, uint32_t permissions); + nub_bool_t DeallocateMemory(nub_addr_t addr); + + mach_port_t ExceptionPort() const; + bool ExceptionPortIsValid() const; + kern_return_t SaveExceptionPortInfo(); + kern_return_t RestoreExceptionPortInfo(); + kern_return_t ShutDownExcecptionThread(); + + bool StartExceptionThread(DNBError &err); + nub_addr_t GetDYLDAllImageInfosAddress(DNBError &err); + kern_return_t BasicInfo(struct task_basic_info *info); + static kern_return_t BasicInfo(task_t task, struct task_basic_info *info); + bool IsValid() const; + static bool IsValid(task_t task); + static void *ExceptionThread(void *arg); + task_t TaskPort() const { return m_task; } + task_t TaskPortForProcessID(DNBError &err, bool force = false); + static task_t TaskPortForProcessID(pid_t pid, DNBError &err, + uint32_t num_retries = 10, + uint32_t usec_interval = 10000); + + MachProcess *Process() { return m_process; } + const MachProcess *Process() const { return m_process; } + + nub_size_t PageSize(); protected: - MachProcess * m_process; // The mach process that owns this MachTask - task_t m_task; - MachVMMemory m_vm_memory; // Special mach memory reading class that will take care of watching for page and region boundaries - MachException::PortInfo - m_exc_port_info; // Saved settings for all exception ports - pthread_t m_exception_thread; // Thread ID for the exception thread in case we need it - mach_port_t m_exception_port; // Exception port on which we will receive child exceptions - - typedef std::map <mach_vm_address_t, size_t> allocation_collection; - allocation_collection m_allocations; + MachProcess *m_process; // The mach process that owns this MachTask + task_t m_task; + MachVMMemory m_vm_memory; // Special mach memory reading class that will take + // care of watching for page and region boundaries + MachException::PortInfo + m_exc_port_info; // Saved settings for all exception ports + pthread_t m_exception_thread; // Thread ID for the exception thread in case we + // need it + mach_port_t m_exception_port; // Exception port on which we will receive child + // exceptions + + typedef std::map<mach_vm_address_t, size_t> allocation_collection; + allocation_collection m_allocations; private: - MachTask(const MachTask&); // Outlaw - MachTask& operator=(const MachTask& rhs);// Outlaw + MachTask(const MachTask &); // Outlaw + MachTask &operator=(const MachTask &rhs); // Outlaw }; -#endif // __MachTask_h__ +#endif // __MachTask_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/MachTask.mm b/lldb/tools/debugserver/source/MacOSX/MachTask.mm index cc1d6a38ec0..f0f086ecbd9 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachTask.mm +++ b/lldb/tools/debugserver/source/MacOSX/MachTask.mm @@ -23,7 +23,7 @@ #include <mach/mach_vm.h> #import <sys/sysctl.h> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <pthread.h> #include <sched.h> #endif @@ -36,25 +36,24 @@ // Project includes #include "CFUtils.h" #include "DNB.h" +#include "DNBDataRef.h" #include "DNBError.h" #include "DNBLog.h" #include "MachProcess.h" -#include "DNBDataRef.h" #ifdef WITH_SPRINGBOARD #include <CoreFoundation/CoreFoundation.h> -#include <SpringBoardServices/SpringBoardServer.h> #include <SpringBoardServices/SBSWatchdogAssertion.h> +#include <SpringBoardServices/SpringBoardServer.h> #endif #ifdef WITH_BKS -extern "C" -{ - #import <Foundation/Foundation.h> - #import <BackBoardServices/BackBoardServices.h> - #import <BackBoardServices/BKSWatchdogAssertion.h> +extern "C" { +#import <BackBoardServices/BKSWatchdogAssertion.h> +#import <BackBoardServices/BackBoardServices.h> +#import <Foundation/Foundation.h> } #endif @@ -66,994 +65,922 @@ extern "C" #include <pmsample.h> #endif - //---------------------------------------------------------------------- // MachTask constructor //---------------------------------------------------------------------- -MachTask::MachTask(MachProcess *process) : - m_process (process), - m_task (TASK_NULL), - m_vm_memory (), - m_exception_thread (0), - m_exception_port (MACH_PORT_NULL) -{ - memset(&m_exc_port_info, 0, sizeof(m_exc_port_info)); +MachTask::MachTask(MachProcess *process) + : m_process(process), m_task(TASK_NULL), m_vm_memory(), + m_exception_thread(0), m_exception_port(MACH_PORT_NULL) { + memset(&m_exc_port_info, 0, sizeof(m_exc_port_info)); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -MachTask::~MachTask() -{ - Clear(); -} - +MachTask::~MachTask() { Clear(); } //---------------------------------------------------------------------- // MachTask::Suspend //---------------------------------------------------------------------- -kern_return_t -MachTask::Suspend() -{ - DNBError err; - task_t task = TaskPort(); - err = ::task_suspend (task); - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - err.LogThreaded("::task_suspend ( target_task = 0x%4.4x )", task); - return err.Error(); +kern_return_t MachTask::Suspend() { + DNBError err; + task_t task = TaskPort(); + err = ::task_suspend(task); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::task_suspend ( target_task = 0x%4.4x )", task); + return err.Error(); } - //---------------------------------------------------------------------- // MachTask::Resume //---------------------------------------------------------------------- -kern_return_t -MachTask::Resume() -{ - struct task_basic_info task_info; - task_t task = TaskPort(); - if (task == TASK_NULL) - return KERN_INVALID_ARGUMENT; - - DNBError err; - err = BasicInfo(task, &task_info); - - if (err.Success()) - { - // task_resume isn't counted like task_suspend calls are, are, so if the - // task is not suspended, don't try and resume it since it is already - // running - if (task_info.suspend_count > 0) - { - err = ::task_resume (task); - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - err.LogThreaded("::task_resume ( target_task = 0x%4.4x )", task); - } +kern_return_t MachTask::Resume() { + struct task_basic_info task_info; + task_t task = TaskPort(); + if (task == TASK_NULL) + return KERN_INVALID_ARGUMENT; + + DNBError err; + err = BasicInfo(task, &task_info); + + if (err.Success()) { + // task_resume isn't counted like task_suspend calls are, are, so if the + // task is not suspended, don't try and resume it since it is already + // running + if (task_info.suspend_count > 0) { + err = ::task_resume(task); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::task_resume ( target_task = 0x%4.4x )", task); } - return err.Error(); + } + return err.Error(); } //---------------------------------------------------------------------- // MachTask::ExceptionPort //---------------------------------------------------------------------- -mach_port_t -MachTask::ExceptionPort() const -{ - return m_exception_port; -} +mach_port_t MachTask::ExceptionPort() const { return m_exception_port; } //---------------------------------------------------------------------- // MachTask::ExceptionPortIsValid //---------------------------------------------------------------------- -bool -MachTask::ExceptionPortIsValid() const -{ - return MACH_PORT_VALID(m_exception_port); +bool MachTask::ExceptionPortIsValid() const { + return MACH_PORT_VALID(m_exception_port); } - //---------------------------------------------------------------------- // MachTask::Clear //---------------------------------------------------------------------- -void -MachTask::Clear() -{ - // Do any cleanup needed for this task - m_task = TASK_NULL; - m_exception_thread = 0; - m_exception_port = MACH_PORT_NULL; - +void MachTask::Clear() { + // Do any cleanup needed for this task + m_task = TASK_NULL; + m_exception_thread = 0; + m_exception_port = MACH_PORT_NULL; } - //---------------------------------------------------------------------- // MachTask::SaveExceptionPortInfo //---------------------------------------------------------------------- -kern_return_t -MachTask::SaveExceptionPortInfo() -{ - return m_exc_port_info.Save(TaskPort()); +kern_return_t MachTask::SaveExceptionPortInfo() { + return m_exc_port_info.Save(TaskPort()); } //---------------------------------------------------------------------- // MachTask::RestoreExceptionPortInfo //---------------------------------------------------------------------- -kern_return_t -MachTask::RestoreExceptionPortInfo() -{ - return m_exc_port_info.Restore(TaskPort()); +kern_return_t MachTask::RestoreExceptionPortInfo() { + return m_exc_port_info.Restore(TaskPort()); } - //---------------------------------------------------------------------- // MachTask::ReadMemory //---------------------------------------------------------------------- -nub_size_t -MachTask::ReadMemory (nub_addr_t addr, nub_size_t size, void *buf) -{ - nub_size_t n = 0; - task_t task = TaskPort(); - if (task != TASK_NULL) - { - n = m_vm_memory.Read(task, addr, buf, size); - - DNBLogThreadedIf(LOG_MEMORY, "MachTask::ReadMemory ( addr = 0x%8.8llx, size = %llu, buf = %p) => %llu bytes read", (uint64_t)addr, (uint64_t)size, buf, (uint64_t)n); - if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8)) - { - DNBDataRef data((uint8_t*)buf, n, false); - data.Dump(0, static_cast<DNBDataRef::offset_t>(n), addr, DNBDataRef::TypeUInt8, 16); - } +nub_size_t MachTask::ReadMemory(nub_addr_t addr, nub_size_t size, void *buf) { + nub_size_t n = 0; + task_t task = TaskPort(); + if (task != TASK_NULL) { + n = m_vm_memory.Read(task, addr, buf, size); + + DNBLogThreadedIf(LOG_MEMORY, "MachTask::ReadMemory ( addr = 0x%8.8llx, " + "size = %llu, buf = %p) => %llu bytes read", + (uint64_t)addr, (uint64_t)size, buf, (uint64_t)n); + if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || + (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8)) { + DNBDataRef data((uint8_t *)buf, n, false); + data.Dump(0, static_cast<DNBDataRef::offset_t>(n), addr, + DNBDataRef::TypeUInt8, 16); } - return n; + } + return n; } - //---------------------------------------------------------------------- // MachTask::WriteMemory //---------------------------------------------------------------------- -nub_size_t -MachTask::WriteMemory (nub_addr_t addr, nub_size_t size, const void *buf) -{ - nub_size_t n = 0; - task_t task = TaskPort(); - if (task != TASK_NULL) - { - n = m_vm_memory.Write(task, addr, buf, size); - DNBLogThreadedIf(LOG_MEMORY, "MachTask::WriteMemory ( addr = 0x%8.8llx, size = %llu, buf = %p) => %llu bytes written", (uint64_t)addr, (uint64_t)size, buf, (uint64_t)n); - if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8)) - { - DNBDataRef data((uint8_t*)buf, n, false); - data.Dump(0, static_cast<DNBDataRef::offset_t>(n), addr, DNBDataRef::TypeUInt8, 16); - } +nub_size_t MachTask::WriteMemory(nub_addr_t addr, nub_size_t size, + const void *buf) { + nub_size_t n = 0; + task_t task = TaskPort(); + if (task != TASK_NULL) { + n = m_vm_memory.Write(task, addr, buf, size); + DNBLogThreadedIf(LOG_MEMORY, "MachTask::WriteMemory ( addr = 0x%8.8llx, " + "size = %llu, buf = %p) => %llu bytes written", + (uint64_t)addr, (uint64_t)size, buf, (uint64_t)n); + if (DNBLogCheckLogBit(LOG_MEMORY_DATA_LONG) || + (DNBLogCheckLogBit(LOG_MEMORY_DATA_SHORT) && size <= 8)) { + DNBDataRef data((uint8_t *)buf, n, false); + data.Dump(0, static_cast<DNBDataRef::offset_t>(n), addr, + DNBDataRef::TypeUInt8, 16); } - return n; + } + return n; } //---------------------------------------------------------------------- // MachTask::MemoryRegionInfo //---------------------------------------------------------------------- -int -MachTask::GetMemoryRegionInfo (nub_addr_t addr, DNBRegionInfo *region_info) -{ - task_t task = TaskPort(); - if (task == TASK_NULL) - return -1; - - int ret = m_vm_memory.GetMemoryRegionInfo(task, addr, region_info); - DNBLogThreadedIf(LOG_MEMORY, "MachTask::MemoryRegionInfo ( addr = 0x%8.8llx ) => %i (start = 0x%8.8llx, size = 0x%8.8llx, permissions = %u)", - (uint64_t)addr, - ret, - (uint64_t)region_info->addr, - (uint64_t)region_info->size, - region_info->permissions); - return ret; +int MachTask::GetMemoryRegionInfo(nub_addr_t addr, DNBRegionInfo *region_info) { + task_t task = TaskPort(); + if (task == TASK_NULL) + return -1; + + int ret = m_vm_memory.GetMemoryRegionInfo(task, addr, region_info); + DNBLogThreadedIf(LOG_MEMORY, "MachTask::MemoryRegionInfo ( addr = 0x%8.8llx " + ") => %i (start = 0x%8.8llx, size = 0x%8.8llx, " + "permissions = %u)", + (uint64_t)addr, ret, (uint64_t)region_info->addr, + (uint64_t)region_info->size, region_info->permissions); + return ret; } -#define TIME_VALUE_TO_TIMEVAL(a, r) do { \ -(r)->tv_sec = (a)->seconds; \ -(r)->tv_usec = (a)->microseconds; \ -} while (0) +#define TIME_VALUE_TO_TIMEVAL(a, r) \ + do { \ + (r)->tv_sec = (a)->seconds; \ + (r)->tv_usec = (a)->microseconds; \ + } while (0) // We should consider moving this into each MacThread. -static void get_threads_profile_data(DNBProfileDataScanType scanType, task_t task, nub_process_t pid, std::vector<uint64_t> &threads_id, std::vector<std::string> &threads_name, std::vector<uint64_t> &threads_used_usec) -{ - kern_return_t kr; - thread_act_array_t threads; - mach_msg_type_number_t tcnt; - - kr = task_threads(task, &threads, &tcnt); +static void get_threads_profile_data(DNBProfileDataScanType scanType, + task_t task, nub_process_t pid, + std::vector<uint64_t> &threads_id, + std::vector<std::string> &threads_name, + std::vector<uint64_t> &threads_used_usec) { + kern_return_t kr; + thread_act_array_t threads; + mach_msg_type_number_t tcnt; + + kr = task_threads(task, &threads, &tcnt); + if (kr != KERN_SUCCESS) + return; + + for (mach_msg_type_number_t i = 0; i < tcnt; i++) { + thread_identifier_info_data_t identifier_info; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + kr = ::thread_info(threads[i], THREAD_IDENTIFIER_INFO, + (thread_info_t)&identifier_info, &count); if (kr != KERN_SUCCESS) - return; - - for (mach_msg_type_number_t i = 0; i < tcnt; i++) - { - thread_identifier_info_data_t identifier_info; - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - kr = ::thread_info(threads[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifier_info, &count); - if (kr != KERN_SUCCESS) continue; - - thread_basic_info_data_t basic_info; - count = THREAD_BASIC_INFO_COUNT; - kr = ::thread_info(threads[i], THREAD_BASIC_INFO, (thread_info_t)&basic_info, &count); - if (kr != KERN_SUCCESS) continue; - - if ((basic_info.flags & TH_FLAGS_IDLE) == 0) - { - nub_thread_t tid = MachThread::GetGloballyUniqueThreadIDForMachPortID (threads[i]); - threads_id.push_back(tid); - - if ((scanType & eProfileThreadName) && (identifier_info.thread_handle != 0)) - { - struct proc_threadinfo proc_threadinfo; - int len = ::proc_pidinfo(pid, PROC_PIDTHREADINFO, identifier_info.thread_handle, &proc_threadinfo, PROC_PIDTHREADINFO_SIZE); - if (len && proc_threadinfo.pth_name[0]) - { - threads_name.push_back(proc_threadinfo.pth_name); - } - else - { - threads_name.push_back(""); - } - } - else - { - threads_name.push_back(""); - } - struct timeval tv; - struct timeval thread_tv; - TIME_VALUE_TO_TIMEVAL(&basic_info.user_time, &thread_tv); - TIME_VALUE_TO_TIMEVAL(&basic_info.system_time, &tv); - timeradd(&thread_tv, &tv, &thread_tv); - uint64_t used_usec = thread_tv.tv_sec * 1000000ULL + thread_tv.tv_usec; - threads_used_usec.push_back(used_usec); + continue; + + thread_basic_info_data_t basic_info; + count = THREAD_BASIC_INFO_COUNT; + kr = ::thread_info(threads[i], THREAD_BASIC_INFO, + (thread_info_t)&basic_info, &count); + if (kr != KERN_SUCCESS) + continue; + + if ((basic_info.flags & TH_FLAGS_IDLE) == 0) { + nub_thread_t tid = + MachThread::GetGloballyUniqueThreadIDForMachPortID(threads[i]); + threads_id.push_back(tid); + + if ((scanType & eProfileThreadName) && + (identifier_info.thread_handle != 0)) { + struct proc_threadinfo proc_threadinfo; + int len = ::proc_pidinfo(pid, PROC_PIDTHREADINFO, + identifier_info.thread_handle, + &proc_threadinfo, PROC_PIDTHREADINFO_SIZE); + if (len && proc_threadinfo.pth_name[0]) { + threads_name.push_back(proc_threadinfo.pth_name); + } else { + threads_name.push_back(""); } - - mach_port_deallocate(mach_task_self(), threads[i]); + } else { + threads_name.push_back(""); + } + struct timeval tv; + struct timeval thread_tv; + TIME_VALUE_TO_TIMEVAL(&basic_info.user_time, &thread_tv); + TIME_VALUE_TO_TIMEVAL(&basic_info.system_time, &tv); + timeradd(&thread_tv, &tv, &thread_tv); + uint64_t used_usec = thread_tv.tv_sec * 1000000ULL + thread_tv.tv_usec; + threads_used_usec.push_back(used_usec); } - mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)threads, tcnt * sizeof(*threads)); + + mach_port_deallocate(mach_task_self(), threads[i]); + } + mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)threads, + tcnt * sizeof(*threads)); } -#define RAW_HEXBASE std::setfill('0') << std::hex << std::right -#define DECIMAL std::dec << std::setfill(' ') -std::string -MachTask::GetProfileData (DNBProfileDataScanType scanType) -{ - std::string result; - - static int32_t numCPU = -1; - struct host_cpu_load_info host_info; - if (scanType & eProfileHostCPU) - { - int32_t mib[] = {CTL_HW, HW_AVAILCPU}; - size_t len = sizeof(numCPU); - if (numCPU == -1) - { - if (sysctl(mib, sizeof(mib) / sizeof(int32_t), &numCPU, &len, NULL, 0) != 0) - return result; - } - - mach_port_t localHost = mach_host_self(); - mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; - kern_return_t kr = host_statistics(localHost, HOST_CPU_LOAD_INFO, (host_info_t)&host_info, &count); - if (kr != KERN_SUCCESS) - return result; - } - - task_t task = TaskPort(); - if (task == TASK_NULL) +#define RAW_HEXBASE std::setfill('0') << std::hex << std::right +#define DECIMAL std::dec << std::setfill(' ') +std::string MachTask::GetProfileData(DNBProfileDataScanType scanType) { + std::string result; + + static int32_t numCPU = -1; + struct host_cpu_load_info host_info; + if (scanType & eProfileHostCPU) { + int32_t mib[] = {CTL_HW, HW_AVAILCPU}; + size_t len = sizeof(numCPU); + if (numCPU == -1) { + if (sysctl(mib, sizeof(mib) / sizeof(int32_t), &numCPU, &len, NULL, 0) != + 0) return result; - - pid_t pid = m_process->ProcessID(); - - struct task_basic_info task_info; - DNBError err; - err = BasicInfo(task, &task_info); - - if (!err.Success()) - return result; - - uint64_t elapsed_usec = 0; - uint64_t task_used_usec = 0; - if (scanType & eProfileCPU) - { - // Get current used time. - struct timeval current_used_time; - struct timeval tv; - TIME_VALUE_TO_TIMEVAL(&task_info.user_time, ¤t_used_time); - TIME_VALUE_TO_TIMEVAL(&task_info.system_time, &tv); - timeradd(¤t_used_time, &tv, ¤t_used_time); - task_used_usec = current_used_time.tv_sec * 1000000ULL + current_used_time.tv_usec; - - struct timeval current_elapsed_time; - int res = gettimeofday(¤t_elapsed_time, NULL); - if (res == 0) - { - elapsed_usec = current_elapsed_time.tv_sec * 1000000ULL + current_elapsed_time.tv_usec; - } } - - std::vector<uint64_t> threads_id; - std::vector<std::string> threads_name; - std::vector<uint64_t> threads_used_usec; - - if (scanType & eProfileThreadsCPU) - { - get_threads_profile_data(scanType, task, pid, threads_id, threads_name, threads_used_usec); + + mach_port_t localHost = mach_host_self(); + mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT; + kern_return_t kr = host_statistics(localHost, HOST_CPU_LOAD_INFO, + (host_info_t)&host_info, &count); + if (kr != KERN_SUCCESS) + return result; + } + + task_t task = TaskPort(); + if (task == TASK_NULL) + return result; + + pid_t pid = m_process->ProcessID(); + + struct task_basic_info task_info; + DNBError err; + err = BasicInfo(task, &task_info); + + if (!err.Success()) + return result; + + uint64_t elapsed_usec = 0; + uint64_t task_used_usec = 0; + if (scanType & eProfileCPU) { + // Get current used time. + struct timeval current_used_time; + struct timeval tv; + TIME_VALUE_TO_TIMEVAL(&task_info.user_time, ¤t_used_time); + TIME_VALUE_TO_TIMEVAL(&task_info.system_time, &tv); + timeradd(¤t_used_time, &tv, ¤t_used_time); + task_used_usec = + current_used_time.tv_sec * 1000000ULL + current_used_time.tv_usec; + + struct timeval current_elapsed_time; + int res = gettimeofday(¤t_elapsed_time, NULL); + if (res == 0) { + elapsed_usec = current_elapsed_time.tv_sec * 1000000ULL + + current_elapsed_time.tv_usec; } - -#if defined (HOST_VM_INFO64_COUNT) - vm_statistics64_data_t vminfo; + } + + std::vector<uint64_t> threads_id; + std::vector<std::string> threads_name; + std::vector<uint64_t> threads_used_usec; + + if (scanType & eProfileThreadsCPU) { + get_threads_profile_data(scanType, task, pid, threads_id, threads_name, + threads_used_usec); + } + +#if defined(HOST_VM_INFO64_COUNT) + vm_statistics64_data_t vminfo; #else - struct vm_statistics vminfo; + struct vm_statistics vminfo; #endif - uint64_t physical_memory; - mach_vm_size_t rprvt = 0; - mach_vm_size_t rsize = 0; - mach_vm_size_t vprvt = 0; - mach_vm_size_t vsize = 0; - mach_vm_size_t dirty_size = 0; - mach_vm_size_t purgeable = 0; - mach_vm_size_t anonymous = 0; - if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), pid, vminfo, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size, purgeable, anonymous)) - { - std::ostringstream profile_data_stream; - - if (scanType & eProfileHostCPU) - { - profile_data_stream << "num_cpu:" << numCPU << ';'; - profile_data_stream << "host_user_ticks:" << host_info.cpu_ticks[CPU_STATE_USER] << ';'; - profile_data_stream << "host_sys_ticks:" << host_info.cpu_ticks[CPU_STATE_SYSTEM] << ';'; - profile_data_stream << "host_idle_ticks:" << host_info.cpu_ticks[CPU_STATE_IDLE] << ';'; - } - - if (scanType & eProfileCPU) - { - profile_data_stream << "elapsed_usec:" << elapsed_usec << ';'; - profile_data_stream << "task_used_usec:" << task_used_usec << ';'; - } - - if (scanType & eProfileThreadsCPU) - { - const size_t num_threads = threads_id.size(); - for (size_t i=0; i<num_threads; i++) - { - profile_data_stream << "thread_used_id:" << std::hex << threads_id[i] << std::dec << ';'; - profile_data_stream << "thread_used_usec:" << threads_used_usec[i] << ';'; - - if (scanType & eProfileThreadName) - { - profile_data_stream << "thread_used_name:"; - const size_t len = threads_name[i].size(); - if (len) - { - const char *thread_name = threads_name[i].c_str(); - // Make sure that thread name doesn't interfere with our delimiter. - profile_data_stream << RAW_HEXBASE << std::setw(2); - const uint8_t *ubuf8 = (const uint8_t *)(thread_name); - for (size_t j=0; j<len; j++) - { - profile_data_stream << (uint32_t)(ubuf8[j]); - } - // Reset back to DECIMAL. - profile_data_stream << DECIMAL; - } - profile_data_stream << ';'; - } + uint64_t physical_memory; + mach_vm_size_t rprvt = 0; + mach_vm_size_t rsize = 0; + mach_vm_size_t vprvt = 0; + mach_vm_size_t vsize = 0; + mach_vm_size_t dirty_size = 0; + mach_vm_size_t purgeable = 0; + mach_vm_size_t anonymous = 0; + if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, + m_process->GetCPUType(), pid, vminfo, + physical_memory, rprvt, rsize, vprvt, vsize, + dirty_size, purgeable, anonymous)) { + std::ostringstream profile_data_stream; + + if (scanType & eProfileHostCPU) { + profile_data_stream << "num_cpu:" << numCPU << ';'; + profile_data_stream << "host_user_ticks:" + << host_info.cpu_ticks[CPU_STATE_USER] << ';'; + profile_data_stream << "host_sys_ticks:" + << host_info.cpu_ticks[CPU_STATE_SYSTEM] << ';'; + profile_data_stream << "host_idle_ticks:" + << host_info.cpu_ticks[CPU_STATE_IDLE] << ';'; + } + + if (scanType & eProfileCPU) { + profile_data_stream << "elapsed_usec:" << elapsed_usec << ';'; + profile_data_stream << "task_used_usec:" << task_used_usec << ';'; + } + + if (scanType & eProfileThreadsCPU) { + const size_t num_threads = threads_id.size(); + for (size_t i = 0; i < num_threads; i++) { + profile_data_stream << "thread_used_id:" << std::hex << threads_id[i] + << std::dec << ';'; + profile_data_stream << "thread_used_usec:" << threads_used_usec[i] + << ';'; + + if (scanType & eProfileThreadName) { + profile_data_stream << "thread_used_name:"; + const size_t len = threads_name[i].size(); + if (len) { + const char *thread_name = threads_name[i].c_str(); + // Make sure that thread name doesn't interfere with our delimiter. + profile_data_stream << RAW_HEXBASE << std::setw(2); + const uint8_t *ubuf8 = (const uint8_t *)(thread_name); + for (size_t j = 0; j < len; j++) { + profile_data_stream << (uint32_t)(ubuf8[j]); } + // Reset back to DECIMAL. + profile_data_stream << DECIMAL; + } + profile_data_stream << ';'; } - - if (scanType & eProfileHostMemory) - profile_data_stream << "total:" << physical_memory << ';'; - - if (scanType & eProfileMemory) - { -#if defined (HOST_VM_INFO64_COUNT) && defined (_VM_PAGE_SIZE_H_) - static vm_size_t pagesize = vm_kernel_page_size; + } + } + + if (scanType & eProfileHostMemory) + profile_data_stream << "total:" << physical_memory << ';'; + + if (scanType & eProfileMemory) { +#if defined(HOST_VM_INFO64_COUNT) && defined(_VM_PAGE_SIZE_H_) + static vm_size_t pagesize = vm_kernel_page_size; #else - static vm_size_t pagesize; - static bool calculated = false; - if (!calculated) - { - calculated = true; - pagesize = PageSize(); - } + static vm_size_t pagesize; + static bool calculated = false; + if (!calculated) { + calculated = true; + pagesize = PageSize(); + } #endif - - /* Unused values. Optimized out for transfer performance. - profile_data_stream << "wired:" << vminfo.wire_count * pagesize << ';'; - profile_data_stream << "active:" << vminfo.active_count * pagesize << ';'; - profile_data_stream << "inactive:" << vminfo.inactive_count * pagesize << ';'; - */ -#if defined (HOST_VM_INFO64_COUNT) - // This mimicks Activity Monitor. - uint64_t total_used_count = (physical_memory / pagesize) - (vminfo.free_count - vminfo.speculative_count) - vminfo.external_page_count - vminfo.purgeable_count; + +/* Unused values. Optimized out for transfer performance. +profile_data_stream << "wired:" << vminfo.wire_count * pagesize << ';'; +profile_data_stream << "active:" << vminfo.active_count * pagesize << ';'; +profile_data_stream << "inactive:" << vminfo.inactive_count * pagesize << ';'; + */ +#if defined(HOST_VM_INFO64_COUNT) + // This mimicks Activity Monitor. + uint64_t total_used_count = + (physical_memory / pagesize) - + (vminfo.free_count - vminfo.speculative_count) - + vminfo.external_page_count - vminfo.purgeable_count; #else - uint64_t total_used_count = vminfo.wire_count + vminfo.inactive_count + vminfo.active_count; + uint64_t total_used_count = + vminfo.wire_count + vminfo.inactive_count + vminfo.active_count; #endif - profile_data_stream << "used:" << total_used_count * pagesize << ';'; - /* Unused values. Optimized out for transfer performance. - profile_data_stream << "free:" << vminfo.free_count * pagesize << ';'; - */ - - profile_data_stream << "rprvt:" << rprvt << ';'; - /* Unused values. Optimized out for transfer performance. - profile_data_stream << "rsize:" << rsize << ';'; - profile_data_stream << "vprvt:" << vprvt << ';'; - profile_data_stream << "vsize:" << vsize << ';'; - */ - - if (scanType & eProfileMemoryDirtyPage) - profile_data_stream << "dirty:" << dirty_size << ';'; - - if (scanType & eProfileMemoryAnonymous) - { - profile_data_stream << "purgeable:" << purgeable << ';'; - profile_data_stream << "anonymous:" << anonymous << ';'; - } - } - - // proc_pid_rusage pm_sample_task_and_pid pm_energy_impact needs to be tested for weakness in Cab + profile_data_stream << "used:" << total_used_count * pagesize << ';'; + /* Unused values. Optimized out for transfer performance. + profile_data_stream << "free:" << vminfo.free_count * pagesize << ';'; + */ + + profile_data_stream << "rprvt:" << rprvt << ';'; + /* Unused values. Optimized out for transfer performance. + profile_data_stream << "rsize:" << rsize << ';'; + profile_data_stream << "vprvt:" << vprvt << ';'; + profile_data_stream << "vsize:" << vsize << ';'; + */ + + if (scanType & eProfileMemoryDirtyPage) + profile_data_stream << "dirty:" << dirty_size << ';'; + + if (scanType & eProfileMemoryAnonymous) { + profile_data_stream << "purgeable:" << purgeable << ';'; + profile_data_stream << "anonymous:" << anonymous << ';'; + } + } + +// proc_pid_rusage pm_sample_task_and_pid pm_energy_impact needs to be tested +// for weakness in Cab #ifdef LLDB_ENERGY - if ((scanType & eProfileEnergy) && (pm_sample_task_and_pid != NULL)) - { - struct rusage_info_v2 info; - int rc = proc_pid_rusage(pid, RUSAGE_INFO_V2, (rusage_info_t *)&info); - if (rc == 0) - { - uint64_t now = mach_absolute_time(); - pm_task_energy_data_t pm_energy; - memset(&pm_energy, 0, sizeof(pm_energy)); - /* - * Disable most features of pm_sample_pid. It will gather - * network/GPU/WindowServer information; fill in the rest. - */ - pm_sample_task_and_pid(task, pid, &pm_energy, now, PM_SAMPLE_ALL & ~PM_SAMPLE_NAME & ~PM_SAMPLE_INTERVAL & ~PM_SAMPLE_CPU & ~PM_SAMPLE_DISK); - pm_energy.sti.total_user = info.ri_user_time; - pm_energy.sti.total_system = info.ri_system_time; - pm_energy.sti.task_interrupt_wakeups = info.ri_interrupt_wkups; - pm_energy.sti.task_platform_idle_wakeups = info.ri_pkg_idle_wkups; - pm_energy.diskio_bytesread = info.ri_diskio_bytesread; - pm_energy.diskio_byteswritten = info.ri_diskio_byteswritten; - pm_energy.pageins = info.ri_pageins; - - uint64_t total_energy = (uint64_t)(pm_energy_impact(&pm_energy) * NSEC_PER_SEC); - //uint64_t process_age = now - info.ri_proc_start_abstime; - //uint64_t avg_energy = 100.0 * (double)total_energy / (double)process_age; - - profile_data_stream << "energy:" << total_energy << ';'; - } - } -#endif - - profile_data_stream << "--end--;"; - - result = profile_data_stream.str(); + if ((scanType & eProfileEnergy) && (pm_sample_task_and_pid != NULL)) { + struct rusage_info_v2 info; + int rc = proc_pid_rusage(pid, RUSAGE_INFO_V2, (rusage_info_t *)&info); + if (rc == 0) { + uint64_t now = mach_absolute_time(); + pm_task_energy_data_t pm_energy; + memset(&pm_energy, 0, sizeof(pm_energy)); + /* + * Disable most features of pm_sample_pid. It will gather + * network/GPU/WindowServer information; fill in the rest. + */ + pm_sample_task_and_pid(task, pid, &pm_energy, now, + PM_SAMPLE_ALL & ~PM_SAMPLE_NAME & + ~PM_SAMPLE_INTERVAL & ~PM_SAMPLE_CPU & + ~PM_SAMPLE_DISK); + pm_energy.sti.total_user = info.ri_user_time; + pm_energy.sti.total_system = info.ri_system_time; + pm_energy.sti.task_interrupt_wakeups = info.ri_interrupt_wkups; + pm_energy.sti.task_platform_idle_wakeups = info.ri_pkg_idle_wkups; + pm_energy.diskio_bytesread = info.ri_diskio_bytesread; + pm_energy.diskio_byteswritten = info.ri_diskio_byteswritten; + pm_energy.pageins = info.ri_pageins; + + uint64_t total_energy = + (uint64_t)(pm_energy_impact(&pm_energy) * NSEC_PER_SEC); + // uint64_t process_age = now - info.ri_proc_start_abstime; + // uint64_t avg_energy = 100.0 * (double)total_energy / + // (double)process_age; + + profile_data_stream << "energy:" << total_energy << ';'; + } } - - return result; -} +#endif + + profile_data_stream << "--end--;"; + result = profile_data_stream.str(); + } + + return result; +} //---------------------------------------------------------------------- // MachTask::TaskPortForProcessID //---------------------------------------------------------------------- -task_t -MachTask::TaskPortForProcessID (DNBError &err, bool force) -{ - if (((m_task == TASK_NULL) || force) && m_process != NULL) - m_task = MachTask::TaskPortForProcessID(m_process->ProcessID(), err); - return m_task; +task_t MachTask::TaskPortForProcessID(DNBError &err, bool force) { + if (((m_task == TASK_NULL) || force) && m_process != NULL) + m_task = MachTask::TaskPortForProcessID(m_process->ProcessID(), err); + return m_task; } //---------------------------------------------------------------------- // MachTask::TaskPortForProcessID //---------------------------------------------------------------------- -task_t -MachTask::TaskPortForProcessID (pid_t pid, DNBError &err, uint32_t num_retries, uint32_t usec_interval) -{ - if (pid != INVALID_NUB_PROCESS) - { - DNBError err; - mach_port_t task_self = mach_task_self (); - task_t task = TASK_NULL; - for (uint32_t i=0; i<num_retries; i++) - { - err = ::task_for_pid ( task_self, pid, &task); - - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - { - char str[1024]; - ::snprintf (str, - sizeof(str), - "::task_for_pid ( target_tport = 0x%4.4x, pid = %d, &task ) => err = 0x%8.8x (%s)", - task_self, - pid, - err.Error(), - err.AsString() ? err.AsString() : "success"); - if (err.Fail()) - err.SetErrorString(str); - err.LogThreaded(str); - } +task_t MachTask::TaskPortForProcessID(pid_t pid, DNBError &err, + uint32_t num_retries, + uint32_t usec_interval) { + if (pid != INVALID_NUB_PROCESS) { + DNBError err; + mach_port_t task_self = mach_task_self(); + task_t task = TASK_NULL; + for (uint32_t i = 0; i < num_retries; i++) { + err = ::task_for_pid(task_self, pid, &task); + + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) { + char str[1024]; + ::snprintf(str, sizeof(str), "::task_for_pid ( target_tport = 0x%4.4x, " + "pid = %d, &task ) => err = 0x%8.8x (%s)", + task_self, pid, err.Error(), + err.AsString() ? err.AsString() : "success"); + if (err.Fail()) + err.SetErrorString(str); + err.LogThreaded(str); + } - if (err.Success()) - return task; + if (err.Success()) + return task; - // Sleep a bit and try again - ::usleep (usec_interval); - } + // Sleep a bit and try again + ::usleep(usec_interval); } - return TASK_NULL; + } + return TASK_NULL; } - //---------------------------------------------------------------------- // MachTask::BasicInfo //---------------------------------------------------------------------- -kern_return_t -MachTask::BasicInfo(struct task_basic_info *info) -{ - return BasicInfo (TaskPort(), info); +kern_return_t MachTask::BasicInfo(struct task_basic_info *info) { + return BasicInfo(TaskPort(), info); } //---------------------------------------------------------------------- // MachTask::BasicInfo //---------------------------------------------------------------------- -kern_return_t -MachTask::BasicInfo(task_t task, struct task_basic_info *info) -{ - if (info == NULL) - return KERN_INVALID_ARGUMENT; - - DNBError err; - mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; - err = ::task_info (task, TASK_BASIC_INFO, (task_info_t)info, &count); - const bool log_process = DNBLogCheckLogBit(LOG_TASK); - if (log_process || err.Fail()) - err.LogThreaded("::task_info ( target_task = 0x%4.4x, flavor = TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => %u )", task, info, count); - if (DNBLogCheckLogBit(LOG_TASK) && DNBLogCheckLogBit(LOG_VERBOSE) && err.Success()) - { - float user = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f; - float system = (float)info->user_time.seconds + (float)info->user_time.microseconds / 1000000.0f; - DNBLogThreaded ("task_basic_info = { suspend_count = %i, virtual_size = 0x%8.8llx, resident_size = 0x%8.8llx, user_time = %f, system_time = %f }", - info->suspend_count, - (uint64_t)info->virtual_size, - (uint64_t)info->resident_size, - user, - system); - } - return err.Error(); +kern_return_t MachTask::BasicInfo(task_t task, struct task_basic_info *info) { + if (info == NULL) + return KERN_INVALID_ARGUMENT; + + DNBError err; + mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT; + err = ::task_info(task, TASK_BASIC_INFO, (task_info_t)info, &count); + const bool log_process = DNBLogCheckLogBit(LOG_TASK); + if (log_process || err.Fail()) + err.LogThreaded("::task_info ( target_task = 0x%4.4x, flavor = " + "TASK_BASIC_INFO, task_info_out => %p, task_info_outCnt => " + "%u )", + task, info, count); + if (DNBLogCheckLogBit(LOG_TASK) && DNBLogCheckLogBit(LOG_VERBOSE) && + err.Success()) { + float user = (float)info->user_time.seconds + + (float)info->user_time.microseconds / 1000000.0f; + float system = (float)info->user_time.seconds + + (float)info->user_time.microseconds / 1000000.0f; + DNBLogThreaded("task_basic_info = { suspend_count = %i, virtual_size = " + "0x%8.8llx, resident_size = 0x%8.8llx, user_time = %f, " + "system_time = %f }", + info->suspend_count, (uint64_t)info->virtual_size, + (uint64_t)info->resident_size, user, system); + } + return err.Error(); } - //---------------------------------------------------------------------- // MachTask::IsValid // // Returns true if a task is a valid task port for a current process. //---------------------------------------------------------------------- -bool -MachTask::IsValid () const -{ - return MachTask::IsValid(TaskPort()); -} +bool MachTask::IsValid() const { return MachTask::IsValid(TaskPort()); } //---------------------------------------------------------------------- // MachTask::IsValid // // Returns true if a task is a valid task port for a current process. //---------------------------------------------------------------------- -bool -MachTask::IsValid (task_t task) -{ - if (task != TASK_NULL) - { - struct task_basic_info task_info; - return BasicInfo(task, &task_info) == KERN_SUCCESS; - } - return false; +bool MachTask::IsValid(task_t task) { + if (task != TASK_NULL) { + struct task_basic_info task_info; + return BasicInfo(task, &task_info) == KERN_SUCCESS; + } + return false; } - -bool -MachTask::StartExceptionThread(DNBError &err) -{ - DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__); - - task_t task = TaskPortForProcessID(err); - if (MachTask::IsValid(task)) - { - // Got the mach port for the current process - mach_port_t task_self = mach_task_self (); - - // Allocate an exception port that we will use to track our child process - err = ::mach_port_allocate (task_self, MACH_PORT_RIGHT_RECEIVE, &m_exception_port); - if (err.Fail()) - return false; - - // Add the ability to send messages on the new exception port - err = ::mach_port_insert_right (task_self, m_exception_port, m_exception_port, MACH_MSG_TYPE_MAKE_SEND); - if (err.Fail()) - return false; - - // Save the original state of the exception ports for our child process - SaveExceptionPortInfo(); - - // We weren't able to save the info for our exception ports, we must stop... - if (m_exc_port_info.mask == 0) - { - err.SetErrorString("failed to get exception port info"); - return false; - } - - // Set the ability to get all exceptions on this port - err = ::task_set_exception_ports (task, m_exc_port_info.mask, m_exception_port, EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); - if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) - { - err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior = 0x%8.8x, new_flavor = 0x%8.8x )", - task, - m_exc_port_info.mask, - m_exception_port, - (EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), - THREAD_STATE_NONE); - } - - if (err.Fail()) - return false; - - // Create the exception thread - err = ::pthread_create (&m_exception_thread, NULL, MachTask::ExceptionThread, this); - return err.Success(); +bool MachTask::StartExceptionThread(DNBError &err) { + DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( )", __FUNCTION__); + + task_t task = TaskPortForProcessID(err); + if (MachTask::IsValid(task)) { + // Got the mach port for the current process + mach_port_t task_self = mach_task_self(); + + // Allocate an exception port that we will use to track our child process + err = ::mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, + &m_exception_port); + if (err.Fail()) + return false; + + // Add the ability to send messages on the new exception port + err = ::mach_port_insert_right(task_self, m_exception_port, + m_exception_port, MACH_MSG_TYPE_MAKE_SEND); + if (err.Fail()) + return false; + + // Save the original state of the exception ports for our child process + SaveExceptionPortInfo(); + + // We weren't able to save the info for our exception ports, we must stop... + if (m_exc_port_info.mask == 0) { + err.SetErrorString("failed to get exception port info"); + return false; } - else - { - DNBLogError("MachTask::%s (): task invalid, exception thread start failed.", __FUNCTION__); + + // Set the ability to get all exceptions on this port + err = ::task_set_exception_ports( + task, m_exc_port_info.mask, m_exception_port, + EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); + if (DNBLogCheckLogBit(LOG_EXCEPTIONS) || err.Fail()) { + err.LogThreaded("::task_set_exception_ports ( task = 0x%4.4x, " + "exception_mask = 0x%8.8x, new_port = 0x%4.4x, behavior " + "= 0x%8.8x, new_flavor = 0x%8.8x )", + task, m_exc_port_info.mask, m_exception_port, + (EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES), + THREAD_STATE_NONE); } - return false; + + if (err.Fail()) + return false; + + // Create the exception thread + err = ::pthread_create(&m_exception_thread, NULL, MachTask::ExceptionThread, + this); + return err.Success(); + } else { + DNBLogError("MachTask::%s (): task invalid, exception thread start failed.", + __FUNCTION__); + } + return false; } -kern_return_t -MachTask::ShutDownExcecptionThread() -{ - DNBError err; +kern_return_t MachTask::ShutDownExcecptionThread() { + DNBError err; - err = RestoreExceptionPortInfo(); + err = RestoreExceptionPortInfo(); - // NULL our our exception port and let our exception thread exit - mach_port_t exception_port = m_exception_port; - m_exception_port = 0; + // NULL our our exception port and let our exception thread exit + mach_port_t exception_port = m_exception_port; + m_exception_port = 0; - err.SetError(::pthread_cancel(m_exception_thread), DNBError::POSIX); - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - err.LogThreaded("::pthread_cancel ( thread = %p )", m_exception_thread); + err.SetError(::pthread_cancel(m_exception_thread), DNBError::POSIX); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::pthread_cancel ( thread = %p )", m_exception_thread); - err.SetError(::pthread_join(m_exception_thread, NULL), DNBError::POSIX); - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - err.LogThreaded("::pthread_join ( thread = %p, value_ptr = NULL)", m_exception_thread); + err.SetError(::pthread_join(m_exception_thread, NULL), DNBError::POSIX); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::pthread_join ( thread = %p, value_ptr = NULL)", + m_exception_thread); - // Deallocate our exception port that we used to track our child process - mach_port_t task_self = mach_task_self (); - err = ::mach_port_deallocate (task_self, exception_port); - if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) - err.LogThreaded("::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", task_self, exception_port); + // Deallocate our exception port that we used to track our child process + mach_port_t task_self = mach_task_self(); + err = ::mach_port_deallocate(task_self, exception_port); + if (DNBLogCheckLogBit(LOG_TASK) || err.Fail()) + err.LogThreaded("::mach_port_deallocate ( task = 0x%4.4x, name = 0x%4.4x )", + task_self, exception_port); - return err.Error(); + return err.Error(); } +void *MachTask::ExceptionThread(void *arg) { + if (arg == NULL) + return NULL; -void * -MachTask::ExceptionThread (void *arg) -{ - if (arg == NULL) - return NULL; - - MachTask *mach_task = (MachTask*) arg; - MachProcess *mach_proc = mach_task->Process(); - DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s ( arg = %p ) starting thread...", __FUNCTION__, arg); - -#if defined (__APPLE__) - pthread_setname_np ("exception monitoring thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } + MachTask *mach_task = (MachTask *)arg; + MachProcess *mach_proc = mach_task->Process(); + DNBLogThreadedIf(LOG_EXCEPTIONS, + "MachTask::%s ( arg = %p ) starting thread...", __FUNCTION__, + arg); + +#if defined(__APPLE__) + pthread_setname_np("exception monitoring thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } #endif #endif - // We keep a count of the number of consecutive exceptions received so - // we know to grab all exceptions without a timeout. We do this to get a - // bunch of related exceptions on our exception port so we can process - // then together. When we have multiple threads, we can get an exception - // per thread and they will come in consecutively. The main loop in this - // thread can stop periodically if needed to service things related to this - // process. - // flag set in the options, so we will wait forever for an exception on - // our exception port. After we get one exception, we then will use the - // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current - // exceptions for our process. After we have received the last pending - // exception, we will get a timeout which enables us to then notify - // our main thread that we have an exception bundle available. We then wait - // for the main thread to tell this exception thread to start trying to get - // exceptions messages again and we start again with a mach_msg read with - // infinite timeout. - uint32_t num_exceptions_received = 0; - DNBError err; - task_t task = mach_task->TaskPort(); - mach_msg_timeout_t periodic_timeout = 0; - -#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - mach_msg_timeout_t watchdog_elapsed = 0; - mach_msg_timeout_t watchdog_timeout = 60 * 1000; - pid_t pid = mach_proc->ProcessID(); - CFReleaser<SBSWatchdogAssertionRef> watchdog; - - if (mach_proc->ProcessUsingSpringBoard()) - { - // Request a renewal for every 60 seconds if we attached using SpringBoard - watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60)); - DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", pid, watchdog.get()); - - if (watchdog.get()) - { - ::SBSWatchdogAssertionRenew (watchdog.get()); - - CFTimeInterval watchdogRenewalInterval = ::SBSWatchdogAssertionGetRenewalInterval (watchdog.get()); - DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", watchdog.get(), watchdogRenewalInterval); - if (watchdogRenewalInterval > 0.0) - { - watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000; - if (watchdog_timeout > 3000) - watchdog_timeout -= 1000; // Give us a second to renew our timeout - else if (watchdog_timeout > 1000) - watchdog_timeout -= 250; // Give us a quarter of a second to renew our timeout - } - } - if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout) - periodic_timeout = watchdog_timeout; + // We keep a count of the number of consecutive exceptions received so + // we know to grab all exceptions without a timeout. We do this to get a + // bunch of related exceptions on our exception port so we can process + // then together. When we have multiple threads, we can get an exception + // per thread and they will come in consecutively. The main loop in this + // thread can stop periodically if needed to service things related to this + // process. + // flag set in the options, so we will wait forever for an exception on + // our exception port. After we get one exception, we then will use the + // MACH_RCV_TIMEOUT option with a zero timeout to grab all other current + // exceptions for our process. After we have received the last pending + // exception, we will get a timeout which enables us to then notify + // our main thread that we have an exception bundle available. We then wait + // for the main thread to tell this exception thread to start trying to get + // exceptions messages again and we start again with a mach_msg read with + // infinite timeout. + uint32_t num_exceptions_received = 0; + DNBError err; + task_t task = mach_task->TaskPort(); + mach_msg_timeout_t periodic_timeout = 0; + +#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) + mach_msg_timeout_t watchdog_elapsed = 0; + mach_msg_timeout_t watchdog_timeout = 60 * 1000; + pid_t pid = mach_proc->ProcessID(); + CFReleaser<SBSWatchdogAssertionRef> watchdog; + + if (mach_proc->ProcessUsingSpringBoard()) { + // Request a renewal for every 60 seconds if we attached using SpringBoard + watchdog.reset(::SBSWatchdogAssertionCreateForPID(NULL, pid, 60)); + DNBLogThreadedIf( + LOG_TASK, "::SBSWatchdogAssertionCreateForPID (NULL, %4.4x, 60 ) => %p", + pid, watchdog.get()); + + if (watchdog.get()) { + ::SBSWatchdogAssertionRenew(watchdog.get()); + + CFTimeInterval watchdogRenewalInterval = + ::SBSWatchdogAssertionGetRenewalInterval(watchdog.get()); + DNBLogThreadedIf( + LOG_TASK, + "::SBSWatchdogAssertionGetRenewalInterval ( %p ) => %g seconds", + watchdog.get(), watchdogRenewalInterval); + if (watchdogRenewalInterval > 0.0) { + watchdog_timeout = (mach_msg_timeout_t)watchdogRenewalInterval * 1000; + if (watchdog_timeout > 3000) + watchdog_timeout -= 1000; // Give us a second to renew our timeout + else if (watchdog_timeout > 1000) + watchdog_timeout -= + 250; // Give us a quarter of a second to renew our timeout + } } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) + if (periodic_timeout == 0 || periodic_timeout > watchdog_timeout) + periodic_timeout = watchdog_timeout; + } +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) #ifdef WITH_BKS - CFReleaser<BKSWatchdogAssertionRef> watchdog; - if (mach_proc->ProcessUsingBackBoard()) - { - pid_t pid = mach_proc->ProcessID(); - CFAllocatorRef alloc = kCFAllocatorDefault; - watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); - } + CFReleaser<BKSWatchdogAssertionRef> watchdog; + if (mach_proc->ProcessUsingBackBoard()) { + pid_t pid = mach_proc->ProcessID(); + CFAllocatorRef alloc = kCFAllocatorDefault; + watchdog.reset(::BKSWatchdogAssertionCreateForPID(alloc, pid)); + } #endif // #ifdef WITH_BKS - while (mach_task->ExceptionPortIsValid()) - { - ::pthread_testcancel (); - - MachException::Message exception_message; - + while (mach_task->ExceptionPortIsValid()) { + ::pthread_testcancel(); + + MachException::Message exception_message; + + if (num_exceptions_received > 0) { + // No timeout, just receive as many exceptions as we can since we already + // have one and we want + // to get all currently available exceptions for this task + err = exception_message.Receive( + mach_task->ExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); + } else if (periodic_timeout > 0) { + // We need to stop periodically in this loop, so try and get a mach + // message with a valid timeout (ms) + err = exception_message.Receive(mach_task->ExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT | + MACH_RCV_TIMEOUT, + periodic_timeout); + } else { + // We don't need to parse all current exceptions or stop periodically, + // just wait for an exception forever. + err = exception_message.Receive(mach_task->ExceptionPort(), + MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); + } - if (num_exceptions_received > 0) - { - // No timeout, just receive as many exceptions as we can since we already have one and we want - // to get all currently available exceptions for this task - err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, 0); - } - else if (periodic_timeout > 0) - { - // We need to stop periodically in this loop, so try and get a mach message with a valid timeout (ms) - err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_TIMEOUT, periodic_timeout); - } - else - { - // We don't need to parse all current exceptions or stop periodically, - // just wait for an exception forever. - err = exception_message.Receive(mach_task->ExceptionPort(), MACH_RCV_MSG | MACH_RCV_INTERRUPT, 0); + if (err.Error() == MACH_RCV_INTERRUPTED) { + // If we have no task port we should exit this thread + if (!mach_task->ExceptionPortIsValid()) { + DNBLogThreadedIf(LOG_EXCEPTIONS, "thread cancelled..."); + break; + } + + // Make sure our task is still valid + if (MachTask::IsValid(task)) { + // Task is still ok + DNBLogThreadedIf(LOG_EXCEPTIONS, + "interrupted, but task still valid, continuing..."); + continue; + } else { + DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited..."); + mach_proc->SetState(eStateExited); + // Our task has died, exit the thread. + break; + } + } else if (err.Error() == MACH_RCV_TIMED_OUT) { + if (num_exceptions_received > 0) { + // We were receiving all current exceptions with a timeout of zero + // it is time to go back to our normal looping mode + num_exceptions_received = 0; + + // Notify our main thread we have a complete exception message + // bundle available and get the possibly updated task port back + // from the process in case we exec'ed and our task port changed + task = mach_proc->ExceptionMessageBundleComplete(); + + // in case we use a timeout value when getting exceptions... + // Make sure our task is still valid + if (MachTask::IsValid(task)) { + // Task is still ok + DNBLogThreadedIf(LOG_EXCEPTIONS, "got a timeout, continuing..."); + continue; + } else { + DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited..."); + mach_proc->SetState(eStateExited); + // Our task has died, exit the thread. + break; } - - if (err.Error() == MACH_RCV_INTERRUPTED) - { - // If we have no task port we should exit this thread - if (!mach_task->ExceptionPortIsValid()) - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "thread cancelled..."); - break; - } - - // Make sure our task is still valid - if (MachTask::IsValid(task)) - { - // Task is still ok - DNBLogThreadedIf(LOG_EXCEPTIONS, "interrupted, but task still valid, continuing..."); - continue; - } - else - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited..."); - mach_proc->SetState(eStateExited); - // Our task has died, exit the thread. - break; - } + } + +#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) + if (watchdog.get()) { + watchdog_elapsed += periodic_timeout; + if (watchdog_elapsed >= watchdog_timeout) { + DNBLogThreadedIf(LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", + watchdog.get()); + ::SBSWatchdogAssertionRenew(watchdog.get()); + watchdog_elapsed = 0; } - else if (err.Error() == MACH_RCV_TIMED_OUT) - { - if (num_exceptions_received > 0) - { - // We were receiving all current exceptions with a timeout of zero - // it is time to go back to our normal looping mode - num_exceptions_received = 0; - - // Notify our main thread we have a complete exception message - // bundle available and get the possibly updated task port back - // from the process in case we exec'ed and our task port changed - task = mach_proc->ExceptionMessageBundleComplete(); - - // in case we use a timeout value when getting exceptions... - // Make sure our task is still valid - if (MachTask::IsValid(task)) - { - // Task is still ok - DNBLogThreadedIf(LOG_EXCEPTIONS, "got a timeout, continuing..."); - continue; - } - else - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "task has exited..."); - mach_proc->SetState(eStateExited); - // Our task has died, exit the thread. - break; - } - } - -#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - if (watchdog.get()) - { - watchdog_elapsed += periodic_timeout; - if (watchdog_elapsed >= watchdog_timeout) - { - DNBLogThreadedIf(LOG_TASK, "SBSWatchdogAssertionRenew ( %p )", watchdog.get()); - ::SBSWatchdogAssertionRenew (watchdog.get()); - watchdog_elapsed = 0; - } - } + } #endif - } - else if (err.Error() != KERN_SUCCESS) - { - DNBLogThreadedIf(LOG_EXCEPTIONS, "got some other error, do something about it??? nah, continuing for now..."); - // TODO: notify of error? - } - else - { - if (exception_message.CatchExceptionRaise(task)) - { - ++num_exceptions_received; - mach_proc->ExceptionMessageReceived(exception_message); - } - } + } else if (err.Error() != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_EXCEPTIONS, "got some other error, do something " + "about it??? nah, continuing for " + "now..."); + // TODO: notify of error? + } else { + if (exception_message.CatchExceptionRaise(task)) { + ++num_exceptions_received; + mach_proc->ExceptionMessageReceived(exception_message); + } } - -#if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - if (watchdog.get()) - { - // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel when we - // all are up and running on systems that support it. The SBS framework has a #define - // that will forward SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel for now - // so it should still build either way. - DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", watchdog.get()); - ::SBSWatchdogAssertionRelease (watchdog.get()); - } -#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) - - DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s (%p): thread exiting...", __FUNCTION__, arg); - return NULL; + } + +#if defined(WITH_SPRINGBOARD) && !defined(WITH_BKS) + if (watchdog.get()) { + // TODO: change SBSWatchdogAssertionRelease to SBSWatchdogAssertionCancel + // when we + // all are up and running on systems that support it. The SBS framework has + // a #define + // that will forward SBSWatchdogAssertionRelease to + // SBSWatchdogAssertionCancel for now + // so it should still build either way. + DNBLogThreadedIf(LOG_TASK, "::SBSWatchdogAssertionRelease(%p)", + watchdog.get()); + ::SBSWatchdogAssertionRelease(watchdog.get()); + } +#endif // #if defined (WITH_SPRINGBOARD) && !defined (WITH_BKS) + + DNBLogThreadedIf(LOG_EXCEPTIONS, "MachTask::%s (%p): thread exiting...", + __FUNCTION__, arg); + return NULL; } - // So the TASK_DYLD_INFO used to just return the address of the all image infos // as a single member called "all_image_info". Then someone decided it would be // a good idea to rename this first member to "all_image_info_addr" and add a // size member called "all_image_info_size". This of course can not be detected // using code or #defines. So to hack around this problem, we define our own -// version of the TASK_DYLD_INFO structure so we can guarantee what is inside it. +// version of the TASK_DYLD_INFO structure so we can guarantee what is inside +// it. struct hack_task_dyld_info { - mach_vm_address_t all_image_info_addr; - mach_vm_size_t all_image_info_size; + mach_vm_address_t all_image_info_addr; + mach_vm_size_t all_image_info_size; }; -nub_addr_t -MachTask::GetDYLDAllImageInfosAddress (DNBError& err) -{ - struct hack_task_dyld_info dyld_info; - mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; - // Make sure that COUNT isn't bigger than our hacked up struct hack_task_dyld_info. - // If it is, then make COUNT smaller to match. - if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t))) - count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)); - - task_t task = TaskPortForProcessID (err); - if (err.Success()) - { - err = ::task_info (task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); - if (err.Success()) - { - // We now have the address of the all image infos structure - return dyld_info.all_image_info_addr; - } +nub_addr_t MachTask::GetDYLDAllImageInfosAddress(DNBError &err) { + struct hack_task_dyld_info dyld_info; + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; + // Make sure that COUNT isn't bigger than our hacked up struct + // hack_task_dyld_info. + // If it is, then make COUNT smaller to match. + if (count > (sizeof(struct hack_task_dyld_info) / sizeof(natural_t))) + count = (sizeof(struct hack_task_dyld_info) / sizeof(natural_t)); + + task_t task = TaskPortForProcessID(err); + if (err.Success()) { + err = ::task_info(task, TASK_DYLD_INFO, (task_info_t)&dyld_info, &count); + if (err.Success()) { + // We now have the address of the all image infos structure + return dyld_info.all_image_info_addr; } - return INVALID_NUB_ADDRESS; + } + return INVALID_NUB_ADDRESS; } - //---------------------------------------------------------------------- // MachTask::AllocateMemory //---------------------------------------------------------------------- -nub_addr_t -MachTask::AllocateMemory (size_t size, uint32_t permissions) -{ - mach_vm_address_t addr; - task_t task = TaskPort(); - if (task == TASK_NULL) - return INVALID_NUB_ADDRESS; +nub_addr_t MachTask::AllocateMemory(size_t size, uint32_t permissions) { + mach_vm_address_t addr; + task_t task = TaskPort(); + if (task == TASK_NULL) + return INVALID_NUB_ADDRESS; - DNBError err; - err = ::mach_vm_allocate (task, &addr, size, TRUE); - if (err.Error() == KERN_SUCCESS) - { - // Set the protections: - vm_prot_t mach_prot = VM_PROT_NONE; - if (permissions & eMemoryPermissionsReadable) - mach_prot |= VM_PROT_READ; - if (permissions & eMemoryPermissionsWritable) - mach_prot |= VM_PROT_WRITE; - if (permissions & eMemoryPermissionsExecutable) - mach_prot |= VM_PROT_EXECUTE; - - - err = ::mach_vm_protect (task, addr, size, 0, mach_prot); - if (err.Error() == KERN_SUCCESS) - { - m_allocations.insert (std::make_pair(addr, size)); - return addr; - } - ::mach_vm_deallocate (task, addr, size); + DNBError err; + err = ::mach_vm_allocate(task, &addr, size, TRUE); + if (err.Error() == KERN_SUCCESS) { + // Set the protections: + vm_prot_t mach_prot = VM_PROT_NONE; + if (permissions & eMemoryPermissionsReadable) + mach_prot |= VM_PROT_READ; + if (permissions & eMemoryPermissionsWritable) + mach_prot |= VM_PROT_WRITE; + if (permissions & eMemoryPermissionsExecutable) + mach_prot |= VM_PROT_EXECUTE; + + err = ::mach_vm_protect(task, addr, size, 0, mach_prot); + if (err.Error() == KERN_SUCCESS) { + m_allocations.insert(std::make_pair(addr, size)); + return addr; } - return INVALID_NUB_ADDRESS; + ::mach_vm_deallocate(task, addr, size); + } + return INVALID_NUB_ADDRESS; } //---------------------------------------------------------------------- // MachTask::DeallocateMemory //---------------------------------------------------------------------- -nub_bool_t -MachTask::DeallocateMemory (nub_addr_t addr) -{ - task_t task = TaskPort(); - if (task == TASK_NULL) - return false; - - // We have to stash away sizes for the allocations... - allocation_collection::iterator pos, end = m_allocations.end(); - for (pos = m_allocations.begin(); pos != end; pos++) - { - if ((*pos).first == addr) - { - m_allocations.erase(pos); +nub_bool_t MachTask::DeallocateMemory(nub_addr_t addr) { + task_t task = TaskPort(); + if (task == TASK_NULL) + return false; + + // We have to stash away sizes for the allocations... + allocation_collection::iterator pos, end = m_allocations.end(); + for (pos = m_allocations.begin(); pos != end; pos++) { + if ((*pos).first == addr) { + m_allocations.erase(pos); #define ALWAYS_ZOMBIE_ALLOCATIONS 0 - if (ALWAYS_ZOMBIE_ALLOCATIONS || getenv ("DEBUGSERVER_ZOMBIE_ALLOCATIONS")) - { - ::mach_vm_protect (task, (*pos).first, (*pos).second, 0, VM_PROT_NONE); - return true; - } - else - return ::mach_vm_deallocate (task, (*pos).first, (*pos).second) == KERN_SUCCESS; - } - + if (ALWAYS_ZOMBIE_ALLOCATIONS || + getenv("DEBUGSERVER_ZOMBIE_ALLOCATIONS")) { + ::mach_vm_protect(task, (*pos).first, (*pos).second, 0, VM_PROT_NONE); + return true; + } else + return ::mach_vm_deallocate(task, (*pos).first, (*pos).second) == + KERN_SUCCESS; } - return false; + } + return false; } -nub_size_t -MachTask::PageSize () -{ - return m_vm_memory.PageSize (m_task); -} +nub_size_t MachTask::PageSize() { return m_vm_memory.PageSize(m_task); } diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp index 89748415608..36aa8c04bf2 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.cpp @@ -11,912 +11,773 @@ // //===----------------------------------------------------------------------===// -#include <inttypes.h> -#include <mach/thread_policy.h> -#include <dlfcn.h> #include "MachThread.h" -#include "MachProcess.h" -#include "DNBLog.h" #include "DNB.h" +#include "DNBLog.h" +#include "MachProcess.h" #include "ThreadInfo.h" +#include <dlfcn.h> +#include <inttypes.h> +#include <mach/thread_policy.h> -static uint32_t -GetSequenceID() -{ - static uint32_t g_nextID = 0; - return ++g_nextID; -} - -MachThread::MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id, thread_t mach_port_num) : - m_process (process), - m_unique_id (unique_thread_id), - m_mach_port_number (mach_port_num), - m_seq_id (GetSequenceID()), - m_state (eStateUnloaded), - m_state_mutex (PTHREAD_MUTEX_RECURSIVE), - m_suspend_count (0), - m_stop_exception (), - m_arch_ap (DNBArchProtocol::Create (this)), - m_reg_sets (NULL), - m_num_reg_sets (0), - m_ident_info(), - m_proc_threadinfo(), - m_dispatch_queue_name(), - m_is_64_bit(is_64_bit), - m_pthread_qos_class_decode (nullptr) -{ - nub_size_t num_reg_sets = 0; - m_reg_sets = m_arch_ap->GetRegisterSetInfo (&num_reg_sets); - m_num_reg_sets = num_reg_sets; - - m_pthread_qos_class_decode = (unsigned int (*)(unsigned long, int*, unsigned long*)) dlsym (RTLD_DEFAULT, "_pthread_qos_class_decode"); - - // Get the thread state so we know if a thread is in a state where we can't - // muck with it and also so we get the suspend count correct in case it was - // already suspended - GetBasicInfo(); - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64 ", seq_id = %u )", &m_process, m_unique_id, m_seq_id); -} - -MachThread::~MachThread() -{ - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", m_unique_id, m_seq_id); -} - - +static uint32_t GetSequenceID() { + static uint32_t g_nextID = 0; + return ++g_nextID; +} + +MachThread::MachThread(MachProcess *process, bool is_64_bit, + uint64_t unique_thread_id, thread_t mach_port_num) + : m_process(process), m_unique_id(unique_thread_id), + m_mach_port_number(mach_port_num), m_seq_id(GetSequenceID()), + m_state(eStateUnloaded), m_state_mutex(PTHREAD_MUTEX_RECURSIVE), + m_suspend_count(0), m_stop_exception(), + m_arch_ap(DNBArchProtocol::Create(this)), m_reg_sets(NULL), + m_num_reg_sets(0), m_ident_info(), m_proc_threadinfo(), + m_dispatch_queue_name(), m_is_64_bit(is_64_bit), + m_pthread_qos_class_decode(nullptr) { + nub_size_t num_reg_sets = 0; + m_reg_sets = m_arch_ap->GetRegisterSetInfo(&num_reg_sets); + m_num_reg_sets = num_reg_sets; + + m_pthread_qos_class_decode = + (unsigned int (*)(unsigned long, int *, unsigned long *))dlsym( + RTLD_DEFAULT, "_pthread_qos_class_decode"); + + // Get the thread state so we know if a thread is in a state where we can't + // muck with it and also so we get the suspend count correct in case it was + // already suspended + GetBasicInfo(); + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, + "MachThread::MachThread ( process = %p, tid = 0x%8.8" PRIx64 + ", seq_id = %u )", + &m_process, m_unique_id, m_seq_id); +} + +MachThread::~MachThread() { + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, + "MachThread::~MachThread() for tid = 0x%8.8" PRIx64 " (%u)", + m_unique_id, m_seq_id); +} + +void MachThread::Suspend() { + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", + __FUNCTION__); + if (MachPortNumberIsValid(m_mach_port_number)) { + DNBError err(::thread_suspend(m_mach_port_number), DNBError::MachKernel); + if (err.Success()) + m_suspend_count++; + if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) + err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); + } +} + +void MachThread::Resume(bool others_stopped) { + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", + __FUNCTION__); + if (MachPortNumberIsValid(m_mach_port_number)) { + SetSuspendCountBeforeResume(others_stopped); + } +} + +bool MachThread::SetSuspendCountBeforeResume(bool others_stopped) { + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", + __FUNCTION__); + DNBError err; + if (MachPortNumberIsValid(m_mach_port_number) == false) + return false; -void -MachThread::Suspend() -{ - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); - if (MachPortNumberIsValid(m_mach_port_number)) - { - DNBError err(::thread_suspend (m_mach_port_number), DNBError::MachKernel); - if (err.Success()) - m_suspend_count++; - if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) - err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); + integer_t times_to_resume; + + if (others_stopped) { + if (GetBasicInfo()) { + times_to_resume = m_basic_info.suspend_count; + m_suspend_count = -(times_to_resume - m_suspend_count); + } else + times_to_resume = 0; + } else { + times_to_resume = m_suspend_count; + m_suspend_count = 0; + } + + if (times_to_resume > 0) { + while (times_to_resume > 0) { + err = ::thread_resume(m_mach_port_number); + if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) + err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); + if (err.Success()) + --times_to_resume; + else { + if (GetBasicInfo()) + times_to_resume = m_basic_info.suspend_count; + else + times_to_resume = 0; + } } + } + return true; } -void -MachThread::Resume(bool others_stopped) -{ - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); - if (MachPortNumberIsValid(m_mach_port_number)) - { - SetSuspendCountBeforeResume(others_stopped); - } -} +bool MachThread::RestoreSuspendCountAfterStop() { + DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", + __FUNCTION__); + DNBError err; + if (MachPortNumberIsValid(m_mach_port_number) == false) + return false; -bool -MachThread::SetSuspendCountBeforeResume(bool others_stopped) -{ - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); - DNBError err; - if (MachPortNumberIsValid(m_mach_port_number) == false) - return false; - - integer_t times_to_resume; - - if (others_stopped) - { + if (m_suspend_count > 0) { + while (m_suspend_count > 0) { + err = ::thread_resume(m_mach_port_number); + if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) + err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); + if (err.Success()) + --m_suspend_count; + else { if (GetBasicInfo()) - { - times_to_resume = m_basic_info.suspend_count; - m_suspend_count = - (times_to_resume - m_suspend_count); - } + m_suspend_count = m_basic_info.suspend_count; else - times_to_resume = 0; + m_suspend_count = 0; + return false; // ??? + } } - else - { - times_to_resume = m_suspend_count; - m_suspend_count = 0; - } - - if (times_to_resume > 0) - { - while (times_to_resume > 0) - { - err = ::thread_resume (m_mach_port_number); - if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) - err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); - if (err.Success()) - --times_to_resume; - else - { - if (GetBasicInfo()) - times_to_resume = m_basic_info.suspend_count; - else - times_to_resume = 0; - } - } - } - return true; -} - -bool -MachThread::RestoreSuspendCountAfterStop () -{ - DNBLogThreadedIf(LOG_THREAD | LOG_VERBOSE, "MachThread::%s ( )", __FUNCTION__); - DNBError err; - if (MachPortNumberIsValid(m_mach_port_number) == false) + } else if (m_suspend_count < 0) { + while (m_suspend_count < 0) { + err = ::thread_suspend(m_mach_port_number); + if (err.Success()) + ++m_suspend_count; + if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) { + err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", + m_mach_port_number); return false; - - if (m_suspend_count > 0) - { - while (m_suspend_count > 0) - { - err = ::thread_resume (m_mach_port_number); - if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) - err.LogThreaded("::thread_resume (%4.4" PRIx32 ")", m_mach_port_number); - if (err.Success()) - --m_suspend_count; - else - { - if (GetBasicInfo()) - m_suspend_count = m_basic_info.suspend_count; - else - m_suspend_count = 0; - return false; // ??? - } - } + } } - else if (m_suspend_count < 0) - { - while (m_suspend_count < 0) - { - err = ::thread_suspend (m_mach_port_number); - if (err.Success()) - ++m_suspend_count; - if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) - { - err.LogThreaded("::thread_suspend (%4.4" PRIx32 ")", m_mach_port_number); - return false; - } + } + return true; +} + +const char *MachThread::GetBasicInfoAsString() const { + static char g_basic_info_string[1024]; + struct thread_basic_info basicInfo; + + if (GetBasicInfo(m_mach_port_number, &basicInfo)) { + + // char run_state_str[32]; + // size_t run_state_str_size = sizeof(run_state_str); + // switch (basicInfo.run_state) + // { + // case TH_STATE_RUNNING: strncpy(run_state_str, "running", + // run_state_str_size); break; + // case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", + // run_state_str_size); break; + // case TH_STATE_WAITING: strncpy(run_state_str, "waiting", + // run_state_str_size); break; + // case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, + // "uninterruptible", run_state_str_size); break; + // case TH_STATE_HALTED: strncpy(run_state_str, "halted", + // run_state_str_size); break; + // default: snprintf(run_state_str, + // run_state_str_size, "%d", basicInfo.run_state); break; // ??? + // } + float user = (float)basicInfo.user_time.seconds + + (float)basicInfo.user_time.microseconds / 1000000.0f; + float system = (float)basicInfo.user_time.seconds + + (float)basicInfo.user_time.microseconds / 1000000.0f; + snprintf(g_basic_info_string, sizeof(g_basic_info_string), + "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d", + m_unique_id, user, system, basicInfo.cpu_usage, + basicInfo.sleep_time); + + return g_basic_info_string; + } + return NULL; +} + +// Finds the Mach port number for a given thread in the inferior process' port +// namespace. +thread_t MachThread::InferiorThreadID() const { + mach_msg_type_number_t i; + mach_port_name_array_t names; + mach_port_type_array_t types; + mach_msg_type_number_t ncount, tcount; + thread_t inferior_tid = INVALID_NUB_THREAD; + task_t my_task = ::mach_task_self(); + task_t task = m_process->Task().TaskPort(); + + kern_return_t kret = + ::mach_port_names(task, &names, &ncount, &types, &tcount); + if (kret == KERN_SUCCESS) { + + for (i = 0; i < ncount; i++) { + mach_port_t my_name; + mach_msg_type_name_t my_type; + + kret = ::mach_port_extract_right(task, names[i], MACH_MSG_TYPE_COPY_SEND, + &my_name, &my_type); + if (kret == KERN_SUCCESS) { + ::mach_port_deallocate(my_task, my_name); + if (my_name == m_mach_port_number) { + inferior_tid = names[i]; + break; } + } } - return true; -} - - -const char * -MachThread::GetBasicInfoAsString () const -{ - static char g_basic_info_string[1024]; - struct thread_basic_info basicInfo; - - if (GetBasicInfo(m_mach_port_number, &basicInfo)) - { - -// char run_state_str[32]; -// size_t run_state_str_size = sizeof(run_state_str); -// switch (basicInfo.run_state) -// { -// case TH_STATE_RUNNING: strncpy(run_state_str, "running", run_state_str_size); break; -// case TH_STATE_STOPPED: strncpy(run_state_str, "stopped", run_state_str_size); break; -// case TH_STATE_WAITING: strncpy(run_state_str, "waiting", run_state_str_size); break; -// case TH_STATE_UNINTERRUPTIBLE: strncpy(run_state_str, "uninterruptible", run_state_str_size); break; -// case TH_STATE_HALTED: strncpy(run_state_str, "halted", run_state_str_size); break; -// default: snprintf(run_state_str, run_state_str_size, "%d", basicInfo.run_state); break; // ??? -// } - float user = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; - float system = (float)basicInfo.user_time.seconds + (float)basicInfo.user_time.microseconds / 1000000.0f; - snprintf(g_basic_info_string, sizeof(g_basic_info_string), "Thread 0x%8.8" PRIx64 ": user=%f system=%f cpu=%d sleep_time=%d", - m_unique_id, - user, - system, - basicInfo.cpu_usage, - basicInfo.sleep_time); - - return g_basic_info_string; - } - return NULL; -} - -// Finds the Mach port number for a given thread in the inferior process' port namespace. -thread_t -MachThread::InferiorThreadID() const -{ - mach_msg_type_number_t i; - mach_port_name_array_t names; - mach_port_type_array_t types; - mach_msg_type_number_t ncount, tcount; - thread_t inferior_tid = INVALID_NUB_THREAD; - task_t my_task = ::mach_task_self(); - task_t task = m_process->Task().TaskPort(); - - kern_return_t kret = ::mach_port_names (task, &names, &ncount, &types, &tcount); - if (kret == KERN_SUCCESS) - { - - for (i = 0; i < ncount; i++) - { - mach_port_t my_name; - mach_msg_type_name_t my_type; - - kret = ::mach_port_extract_right (task, names[i], MACH_MSG_TYPE_COPY_SEND, &my_name, &my_type); - if (kret == KERN_SUCCESS) - { - ::mach_port_deallocate (my_task, my_name); - if (my_name == m_mach_port_number) - { - inferior_tid = names[i]; - break; - } - } - } - // Free up the names and types - ::vm_deallocate (my_task, (vm_address_t) names, ncount * sizeof (mach_port_name_t)); - ::vm_deallocate (my_task, (vm_address_t) types, tcount * sizeof (mach_port_type_t)); - } - return inferior_tid; -} - -bool -MachThread::IsUserReady() -{ - if (m_basic_info.run_state == 0) - GetBasicInfo (); - - switch (m_basic_info.run_state) - { - default: - case TH_STATE_UNINTERRUPTIBLE: - break; - - case TH_STATE_RUNNING: - case TH_STATE_STOPPED: - case TH_STATE_WAITING: - case TH_STATE_HALTED: - return true; - } - return false; -} - -struct thread_basic_info * -MachThread::GetBasicInfo () -{ - if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info)) - return &m_basic_info; - return NULL; -} - - -bool -MachThread::GetBasicInfo(thread_t thread, struct thread_basic_info *basicInfoPtr) -{ - if (MachPortNumberIsValid(thread)) - { - unsigned int info_count = THREAD_BASIC_INFO_COUNT; - kern_return_t err = ::thread_info (thread, THREAD_BASIC_INFO, (thread_info_t) basicInfoPtr, &info_count); - if (err == KERN_SUCCESS) - return true; - } - ::memset (basicInfoPtr, 0, sizeof (struct thread_basic_info)); - return false; -} - - -bool -MachThread::ThreadIDIsValid(uint64_t thread) -{ - return thread != 0; -} - -bool -MachThread::MachPortNumberIsValid(thread_t thread) -{ - return thread != THREAD_NULL; -} - -bool -MachThread::GetRegisterState(int flavor, bool force) -{ - return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS; + // Free up the names and types + ::vm_deallocate(my_task, (vm_address_t)names, + ncount * sizeof(mach_port_name_t)); + ::vm_deallocate(my_task, (vm_address_t)types, + tcount * sizeof(mach_port_type_t)); + } + return inferior_tid; } -bool -MachThread::SetRegisterState(int flavor) -{ - return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS; -} +bool MachThread::IsUserReady() { + if (m_basic_info.run_state == 0) + GetBasicInfo(); -uint64_t -MachThread::GetPC(uint64_t failValue) -{ - // Get program counter - return m_arch_ap->GetPC(failValue); -} + switch (m_basic_info.run_state) { + default: + case TH_STATE_UNINTERRUPTIBLE: + break; -bool -MachThread::SetPC(uint64_t value) -{ - // Set program counter - return m_arch_ap->SetPC(value); + case TH_STATE_RUNNING: + case TH_STATE_STOPPED: + case TH_STATE_WAITING: + case TH_STATE_HALTED: + return true; + } + return false; } -uint64_t -MachThread::GetSP(uint64_t failValue) -{ - // Get stack pointer - return m_arch_ap->GetSP(failValue); -} - -nub_process_t -MachThread::ProcessID() const -{ - if (m_process) - return m_process->ProcessID(); - return INVALID_NUB_PROCESS; -} - -void -MachThread::Dump(uint32_t index) -{ - const char * thread_run_state = NULL; - - switch (m_basic_info.run_state) - { - case TH_STATE_RUNNING: thread_run_state = "running"; break; // 1 thread is running normally - case TH_STATE_STOPPED: thread_run_state = "stopped"; break; // 2 thread is stopped - case TH_STATE_WAITING: thread_run_state = "waiting"; break; // 3 thread is waiting normally - case TH_STATE_UNINTERRUPTIBLE: thread_run_state = "uninter"; break; // 4 thread is in an uninterruptible wait - case TH_STATE_HALTED: thread_run_state = "halted "; break; // 5 thread is halted at a - default: thread_run_state = "???"; break; - } +struct thread_basic_info *MachThread::GetBasicInfo() { + if (MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info)) + return &m_basic_info; + return NULL; +} - DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", - index, - m_seq_id, - m_unique_id, - GetPC(INVALID_NUB_ADDRESS), - GetSP(INVALID_NUB_ADDRESS), - m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, - m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, - m_basic_info.cpu_usage, - m_basic_info.policy, - m_basic_info.run_state, - thread_run_state, - m_basic_info.flags, - m_basic_info.suspend_count, m_suspend_count, - m_basic_info.sleep_time); - //DumpRegisterState(0); -} - -void -MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, bool others_stopped) -{ - if (thread_action->addr != INVALID_NUB_ADDRESS) - SetPC (thread_action->addr); - - SetState (thread_action->state); - switch (thread_action->state) - { - case eStateStopped: - case eStateSuspended: - assert (others_stopped == false); - Suspend(); - break; - - case eStateRunning: - case eStateStepping: - Resume(others_stopped); - break; - default: - break; - } - m_arch_ap->ThreadWillResume(); - m_stop_exception.Clear(); -} +bool MachThread::GetBasicInfo(thread_t thread, + struct thread_basic_info *basicInfoPtr) { + if (MachPortNumberIsValid(thread)) { + unsigned int info_count = THREAD_BASIC_INFO_COUNT; + kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, + (thread_info_t)basicInfoPtr, &info_count); + if (err == KERN_SUCCESS) + return true; + } + ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); + return false; +} + +bool MachThread::ThreadIDIsValid(uint64_t thread) { return thread != 0; } -DNBBreakpoint * -MachThread::CurrentBreakpoint() -{ - return m_process->Breakpoints().FindByAddress(GetPC()); -} +bool MachThread::MachPortNumberIsValid(thread_t thread) { + return thread != THREAD_NULL; +} -bool -MachThread::ShouldStop(bool &step_more) -{ - // See if this thread is at a breakpoint? - DNBBreakpoint *bp = CurrentBreakpoint(); +bool MachThread::GetRegisterState(int flavor, bool force) { + return m_arch_ap->GetRegisterState(flavor, force) == KERN_SUCCESS; +} + +bool MachThread::SetRegisterState(int flavor) { + return m_arch_ap->SetRegisterState(flavor) == KERN_SUCCESS; +} + +uint64_t MachThread::GetPC(uint64_t failValue) { + // Get program counter + return m_arch_ap->GetPC(failValue); +} + +bool MachThread::SetPC(uint64_t value) { + // Set program counter + return m_arch_ap->SetPC(value); +} + +uint64_t MachThread::GetSP(uint64_t failValue) { + // Get stack pointer + return m_arch_ap->GetSP(failValue); +} + +nub_process_t MachThread::ProcessID() const { + if (m_process) + return m_process->ProcessID(); + return INVALID_NUB_PROCESS; +} + +void MachThread::Dump(uint32_t index) { + const char *thread_run_state = NULL; + + switch (m_basic_info.run_state) { + case TH_STATE_RUNNING: + thread_run_state = "running"; + break; // 1 thread is running normally + case TH_STATE_STOPPED: + thread_run_state = "stopped"; + break; // 2 thread is stopped + case TH_STATE_WAITING: + thread_run_state = "waiting"; + break; // 3 thread is waiting normally + case TH_STATE_UNINTERRUPTIBLE: + thread_run_state = "uninter"; + break; // 4 thread is in an uninterruptible wait + case TH_STATE_HALTED: + thread_run_state = "halted "; + break; // 5 thread is halted at a + default: + thread_run_state = "???"; + break; + } + + DNBLogThreaded( + "[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 + ", sp: 0x%16.16" PRIx64 + ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: " + "%2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", + index, m_seq_id, m_unique_id, GetPC(INVALID_NUB_ADDRESS), + GetSP(INVALID_NUB_ADDRESS), m_basic_info.user_time.seconds, + m_basic_info.user_time.microseconds, m_basic_info.system_time.seconds, + m_basic_info.system_time.microseconds, m_basic_info.cpu_usage, + m_basic_info.policy, m_basic_info.run_state, thread_run_state, + m_basic_info.flags, m_basic_info.suspend_count, m_suspend_count, + m_basic_info.sleep_time); + // DumpRegisterState(0); +} + +void MachThread::ThreadWillResume(const DNBThreadResumeAction *thread_action, + bool others_stopped) { + if (thread_action->addr != INVALID_NUB_ADDRESS) + SetPC(thread_action->addr); - if (bp) - { - // This thread is sitting at a breakpoint, ask the breakpoint - // if we should be stopping here. - return true; - } - else - { - if (m_arch_ap->StepNotComplete()) - { - step_more = true; - return false; - } - // The thread state is used to let us know what the thread was - // trying to do. MachThread::ThreadWillResume() will set the - // thread state to various values depending if the thread was - // the current thread and if it was to be single stepped, or - // resumed. - if (GetState() == eStateRunning) - { - // If our state is running, then we should continue as we are in - // the process of stepping over a breakpoint. - return false; - } - else - { - // Stop if we have any kind of valid exception for this - // thread. - if (GetStopException().IsValid()) - return true; - } - } - return false; + SetState(thread_action->state); + switch (thread_action->state) { + case eStateStopped: + case eStateSuspended: + assert(others_stopped == false); + Suspend(); + break; + + case eStateRunning: + case eStateStepping: + Resume(others_stopped); + break; + default: + break; + } + m_arch_ap->ThreadWillResume(); + m_stop_exception.Clear(); } -bool -MachThread::IsStepping() -{ - return GetState() == eStateStepping; -} - - -bool -MachThread::ThreadDidStop() -{ - // This thread has existed prior to resuming under debug nub control, - // and has just been stopped. Do any cleanup that needs to be done - // after running. - - // The thread state and breakpoint will still have the same values - // as they had prior to resuming the thread, so it makes it easy to check - // if we were trying to step a thread, or we tried to resume while being - // at a breakpoint. - - // When this method gets called, the process state is still in the - // state it was in while running so we can act accordingly. - m_arch_ap->ThreadDidStop(); - - // We may have suspended this thread so the primary thread could step - // without worrying about race conditions, so lets restore our suspend - // count. - RestoreSuspendCountAfterStop(); - - // Update the basic information for a thread - MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); - - if (m_basic_info.suspend_count > 0) - SetState(eStateSuspended); - else - SetState(eStateStopped); +DNBBreakpoint *MachThread::CurrentBreakpoint() { + return m_process->Breakpoints().FindByAddress(GetPC()); +} + +bool MachThread::ShouldStop(bool &step_more) { + // See if this thread is at a breakpoint? + DNBBreakpoint *bp = CurrentBreakpoint(); + + if (bp) { + // This thread is sitting at a breakpoint, ask the breakpoint + // if we should be stopping here. return true; -} - -bool -MachThread::NotifyException(MachException::Data& exc) -{ - // Allow the arch specific protocol to process (MachException::Data &)exc - // first before possible reassignment of m_stop_exception with exc. - // See also MachThread::GetStopException(). - bool handled = m_arch_ap->NotifyException(exc); - - if (m_stop_exception.IsValid()) - { - // We may have more than one exception for a thread, but we need to - // only remember the one that we will say is the reason we stopped. - // We may have been single stepping and also gotten a signal exception, - // so just remember the most pertinent one. - if (m_stop_exception.IsBreakpoint()) - m_stop_exception = exc; + } else { + if (m_arch_ap->StepNotComplete()) { + step_more = true; + return false; } - else - { - m_stop_exception = exc; - } - - return handled; -} - - -nub_state_t -MachThread::GetState() -{ - // If any other threads access this we will need a mutex for it - PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); - return m_state; -} - -void -MachThread::SetState(nub_state_t state) -{ - PTHREAD_MUTEX_LOCKER (locker, m_state_mutex); - m_state = state; - DNBLogThreadedIf(LOG_THREAD, "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", DNBStateAsString(state), m_unique_id); -} - -nub_size_t -MachThread::GetNumRegistersInSet(nub_size_t regSet) const -{ - if (regSet < m_num_reg_sets) - return m_reg_sets[regSet].num_registers; - return 0; -} - -const char * -MachThread::GetRegisterSetName(nub_size_t regSet) const -{ - if (regSet < m_num_reg_sets) - return m_reg_sets[regSet].name; - return NULL; -} - -const DNBRegisterInfo * -MachThread::GetRegisterInfo(nub_size_t regSet, nub_size_t regIndex) const -{ - if (regSet < m_num_reg_sets) - if (regIndex < m_reg_sets[regSet].num_registers) - return &m_reg_sets[regSet].registers[regIndex]; - return NULL; -} -void -MachThread::DumpRegisterState(nub_size_t regSet) -{ - if (regSet == REGISTER_SET_ALL) - { - for (regSet = 1; regSet < m_num_reg_sets; regSet++) - DumpRegisterState(regSet); + // The thread state is used to let us know what the thread was + // trying to do. MachThread::ThreadWillResume() will set the + // thread state to various values depending if the thread was + // the current thread and if it was to be single stepped, or + // resumed. + if (GetState() == eStateRunning) { + // If our state is running, then we should continue as we are in + // the process of stepping over a breakpoint. + return false; + } else { + // Stop if we have any kind of valid exception for this + // thread. + if (GetStopException().IsValid()) + return true; } - else - { - if (m_arch_ap->RegisterSetStateIsValid((int)regSet)) - { - const size_t numRegisters = GetNumRegistersInSet(regSet); - uint32_t regIndex = 0; - DNBRegisterValueClass reg; - for (regIndex = 0; regIndex < numRegisters; ++regIndex) - { - if (m_arch_ap->GetRegisterValue((uint32_t)regSet, regIndex, ®)) - { - reg.Dump(NULL, NULL); - } - } - } - else - { - DNBLog("%s: registers are not currently valid.", GetRegisterSetName(regSet)); + } + return false; +} +bool MachThread::IsStepping() { return GetState() == eStateStepping; } + +bool MachThread::ThreadDidStop() { + // This thread has existed prior to resuming under debug nub control, + // and has just been stopped. Do any cleanup that needs to be done + // after running. + + // The thread state and breakpoint will still have the same values + // as they had prior to resuming the thread, so it makes it easy to check + // if we were trying to step a thread, or we tried to resume while being + // at a breakpoint. + + // When this method gets called, the process state is still in the + // state it was in while running so we can act accordingly. + m_arch_ap->ThreadDidStop(); + + // We may have suspended this thread so the primary thread could step + // without worrying about race conditions, so lets restore our suspend + // count. + RestoreSuspendCountAfterStop(); + + // Update the basic information for a thread + MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); + + if (m_basic_info.suspend_count > 0) + SetState(eStateSuspended); + else + SetState(eStateStopped); + return true; +} + +bool MachThread::NotifyException(MachException::Data &exc) { + // Allow the arch specific protocol to process (MachException::Data &)exc + // first before possible reassignment of m_stop_exception with exc. + // See also MachThread::GetStopException(). + bool handled = m_arch_ap->NotifyException(exc); + + if (m_stop_exception.IsValid()) { + // We may have more than one exception for a thread, but we need to + // only remember the one that we will say is the reason we stopped. + // We may have been single stepping and also gotten a signal exception, + // so just remember the most pertinent one. + if (m_stop_exception.IsBreakpoint()) + m_stop_exception = exc; + } else { + m_stop_exception = exc; + } + + return handled; +} + +nub_state_t MachThread::GetState() { + // If any other threads access this we will need a mutex for it + PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); + return m_state; +} + +void MachThread::SetState(nub_state_t state) { + PTHREAD_MUTEX_LOCKER(locker, m_state_mutex); + m_state = state; + DNBLogThreadedIf(LOG_THREAD, + "MachThread::SetState ( %s ) for tid = 0x%8.8" PRIx64 "", + DNBStateAsString(state), m_unique_id); +} + +nub_size_t MachThread::GetNumRegistersInSet(nub_size_t regSet) const { + if (regSet < m_num_reg_sets) + return m_reg_sets[regSet].num_registers; + return 0; +} + +const char *MachThread::GetRegisterSetName(nub_size_t regSet) const { + if (regSet < m_num_reg_sets) + return m_reg_sets[regSet].name; + return NULL; +} + +const DNBRegisterInfo *MachThread::GetRegisterInfo(nub_size_t regSet, + nub_size_t regIndex) const { + if (regSet < m_num_reg_sets) + if (regIndex < m_reg_sets[regSet].num_registers) + return &m_reg_sets[regSet].registers[regIndex]; + return NULL; +} +void MachThread::DumpRegisterState(nub_size_t regSet) { + if (regSet == REGISTER_SET_ALL) { + for (regSet = 1; regSet < m_num_reg_sets; regSet++) + DumpRegisterState(regSet); + } else { + if (m_arch_ap->RegisterSetStateIsValid((int)regSet)) { + const size_t numRegisters = GetNumRegistersInSet(regSet); + uint32_t regIndex = 0; + DNBRegisterValueClass reg; + for (regIndex = 0; regIndex < numRegisters; ++regIndex) { + if (m_arch_ap->GetRegisterValue((uint32_t)regSet, regIndex, ®)) { + reg.Dump(NULL, NULL); } + } + } else { + DNBLog("%s: registers are not currently valid.", + GetRegisterSetName(regSet)); } + } } const DNBRegisterSetInfo * -MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets ) const -{ - *num_reg_sets = m_num_reg_sets; - return &m_reg_sets[0]; +MachThread::GetRegisterSetInfo(nub_size_t *num_reg_sets) const { + *num_reg_sets = m_num_reg_sets; + return &m_reg_sets[0]; } -bool -MachThread::GetRegisterValue ( uint32_t set, uint32_t reg, DNBRegisterValue *value ) -{ - return m_arch_ap->GetRegisterValue(set, reg, value); +bool MachThread::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + return m_arch_ap->GetRegisterValue(set, reg, value); } -bool -MachThread::SetRegisterValue ( uint32_t set, uint32_t reg, const DNBRegisterValue *value ) -{ - return m_arch_ap->SetRegisterValue(set, reg, value); +bool MachThread::SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + return m_arch_ap->SetRegisterValue(set, reg, value); } -nub_size_t -MachThread::GetRegisterContext (void *buf, nub_size_t buf_len) -{ - return m_arch_ap->GetRegisterContext(buf, buf_len); +nub_size_t MachThread::GetRegisterContext(void *buf, nub_size_t buf_len) { + return m_arch_ap->GetRegisterContext(buf, buf_len); } -nub_size_t -MachThread::SetRegisterContext (const void *buf, nub_size_t buf_len) -{ - return m_arch_ap->SetRegisterContext(buf, buf_len); +nub_size_t MachThread::SetRegisterContext(const void *buf, nub_size_t buf_len) { + return m_arch_ap->SetRegisterContext(buf, buf_len); } -uint32_t -MachThread::SaveRegisterState () -{ - return m_arch_ap->SaveRegisterState(); - +uint32_t MachThread::SaveRegisterState() { + return m_arch_ap->SaveRegisterState(); } -bool -MachThread::RestoreRegisterState (uint32_t save_id) -{ - return m_arch_ap->RestoreRegisterState(save_id); +bool MachThread::RestoreRegisterState(uint32_t save_id) { + return m_arch_ap->RestoreRegisterState(save_id); } -uint32_t -MachThread::EnableHardwareBreakpoint (const DNBBreakpoint *bp) -{ - if (bp != NULL && bp->IsBreakpoint()) - return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); - return INVALID_NUB_HW_INDEX; +uint32_t MachThread::EnableHardwareBreakpoint(const DNBBreakpoint *bp) { + if (bp != NULL && bp->IsBreakpoint()) + return m_arch_ap->EnableHardwareBreakpoint(bp->Address(), bp->ByteSize()); + return INVALID_NUB_HW_INDEX; } -uint32_t -MachThread::EnableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task) -{ - if (wp != NULL && wp->IsWatchpoint()) - return m_arch_ap->EnableHardwareWatchpoint(wp->Address(), wp->ByteSize(), wp->WatchpointRead(), wp->WatchpointWrite(), also_set_on_task); - return INVALID_NUB_HW_INDEX; +uint32_t MachThread::EnableHardwareWatchpoint(const DNBBreakpoint *wp, + bool also_set_on_task) { + if (wp != NULL && wp->IsWatchpoint()) + return m_arch_ap->EnableHardwareWatchpoint( + wp->Address(), wp->ByteSize(), wp->WatchpointRead(), + wp->WatchpointWrite(), also_set_on_task); + return INVALID_NUB_HW_INDEX; } -bool -MachThread::RollbackTransForHWP() -{ - return m_arch_ap->RollbackTransForHWP(); +bool MachThread::RollbackTransForHWP() { + return m_arch_ap->RollbackTransForHWP(); } -bool -MachThread::FinishTransForHWP() -{ - return m_arch_ap->FinishTransForHWP(); -} +bool MachThread::FinishTransForHWP() { return m_arch_ap->FinishTransForHWP(); } -bool -MachThread::DisableHardwareBreakpoint (const DNBBreakpoint *bp) -{ - if (bp != NULL && bp->IsHardware()) - return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex()); - return false; +bool MachThread::DisableHardwareBreakpoint(const DNBBreakpoint *bp) { + if (bp != NULL && bp->IsHardware()) + return m_arch_ap->DisableHardwareBreakpoint(bp->GetHardwareIndex()); + return false; } -bool -MachThread::DisableHardwareWatchpoint (const DNBBreakpoint *wp, bool also_set_on_task) -{ - if (wp != NULL && wp->IsHardware()) - return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), also_set_on_task); - return false; +bool MachThread::DisableHardwareWatchpoint(const DNBBreakpoint *wp, + bool also_set_on_task) { + if (wp != NULL && wp->IsHardware()) + return m_arch_ap->DisableHardwareWatchpoint(wp->GetHardwareIndex(), + also_set_on_task); + return false; } -uint32_t -MachThread::NumSupportedHardwareWatchpoints () const -{ - return m_arch_ap->NumSupportedHardwareWatchpoints(); +uint32_t MachThread::NumSupportedHardwareWatchpoints() const { + return m_arch_ap->NumSupportedHardwareWatchpoints(); } -bool -MachThread::GetIdentifierInfo () -{ - // Don't try to get the thread info once and cache it for the life of the thread. It changes over time, for instance - // if the thread name changes, then the thread_handle also changes... So you have to refetch it every time. - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - kern_return_t kret = ::thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t) &m_ident_info, &count); - return kret == KERN_SUCCESS; +bool MachThread::GetIdentifierInfo() { + // Don't try to get the thread info once and cache it for the life of the + // thread. It changes over time, for instance + // if the thread name changes, then the thread_handle also changes... So you + // have to refetch it every time. + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + kern_return_t kret = ::thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, + (thread_info_t)&m_ident_info, &count); + return kret == KERN_SUCCESS; - return false; + return false; } +const char *MachThread::GetName() { + if (GetIdentifierInfo()) { + int len = ::proc_pidinfo(m_process->ProcessID(), PROC_PIDTHREADINFO, + m_ident_info.thread_handle, &m_proc_threadinfo, + sizeof(m_proc_threadinfo)); -const char * -MachThread::GetName () -{ - if (GetIdentifierInfo ()) - { - int len = ::proc_pidinfo (m_process->ProcessID(), PROC_PIDTHREADINFO, m_ident_info.thread_handle, &m_proc_threadinfo, sizeof (m_proc_threadinfo)); - - if (len && m_proc_threadinfo.pth_name[0]) - return m_proc_threadinfo.pth_name; - } - return NULL; + if (len && m_proc_threadinfo.pth_name[0]) + return m_proc_threadinfo.pth_name; + } + return NULL; } - -uint64_t -MachThread::GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id) -{ +uint64_t +MachThread::GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id) { + kern_return_t kr; + thread_identifier_info_data_t tident; + mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; + kr = thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, (thread_info_t)&tident, + &tident_count); + if (kr != KERN_SUCCESS) { + return mach_port_id; + } + return tident.thread_id; +} + +nub_addr_t MachThread::GetPThreadT() { + nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS; + if (MachPortNumberIsValid(m_mach_port_number)) { kern_return_t kr; thread_identifier_info_data_t tident; mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; - kr = thread_info (mach_port_id, THREAD_IDENTIFIER_INFO, - (thread_info_t) &tident, &tident_count); - if (kr != KERN_SUCCESS) - { - return mach_port_id; - } - return tident.thread_id; -} - -nub_addr_t -MachThread::GetPThreadT () -{ - nub_addr_t pthread_t_value = INVALID_NUB_ADDRESS; - if (MachPortNumberIsValid (m_mach_port_number)) - { - kern_return_t kr; - thread_identifier_info_data_t tident; - mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; - kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, - (thread_info_t) &tident, &tident_count); - if (kr == KERN_SUCCESS) - { - // Dereference thread_handle to get the pthread_t value for this thread. - if (m_is_64_bit) - { - uint64_t addr; - if (m_process->ReadMemory (tident.thread_handle, 8, &addr) == 8) - { - if (addr != 0) - { - pthread_t_value = addr; - } - } - } - else - { - uint32_t addr; - if (m_process->ReadMemory (tident.thread_handle, 4, &addr) == 4) - { - if (addr != 0) - { - pthread_t_value = addr; - } - } - } + kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, + (thread_info_t)&tident, &tident_count); + if (kr == KERN_SUCCESS) { + // Dereference thread_handle to get the pthread_t value for this thread. + if (m_is_64_bit) { + uint64_t addr; + if (m_process->ReadMemory(tident.thread_handle, 8, &addr) == 8) { + if (addr != 0) { + pthread_t_value = addr; + } + } + } else { + uint32_t addr; + if (m_process->ReadMemory(tident.thread_handle, 4, &addr) == 4) { + if (addr != 0) { + pthread_t_value = addr; + } } + } } - return pthread_t_value; + } + return pthread_t_value; } // Return this thread's TSD (Thread Specific Data) address. // This is computed based on this thread's pthread_t value. // // We compute the TSD from the pthread_t by one of two methods. -// -// If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we add to +// +// If plo_pthread_tsd_base_offset is non-zero, this is a simple offset that we +// add to // the pthread_t to get the TSD base address. // -// Else we read a pointer from memory at pthread_t + plo_pthread_tsd_base_address_offset and +// Else we read a pointer from memory at pthread_t + +// plo_pthread_tsd_base_address_offset and // that gives us the TSD address. // -// These plo_pthread_tsd_base values must be read out of libpthread by lldb & provided to debugserver. +// These plo_pthread_tsd_base values must be read out of libpthread by lldb & +// provided to debugserver. nub_addr_t -MachThread::GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) -{ - nub_addr_t tsd_addr = INVALID_NUB_ADDRESS; - nub_addr_t pthread_t_value = GetPThreadT(); - if (plo_pthread_tsd_base_offset != 0 && plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) - { - tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset; - } - else - { - if (plo_pthread_tsd_entry_size == 4) - { - uint32_t addr = 0; - if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 4, &addr) == 4) - { - if (addr != 0) - { - tsd_addr = addr; - } - } +MachThread::GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size) { + nub_addr_t tsd_addr = INVALID_NUB_ADDRESS; + nub_addr_t pthread_t_value = GetPThreadT(); + if (plo_pthread_tsd_base_offset != 0 && + plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS) { + tsd_addr = pthread_t_value + plo_pthread_tsd_base_offset; + } else { + if (plo_pthread_tsd_entry_size == 4) { + uint32_t addr = 0; + if (m_process->ReadMemory(pthread_t_value + + plo_pthread_tsd_base_address_offset, + 4, &addr) == 4) { + if (addr != 0) { + tsd_addr = addr; } - if (plo_pthread_tsd_entry_size == 4) - { - uint64_t addr = 0; - if (m_process->ReadMemory (pthread_t_value + plo_pthread_tsd_base_address_offset, 8, &addr) == 8) - { - if (addr != 0) - { - tsd_addr = addr; - } - } + } + } + if (plo_pthread_tsd_entry_size == 4) { + uint64_t addr = 0; + if (m_process->ReadMemory(pthread_t_value + + plo_pthread_tsd_base_address_offset, + 8, &addr) == 8) { + if (addr != 0) { + tsd_addr = addr; } + } } - return tsd_addr; + } + return tsd_addr; } - -nub_addr_t -MachThread::GetDispatchQueueT () -{ - nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS; - if (MachPortNumberIsValid (m_mach_port_number)) - { - kern_return_t kr; - thread_identifier_info_data_t tident; - mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; - kr = thread_info (m_mach_port_number, THREAD_IDENTIFIER_INFO, - (thread_info_t) &tident, &tident_count); - if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && tident.dispatch_qaddr != INVALID_NUB_ADDRESS) - { - // Dereference dispatch_qaddr to get the dispatch_queue_t value for this thread's queue, if any. - if (m_is_64_bit) - { - uint64_t addr; - if (m_process->ReadMemory (tident.dispatch_qaddr, 8, &addr) == 8) - { - if (addr != 0) - dispatch_queue_t_value = addr; - } - } - else - { - uint32_t addr; - if (m_process->ReadMemory (tident.dispatch_qaddr, 4, &addr) == 4) - { - if (addr != 0) - dispatch_queue_t_value = addr; - } - } - } - } - return dispatch_queue_t_value; -} - - -ThreadInfo::QoS -MachThread::GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index) -{ - ThreadInfo::QoS qos_value; - if (MachPortNumberIsValid (m_mach_port_number) && m_pthread_qos_class_decode != nullptr) - { - uint64_t pthread_priority_value = 0; - if (m_is_64_bit) - { - uint64_t pri; - if (m_process->ReadMemory (tsd + (dti_qos_class_index * 8), 8, &pri) == 8) - { - pthread_priority_value = pri; - } +nub_addr_t MachThread::GetDispatchQueueT() { + nub_addr_t dispatch_queue_t_value = INVALID_NUB_ADDRESS; + if (MachPortNumberIsValid(m_mach_port_number)) { + kern_return_t kr; + thread_identifier_info_data_t tident; + mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; + kr = thread_info(m_mach_port_number, THREAD_IDENTIFIER_INFO, + (thread_info_t)&tident, &tident_count); + if (kr == KERN_SUCCESS && tident.dispatch_qaddr != 0 && + tident.dispatch_qaddr != INVALID_NUB_ADDRESS) { + // Dereference dispatch_qaddr to get the dispatch_queue_t value for this + // thread's queue, if any. + if (m_is_64_bit) { + uint64_t addr; + if (m_process->ReadMemory(tident.dispatch_qaddr, 8, &addr) == 8) { + if (addr != 0) + dispatch_queue_t_value = addr; } - else - { - uint32_t pri; - if (m_process->ReadMemory (tsd + (dti_qos_class_index * 4), 4, &pri) == 4) - { - pthread_priority_value = pri; - } + } else { + uint32_t addr; + if (m_process->ReadMemory(tident.dispatch_qaddr, 4, &addr) == 4) { + if (addr != 0) + dispatch_queue_t_value = addr; } + } + } + } + return dispatch_queue_t_value; +} + +ThreadInfo::QoS MachThread::GetRequestedQoS(nub_addr_t tsd, + uint64_t dti_qos_class_index) { + ThreadInfo::QoS qos_value; + if (MachPortNumberIsValid(m_mach_port_number) && + m_pthread_qos_class_decode != nullptr) { + uint64_t pthread_priority_value = 0; + if (m_is_64_bit) { + uint64_t pri; + if (m_process->ReadMemory(tsd + (dti_qos_class_index * 8), 8, &pri) == + 8) { + pthread_priority_value = pri; + } + } else { + uint32_t pri; + if (m_process->ReadMemory(tsd + (dti_qos_class_index * 4), 4, &pri) == + 4) { + pthread_priority_value = pri; + } + } - uint32_t requested_qos = m_pthread_qos_class_decode (pthread_priority_value, NULL, NULL); - - switch (requested_qos) - { - // These constants from <pthread/qos.h> - case 0x21: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE"; - qos_value.printable_name = "User Interactive"; - break; - case 0x19: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_USER_INITIATED"; - qos_value.printable_name = "User Initiated"; - break; - case 0x15: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_DEFAULT"; - qos_value.printable_name = "Default"; - break; - case 0x11: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_UTILITY"; - qos_value.printable_name = "Utility"; - break; - case 0x09: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_BACKGROUND"; - qos_value.printable_name = "Background"; - break; - case 0x00: - qos_value.enum_value = requested_qos; - qos_value.constant_name = "QOS_CLASS_UNSPECIFIED"; - qos_value.printable_name = "Unspecified"; - break; - } + uint32_t requested_qos = + m_pthread_qos_class_decode(pthread_priority_value, NULL, NULL); + + switch (requested_qos) { + // These constants from <pthread/qos.h> + case 0x21: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_USER_INTERACTIVE"; + qos_value.printable_name = "User Interactive"; + break; + case 0x19: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_USER_INITIATED"; + qos_value.printable_name = "User Initiated"; + break; + case 0x15: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_DEFAULT"; + qos_value.printable_name = "Default"; + break; + case 0x11: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_UTILITY"; + qos_value.printable_name = "Utility"; + break; + case 0x09: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_BACKGROUND"; + qos_value.printable_name = "Background"; + break; + case 0x00: + qos_value.enum_value = requested_qos; + qos_value.constant_name = "QOS_CLASS_UNSPECIFIED"; + qos_value.printable_name = "Unspecified"; + break; } - return qos_value; + } + return qos_value; } diff --git a/lldb/tools/debugserver/source/MacOSX/MachThread.h b/lldb/tools/debugserver/source/MacOSX/MachThread.h index a2a31817258..a98d8aa2b05 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThread.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThread.h @@ -22,11 +22,11 @@ #include <pthread.h> #include <sys/signal.h> -#include "PThreadCondition.h" -#include "PThreadMutex.h" -#include "MachException.h" #include "DNBArch.h" #include "DNBRegisterInfo.h" +#include "MachException.h" +#include "PThreadCondition.h" +#include "PThreadMutex.h" #include "ThreadInfo.h" @@ -34,124 +34,135 @@ class DNBBreakpoint; class MachProcess; class MachThreadList; -class MachThread -{ +class MachThread { public: - - MachThread (MachProcess *process, bool is_64_bit, uint64_t unique_thread_id = 0, thread_t mach_port_number = 0); - ~MachThread (); - - MachProcess * Process() { return m_process; } - const MachProcess * - Process() const { return m_process; } - nub_process_t ProcessID() const; - void Dump(uint32_t index); - uint64_t ThreadID() const { return m_unique_id; } - thread_t MachPortNumber() const { return m_mach_port_number; } - thread_t InferiorThreadID() const; - - uint32_t SequenceID() const { return m_seq_id; } - static bool ThreadIDIsValid(uint64_t thread); // The 64-bit system-wide unique thread identifier - static bool MachPortNumberIsValid(thread_t thread); // The mach port # for this thread in debugserver namespace - void Resume(bool others_stopped); - void Suspend(); - bool SetSuspendCountBeforeResume(bool others_stopped); - bool RestoreSuspendCountAfterStop(); - - bool GetRegisterState(int flavor, bool force); - bool SetRegisterState(int flavor); - uint64_t GetPC(uint64_t failValue = INVALID_NUB_ADDRESS); // Get program counter - bool SetPC(uint64_t value); // Set program counter - uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer - - DNBBreakpoint * CurrentBreakpoint(); - uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *breakpoint); - uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *watchpoint, bool also_set_on_task); - bool DisableHardwareBreakpoint (const DNBBreakpoint *breakpoint); - bool DisableHardwareWatchpoint (const DNBBreakpoint *watchpoint, bool also_set_on_task); - uint32_t NumSupportedHardwareWatchpoints () const; - bool RollbackTransForHWP(); - bool FinishTransForHWP(); - - nub_state_t GetState(); - void SetState(nub_state_t state); - - void ThreadWillResume (const DNBThreadResumeAction *thread_action, bool others_stopped = false); - bool ShouldStop(bool &step_more); - bool IsStepping(); - bool ThreadDidStop(); - bool NotifyException(MachException::Data& exc); - const MachException::Data& GetStopException() { return m_stop_exception; } - - nub_size_t GetNumRegistersInSet(nub_size_t regSet) const; - const char * GetRegisterSetName(nub_size_t regSet) const; - const DNBRegisterInfo * - GetRegisterInfo(nub_size_t regSet, nub_size_t regIndex) const; - void DumpRegisterState(nub_size_t regSet); - const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets ) const; - bool GetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, DNBRegisterValue *reg_value ); - bool SetRegisterValue ( uint32_t reg_set_idx, uint32_t reg_idx, const DNBRegisterValue *reg_value ); - nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); - nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - uint32_t SaveRegisterState (); - bool RestoreRegisterState (uint32_t save_id); - - void NotifyBreakpointChanged (const DNBBreakpoint *bp) - { - } - - bool IsUserReady(); - struct thread_basic_info * - GetBasicInfo (); - const char * GetBasicInfoAsString () const; - const char * GetName (); - - DNBArchProtocol* - GetArchProtocol() - { - return m_arch_ap.get(); - } - - ThreadInfo::QoS GetRequestedQoS (nub_addr_t tsd, uint64_t dti_qos_class_index); - nub_addr_t GetPThreadT(); - nub_addr_t GetDispatchQueueT(); - nub_addr_t GetTSDAddressForThread (uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); - - static uint64_t GetGloballyUniqueThreadIDForMachPortID (thread_t mach_port_id); + MachThread(MachProcess *process, bool is_64_bit, + uint64_t unique_thread_id = 0, thread_t mach_port_number = 0); + ~MachThread(); + + MachProcess *Process() { return m_process; } + const MachProcess *Process() const { return m_process; } + nub_process_t ProcessID() const; + void Dump(uint32_t index); + uint64_t ThreadID() const { return m_unique_id; } + thread_t MachPortNumber() const { return m_mach_port_number; } + thread_t InferiorThreadID() const; + + uint32_t SequenceID() const { return m_seq_id; } + static bool ThreadIDIsValid( + uint64_t thread); // The 64-bit system-wide unique thread identifier + static bool MachPortNumberIsValid(thread_t thread); // The mach port # for + // this thread in + // debugserver namespace + void Resume(bool others_stopped); + void Suspend(); + bool SetSuspendCountBeforeResume(bool others_stopped); + bool RestoreSuspendCountAfterStop(); + + bool GetRegisterState(int flavor, bool force); + bool SetRegisterState(int flavor); + uint64_t + GetPC(uint64_t failValue = INVALID_NUB_ADDRESS); // Get program counter + bool SetPC(uint64_t value); // Set program counter + uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer + + DNBBreakpoint *CurrentBreakpoint(); + uint32_t EnableHardwareBreakpoint(const DNBBreakpoint *breakpoint); + uint32_t EnableHardwareWatchpoint(const DNBBreakpoint *watchpoint, + bool also_set_on_task); + bool DisableHardwareBreakpoint(const DNBBreakpoint *breakpoint); + bool DisableHardwareWatchpoint(const DNBBreakpoint *watchpoint, + bool also_set_on_task); + uint32_t NumSupportedHardwareWatchpoints() const; + bool RollbackTransForHWP(); + bool FinishTransForHWP(); + + nub_state_t GetState(); + void SetState(nub_state_t state); + + void ThreadWillResume(const DNBThreadResumeAction *thread_action, + bool others_stopped = false); + bool ShouldStop(bool &step_more); + bool IsStepping(); + bool ThreadDidStop(); + bool NotifyException(MachException::Data &exc); + const MachException::Data &GetStopException() { return m_stop_exception; } + + nub_size_t GetNumRegistersInSet(nub_size_t regSet) const; + const char *GetRegisterSetName(nub_size_t regSet) const; + const DNBRegisterInfo *GetRegisterInfo(nub_size_t regSet, + nub_size_t regIndex) const; + void DumpRegisterState(nub_size_t regSet); + const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets) const; + bool GetRegisterValue(uint32_t reg_set_idx, uint32_t reg_idx, + DNBRegisterValue *reg_value); + bool SetRegisterValue(uint32_t reg_set_idx, uint32_t reg_idx, + const DNBRegisterValue *reg_value); + nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); + nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); + uint32_t SaveRegisterState(); + bool RestoreRegisterState(uint32_t save_id); + + void NotifyBreakpointChanged(const DNBBreakpoint *bp) {} + + bool IsUserReady(); + struct thread_basic_info *GetBasicInfo(); + const char *GetBasicInfoAsString() const; + const char *GetName(); + + DNBArchProtocol *GetArchProtocol() { return m_arch_ap.get(); } + + ThreadInfo::QoS GetRequestedQoS(nub_addr_t tsd, uint64_t dti_qos_class_index); + nub_addr_t GetPThreadT(); + nub_addr_t GetDispatchQueueT(); + nub_addr_t + GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size); + + static uint64_t GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id); protected: - static bool GetBasicInfo(thread_t threadID, struct thread_basic_info *basic_info); - - bool - GetIdentifierInfo (); - -// const char * -// GetDispatchQueueName(); -// - MachProcess * m_process; // The process that owns this thread - uint64_t m_unique_id; // The globally unique ID for this thread (nub_thread_t) - thread_t m_mach_port_number; // The mach port # for this thread in debugserver namesp. - uint32_t m_seq_id; // A Sequential ID that increments with each new thread - nub_state_t m_state; // The state of our process - PThreadMutex m_state_mutex; // Multithreaded protection for m_state - struct thread_basic_info m_basic_info; // Basic information for a thread used to see if a thread is valid - int32_t m_suspend_count; // The current suspend count > 0 means we have suspended m_suspendCount times, - // < 0 means we have resumed it m_suspendCount times. - MachException::Data m_stop_exception; // The best exception that describes why this thread is stopped - std::unique_ptr<DNBArchProtocol> m_arch_ap; // Arch specific information for register state and more - const DNBRegisterSetInfo * m_reg_sets; // Register set information for this thread - nub_size_t m_num_reg_sets; - thread_identifier_info_data_t m_ident_info; - struct proc_threadinfo m_proc_threadinfo; - std::string m_dispatch_queue_name; - bool m_is_64_bit; - - // qos_class_t _pthread_qos_class_decode(pthread_priority_t priority, int *, unsigned long *); - unsigned int (*m_pthread_qos_class_decode) (unsigned long priority, int*, unsigned long *); + static bool GetBasicInfo(thread_t threadID, + struct thread_basic_info *basic_info); + + bool GetIdentifierInfo(); + + // const char * + // GetDispatchQueueName(); + // + MachProcess *m_process; // The process that owns this thread + uint64_t m_unique_id; // The globally unique ID for this thread (nub_thread_t) + thread_t m_mach_port_number; // The mach port # for this thread in debugserver + // namesp. + uint32_t m_seq_id; // A Sequential ID that increments with each new thread + nub_state_t m_state; // The state of our process + PThreadMutex m_state_mutex; // Multithreaded protection for m_state + struct thread_basic_info m_basic_info; // Basic information for a thread used + // to see if a thread is valid + int32_t m_suspend_count; // The current suspend count > 0 means we have + // suspended m_suspendCount times, + // < 0 means we have resumed it m_suspendCount + // times. + MachException::Data m_stop_exception; // The best exception that describes why + // this thread is stopped + std::unique_ptr<DNBArchProtocol> + m_arch_ap; // Arch specific information for register state and more + const DNBRegisterSetInfo + *m_reg_sets; // Register set information for this thread + nub_size_t m_num_reg_sets; + thread_identifier_info_data_t m_ident_info; + struct proc_threadinfo m_proc_threadinfo; + std::string m_dispatch_queue_name; + bool m_is_64_bit; + + // qos_class_t _pthread_qos_class_decode(pthread_priority_t priority, int *, + // unsigned long *); + unsigned int (*m_pthread_qos_class_decode)(unsigned long priority, int *, + unsigned long *); private: - friend class MachThreadList; + friend class MachThreadList; }; typedef std::shared_ptr<MachThread> MachThreadSP; diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp index 8a7da6f4531..cf0e205b349 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.cpp @@ -20,501 +20,434 @@ #include "DNBThreadResumeActions.h" #include "MachProcess.h" -MachThreadList::MachThreadList() : - m_threads(), - m_threads_mutex(PTHREAD_MUTEX_RECURSIVE), - m_is_64_bit(false) -{ -} +MachThreadList::MachThreadList() + : m_threads(), m_threads_mutex(PTHREAD_MUTEX_RECURSIVE), + m_is_64_bit(false) {} -MachThreadList::~MachThreadList() -{ -} +MachThreadList::~MachThreadList() {} -nub_state_t -MachThreadList::GetState(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetState(); - return eStateInvalid; +nub_state_t MachThreadList::GetState(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetState(); + return eStateInvalid; } -const char * -MachThreadList::GetName (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetName(); - return NULL; +const char *MachThreadList::GetName(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetName(); + return NULL; } -ThreadInfo::QoS -MachThreadList::GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); - return ThreadInfo::QoS(); +ThreadInfo::QoS MachThreadList::GetRequestedQoS(nub_thread_t tid, + nub_addr_t tsd, + uint64_t dti_qos_class_index) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetRequestedQoS(tsd, dti_qos_class_index); + return ThreadInfo::QoS(); } -nub_addr_t -MachThreadList::GetPThreadT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetPThreadT(); - return INVALID_NUB_ADDRESS; +nub_addr_t MachThreadList::GetPThreadT(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetPThreadT(); + return INVALID_NUB_ADDRESS; } -nub_addr_t -MachThreadList::GetDispatchQueueT (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetDispatchQueueT(); - return INVALID_NUB_ADDRESS; +nub_addr_t MachThreadList::GetDispatchQueueT(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetDispatchQueueT(); + return INVALID_NUB_ADDRESS; } -nub_addr_t -MachThreadList::GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetTSDAddressForThread(plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); - return INVALID_NUB_ADDRESS; +nub_addr_t MachThreadList::GetTSDAddressForThread( + nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetTSDAddressForThread( + plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, + plo_pthread_tsd_entry_size); + return INVALID_NUB_ADDRESS; } -nub_thread_t -MachThreadList::SetCurrentThread(nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - { - m_current_thread = thread_sp; - return tid; - } - return INVALID_NUB_THREAD; +nub_thread_t MachThreadList::SetCurrentThread(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) { + m_current_thread = thread_sp; + return tid; + } + return INVALID_NUB_THREAD; } - -bool -MachThreadList::GetThreadStoppedReason(nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetStopException().GetStopInfo(stop_info); - return false; +bool MachThreadList::GetThreadStoppedReason( + nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetStopException().GetStopInfo(stop_info); + return false; } -bool -MachThreadList::GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info) -{ - thread_t mach_port_number = GetMachPortNumberByThreadID (tid); +bool MachThreadList::GetIdentifierInfo( + nub_thread_t tid, thread_identifier_info_data_t *ident_info) { + thread_t mach_port_number = GetMachPortNumberByThreadID(tid); - mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; - return ::thread_info (mach_port_number, THREAD_IDENTIFIER_INFO, (thread_info_t)ident_info, &count) == KERN_SUCCESS; + mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; + return ::thread_info(mach_port_number, THREAD_IDENTIFIER_INFO, + (thread_info_t)ident_info, &count) == KERN_SUCCESS; } -void -MachThreadList::DumpThreadStoppedReason (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - thread_sp->GetStopException().DumpStopReason(); +void MachThreadList::DumpThreadStoppedReason(nub_thread_t tid) const { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + thread_sp->GetStopException().DumpStopReason(); } -const char * -MachThreadList::GetThreadInfo (nub_thread_t tid) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetBasicInfoAsString(); - return NULL; +const char *MachThreadList::GetThreadInfo(nub_thread_t tid) const { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetBasicInfoAsString(); + return NULL; } -MachThreadSP -MachThreadList::GetThreadByID (nub_thread_t tid) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->ThreadID() == tid) - { - thread_sp = m_threads[idx]; - break; - } +MachThreadSP MachThreadList::GetThreadByID(nub_thread_t tid) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + MachThreadSP thread_sp; + const size_t num_threads = m_threads.size(); + for (size_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->ThreadID() == tid) { + thread_sp = m_threads[idx]; + break; } - return thread_sp; + } + return thread_sp; } MachThreadSP -MachThreadList::GetThreadByMachPortNumber (thread_t mach_port_number) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->MachPortNumber() == mach_port_number) - { - thread_sp = m_threads[idx]; - break; - } +MachThreadList::GetThreadByMachPortNumber(thread_t mach_port_number) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + MachThreadSP thread_sp; + const size_t num_threads = m_threads.size(); + for (size_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->MachPortNumber() == mach_port_number) { + thread_sp = m_threads[idx]; + break; } - return thread_sp; + } + return thread_sp; } nub_thread_t -MachThreadList::GetThreadIDByMachPortNumber (thread_t mach_port_number) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->MachPortNumber() == mach_port_number) - { - return m_threads[idx]->ThreadID(); - } +MachThreadList::GetThreadIDByMachPortNumber(thread_t mach_port_number) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + MachThreadSP thread_sp; + const size_t num_threads = m_threads.size(); + for (size_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->MachPortNumber() == mach_port_number) { + return m_threads[idx]->ThreadID(); } - return INVALID_NUB_THREAD; -} - -thread_t -MachThreadList::GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - MachThreadSP thread_sp; - const size_t num_threads = m_threads.size(); - for (size_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->ThreadID() == globally_unique_id) - { - return m_threads[idx]->MachPortNumber(); - } + } + return INVALID_NUB_THREAD; +} + +thread_t MachThreadList::GetMachPortNumberByThreadID( + nub_thread_t globally_unique_id) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + MachThreadSP thread_sp; + const size_t num_threads = m_threads.size(); + for (size_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->ThreadID() == globally_unique_id) { + return m_threads[idx]->MachPortNumber(); } - return 0; + } + return 0; } -bool -MachThreadList::GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterValue(set, reg, reg_value); +bool MachThreadList::GetRegisterValue(nub_thread_t tid, uint32_t set, + uint32_t reg, + DNBRegisterValue *reg_value) const { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetRegisterValue(set, reg, reg_value); - return false; + return false; } -bool -MachThreadList::SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value ) const -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterValue(set, reg, reg_value); +bool MachThreadList::SetRegisterValue(nub_thread_t tid, uint32_t set, + uint32_t reg, + const DNBRegisterValue *reg_value) const { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->SetRegisterValue(set, reg, reg_value); - return false; + return false; } -nub_size_t -MachThreadList::GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->GetRegisterContext (buf, buf_len); - return 0; +nub_size_t MachThreadList::GetRegisterContext(nub_thread_t tid, void *buf, + size_t buf_len) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->GetRegisterContext(buf, buf_len); + return 0; } -nub_size_t -MachThreadList::SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SetRegisterContext (buf, buf_len); - return 0; +nub_size_t MachThreadList::SetRegisterContext(nub_thread_t tid, const void *buf, + size_t buf_len) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->SetRegisterContext(buf, buf_len); + return 0; } -uint32_t -MachThreadList::SaveRegisterState (nub_thread_t tid) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->SaveRegisterState (); - return 0; +uint32_t MachThreadList::SaveRegisterState(nub_thread_t tid) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->SaveRegisterState(); + return 0; } -bool -MachThreadList::RestoreRegisterState (nub_thread_t tid, uint32_t save_id) -{ - MachThreadSP thread_sp (GetThreadByID (tid)); - if (thread_sp) - return thread_sp->RestoreRegisterState (save_id); - return 0; +bool MachThreadList::RestoreRegisterState(nub_thread_t tid, uint32_t save_id) { + MachThreadSP thread_sp(GetThreadByID(tid)); + if (thread_sp) + return thread_sp->RestoreRegisterState(save_id); + return 0; } +nub_size_t MachThreadList::NumThreads() const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + return m_threads.size(); +} -nub_size_t -MachThreadList::NumThreads () const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - return m_threads.size(); +nub_thread_t MachThreadList::ThreadIDAtIndex(nub_size_t idx) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + if (idx < m_threads.size()) + return m_threads[idx]->ThreadID(); + return INVALID_NUB_THREAD; } -nub_thread_t -MachThreadList::ThreadIDAtIndex (nub_size_t idx) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (idx < m_threads.size()) - return m_threads[idx]->ThreadID(); - return INVALID_NUB_THREAD; +nub_thread_t MachThreadList::CurrentThreadID() { + MachThreadSP thread_sp; + CurrentThread(thread_sp); + if (thread_sp.get()) + return thread_sp->ThreadID(); + return INVALID_NUB_THREAD; } -nub_thread_t -MachThreadList::CurrentThreadID ( ) -{ - MachThreadSP thread_sp; - CurrentThread(thread_sp); - if (thread_sp.get()) - return thread_sp->ThreadID(); - return INVALID_NUB_THREAD; -} - -bool -MachThreadList::NotifyException(MachException::Data& exc) -{ - MachThreadSP thread_sp (GetThreadByMachPortNumber (exc.thread_port)); - if (thread_sp) - { - thread_sp->NotifyException(exc); - return true; - } - return false; +bool MachThreadList::NotifyException(MachException::Data &exc) { + MachThreadSP thread_sp(GetThreadByMachPortNumber(exc.thread_port)); + if (thread_sp) { + thread_sp->NotifyException(exc); + return true; + } + return false; } -void -MachThreadList::Clear() -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - m_threads.clear(); +void MachThreadList::Clear() { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + m_threads.clear(); } uint32_t -MachThreadList::UpdateThreadList(MachProcess *process, bool update, MachThreadList::collection *new_threads) -{ - // locker will keep a mutex locked until it goes out of scope - DNBLogThreadedIf (LOG_THREAD, "MachThreadList::UpdateThreadList (pid = %4.4x, update = %u) process stop count = %u", process->ProcessID(), update, process->StopCount()); - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - - if (process->StopCount() == 0) - { - int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, process->ProcessID() }; - struct kinfo_proc processInfo; - size_t bufsize = sizeof(processInfo); - if (sysctl(mib, (unsigned)(sizeof(mib)/sizeof(int)), &processInfo, &bufsize, NULL, 0) == 0 && bufsize > 0) - { - if (processInfo.kp_proc.p_flag & P_LP64) - m_is_64_bit = true; - } -#if defined (__i386__) || defined (__x86_64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); -#elif defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - if (m_is_64_bit) - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); - else - DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); -#endif +MachThreadList::UpdateThreadList(MachProcess *process, bool update, + MachThreadList::collection *new_threads) { + // locker will keep a mutex locked until it goes out of scope + DNBLogThreadedIf(LOG_THREAD, "MachThreadList::UpdateThreadList (pid = %4.4x, " + "update = %u) process stop count = %u", + process->ProcessID(), update, process->StopCount()); + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + + if (process->StopCount() == 0) { + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, process->ProcessID()}; + struct kinfo_proc processInfo; + size_t bufsize = sizeof(processInfo); + if (sysctl(mib, (unsigned)(sizeof(mib) / sizeof(int)), &processInfo, + &bufsize, NULL, 0) == 0 && + bufsize > 0) { + if (processInfo.kp_proc.p_flag & P_LP64) + m_is_64_bit = true; } - - if (m_threads.empty() || update) - { - thread_array_t thread_list = NULL; - mach_msg_type_number_t thread_list_count = 0; - task_t task = process->Task().TaskPort(); - DNBError err(::task_threads (task, &thread_list, &thread_list_count), DNBError::MachKernel); - - if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) - err.LogThreaded("::task_threads ( task = 0x%4.4x, thread_list => %p, thread_list_count => %u )", task, thread_list, thread_list_count); - - if (err.Error() == KERN_SUCCESS && thread_list_count > 0) - { - MachThreadList::collection currThreads; - size_t idx; - // Iterator through the current thread list and see which threads - // we already have in our list (keep them), which ones we don't - // (add them), and which ones are not around anymore (remove them). - for (idx = 0; idx < thread_list_count; ++idx) - { - const thread_t mach_port_num = thread_list[idx]; - - uint64_t unique_thread_id = MachThread::GetGloballyUniqueThreadIDForMachPortID (mach_port_num); - MachThreadSP thread_sp (GetThreadByID (unique_thread_id)); - if (thread_sp) - { - // Keep the existing thread class - currThreads.push_back(thread_sp); - } - else - { - // We don't have this thread, lets add it. - thread_sp.reset(new MachThread(process, m_is_64_bit, unique_thread_id, mach_port_num)); - - // Add the new thread regardless of its is user ready state... - // Make sure the thread is ready to be displayed and shown to users - // before we add this thread to our list... - if (thread_sp->IsUserReady()) - { - if (new_threads) - new_threads->push_back(thread_sp); - - currThreads.push_back(thread_sp); - } - } - } - - m_threads.swap(currThreads); - m_current_thread.reset(); - - // Free the vm memory given to us by ::task_threads() - vm_size_t thread_list_size = (vm_size_t) (thread_list_count * sizeof (thread_t)); - ::vm_deallocate (::mach_task_self(), - (vm_address_t)thread_list, - thread_list_size); - } - } - return static_cast<uint32_t>(m_threads.size()); -} - - -void -MachThreadList::CurrentThread (MachThreadSP& thread_sp) -{ - // locker will keep a mutex locked until it goes out of scope - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - if (m_current_thread.get() == NULL) - { - // Figure out which thread is going to be our current thread. - // This is currently done by finding the first thread in the list - // that has a valid exception. - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().IsValid()) - { - m_current_thread = m_threads[idx]; - break; - } +#if defined(__i386__) || defined(__x86_64__) + if (m_is_64_bit) + DNBArchProtocol::SetArchitecture(CPU_TYPE_X86_64); + else + DNBArchProtocol::SetArchitecture(CPU_TYPE_I386); +#elif defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (m_is_64_bit) + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM64); + else + DNBArchProtocol::SetArchitecture(CPU_TYPE_ARM); +#endif + } + + if (m_threads.empty() || update) { + thread_array_t thread_list = NULL; + mach_msg_type_number_t thread_list_count = 0; + task_t task = process->Task().TaskPort(); + DNBError err(::task_threads(task, &thread_list, &thread_list_count), + DNBError::MachKernel); + + if (DNBLogCheckLogBit(LOG_THREAD) || err.Fail()) + err.LogThreaded("::task_threads ( task = 0x%4.4x, thread_list => %p, " + "thread_list_count => %u )", + task, thread_list, thread_list_count); + + if (err.Error() == KERN_SUCCESS && thread_list_count > 0) { + MachThreadList::collection currThreads; + size_t idx; + // Iterator through the current thread list and see which threads + // we already have in our list (keep them), which ones we don't + // (add them), and which ones are not around anymore (remove them). + for (idx = 0; idx < thread_list_count; ++idx) { + const thread_t mach_port_num = thread_list[idx]; + + uint64_t unique_thread_id = + MachThread::GetGloballyUniqueThreadIDForMachPortID(mach_port_num); + MachThreadSP thread_sp(GetThreadByID(unique_thread_id)); + if (thread_sp) { + // Keep the existing thread class + currThreads.push_back(thread_sp); + } else { + // We don't have this thread, lets add it. + thread_sp.reset(new MachThread(process, m_is_64_bit, unique_thread_id, + mach_port_num)); + + // Add the new thread regardless of its is user ready state... + // Make sure the thread is ready to be displayed and shown to users + // before we add this thread to our list... + if (thread_sp->IsUserReady()) { + if (new_threads) + new_threads->push_back(thread_sp); + + currThreads.push_back(thread_sp); + } } + } + + m_threads.swap(currThreads); + m_current_thread.reset(); + + // Free the vm memory given to us by ::task_threads() + vm_size_t thread_list_size = + (vm_size_t)(thread_list_count * sizeof(thread_t)); + ::vm_deallocate(::mach_task_self(), (vm_address_t)thread_list, + thread_list_size); } - thread_sp = m_current_thread; + } + return static_cast<uint32_t>(m_threads.size()); } -void -MachThreadList::Dump() const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); +void MachThreadList::CurrentThread(MachThreadSP &thread_sp) { + // locker will keep a mutex locked until it goes out of scope + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + if (m_current_thread.get() == NULL) { + // Figure out which thread is going to be our current thread. + // This is currently done by finding the first thread in the list + // that has a valid exception. const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->Dump(idx); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetStopException().IsValid()) { + m_current_thread = m_threads[idx]; + break; + } } -} - - -void -MachThreadList::ProcessWillResume(MachProcess *process, const DNBThreadResumeActions &thread_actions) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - - // Update our thread list, because sometimes libdispatch or the kernel - // will spawn threads while a task is suspended. - MachThreadList::collection new_threads; - - // First figure out if we were planning on running only one thread, and if so force that thread to resume. - bool run_one_thread; - nub_thread_t solo_thread = INVALID_NUB_THREAD; - if (thread_actions.GetSize() > 0 - && thread_actions.NumActionsWithState(eStateStepping) + thread_actions.NumActionsWithState (eStateRunning) == 1) - { - run_one_thread = true; - const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); - size_t num_actions = thread_actions.GetSize(); - for (size_t i = 0; i < num_actions; i++, action_ptr++) - { - if (action_ptr->state == eStateStepping || action_ptr->state == eStateRunning) - { - solo_thread = action_ptr->tid; - break; - } - } + } + thread_sp = m_current_thread; +} + +void MachThreadList::Dump() const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + m_threads[idx]->Dump(idx); + } +} + +void MachThreadList::ProcessWillResume( + MachProcess *process, const DNBThreadResumeActions &thread_actions) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + + // Update our thread list, because sometimes libdispatch or the kernel + // will spawn threads while a task is suspended. + MachThreadList::collection new_threads; + + // First figure out if we were planning on running only one thread, and if so + // force that thread to resume. + bool run_one_thread; + nub_thread_t solo_thread = INVALID_NUB_THREAD; + if (thread_actions.GetSize() > 0 && + thread_actions.NumActionsWithState(eStateStepping) + + thread_actions.NumActionsWithState(eStateRunning) == + 1) { + run_one_thread = true; + const DNBThreadResumeAction *action_ptr = thread_actions.GetFirst(); + size_t num_actions = thread_actions.GetSize(); + for (size_t i = 0; i < num_actions; i++, action_ptr++) { + if (action_ptr->state == eStateStepping || + action_ptr->state == eStateRunning) { + solo_thread = action_ptr->tid; + break; + } + } + } else + run_one_thread = false; + + UpdateThreadList(process, true, &new_threads); + + DNBThreadResumeAction resume_new_threads = {-1U, eStateRunning, 0, + INVALID_NUB_ADDRESS}; + // If we are planning to run only one thread, any new threads should be + // suspended. + if (run_one_thread) + resume_new_threads.state = eStateSuspended; + + const size_t num_new_threads = new_threads.size(); + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + MachThread *thread = m_threads[idx].get(); + bool handled = false; + for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) { + if (thread == new_threads[new_idx].get()) { + thread->ThreadWillResume(&resume_new_threads); + handled = true; + break; + } } - else - run_one_thread = false; - - UpdateThreadList(process, true, &new_threads); - - DNBThreadResumeAction resume_new_threads = { -1U, eStateRunning, 0, INVALID_NUB_ADDRESS }; - // If we are planning to run only one thread, any new threads should be suspended. - if (run_one_thread) - resume_new_threads.state = eStateSuspended; - - const size_t num_new_threads = new_threads.size(); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - MachThread *thread = m_threads[idx].get(); - bool handled = false; - for (uint32_t new_idx = 0; new_idx < num_new_threads; ++new_idx) - { - if (thread == new_threads[new_idx].get()) - { - thread->ThreadWillResume(&resume_new_threads); - handled = true; - break; - } - } - if (!handled) - { - const DNBThreadResumeAction *thread_action = thread_actions.GetActionForThread (thread->ThreadID(), true); - // There must always be a thread action for every thread. - assert (thread_action); - bool others_stopped = false; - if (solo_thread == thread->ThreadID()) - others_stopped = true; - thread->ThreadWillResume (thread_action, others_stopped); - } + if (!handled) { + const DNBThreadResumeAction *thread_action = + thread_actions.GetActionForThread(thread->ThreadID(), true); + // There must always be a thread action for every thread. + assert(thread_action); + bool others_stopped = false; + if (solo_thread == thread->ThreadID()) + others_stopped = true; + thread->ThreadWillResume(thread_action, others_stopped); } - - if (new_threads.size()) - { - for (uint32_t idx = 0; idx < num_new_threads; ++idx) - { - DNBLogThreadedIf (LOG_THREAD, "MachThreadList::ProcessWillResume (pid = %4.4x) stop-id=%u, resuming newly discovered thread: 0x%8.8" PRIx64 ", thread-is-user-ready=%i)", - process->ProcessID(), - process->StopCount(), - new_threads[idx]->ThreadID(), - new_threads[idx]->IsUserReady()); - } + } + + if (new_threads.size()) { + for (uint32_t idx = 0; idx < num_new_threads; ++idx) { + DNBLogThreadedIf( + LOG_THREAD, "MachThreadList::ProcessWillResume (pid = %4.4x) " + "stop-id=%u, resuming newly discovered thread: " + "0x%8.8" PRIx64 ", thread-is-user-ready=%i)", + process->ProcessID(), process->StopCount(), + new_threads[idx]->ThreadID(), new_threads[idx]->IsUserReady()); } + } } -uint32_t -MachThreadList::ProcessDidStop(MachProcess *process) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - // Update our thread list - const uint32_t num_threads = UpdateThreadList(process, true); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->ThreadDidStop(); - } - return num_threads; +uint32_t MachThreadList::ProcessDidStop(MachProcess *process) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + // Update our thread list + const uint32_t num_threads = UpdateThreadList(process, true); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + m_threads[idx]->ThreadDidStop(); + } + return num_threads; } //---------------------------------------------------------------------- @@ -528,141 +461,122 @@ MachThreadList::ProcessDidStop(MachProcess *process) // true if we should stop and notify our clients // false if we should resume our child process and skip notification //---------------------------------------------------------------------- -bool -MachThreadList::ShouldStop(bool &step_more) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - uint32_t should_stop = false; - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) - { - should_stop = m_threads[idx]->ShouldStop(step_more); - } - return should_stop; +bool MachThreadList::ShouldStop(bool &step_more) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + uint32_t should_stop = false; + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) { + should_stop = m_threads[idx]->ShouldStop(step_more); + } + return should_stop; } - -void -MachThreadList::NotifyBreakpointChanged (const DNBBreakpoint *bp) -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->NotifyBreakpointChanged(bp); - } +void MachThreadList::NotifyBreakpointChanged(const DNBBreakpoint *bp) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + m_threads[idx]->NotifyBreakpointChanged(bp); + } } - uint32_t -MachThreadList::EnableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->EnableHardwareBreakpoint(bp); - } - return INVALID_NUB_HW_INDEX; +MachThreadList::EnableHardwareBreakpoint(const DNBBreakpoint *bp) const { + if (bp != NULL) { + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->EnableHardwareBreakpoint(bp); + } + return INVALID_NUB_HW_INDEX; } -bool -MachThreadList::DisableHardwareBreakpoint (const DNBBreakpoint* bp) const -{ - if (bp != NULL) - { - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->DisableHardwareBreakpoint(bp); - } - return false; +bool MachThreadList::DisableHardwareBreakpoint(const DNBBreakpoint *bp) const { + if (bp != NULL) { + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->DisableHardwareBreakpoint(bp); + } + return false; } -// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> MachProcess::EnableWatchpoint() +// DNBWatchpointSet() -> MachProcess::CreateWatchpoint() -> +// MachProcess::EnableWatchpoint() // -> MachThreadList::EnableHardwareWatchpoint(). uint32_t -MachThreadList::EnableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - uint32_t hw_index = INVALID_NUB_HW_INDEX; - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - // On Mac OS X we have to prime the control registers for new threads. We do this - // using the control register data for the first thread, for lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint(wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) - { - // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return INVALID_NUB_HW_INDEX; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - } - return hw_index; -} - -bool -MachThreadList::DisableHardwareWatchpoint (const DNBBreakpoint* wp) const -{ - if (wp != NULL) - { - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - const size_t num_threads = m_threads.size(); - - // On Mac OS X we have to prime the control registers for new threads. We do this - // using the control register data for the first thread, for lack of a better way of choosing. - bool also_set_on_task = true; - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) - { - // We know that idx failed for some reason. Let's rollback the transaction for [0, idx). - for (uint32_t i = 0; i < idx; ++i) - m_threads[i]->RollbackTransForHWP(); - return false; - } - also_set_on_task = false; - } - // Notify each thread to commit the pending transaction. - for (uint32_t idx = 0; idx < num_threads; ++idx) - m_threads[idx]->FinishTransForHWP(); - - return true; +MachThreadList::EnableHardwareWatchpoint(const DNBBreakpoint *wp) const { + uint32_t hw_index = INVALID_NUB_HW_INDEX; + if (wp != NULL) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + // On Mac OS X we have to prime the control registers for new threads. We + // do this + // using the control register data for the first thread, for lack of a + // better way of choosing. + bool also_set_on_task = true; + for (uint32_t idx = 0; idx < num_threads; ++idx) { + if ((hw_index = m_threads[idx]->EnableHardwareWatchpoint( + wp, also_set_on_task)) == INVALID_NUB_HW_INDEX) { + // We know that idx failed for some reason. Let's rollback the + // transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); + return INVALID_NUB_HW_INDEX; + } + also_set_on_task = false; } - return false; + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + } + return hw_index; } -uint32_t -MachThreadList::NumSupportedHardwareWatchpoints () const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); +bool MachThreadList::DisableHardwareWatchpoint(const DNBBreakpoint *wp) const { + if (wp != NULL) { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); const size_t num_threads = m_threads.size(); - // Use an arbitrary thread to retrieve the number of supported hardware watchpoints. - if (num_threads) - return m_threads[0]->NumSupportedHardwareWatchpoints(); - return 0; -} -uint32_t -MachThreadList::GetThreadIndexForThreadStoppedWithSignal (const int signo) const -{ - PTHREAD_MUTEX_LOCKER (locker, m_threads_mutex); - uint32_t should_stop = false; - const size_t num_threads = m_threads.size(); - for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) - { - if (m_threads[idx]->GetStopException().SoftSignal () == signo) - return idx; + // On Mac OS X we have to prime the control registers for new threads. We + // do this + // using the control register data for the first thread, for lack of a + // better way of choosing. + bool also_set_on_task = true; + for (uint32_t idx = 0; idx < num_threads; ++idx) { + if (!m_threads[idx]->DisableHardwareWatchpoint(wp, also_set_on_task)) { + // We know that idx failed for some reason. Let's rollback the + // transaction for [0, idx). + for (uint32_t i = 0; i < idx; ++i) + m_threads[i]->RollbackTransForHWP(); + return false; + } + also_set_on_task = false; } - return UINT32_MAX; + // Notify each thread to commit the pending transaction. + for (uint32_t idx = 0; idx < num_threads; ++idx) + m_threads[idx]->FinishTransForHWP(); + + return true; + } + return false; +} + +uint32_t MachThreadList::NumSupportedHardwareWatchpoints() const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + const size_t num_threads = m_threads.size(); + // Use an arbitrary thread to retrieve the number of supported hardware + // watchpoints. + if (num_threads) + return m_threads[0]->NumSupportedHardwareWatchpoints(); + return 0; +} + +uint32_t MachThreadList::GetThreadIndexForThreadStoppedWithSignal( + const int signo) const { + PTHREAD_MUTEX_LOCKER(locker, m_threads_mutex); + uint32_t should_stop = false; + const size_t num_threads = m_threads.size(); + for (uint32_t idx = 0; !should_stop && idx < num_threads; ++idx) { + if (m_threads[idx]->GetStopException().SoftSignal() == signo) + return idx; + } + return UINT32_MAX; } - diff --git a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h index 0ab550e83fc..bcef695edf8 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachThreadList.h +++ b/lldb/tools/debugserver/source/MacOSX/MachThreadList.h @@ -19,69 +19,79 @@ class DNBThreadResumeActions; -class MachThreadList -{ +class MachThreadList { public: - MachThreadList (); - ~MachThreadList (); + MachThreadList(); + ~MachThreadList(); - void Clear (); - void Dump () const; - bool GetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, DNBRegisterValue *reg_value) const; - bool SetRegisterValue (nub_thread_t tid, uint32_t set, uint32_t reg, const DNBRegisterValue *reg_value) const; - nub_size_t GetRegisterContext (nub_thread_t tid, void *buf, size_t buf_len); - nub_size_t SetRegisterContext (nub_thread_t tid, const void *buf, size_t buf_len); - uint32_t SaveRegisterState (nub_thread_t tid); - bool RestoreRegisterState (nub_thread_t tid, uint32_t save_id); - const char * GetThreadInfo (nub_thread_t tid) const; - void ProcessWillResume (MachProcess *process, const DNBThreadResumeActions &thread_actions); - uint32_t ProcessDidStop (MachProcess *process); - bool NotifyException (MachException::Data& exc); - bool ShouldStop (bool &step_more); - const char * GetName (nub_thread_t tid); - nub_state_t GetState (nub_thread_t tid); - nub_thread_t SetCurrentThread (nub_thread_t tid); + void Clear(); + void Dump() const; + bool GetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + DNBRegisterValue *reg_value) const; + bool SetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg, + const DNBRegisterValue *reg_value) const; + nub_size_t GetRegisterContext(nub_thread_t tid, void *buf, size_t buf_len); + nub_size_t SetRegisterContext(nub_thread_t tid, const void *buf, + size_t buf_len); + uint32_t SaveRegisterState(nub_thread_t tid); + bool RestoreRegisterState(nub_thread_t tid, uint32_t save_id); + const char *GetThreadInfo(nub_thread_t tid) const; + void ProcessWillResume(MachProcess *process, + const DNBThreadResumeActions &thread_actions); + uint32_t ProcessDidStop(MachProcess *process); + bool NotifyException(MachException::Data &exc); + bool ShouldStop(bool &step_more); + const char *GetName(nub_thread_t tid); + nub_state_t GetState(nub_thread_t tid); + nub_thread_t SetCurrentThread(nub_thread_t tid); - ThreadInfo::QoS GetRequestedQoS (nub_thread_t tid, nub_addr_t tsd, uint64_t dti_qos_class_index); - nub_addr_t GetPThreadT (nub_thread_t tid); - nub_addr_t GetDispatchQueueT (nub_thread_t tid); - nub_addr_t GetTSDAddressForThread (nub_thread_t tid, uint64_t plo_pthread_tsd_base_address_offset, uint64_t plo_pthread_tsd_base_offset, uint64_t plo_pthread_tsd_entry_size); + ThreadInfo::QoS GetRequestedQoS(nub_thread_t tid, nub_addr_t tsd, + uint64_t dti_qos_class_index); + nub_addr_t GetPThreadT(nub_thread_t tid); + nub_addr_t GetDispatchQueueT(nub_thread_t tid); + nub_addr_t + GetTSDAddressForThread(nub_thread_t tid, + uint64_t plo_pthread_tsd_base_address_offset, + uint64_t plo_pthread_tsd_base_offset, + uint64_t plo_pthread_tsd_entry_size); - bool GetThreadStoppedReason (nub_thread_t tid, struct DNBThreadStopInfo *stop_info) const; - void DumpThreadStoppedReason (nub_thread_t tid) const; - bool GetIdentifierInfo (nub_thread_t tid, thread_identifier_info_data_t *ident_info); - nub_size_t NumThreads () const; - nub_thread_t ThreadIDAtIndex (nub_size_t idx) const; - nub_thread_t CurrentThreadID (); - void CurrentThread (MachThreadSP& threadSP); - void NotifyBreakpointChanged (const DNBBreakpoint *bp); - uint32_t EnableHardwareBreakpoint (const DNBBreakpoint *bp) const; - bool DisableHardwareBreakpoint (const DNBBreakpoint *bp) const; - uint32_t EnableHardwareWatchpoint (const DNBBreakpoint *wp) const; - bool DisableHardwareWatchpoint (const DNBBreakpoint *wp) const; - uint32_t NumSupportedHardwareWatchpoints () const; + bool GetThreadStoppedReason(nub_thread_t tid, + struct DNBThreadStopInfo *stop_info) const; + void DumpThreadStoppedReason(nub_thread_t tid) const; + bool GetIdentifierInfo(nub_thread_t tid, + thread_identifier_info_data_t *ident_info); + nub_size_t NumThreads() const; + nub_thread_t ThreadIDAtIndex(nub_size_t idx) const; + nub_thread_t CurrentThreadID(); + void CurrentThread(MachThreadSP &threadSP); + void NotifyBreakpointChanged(const DNBBreakpoint *bp); + uint32_t EnableHardwareBreakpoint(const DNBBreakpoint *bp) const; + bool DisableHardwareBreakpoint(const DNBBreakpoint *bp) const; + uint32_t EnableHardwareWatchpoint(const DNBBreakpoint *wp) const; + bool DisableHardwareWatchpoint(const DNBBreakpoint *wp) const; + uint32_t NumSupportedHardwareWatchpoints() const; - uint32_t GetThreadIndexForThreadStoppedWithSignal (const int signo) const; + uint32_t GetThreadIndexForThreadStoppedWithSignal(const int signo) const; - MachThreadSP GetThreadByID (nub_thread_t tid) const; + MachThreadSP GetThreadByID(nub_thread_t tid) const; - MachThreadSP GetThreadByMachPortNumber (thread_t mach_port_number) const; - nub_thread_t GetThreadIDByMachPortNumber (thread_t mach_port_number) const; - thread_t GetMachPortNumberByThreadID (nub_thread_t globally_unique_id) const; + MachThreadSP GetThreadByMachPortNumber(thread_t mach_port_number) const; + nub_thread_t GetThreadIDByMachPortNumber(thread_t mach_port_number) const; + thread_t GetMachPortNumberByThreadID(nub_thread_t globally_unique_id) const; protected: - typedef std::vector<MachThreadSP> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; + typedef std::vector<MachThreadSP> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; - uint32_t UpdateThreadList (MachProcess *process, bool update, collection *num_threads = NULL); -// const_iterator FindThreadByID (thread_t tid) const; + uint32_t UpdateThreadList(MachProcess *process, bool update, + collection *num_threads = NULL); + // const_iterator FindThreadByID (thread_t tid) const; - collection m_threads; - mutable PThreadMutex m_threads_mutex; - MachThreadSP m_current_thread; - bool m_is_64_bit; + collection m_threads; + mutable PThreadMutex m_threads_mutex; + MachThreadSP m_current_thread; + bool m_is_64_bit; }; #endif // #ifndef __MachThreadList_h__ - diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp index 3b86a83024d..76806ab1cc1 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.cpp @@ -12,587 +12,559 @@ //===----------------------------------------------------------------------===// #include "MachVMMemory.h" -#include "MachVMRegion.h" #include "DNBLog.h" +#include "MachVMRegion.h" +#include <dlfcn.h> #include <mach/mach_vm.h> #include <mach/shared_region.h> #include <sys/sysctl.h> -#include <dlfcn.h> static const vm_size_t kInvalidPageSize = ~0; -MachVMMemory::MachVMMemory() : - m_page_size (kInvalidPageSize), - m_err (0) -{ +MachVMMemory::MachVMMemory() : m_page_size(kInvalidPageSize), m_err(0) {} + +MachVMMemory::~MachVMMemory() {} + +nub_size_t MachVMMemory::PageSize(task_t task) { + if (m_page_size == kInvalidPageSize) { +#if defined(TASK_VM_INFO) && TASK_VM_INFO >= 22 + if (task != TASK_NULL) { + kern_return_t kr; + mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT; + task_vm_info_data_t vm_info; + kr = task_info(task, TASK_VM_INFO, (task_info_t)&vm_info, &info_count); + if (kr == KERN_SUCCESS) { + DNBLogThreadedIf( + LOG_TASK, + "MachVMMemory::PageSize task_info returned page size of 0x%x", + (int)vm_info.page_size); + m_page_size = vm_info.page_size; + return m_page_size; + } else { + DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info call " + "failed to get page size, TASK_VM_INFO %d, " + "TASK_VM_INFO_COUNT %d, kern return %d", + TASK_VM_INFO, TASK_VM_INFO_COUNT, kr); + } + } +#endif + m_err = ::host_page_size(::mach_host_self(), &m_page_size); + if (m_err.Fail()) + m_page_size = 0; + } + return m_page_size; } -MachVMMemory::~MachVMMemory() -{ +nub_size_t MachVMMemory::MaxBytesLeftInPage(task_t task, nub_addr_t addr, + nub_size_t count) { + const nub_size_t page_size = PageSize(task); + if (page_size > 0) { + nub_size_t page_offset = (addr % page_size); + nub_size_t bytes_left_in_page = page_size - page_offset; + if (count > bytes_left_in_page) + count = bytes_left_in_page; + } + return count; } -nub_size_t -MachVMMemory::PageSize(task_t task) -{ - if (m_page_size == kInvalidPageSize) - { -#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22 - if (task != TASK_NULL) - { - kern_return_t kr; - mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT; - task_vm_info_data_t vm_info; - kr = task_info (task, TASK_VM_INFO, (task_info_t) &vm_info, &info_count); - if (kr == KERN_SUCCESS) - { - DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info returned page size of 0x%x", (int) vm_info.page_size); - m_page_size = vm_info.page_size; - return m_page_size; - } - else - { - DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info call failed to get page size, TASK_VM_INFO %d, TASK_VM_INFO_COUNT %d, kern return %d", TASK_VM_INFO, TASK_VM_INFO_COUNT, kr); - } - } -#endif - m_err = ::host_page_size( ::mach_host_self(), &m_page_size); - if (m_err.Fail()) - m_page_size = 0; +nub_bool_t MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, + DNBRegionInfo *region_info) { + MachVMRegion vmRegion(task); + + if (vmRegion.GetRegionForAddress(address)) { + region_info->addr = vmRegion.StartAddress(); + region_info->size = vmRegion.GetByteSize(); + region_info->permissions = vmRegion.GetDNBPermissions(); + } else { + region_info->addr = address; + region_info->size = 0; + if (vmRegion.GetError().Success()) { + // vmRegion.GetRegionForAddress() return false, indicating that "address" + // wasn't in a valid region, but the "vmRegion" info was successfully + // read from the task which means the info describes the next valid + // region from which we can infer the size of this invalid region + mach_vm_address_t start_addr = vmRegion.StartAddress(); + if (address < start_addr) + region_info->size = start_addr - address; } - return m_page_size; + // If we can't get any info about the size from the next region it means + // we asked about an address that was past all mappings, so the size + // of this region will take up all remaining address space. + if (region_info->size == 0) + region_info->size = INVALID_NUB_ADDRESS - region_info->addr; + + // Not readable, writeable or executable + region_info->permissions = 0; + } + return true; } -nub_size_t -MachVMMemory::MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count) -{ - const nub_size_t page_size = PageSize(task); - if (page_size > 0) - { - nub_size_t page_offset = (addr % page_size); - nub_size_t bytes_left_in_page = page_size - page_offset; - if (count > bytes_left_in_page) - count = bytes_left_in_page; +// For integrated graphics chip, this makes the accounting info for 'wired' +// memory more like top. +uint64_t MachVMMemory::GetStolenPages(task_t task) { + static uint64_t stolenPages = 0; + static bool calculated = false; + if (calculated) + return stolenPages; + + static int mib_reserved[CTL_MAXNAME]; + static int mib_unusable[CTL_MAXNAME]; + static int mib_other[CTL_MAXNAME]; + static size_t mib_reserved_len = 0; + static size_t mib_unusable_len = 0; + static size_t mib_other_len = 0; + int r; + + /* This can be used for testing: */ + // tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize; + + if (0 == mib_reserved_len) { + mib_reserved_len = CTL_MAXNAME; + + r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved, + &mib_reserved_len); + + if (-1 == r) { + mib_reserved_len = 0; + return 0; } - return count; -} -nub_bool_t -MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info) -{ - MachVMRegion vmRegion(task); + mib_unusable_len = CTL_MAXNAME; - if (vmRegion.GetRegionForAddress(address)) - { - region_info->addr = vmRegion.StartAddress(); - region_info->size = vmRegion.GetByteSize(); - region_info->permissions = vmRegion.GetDNBPermissions(); + r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable, + &mib_unusable_len); + + if (-1 == r) { + mib_reserved_len = 0; + return 0; } - else - { - region_info->addr = address; - region_info->size = 0; - if (vmRegion.GetError().Success()) - { - // vmRegion.GetRegionForAddress() return false, indicating that "address" - // wasn't in a valid region, but the "vmRegion" info was successfully - // read from the task which means the info describes the next valid - // region from which we can infer the size of this invalid region - mach_vm_address_t start_addr = vmRegion.StartAddress(); - if (address < start_addr) - region_info->size = start_addr - address; - } - // If we can't get any info about the size from the next region it means - // we asked about an address that was past all mappings, so the size - // of this region will take up all remaining address space. - if (region_info->size == 0) - region_info->size = INVALID_NUB_ADDRESS - region_info->addr; - - // Not readable, writeable or executable - region_info->permissions = 0; + + mib_other_len = CTL_MAXNAME; + + r = sysctlnametomib("machdep.memmap.Other", mib_other, &mib_other_len); + + if (-1 == r) { + mib_reserved_len = 0; + return 0; } - return true; -} + } -// For integrated graphics chip, this makes the accounting info for 'wired' memory more like top. -uint64_t -MachVMMemory::GetStolenPages(task_t task) -{ - static uint64_t stolenPages = 0; - static bool calculated = false; - if (calculated) return stolenPages; - - static int mib_reserved[CTL_MAXNAME]; - static int mib_unusable[CTL_MAXNAME]; - static int mib_other[CTL_MAXNAME]; - static size_t mib_reserved_len = 0; - static size_t mib_unusable_len = 0; - static size_t mib_other_len = 0; - int r; - - /* This can be used for testing: */ - //tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize; - - if(0 == mib_reserved_len) - { - mib_reserved_len = CTL_MAXNAME; - - r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved, - &mib_reserved_len); - - if(-1 == r) - { - mib_reserved_len = 0; - return 0; - } - - mib_unusable_len = CTL_MAXNAME; - - r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable, - &mib_unusable_len); - - if(-1 == r) - { - mib_reserved_len = 0; - return 0; - } - - - mib_other_len = CTL_MAXNAME; - - r = sysctlnametomib("machdep.memmap.Other", mib_other, - &mib_other_len); - - if(-1 == r) - { - mib_reserved_len = 0; - return 0; - } - } - - if(mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0) - { - uint64_t reserved = 0, unusable = 0, other = 0; - size_t reserved_len; - size_t unusable_len; - size_t other_len; - - reserved_len = sizeof(reserved); - unusable_len = sizeof(unusable); - other_len = sizeof(other); - - /* These are all declared as QUAD/uint64_t sysctls in the kernel. */ - - if (sysctl (mib_reserved, - static_cast<u_int>(mib_reserved_len), - &reserved, - &reserved_len, - NULL, - 0)) - { - return 0; - } - - if (sysctl (mib_unusable, - static_cast<u_int>(mib_unusable_len), - &unusable, - &unusable_len, - NULL, - 0)) - { - return 0; - } - - if (sysctl (mib_other, - static_cast<u_int>(mib_other_len), - &other, - &other_len, - NULL, - 0)) - { - return 0; - } - - if (reserved_len == sizeof(reserved) && - unusable_len == sizeof(unusable) && - other_len == sizeof(other)) - { - uint64_t stolen = reserved + unusable + other; - uint64_t mb128 = 128 * 1024 * 1024ULL; - - if(stolen >= mb128) - { - stolen = (stolen & ~((128 * 1024 * 1024ULL) - 1)); // rounding down - stolenPages = stolen / PageSize (task); - } - } - } - - calculated = true; - return stolenPages; + if (mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0) { + uint64_t reserved = 0, unusable = 0, other = 0; + size_t reserved_len; + size_t unusable_len; + size_t other_len; + + reserved_len = sizeof(reserved); + unusable_len = sizeof(unusable); + other_len = sizeof(other); + + /* These are all declared as QUAD/uint64_t sysctls in the kernel. */ + + if (sysctl(mib_reserved, static_cast<u_int>(mib_reserved_len), &reserved, + &reserved_len, NULL, 0)) { + return 0; + } + + if (sysctl(mib_unusable, static_cast<u_int>(mib_unusable_len), &unusable, + &unusable_len, NULL, 0)) { + return 0; + } + + if (sysctl(mib_other, static_cast<u_int>(mib_other_len), &other, &other_len, + NULL, 0)) { + return 0; + } + + if (reserved_len == sizeof(reserved) && unusable_len == sizeof(unusable) && + other_len == sizeof(other)) { + uint64_t stolen = reserved + unusable + other; + uint64_t mb128 = 128 * 1024 * 1024ULL; + + if (stolen >= mb128) { + stolen = (stolen & ~((128 * 1024 * 1024ULL) - 1)); // rounding down + stolenPages = stolen / PageSize(task); + } + } + } + + calculated = true; + return stolenPages; } -static uint64_t GetPhysicalMemory() -{ - // This doesn't change often at all. No need to poll each time. - static uint64_t physical_memory = 0; - static bool calculated = false; - if (calculated) return physical_memory; - - size_t len = sizeof(physical_memory); - sysctlbyname("hw.memsize", &physical_memory, &len, NULL, 0); - - calculated = true; +static uint64_t GetPhysicalMemory() { + // This doesn't change often at all. No need to poll each time. + static uint64_t physical_memory = 0; + static bool calculated = false; + if (calculated) return physical_memory; + + size_t len = sizeof(physical_memory); + sysctlbyname("hw.memsize", &physical_memory, &len, NULL, 0); + + calculated = true; + return physical_memory; } -// rsize and dirty_size is not adjusted for dyld shared cache and multiple __LINKEDIT segment, as in vmmap. In practice, dirty_size doesn't differ much but rsize may. There is performance penalty for the adjustment. Right now, only use the dirty_size. -void -MachVMMemory::GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size) -{ -#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22 - - task_vm_info_data_t vm_info; - mach_msg_type_number_t info_count; - kern_return_t kr; - - info_count = TASK_VM_INFO_COUNT; - kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count); - if (kr == KERN_SUCCESS) - dirty_size = vm_info.internal; +// rsize and dirty_size is not adjusted for dyld shared cache and multiple +// __LINKEDIT segment, as in vmmap. In practice, dirty_size doesn't differ much +// but rsize may. There is performance penalty for the adjustment. Right now, +// only use the dirty_size. +void MachVMMemory::GetRegionSizes(task_t task, mach_vm_size_t &rsize, + mach_vm_size_t &dirty_size) { +#if defined(TASK_VM_INFO) && TASK_VM_INFO >= 22 + + task_vm_info_data_t vm_info; + mach_msg_type_number_t info_count; + kern_return_t kr; + + info_count = TASK_VM_INFO_COUNT; + kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, + &info_count); + if (kr == KERN_SUCCESS) + dirty_size = vm_info.internal; #endif } // Test whether the virtual address is within the architecture's shared region. -static bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type) -{ - mach_vm_address_t base = 0, size = 0; - - switch(type) { -#if defined (CPU_TYPE_ARM64) && defined (SHARED_REGION_BASE_ARM64) - case CPU_TYPE_ARM64: - base = SHARED_REGION_BASE_ARM64; - size = SHARED_REGION_SIZE_ARM64; - break; +static bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type) { + mach_vm_address_t base = 0, size = 0; + + switch (type) { +#if defined(CPU_TYPE_ARM64) && defined(SHARED_REGION_BASE_ARM64) + case CPU_TYPE_ARM64: + base = SHARED_REGION_BASE_ARM64; + size = SHARED_REGION_SIZE_ARM64; + break; #endif - case CPU_TYPE_ARM: - base = SHARED_REGION_BASE_ARM; - size = SHARED_REGION_SIZE_ARM; - break; - - case CPU_TYPE_X86_64: - base = SHARED_REGION_BASE_X86_64; - size = SHARED_REGION_SIZE_X86_64; - break; - - case CPU_TYPE_I386: - base = SHARED_REGION_BASE_I386; - size = SHARED_REGION_SIZE_I386; - break; - - default: { - // Log error abut unknown CPU type - break; - } - } - - - return(addr >= base && addr < (base + size)); + case CPU_TYPE_ARM: + base = SHARED_REGION_BASE_ARM; + size = SHARED_REGION_SIZE_ARM; + break; + + case CPU_TYPE_X86_64: + base = SHARED_REGION_BASE_X86_64; + size = SHARED_REGION_SIZE_X86_64; + break; + + case CPU_TYPE_I386: + base = SHARED_REGION_BASE_I386; + size = SHARED_REGION_SIZE_I386; + break; + + default: { + // Log error abut unknown CPU type + break; + } + } + + return (addr >= base && addr < (base + size)); } -void -MachVMMemory::GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt) -{ - // Collecting some other info cheaply but not reporting for now. - mach_vm_size_t empty = 0; - mach_vm_size_t fw_private = 0; - - mach_vm_size_t aliased = 0; - bool global_shared_text_data_mapped = false; - vm_size_t pagesize = PageSize (task); - - for (mach_vm_address_t addr=0, size=0; ; addr += size) - { - vm_region_top_info_data_t info; - mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT; - mach_port_t object_name; - - kern_return_t kr = mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, &object_name); - if (kr != KERN_SUCCESS) break; - - if (InSharedRegion(addr, cputype)) - { - // Private Shared - fw_private += info.private_pages_resident * pagesize; - - // Check if this process has the globally shared text and data regions mapped in. If so, set global_shared_text_data_mapped to TRUE and avoid checking again. - if (global_shared_text_data_mapped == FALSE && info.share_mode == SM_EMPTY) { - vm_region_basic_info_data_64_t b_info; - mach_vm_address_t b_addr = addr; - mach_vm_size_t b_size = size; - count = VM_REGION_BASIC_INFO_COUNT_64; - - kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &count, &object_name); - if (kr != KERN_SUCCESS) break; - - if (b_info.reserved) { - global_shared_text_data_mapped = TRUE; - } - } - - // Short circuit the loop if this isn't a shared private region, since that's the only region type we care about within the current address range. - if (info.share_mode != SM_PRIVATE) - { - continue; - } +void MachVMMemory::GetMemorySizes(task_t task, cpu_type_t cputype, + nub_process_t pid, mach_vm_size_t &rprvt, + mach_vm_size_t &vprvt) { + // Collecting some other info cheaply but not reporting for now. + mach_vm_size_t empty = 0; + mach_vm_size_t fw_private = 0; + + mach_vm_size_t aliased = 0; + bool global_shared_text_data_mapped = false; + vm_size_t pagesize = PageSize(task); + + for (mach_vm_address_t addr = 0, size = 0;; addr += size) { + vm_region_top_info_data_t info; + mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT; + mach_port_t object_name; + + kern_return_t kr = + mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, + (vm_region_info_t)&info, &count, &object_name); + if (kr != KERN_SUCCESS) + break; + + if (InSharedRegion(addr, cputype)) { + // Private Shared + fw_private += info.private_pages_resident * pagesize; + + // Check if this process has the globally shared text and data regions + // mapped in. If so, set global_shared_text_data_mapped to TRUE and avoid + // checking again. + if (global_shared_text_data_mapped == FALSE && + info.share_mode == SM_EMPTY) { + vm_region_basic_info_data_64_t b_info; + mach_vm_address_t b_addr = addr; + mach_vm_size_t b_size = size; + count = VM_REGION_BASIC_INFO_COUNT_64; + + kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, + (vm_region_info_t)&b_info, &count, &object_name); + if (kr != KERN_SUCCESS) + break; + + if (b_info.reserved) { + global_shared_text_data_mapped = TRUE; } - - // Update counters according to the region type. - if (info.share_mode == SM_COW && info.ref_count == 1) - { - // Treat single reference SM_COW as SM_PRIVATE - info.share_mode = SM_PRIVATE; - } - - switch (info.share_mode) - { - case SM_LARGE_PAGE: - // Treat SM_LARGE_PAGE the same as SM_PRIVATE - // since they are not shareable and are wired. - case SM_PRIVATE: - rprvt += info.private_pages_resident * pagesize; - rprvt += info.shared_pages_resident * pagesize; - vprvt += size; - break; - - case SM_EMPTY: - empty += size; - break; - - case SM_COW: - case SM_SHARED: - { - if (pid == 0) - { - // Treat kernel_task specially - if (info.share_mode == SM_COW) - { - rprvt += info.private_pages_resident * pagesize; - vprvt += size; - } - break; - } - - if (info.share_mode == SM_COW) - { - rprvt += info.private_pages_resident * pagesize; - vprvt += info.private_pages_resident * pagesize; - } - break; - } - default: - // log that something is really bad. - break; + } + + // Short circuit the loop if this isn't a shared private region, since + // that's the only region type we care about within the current address + // range. + if (info.share_mode != SM_PRIVATE) { + continue; + } + } + + // Update counters according to the region type. + if (info.share_mode == SM_COW && info.ref_count == 1) { + // Treat single reference SM_COW as SM_PRIVATE + info.share_mode = SM_PRIVATE; + } + + switch (info.share_mode) { + case SM_LARGE_PAGE: + // Treat SM_LARGE_PAGE the same as SM_PRIVATE + // since they are not shareable and are wired. + case SM_PRIVATE: + rprvt += info.private_pages_resident * pagesize; + rprvt += info.shared_pages_resident * pagesize; + vprvt += size; + break; + + case SM_EMPTY: + empty += size; + break; + + case SM_COW: + case SM_SHARED: { + if (pid == 0) { + // Treat kernel_task specially + if (info.share_mode == SM_COW) { + rprvt += info.private_pages_resident * pagesize; + vprvt += size; } + break; + } + + if (info.share_mode == SM_COW) { + rprvt += info.private_pages_resident * pagesize; + vprvt += info.private_pages_resident * pagesize; + } + break; + } + default: + // log that something is really bad. + break; } - - rprvt += aliased; + } + + rprvt += aliased; } -static void -GetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, uint64_t &anonymous) -{ -#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22 - - kern_return_t kr; - mach_msg_type_number_t info_count; - task_vm_info_data_t vm_info; - - info_count = TASK_VM_INFO_COUNT; - kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count); - if (kr == KERN_SUCCESS) - { - purgeable = vm_info.purgeable_volatile_resident; - anonymous = vm_info.internal + vm_info.compressed - vm_info.purgeable_volatile_pmap; - } +static void GetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, + uint64_t &anonymous) { +#if defined(TASK_VM_INFO) && TASK_VM_INFO >= 22 + + kern_return_t kr; + mach_msg_type_number_t info_count; + task_vm_info_data_t vm_info; + + info_count = TASK_VM_INFO_COUNT; + kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, + &info_count); + if (kr == KERN_SUCCESS) { + purgeable = vm_info.purgeable_volatile_resident; + anonymous = + vm_info.internal + vm_info.compressed - vm_info.purgeable_volatile_pmap; + } #endif } -#if defined (HOST_VM_INFO64_COUNT) -nub_bool_t -MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics64_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous) +#if defined(HOST_VM_INFO64_COUNT) +nub_bool_t MachVMMemory::GetMemoryProfile( + DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, + cpu_type_t cputype, nub_process_t pid, vm_statistics64_data_t &vminfo, + uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, + mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, + mach_vm_size_t &purgeable, mach_vm_size_t &anonymous) #else -nub_bool_t -MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous) +nub_bool_t MachVMMemory::GetMemoryProfile( + DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, + cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vminfo, + uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, + mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, + mach_vm_size_t &purgeable, mach_vm_size_t &anonymous) #endif { - if (scanType & eProfileHostMemory) - physical_memory = GetPhysicalMemory(); - - if (scanType & eProfileMemory) - { - static mach_port_t localHost = mach_host_self(); -#if defined (HOST_VM_INFO64_COUNT) - mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; - host_statistics64(localHost, HOST_VM_INFO64, (host_info64_t)&vminfo, &count); + if (scanType & eProfileHostMemory) + physical_memory = GetPhysicalMemory(); + + if (scanType & eProfileMemory) { + static mach_port_t localHost = mach_host_self(); +#if defined(HOST_VM_INFO64_COUNT) + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + host_statistics64(localHost, HOST_VM_INFO64, (host_info64_t)&vminfo, + &count); #else - mach_msg_type_number_t count = HOST_VM_INFO_COUNT; - host_statistics(localHost, HOST_VM_INFO, (host_info_t)&vminfo, &count); - vminfo.wire_count += GetStolenPages(task); + mach_msg_type_number_t count = HOST_VM_INFO_COUNT; + host_statistics(localHost, HOST_VM_INFO, (host_info_t)&vminfo, &count); + vminfo.wire_count += GetStolenPages(task); #endif - - /* We are no longer reporting these. Let's not waste time. - GetMemorySizes(task, cputype, pid, rprvt, vprvt); - rsize = ti.resident_size; - vsize = ti.virtual_size; - - if (scanType & eProfileMemoryDirtyPage) - { - // This uses vmmap strategy. We don't use the returned rsize for now. We prefer to match top's version since that's what we do for the rest of the metrics. - GetRegionSizes(task, rsize, dirty_size); - } - */ - - if (scanType & eProfileMemoryAnonymous) - { - GetPurgeableAndAnonymous(task, purgeable, anonymous); - } - } - - return true; -} -nub_size_t -MachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count) -{ - if (data == NULL || data_count == 0) - return 0; + /* We are no longer reporting these. Let's not waste time. + GetMemorySizes(task, cputype, pid, rprvt, vprvt); + rsize = ti.resident_size; + vsize = ti.virtual_size; - nub_size_t total_bytes_read = 0; - nub_addr_t curr_addr = address; - uint8_t *curr_data = (uint8_t*)data; - while (total_bytes_read < data_count) + if (scanType & eProfileMemoryDirtyPage) { - mach_vm_size_t curr_size = MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_read); - mach_msg_type_number_t curr_bytes_read = 0; - vm_offset_t vm_memory = 0; - m_err = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read); - - if (DNBLogCheckLogBit(LOG_MEMORY)) - m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i )", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read); - - if (m_err.Success()) - { - if (curr_bytes_read != curr_size) - { - if (DNBLogCheckLogBit(LOG_MEMORY)) - m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i ) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size); - } - ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read); - ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read); - total_bytes_read += curr_bytes_read; - curr_addr += curr_bytes_read; - curr_data += curr_bytes_read; - } - else - { - break; - } + // This uses vmmap strategy. We don't use the returned rsize for now. We + prefer to match top's version since that's what we do for the rest of the + metrics. + GetRegionSizes(task, rsize, dirty_size); } - return total_bytes_read; -} - + */ -nub_size_t -MachVMMemory::Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count) -{ - MachVMRegion vmRegion(task); + if (scanType & eProfileMemoryAnonymous) { + GetPurgeableAndAnonymous(task, purgeable, anonymous); + } + } - nub_size_t total_bytes_written = 0; - nub_addr_t curr_addr = address; - const uint8_t *curr_data = (const uint8_t*)data; + return true; +} +nub_size_t MachVMMemory::Read(task_t task, nub_addr_t address, void *data, + nub_size_t data_count) { + if (data == NULL || data_count == 0) + return 0; + + nub_size_t total_bytes_read = 0; + nub_addr_t curr_addr = address; + uint8_t *curr_data = (uint8_t *)data; + while (total_bytes_read < data_count) { + mach_vm_size_t curr_size = + MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_read); + mach_msg_type_number_t curr_bytes_read = 0; + vm_offset_t vm_memory = 0; + m_err = ::mach_vm_read(task, curr_addr, curr_size, &vm_memory, + &curr_bytes_read); + + if (DNBLogCheckLogBit(LOG_MEMORY)) + m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, " + "size = %llu, data => %8.8p, dataCnt => %i )", + task, (uint64_t)curr_addr, (uint64_t)curr_size, + vm_memory, curr_bytes_read); + + if (m_err.Success()) { + if (curr_bytes_read != curr_size) { + if (DNBLogCheckLogBit(LOG_MEMORY)) + m_err.LogThreaded( + "::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, " + "data => %8.8p, dataCnt=>%i ) only read %u of %llu bytes", + task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, + curr_bytes_read, curr_bytes_read, (uint64_t)curr_size); + } + ::memcpy(curr_data, (void *)vm_memory, curr_bytes_read); + ::vm_deallocate(mach_task_self(), vm_memory, curr_bytes_read); + total_bytes_read += curr_bytes_read; + curr_addr += curr_bytes_read; + curr_data += curr_bytes_read; + } else { + break; + } + } + return total_bytes_read; +} - while (total_bytes_written < data_count) - { - if (vmRegion.GetRegionForAddress(curr_addr)) - { - mach_vm_size_t curr_data_count = data_count - total_bytes_written; - mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr); - if (region_bytes_left == 0) - { - break; - } - if (curr_data_count > region_bytes_left) - curr_data_count = region_bytes_left; - - if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE)) - { - nub_size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count); - if (bytes_written <= 0) - { - // Error should have already be posted by WriteRegion... - break; - } - else - { - total_bytes_written += bytes_written; - curr_addr += bytes_written; - curr_data += bytes_written; - } - } - else - { - DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count)); - break; - } - } - else - { - DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address); - break; +nub_size_t MachVMMemory::Write(task_t task, nub_addr_t address, + const void *data, nub_size_t data_count) { + MachVMRegion vmRegion(task); + + nub_size_t total_bytes_written = 0; + nub_addr_t curr_addr = address; + const uint8_t *curr_data = (const uint8_t *)data; + + while (total_bytes_written < data_count) { + if (vmRegion.GetRegionForAddress(curr_addr)) { + mach_vm_size_t curr_data_count = data_count - total_bytes_written; + mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr); + if (region_bytes_left == 0) { + break; + } + if (curr_data_count > region_bytes_left) + curr_data_count = region_bytes_left; + + if (vmRegion.SetProtections(curr_addr, curr_data_count, + VM_PROT_READ | VM_PROT_WRITE)) { + nub_size_t bytes_written = + WriteRegion(task, curr_addr, curr_data, curr_data_count); + if (bytes_written <= 0) { + // Error should have already be posted by WriteRegion... + break; + } else { + total_bytes_written += bytes_written; + curr_addr += bytes_written; + curr_data += bytes_written; } + } else { + DNBLogThreadedIf( + LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on " + "region for address: [0x%8.8llx-0x%8.8llx)", + (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count)); + break; + } + } else { + DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, + "Failed to get region for address: 0x%8.8llx", + (uint64_t)address); + break; } + } - return total_bytes_written; + return total_bytes_written; } - -nub_size_t -MachVMMemory::WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count) -{ - if (data == NULL || data_count == 0) - return 0; - - nub_size_t total_bytes_written = 0; - nub_addr_t curr_addr = address; - const uint8_t *curr_data = (const uint8_t*)data; - while (total_bytes_written < data_count) - { - mach_msg_type_number_t curr_data_count = static_cast<mach_msg_type_number_t>(MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_written)); - m_err = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count); - if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail()) - m_err.LogThreaded("::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count); - -#if !defined (__i386__) && !defined (__x86_64__) - vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH; - - m_err = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value); - if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail()) - m_err.LogThreaded("::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count); +nub_size_t MachVMMemory::WriteRegion(task_t task, const nub_addr_t address, + const void *data, + const nub_size_t data_count) { + if (data == NULL || data_count == 0) + return 0; + + nub_size_t total_bytes_written = 0; + nub_addr_t curr_addr = address; + const uint8_t *curr_data = (const uint8_t *)data; + while (total_bytes_written < data_count) { + mach_msg_type_number_t curr_data_count = + static_cast<mach_msg_type_number_t>(MaxBytesLeftInPage( + task, curr_addr, data_count - total_bytes_written)); + m_err = + ::mach_vm_write(task, curr_addr, (pointer_t)curr_data, curr_data_count); + if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail()) + m_err.LogThreaded("::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, " + "data = %8.8p, dataCnt = %u )", + task, (uint64_t)curr_addr, curr_data, curr_data_count); + +#if !defined(__i386__) && !defined(__x86_64__) + vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH; + + m_err = ::vm_machine_attribute(task, curr_addr, curr_data_count, + MATTR_CACHE, &mattr_value); + if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail()) + m_err.LogThreaded("::vm_machine_attribute ( task = 0x%4.4x, addr = " + "0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value " + "=> MATTR_VAL_CACHE_FLUSH )", + task, (uint64_t)curr_addr, curr_data_count); #endif - if (m_err.Success()) - { - total_bytes_written += curr_data_count; - curr_addr += curr_data_count; - curr_data += curr_data_count; - } - else - { - break; - } + if (m_err.Success()) { + total_bytes_written += curr_data_count; + curr_addr += curr_data_count; + curr_data += curr_data_count; + } else { + break; } - return total_bytes_written; + } + return total_bytes_written; } diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h index abaa20368a2..c4d3f533137 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h +++ b/lldb/tools/debugserver/source/MacOSX/MachVMMemory.h @@ -18,34 +18,51 @@ #include "DNBError.h" #include <mach/mach.h> -class MachVMMemory -{ +class MachVMMemory { public: - MachVMMemory(); - ~MachVMMemory(); - nub_size_t Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count); - nub_size_t Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count); - nub_size_t PageSize(task_t task); - nub_bool_t GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info); -#if defined (HOST_VM_INFO64_COUNT) - nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics64_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous); + MachVMMemory(); + ~MachVMMemory(); + nub_size_t Read(task_t task, nub_addr_t address, void *data, + nub_size_t data_count); + nub_size_t Write(task_t task, nub_addr_t address, const void *data, + nub_size_t data_count); + nub_size_t PageSize(task_t task); + nub_bool_t GetMemoryRegionInfo(task_t task, nub_addr_t address, + DNBRegionInfo *region_info); +#if defined(HOST_VM_INFO64_COUNT) + nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, + struct task_basic_info ti, cpu_type_t cputype, + nub_process_t pid, vm_statistics64_data_t &vminfo, + uint64_t &physical_memory, mach_vm_size_t &rprvt, + mach_vm_size_t &rsize, mach_vm_size_t &vprvt, + mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, + mach_vm_size_t &purgeable, + mach_vm_size_t &anonymous); #else - nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous); + nub_bool_t GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, + struct task_basic_info ti, cpu_type_t cputype, + nub_process_t pid, vm_statistics_data_t &vminfo, + uint64_t &physical_memory, mach_vm_size_t &rprvt, + mach_vm_size_t &rsize, mach_vm_size_t &vprvt, + mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, + mach_vm_size_t &purgeable, + mach_vm_size_t &anonymous); #endif protected: - nub_size_t MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count); + nub_size_t MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count); - uint64_t GetStolenPages(task_t task); - void GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size); - void GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt); + uint64_t GetStolenPages(task_t task); + void GetRegionSizes(task_t task, mach_vm_size_t &rsize, + mach_vm_size_t &dirty_size); + void GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, + mach_vm_size_t &rprvt, mach_vm_size_t &vprvt); + nub_size_t WriteRegion(task_t task, const nub_addr_t address, + const void *data, const nub_size_t data_count); - nub_size_t WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count); - - vm_size_t m_page_size; - DNBError m_err; + vm_size_t m_page_size; + DNBError m_err; }; - #endif // #ifndef __MachVMMemory_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp index 38757595cfe..c011c133ac3 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp +++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.cpp @@ -12,191 +12,177 @@ //===----------------------------------------------------------------------===// #include "MachVMRegion.h" -#include <mach/mach_vm.h> #include "DNBLog.h" #include <assert.h> +#include <mach/mach_vm.h> -MachVMRegion::MachVMRegion(task_t task) : - m_task(task), - m_addr(INVALID_NUB_ADDRESS), - m_err(), - m_start(INVALID_NUB_ADDRESS), - m_size(0), - m_depth(-1), - m_curr_protection(0), - m_protection_addr(INVALID_NUB_ADDRESS), - m_protection_size(0) -{ - memset(&m_data, 0, sizeof(m_data)); +MachVMRegion::MachVMRegion(task_t task) + : m_task(task), m_addr(INVALID_NUB_ADDRESS), m_err(), + m_start(INVALID_NUB_ADDRESS), m_size(0), m_depth(-1), + m_curr_protection(0), m_protection_addr(INVALID_NUB_ADDRESS), + m_protection_size(0) { + memset(&m_data, 0, sizeof(m_data)); } -MachVMRegion::~MachVMRegion() -{ - // Restore any original protections and clear our vars - Clear(); +MachVMRegion::~MachVMRegion() { + // Restore any original protections and clear our vars + Clear(); } -void -MachVMRegion::Clear() -{ - RestoreProtections(); - m_addr = INVALID_NUB_ADDRESS; - m_err.Clear(); - m_start = INVALID_NUB_ADDRESS; - m_size = 0; - m_depth = -1; - memset(&m_data, 0, sizeof(m_data)); - m_curr_protection = 0; - m_protection_addr = INVALID_NUB_ADDRESS; - m_protection_size = 0; +void MachVMRegion::Clear() { + RestoreProtections(); + m_addr = INVALID_NUB_ADDRESS; + m_err.Clear(); + m_start = INVALID_NUB_ADDRESS; + m_size = 0; + m_depth = -1; + memset(&m_data, 0, sizeof(m_data)); + m_curr_protection = 0; + m_protection_addr = INVALID_NUB_ADDRESS; + m_protection_size = 0; } -bool -MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot) -{ - if (ContainsAddress(addr)) - { - mach_vm_size_t prot_size = size; - mach_vm_address_t end_addr = EndAddress(); - if (prot_size > (end_addr - addr)) - prot_size = end_addr - addr; - - if (prot_size > 0) - { - if (prot == (m_curr_protection & VM_PROT_ALL)) - { - DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, "MachVMRegion::%s: protections (%u) already sufficient for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, prot, m_task, (uint64_t)addr); - // Protections are already set as requested... - return true; - } - else - { - m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot); - if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS)) - m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot); - if (m_err.Fail()) - { - // Try again with the ability to create a copy on write region - m_err = ::mach_vm_protect (m_task, addr, prot_size, 0, prot | VM_PROT_COPY); - if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail()) - m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)addr, (uint64_t)prot_size, 0, prot | VM_PROT_COPY); - } - if (m_err.Success()) - { - m_curr_protection = prot; - m_protection_addr = addr; - m_protection_size = prot_size; - return true; - } - } +bool MachVMRegion::SetProtections(mach_vm_address_t addr, mach_vm_size_t size, + vm_prot_t prot) { + if (ContainsAddress(addr)) { + mach_vm_size_t prot_size = size; + mach_vm_address_t end_addr = EndAddress(); + if (prot_size > (end_addr - addr)) + prot_size = end_addr - addr; + + if (prot_size > 0) { + if (prot == (m_curr_protection & VM_PROT_ALL)) { + DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, + "MachVMRegion::%s: protections (%u) already " + "sufficient for task 0x%4.4x at address 0x%8.8llx) ", + __FUNCTION__, prot, m_task, (uint64_t)addr); + // Protections are already set as requested... + return true; + } else { + m_err = ::mach_vm_protect(m_task, addr, prot_size, 0, prot); + if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS)) + m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = " + "0x%8.8llx, size = %llu, set_max = %i, prot = %u )", + m_task, (uint64_t)addr, (uint64_t)prot_size, 0, + prot); + if (m_err.Fail()) { + // Try again with the ability to create a copy on write region + m_err = ::mach_vm_protect(m_task, addr, prot_size, 0, + prot | VM_PROT_COPY); + if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail()) + m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = " + "0x%8.8llx, size = %llu, set_max = %i, prot = %u " + ")", + m_task, (uint64_t)addr, (uint64_t)prot_size, 0, + prot | VM_PROT_COPY); } - else - { - DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, "%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", __FUNCTION__, m_task, (uint64_t)addr); + if (m_err.Success()) { + m_curr_protection = prot; + m_protection_addr = addr; + m_protection_size = prot_size; + return true; } + } + } else { + DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS | LOG_VERBOSE, + "%s: Zero size for task 0x%4.4x at address 0x%8.8llx) ", + __FUNCTION__, m_task, (uint64_t)addr); } - return false; + } + return false; } -bool -MachVMRegion::RestoreProtections() -{ - if (m_curr_protection != m_data.protection && m_protection_size > 0) - { - m_err = ::mach_vm_protect (m_task, m_protection_addr, m_protection_size, 0, m_data.protection); - if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail()) - m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, set_max = %i, prot = %u )", m_task, (uint64_t)m_protection_addr, (uint64_t)m_protection_size, 0, m_data.protection); - if (m_err.Success()) - { - m_protection_size = 0; - m_protection_addr = INVALID_NUB_ADDRESS; - m_curr_protection = m_data.protection; - return true; - } - } - else - { - m_err.Clear(); - return true; +bool MachVMRegion::RestoreProtections() { + if (m_curr_protection != m_data.protection && m_protection_size > 0) { + m_err = ::mach_vm_protect(m_task, m_protection_addr, m_protection_size, 0, + m_data.protection); + if (DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS) || m_err.Fail()) + m_err.LogThreaded("::mach_vm_protect ( task = 0x%4.4x, addr = 0x%8.8llx, " + "size = %llu, set_max = %i, prot = %u )", + m_task, (uint64_t)m_protection_addr, + (uint64_t)m_protection_size, 0, m_data.protection); + if (m_err.Success()) { + m_protection_size = 0; + m_protection_addr = INVALID_NUB_ADDRESS; + m_curr_protection = m_data.protection; + return true; } + } else { + m_err.Clear(); + return true; + } - return false; + return false; } -bool -MachVMRegion::GetRegionForAddress(nub_addr_t addr) -{ - // Restore any original protections and clear our vars - Clear(); - m_err.Clear(); - m_addr = addr; - m_start = addr; - m_depth = 1024; - mach_msg_type_number_t info_size = kRegionInfoSize; - assert(sizeof(info_size) == 4); - m_err = ::mach_vm_region_recurse (m_task, &m_start, &m_size, &m_depth, (vm_region_recurse_info_t)&m_data, &info_size); - - const bool failed = m_err.Fail(); - const bool log_protections = DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS); - - if (log_protections || failed) - m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => 0x%8.8llx, size => %llu, nesting_depth => %d, info => %p, infoCnt => %d) addr = 0x%8.8llx ", m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, &m_data, info_size, (uint64_t)addr); - - if (failed) - return false; - if (log_protections) - { - DNBLogThreaded("info = { prot = %u, " - "max_prot = %u, " - "inheritance = 0x%8.8x, " - "offset = 0x%8.8llx, " - "user_tag = 0x%8.8x, " - "ref_count = %u, " - "shadow_depth = %u, " - "ext_pager = %u, " - "share_mode = %u, " - "is_submap = %d, " - "behavior = %d, " - "object_id = 0x%8.8x, " - "user_wired_count = 0x%4.4x }", - m_data.protection, - m_data.max_protection, - m_data.inheritance, - (uint64_t)m_data.offset, - m_data.user_tag, - m_data.ref_count, - m_data.shadow_depth, - m_data.external_pager, - m_data.share_mode, - m_data.is_submap, - m_data.behavior, - m_data.object_id, - m_data.user_wired_count); - } - m_curr_protection = m_data.protection; - - // We make a request for an address and got no error back, but this - // doesn't mean that "addr" is in the range. The data in this object will - // be valid though, so you could see where the next region begins. So we - // return false, yet leave "m_err" with a successfull return code. - if ((addr < m_start) || (addr >= (m_start + m_size))) - return false; +bool MachVMRegion::GetRegionForAddress(nub_addr_t addr) { + // Restore any original protections and clear our vars + Clear(); + m_err.Clear(); + m_addr = addr; + m_start = addr; + m_depth = 1024; + mach_msg_type_number_t info_size = kRegionInfoSize; + assert(sizeof(info_size) == 4); + m_err = + ::mach_vm_region_recurse(m_task, &m_start, &m_size, &m_depth, + (vm_region_recurse_info_t)&m_data, &info_size); - return true; + const bool failed = m_err.Fail(); + const bool log_protections = DNBLogCheckLogBit(LOG_MEMORY_PROTECTIONS); + + if (log_protections || failed) + m_err.LogThreaded("::mach_vm_region_recurse ( task = 0x%4.4x, address => " + "0x%8.8llx, size => %llu, nesting_depth => %d, info => " + "%p, infoCnt => %d) addr = 0x%8.8llx ", + m_task, (uint64_t)m_start, (uint64_t)m_size, m_depth, + &m_data, info_size, (uint64_t)addr); + + if (failed) + return false; + if (log_protections) { + DNBLogThreaded("info = { prot = %u, " + "max_prot = %u, " + "inheritance = 0x%8.8x, " + "offset = 0x%8.8llx, " + "user_tag = 0x%8.8x, " + "ref_count = %u, " + "shadow_depth = %u, " + "ext_pager = %u, " + "share_mode = %u, " + "is_submap = %d, " + "behavior = %d, " + "object_id = 0x%8.8x, " + "user_wired_count = 0x%4.4x }", + m_data.protection, m_data.max_protection, m_data.inheritance, + (uint64_t)m_data.offset, m_data.user_tag, m_data.ref_count, + m_data.shadow_depth, m_data.external_pager, + m_data.share_mode, m_data.is_submap, m_data.behavior, + m_data.object_id, m_data.user_wired_count); + } + m_curr_protection = m_data.protection; + + // We make a request for an address and got no error back, but this + // doesn't mean that "addr" is in the range. The data in this object will + // be valid though, so you could see where the next region begins. So we + // return false, yet leave "m_err" with a successfull return code. + if ((addr < m_start) || (addr >= (m_start + m_size))) + return false; + + return true; } -uint32_t -MachVMRegion::GetDNBPermissions () const -{ - if (m_addr == INVALID_NUB_ADDRESS || m_start == INVALID_NUB_ADDRESS || m_size == 0) - return 0; - uint32_t dnb_permissions = 0; - - if ((m_data.protection & VM_PROT_READ) == VM_PROT_READ) - dnb_permissions |= eMemoryPermissionsReadable; - if ((m_data.protection & VM_PROT_WRITE) == VM_PROT_WRITE) - dnb_permissions |= eMemoryPermissionsWritable; - if ((m_data.protection & VM_PROT_EXECUTE) == VM_PROT_EXECUTE) - dnb_permissions |= eMemoryPermissionsExecutable; - return dnb_permissions; +uint32_t MachVMRegion::GetDNBPermissions() const { + if (m_addr == INVALID_NUB_ADDRESS || m_start == INVALID_NUB_ADDRESS || + m_size == 0) + return 0; + uint32_t dnb_permissions = 0; + + if ((m_data.protection & VM_PROT_READ) == VM_PROT_READ) + dnb_permissions |= eMemoryPermissionsReadable; + if ((m_data.protection & VM_PROT_WRITE) == VM_PROT_WRITE) + dnb_permissions |= eMemoryPermissionsWritable; + if ((m_data.protection & VM_PROT_EXECUTE) == VM_PROT_EXECUTE) + dnb_permissions |= eMemoryPermissionsExecutable; + return dnb_permissions; } diff --git a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h index bcac60b8318..758112d236d 100644 --- a/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h +++ b/lldb/tools/debugserver/source/MacOSX/MachVMRegion.h @@ -18,60 +18,56 @@ #include "DNBError.h" #include <mach/mach.h> -class MachVMRegion -{ +class MachVMRegion { public: - MachVMRegion(task_t task); - ~MachVMRegion(); + MachVMRegion(task_t task); + ~MachVMRegion(); - void Clear(); - mach_vm_address_t StartAddress() const { return m_start; } - mach_vm_address_t EndAddress() const { return m_start + m_size; } - mach_vm_size_t GetByteSize () const { return m_size; } - mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const - { - if (ContainsAddress(addr)) - return m_size - (addr - m_start); - else - return 0; - } - bool ContainsAddress(mach_vm_address_t addr) const - { - return addr >= StartAddress() && addr < EndAddress(); - } + void Clear(); + mach_vm_address_t StartAddress() const { return m_start; } + mach_vm_address_t EndAddress() const { return m_start + m_size; } + mach_vm_size_t GetByteSize() const { return m_size; } + mach_vm_address_t BytesRemaining(mach_vm_address_t addr) const { + if (ContainsAddress(addr)) + return m_size - (addr - m_start); + else + return 0; + } + bool ContainsAddress(mach_vm_address_t addr) const { + return addr >= StartAddress() && addr < EndAddress(); + } - bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, vm_prot_t prot); - bool RestoreProtections(); - bool GetRegionForAddress(nub_addr_t addr); + bool SetProtections(mach_vm_address_t addr, mach_vm_size_t size, + vm_prot_t prot); + bool RestoreProtections(); + bool GetRegionForAddress(nub_addr_t addr); - uint32_t - GetDNBPermissions () const; + uint32_t GetDNBPermissions() const; + + const DNBError &GetError() { return m_err; } - const DNBError & - GetError () - { - return m_err; - } protected: -#if defined (VM_REGION_SUBMAP_SHORT_INFO_COUNT_64) - typedef vm_region_submap_short_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; +#if defined(VM_REGION_SUBMAP_SHORT_INFO_COUNT_64) + typedef vm_region_submap_short_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 }; #else - typedef vm_region_submap_info_data_64_t RegionInfo; - enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 }; + typedef vm_region_submap_info_data_64_t RegionInfo; + enum { kRegionInfoSize = VM_REGION_SUBMAP_INFO_COUNT_64 }; #endif - task_t m_task; - mach_vm_address_t m_addr; - DNBError m_err; - mach_vm_address_t m_start; - mach_vm_size_t m_size; - natural_t m_depth; - RegionInfo m_data; - vm_prot_t m_curr_protection; // The current, possibly modified protections. Original value is saved in m_data.protections. - mach_vm_address_t m_protection_addr; // The start address at which protections were changed - mach_vm_size_t m_protection_size; // The size of memory that had its protections changed - + task_t m_task; + mach_vm_address_t m_addr; + DNBError m_err; + mach_vm_address_t m_start; + mach_vm_size_t m_size; + natural_t m_depth; + RegionInfo m_data; + vm_prot_t m_curr_protection; // The current, possibly modified protections. + // Original value is saved in m_data.protections. + mach_vm_address_t + m_protection_addr; // The start address at which protections were changed + mach_vm_size_t + m_protection_size; // The size of memory that had its protections changed }; -#endif // #ifndef __MachVMRegion_h__ +#endif // #ifndef __MachVMRegion_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/OsLogger.cpp b/lldb/tools/debugserver/source/MacOSX/OsLogger.cpp index 1f424e7da17..efecea30212 100644 --- a/lldb/tools/debugserver/source/MacOSX/OsLogger.cpp +++ b/lldb/tools/debugserver/source/MacOSX/OsLogger.cpp @@ -18,54 +18,49 @@ #define LLDB_OS_LOG_MAX_BUFFER_LENGTH 256 -namespace -{ - //---------------------------------------------------------------------- - // Darwin os_log logging callback that can be registered with - // DNBLogSetLogCallback - //---------------------------------------------------------------------- - void - DarwinLogCallback(void *baton, uint32_t flags, const char *format, - va_list args) - { - if (format == nullptr) - return; +namespace { +//---------------------------------------------------------------------- +// Darwin os_log logging callback that can be registered with +// DNBLogSetLogCallback +//---------------------------------------------------------------------- +void DarwinLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { + if (format == nullptr) + return; - static os_log_t g_logger; - if (!g_logger) - { - g_logger = os_log_create("com.apple.dt.lldb", "debugserver"); - if (!g_logger) - return; - } + static os_log_t g_logger; + if (!g_logger) { + g_logger = os_log_create("com.apple.dt.lldb", "debugserver"); + if (!g_logger) + return; + } - os_log_type_t log_type; - if (flags & DNBLOG_FLAG_FATAL) log_type = OS_LOG_TYPE_FAULT; - else if (flags & DNBLOG_FLAG_ERROR) log_type = OS_LOG_TYPE_ERROR; - else if (flags & DNBLOG_FLAG_WARNING) log_type = OS_LOG_TYPE_DEFAULT; - else if (flags & DNBLOG_FLAG_VERBOSE) log_type = OS_LOG_TYPE_DEBUG; - else log_type = OS_LOG_TYPE_DEFAULT; + os_log_type_t log_type; + if (flags & DNBLOG_FLAG_FATAL) + log_type = OS_LOG_TYPE_FAULT; + else if (flags & DNBLOG_FLAG_ERROR) + log_type = OS_LOG_TYPE_ERROR; + else if (flags & DNBLOG_FLAG_WARNING) + log_type = OS_LOG_TYPE_DEFAULT; + else if (flags & DNBLOG_FLAG_VERBOSE) + log_type = OS_LOG_TYPE_DEBUG; + else + log_type = OS_LOG_TYPE_DEFAULT; - // This code is unfortunate. os_log* only takes static strings, but - // our current log API isn't set up to make use of that style. - char buffer[LLDB_OS_LOG_MAX_BUFFER_LENGTH]; - vsnprintf(buffer, sizeof(buffer), format, args); - os_log_with_type(g_logger, log_type, "%{public}s", buffer); - } + // This code is unfortunate. os_log* only takes static strings, but + // our current log API isn't set up to make use of that style. + char buffer[LLDB_OS_LOG_MAX_BUFFER_LENGTH]; + vsnprintf(buffer, sizeof(buffer), format, args); + os_log_with_type(g_logger, log_type, "%{public}s", buffer); +} } -DNBCallbackLog -OsLogger::GetLogFunction() -{ - return _os_log_impl ? DarwinLogCallback : nullptr; +DNBCallbackLog OsLogger::GetLogFunction() { + return _os_log_impl ? DarwinLogCallback : nullptr; } #else -DNBCallbackLog -OsLogger::GetLogFunction() -{ - return nullptr; -} +DNBCallbackLog OsLogger::GetLogFunction() { return nullptr; } #endif diff --git a/lldb/tools/debugserver/source/MacOSX/OsLogger.h b/lldb/tools/debugserver/source/MacOSX/OsLogger.h index 6733b925335..9afdcb974d9 100644 --- a/lldb/tools/debugserver/source/MacOSX/OsLogger.h +++ b/lldb/tools/debugserver/source/MacOSX/OsLogger.h @@ -12,13 +12,9 @@ #include "DNBDefs.h" -class OsLogger -{ +class OsLogger { public: - - static DNBCallbackLog - GetLogFunction(); - + static DNBCallbackLog GetLogFunction(); }; #endif /* OsLogger_h */ diff --git a/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h b/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h index 1fd9d5790cf..e9773caf9ea 100644 --- a/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h +++ b/lldb/tools/debugserver/source/MacOSX/ThreadInfo.h @@ -1,4 +1,5 @@ -//===-- ThreadInfo.h -----------------------------------------------*- C++ -*-===// +//===-- ThreadInfo.h -----------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -14,13 +15,12 @@ namespace ThreadInfo { class QoS { public: - QoS () : constant_name(), printable_name(), enum_value(UINT32_MAX) { } - bool IsValid () { return enum_value != UINT32_MAX; } - std::string constant_name; - std::string printable_name; - uint32_t enum_value; + QoS() : constant_name(), printable_name(), enum_value(UINT32_MAX) {} + bool IsValid() { return enum_value != UINT32_MAX; } + std::string constant_name; + std::string printable_name; + uint32_t enum_value; }; - }; #endif // __ThreadInfo_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp index 2eac47b045c..175aab1ae3f 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp @@ -11,93 +11,93 @@ // //===----------------------------------------------------------------------===// -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #include "MacOSX/arm/DNBArchImpl.h" -#include "MacOSX/MachProcess.h" -#include "MacOSX/MachThread.h" +#include "ARM_DWARF_Registers.h" +#include "ARM_ehframe_Registers.h" +#include "DNB.h" #include "DNBBreakpoint.h" #include "DNBLog.h" #include "DNBRegisterInfo.h" -#include "DNB.h" -#include "ARM_ehframe_Registers.h" -#include "ARM_DWARF_Registers.h" +#include "MacOSX/MachProcess.h" +#include "MacOSX/MachThread.h" #include <inttypes.h> #include <sys/sysctl.h> // BCR address match type -#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21)) -#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21)) -#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21)) -#define BCR_M_RESERVED ((uint32_t)(3u << 21)) +#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21)) +#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21)) +#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21)) +#define BCR_M_RESERVED ((uint32_t)(3u << 21)) // Link a BVR/BCR or WVR/WCR pair to another -#define E_ENABLE_LINKING ((uint32_t)(1u << 20)) +#define E_ENABLE_LINKING ((uint32_t)(1u << 20)) // Byte Address Select -#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5)) -#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6)) -#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7)) -#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8)) -#define BAS_IMVA_0_1 ((uint32_t)(3u << 5)) -#define BAS_IMVA_2_3 ((uint32_t)(3u << 7)) -#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5)) +#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5)) +#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6)) +#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7)) +#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8)) +#define BAS_IMVA_0_1 ((uint32_t)(3u << 5)) +#define BAS_IMVA_2_3 ((uint32_t)(3u << 7)) +#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5)) // Break only in privileged or user mode -#define S_RSVD ((uint32_t)(0u << 1)) -#define S_PRIV ((uint32_t)(1u << 1)) -#define S_USER ((uint32_t)(2u << 1)) -#define S_PRIV_USER ((S_PRIV) | (S_USER)) +#define S_RSVD ((uint32_t)(0u << 1)) +#define S_PRIV ((uint32_t)(1u << 1)) +#define S_USER ((uint32_t)(2u << 1)) +#define S_PRIV_USER ((S_PRIV) | (S_USER)) -#define BCR_ENABLE ((uint32_t)(1u)) -#define WCR_ENABLE ((uint32_t)(1u)) +#define BCR_ENABLE ((uint32_t)(1u)) +#define WCR_ENABLE ((uint32_t)(1u)) // Watchpoint load/store -#define WCR_LOAD ((uint32_t)(1u << 3)) -#define WCR_STORE ((uint32_t)(1u << 4)) +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) // Definitions for the Debug Status and Control Register fields: // [5:2] => Method of debug entry //#define WATCHPOINT_OCCURRED ((uint32_t)(2u)) // I'm seeing this, instead. -#define WATCHPOINT_OCCURRED ((uint32_t)(10u)) +#define WATCHPOINT_OCCURRED ((uint32_t)(10u)) // 0xE120BE70 -static const uint8_t g_arm_breakpoint_opcode[] = { 0x70, 0xBE, 0x20, 0xE1 }; -static const uint8_t g_thumb_breakpoint_opcode[] = { 0x70, 0xBE }; +static const uint8_t g_arm_breakpoint_opcode[] = {0x70, 0xBE, 0x20, 0xE1}; +static const uint8_t g_thumb_breakpoint_opcode[] = {0x70, 0xBE}; // A watchpoint may need to be implemented using two watchpoint registers. // e.g. watching an 8-byte region when the device can only watch 4-bytes. // // This stores the lo->hi mappings. It's safe to initialize to all 0's // since hi > lo and therefore LoHi[i] cannot be 0. -static uint32_t LoHi[16] = { 0 }; +static uint32_t LoHi[16] = {0}; // ARM constants used during decoding -#define REG_RD 0 -#define LDM_REGLIST 1 -#define PC_REG 15 -#define PC_REGLIST_BIT 0x8000 +#define REG_RD 0 +#define LDM_REGLIST 1 +#define PC_REG 15 +#define PC_REGLIST_BIT 0x8000 // ARM conditions -#define COND_EQ 0x0 -#define COND_NE 0x1 -#define COND_CS 0x2 -#define COND_HS 0x2 -#define COND_CC 0x3 -#define COND_LO 0x3 -#define COND_MI 0x4 -#define COND_PL 0x5 -#define COND_VS 0x6 -#define COND_VC 0x7 -#define COND_HI 0x8 -#define COND_LS 0x9 -#define COND_GE 0xA -#define COND_LT 0xB -#define COND_GT 0xC -#define COND_LE 0xD -#define COND_AL 0xE +#define COND_EQ 0x0 +#define COND_NE 0x1 +#define COND_CS 0x2 +#define COND_HS 0x2 +#define COND_CC 0x3 +#define COND_LO 0x3 +#define COND_MI 0x4 +#define COND_PL 0x5 +#define COND_VS 0x6 +#define COND_VC 0x7 +#define COND_HI 0x8 +#define COND_LS 0x9 +#define COND_GE 0xA +#define COND_LT 0xB +#define COND_GT 0xC +#define COND_LE 0xD +#define COND_AL 0xE #define COND_UNCOND 0xF #define MASK_CPSR_T (1u << 5) @@ -108,962 +108,971 @@ static uint32_t LoHi[16] = { 0 }; // Returns true if the first 16 bit opcode of a thumb instruction indicates // the instruction will be a 32 bit thumb opcode -static bool -IsThumb32Opcode (uint16_t opcode) -{ - if (((opcode & 0xE000) == 0xE000) && (opcode & 0x1800)) - return true; - return false; +static bool IsThumb32Opcode(uint16_t opcode) { + if (((opcode & 0xE000) == 0xE000) && (opcode & 0x1800)) + return true; + return false; } -void -DNBArchMachARM::Initialize() -{ - DNBArchPluginInfo arch_plugin_info = - { - CPU_TYPE_ARM, - DNBArchMachARM::Create, - DNBArchMachARM::GetRegisterSetInfo, - DNBArchMachARM::SoftwareBreakpointOpcode - }; - - // Register this arch plug-in with the main protocol class - DNBArchProtocol::RegisterArchPlugin (arch_plugin_info); -} +void DNBArchMachARM::Initialize() { + DNBArchPluginInfo arch_plugin_info = { + CPU_TYPE_ARM, DNBArchMachARM::Create, DNBArchMachARM::GetRegisterSetInfo, + DNBArchMachARM::SoftwareBreakpointOpcode}; - -DNBArchProtocol * -DNBArchMachARM::Create (MachThread *thread) -{ - DNBArchMachARM *obj = new DNBArchMachARM (thread); - return obj; + // Register this arch plug-in with the main protocol class + DNBArchProtocol::RegisterArchPlugin(arch_plugin_info); } -const uint8_t * -DNBArchMachARM::SoftwareBreakpointOpcode (nub_size_t byte_size) -{ - switch (byte_size) - { - case 2: return g_thumb_breakpoint_opcode; - case 4: return g_arm_breakpoint_opcode; - } - return NULL; +DNBArchProtocol *DNBArchMachARM::Create(MachThread *thread) { + DNBArchMachARM *obj = new DNBArchMachARM(thread); + return obj; } -uint32_t -DNBArchMachARM::GetCPUType() -{ - return CPU_TYPE_ARM; +const uint8_t *DNBArchMachARM::SoftwareBreakpointOpcode(nub_size_t byte_size) { + switch (byte_size) { + case 2: + return g_thumb_breakpoint_opcode; + case 4: + return g_arm_breakpoint_opcode; + } + return NULL; } -uint64_t -DNBArchMachARM::GetPC(uint64_t failValue) -{ - // Get program counter - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__pc; - return failValue; -} +uint32_t DNBArchMachARM::GetCPUType() { return CPU_TYPE_ARM; } -kern_return_t -DNBArchMachARM::SetPC(uint64_t value) -{ - // Get program counter - kern_return_t err = GetGPRState(false); - if (err == KERN_SUCCESS) - { - m_state.context.gpr.__pc = (uint32_t) value; - err = SetGPRState(); - } - return err == KERN_SUCCESS; +uint64_t DNBArchMachARM::GetPC(uint64_t failValue) { + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__pc; + return failValue; } -uint64_t -DNBArchMachARM::GetSP(uint64_t failValue) -{ - // Get stack pointer - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__sp; - return failValue; +kern_return_t DNBArchMachARM::SetPC(uint64_t value) { + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) { + m_state.context.gpr.__pc = (uint32_t)value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; } -kern_return_t -DNBArchMachARM::GetGPRState(bool force) -{ - int set = e_regSetGPR; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - // Read the registers from our thread - mach_msg_type_number_t count = ARM_THREAD_STATE_COUNT; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE, (thread_state_t)&m_state.context.gpr, &count); - uint32_t *r = &m_state.context.gpr.__r[0]; - DNBLogThreadedIf(LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs r0=%8.8x r1=%8.8x r2=%8.8x r3=%8.8x r4=%8.8x r5=%8.8x r6=%8.8x r7=%8.8x r8=%8.8x r9=%8.8x r10=%8.8x r11=%8.8x s12=%8.8x sp=%8.8x lr=%8.8x pc=%8.8x cpsr=%8.8x", - m_thread->MachPortNumber(), - ARM_THREAD_STATE, - ARM_THREAD_STATE_COUNT, - kret, - count, - r[0], - r[1], - r[2], - r[3], - r[4], - r[5], - r[6], - r[7], - r[8], - r[9], - r[10], - r[11], - r[12], - r[13], - r[14], - r[15], - r[16]); - m_state.SetError(set, Read, kret); - return kret; +uint64_t DNBArchMachARM::GetSP(uint64_t failValue) { + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__sp; + return failValue; } -kern_return_t -DNBArchMachARM::GetVFPState(bool force) -{ - int set = e_regSetVFP; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - kern_return_t kret; - -#if defined (__arm64__) || defined (__aarch64__) - // Read the registers from our thread - mach_msg_type_number_t count = ARM_NEON_STATE_COUNT; - kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE, (thread_state_t)&m_state.context.vfp, &count); - if (DNBLogEnabledForAny (LOG_THREAD)) - { - DNBLogThreaded("thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" - "\n q0 = 0x%16.16llx%16.16llx" - "\n q1 = 0x%16.16llx%16.16llx" - "\n q2 = 0x%16.16llx%16.16llx" - "\n q3 = 0x%16.16llx%16.16llx" - "\n q4 = 0x%16.16llx%16.16llx" - "\n q5 = 0x%16.16llx%16.16llx" - "\n q6 = 0x%16.16llx%16.16llx" - "\n q7 = 0x%16.16llx%16.16llx" - "\n q8 = 0x%16.16llx%16.16llx" - "\n q9 = 0x%16.16llx%16.16llx" - "\n q10 = 0x%16.16llx%16.16llx" - "\n q11 = 0x%16.16llx%16.16llx" - "\n q12 = 0x%16.16llx%16.16llx" - "\n q13 = 0x%16.16llx%16.16llx" - "\n q14 = 0x%16.16llx%16.16llx" - "\n q15 = 0x%16.16llx%16.16llx" - "\n fpsr = 0x%8.8x" - "\n fpcr = 0x%8.8x\n\n", - m_thread->MachPortNumber(), - ARM_NEON_STATE, - ARM_NEON_STATE_COUNT, - kret, - count, - ((uint64_t *)&m_state.context.vfp.__v[0])[0] , ((uint64_t *)&m_state.context.vfp.__v[0])[1], - ((uint64_t *)&m_state.context.vfp.__v[1])[0] , ((uint64_t *)&m_state.context.vfp.__v[1])[1], - ((uint64_t *)&m_state.context.vfp.__v[2])[0] , ((uint64_t *)&m_state.context.vfp.__v[2])[1], - ((uint64_t *)&m_state.context.vfp.__v[3])[0] , ((uint64_t *)&m_state.context.vfp.__v[3])[1], - ((uint64_t *)&m_state.context.vfp.__v[4])[0] , ((uint64_t *)&m_state.context.vfp.__v[4])[1], - ((uint64_t *)&m_state.context.vfp.__v[5])[0] , ((uint64_t *)&m_state.context.vfp.__v[5])[1], - ((uint64_t *)&m_state.context.vfp.__v[6])[0] , ((uint64_t *)&m_state.context.vfp.__v[6])[1], - ((uint64_t *)&m_state.context.vfp.__v[7])[0] , ((uint64_t *)&m_state.context.vfp.__v[7])[1], - ((uint64_t *)&m_state.context.vfp.__v[8])[0] , ((uint64_t *)&m_state.context.vfp.__v[8])[1], - ((uint64_t *)&m_state.context.vfp.__v[9])[0] , ((uint64_t *)&m_state.context.vfp.__v[9])[1], - ((uint64_t *)&m_state.context.vfp.__v[10])[0], ((uint64_t *)&m_state.context.vfp.__v[10])[1], - ((uint64_t *)&m_state.context.vfp.__v[11])[0], ((uint64_t *)&m_state.context.vfp.__v[11])[1], - ((uint64_t *)&m_state.context.vfp.__v[12])[0], ((uint64_t *)&m_state.context.vfp.__v[12])[1], - ((uint64_t *)&m_state.context.vfp.__v[13])[0], ((uint64_t *)&m_state.context.vfp.__v[13])[1], - ((uint64_t *)&m_state.context.vfp.__v[14])[0], ((uint64_t *)&m_state.context.vfp.__v[14])[1], - ((uint64_t *)&m_state.context.vfp.__v[15])[0], ((uint64_t *)&m_state.context.vfp.__v[15])[1], - m_state.context.vfp.__fpsr, - m_state.context.vfp.__fpcr); +kern_return_t DNBArchMachARM::GetGPRState(bool force) { + int set = e_regSetGPR; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = ARM_THREAD_STATE_COUNT; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, &count); + uint32_t *r = &m_state.context.gpr.__r[0]; + DNBLogThreadedIf( + LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = " + "%u) regs r0=%8.8x r1=%8.8x r2=%8.8x r3=%8.8x r4=%8.8x " + "r5=%8.8x r6=%8.8x r7=%8.8x r8=%8.8x r9=%8.8x r10=%8.8x " + "r11=%8.8x s12=%8.8x sp=%8.8x lr=%8.8x pc=%8.8x cpsr=%8.8x", + m_thread->MachPortNumber(), ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT, + kret, count, r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7], r[8], r[9], + r[10], r[11], r[12], r[13], r[14], r[15], r[16]); + m_state.SetError(set, Read, kret); + return kret; +} - } +kern_return_t DNBArchMachARM::GetVFPState(bool force) { + int set = e_regSetVFP; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + kern_return_t kret; + +#if defined(__arm64__) || defined(__aarch64__) + // Read the registers from our thread + mach_msg_type_number_t count = ARM_NEON_STATE_COUNT; + kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE, + (thread_state_t)&m_state.context.vfp, &count); + if (DNBLogEnabledForAny(LOG_THREAD)) { + DNBLogThreaded( + "thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" + "\n q0 = 0x%16.16llx%16.16llx" + "\n q1 = 0x%16.16llx%16.16llx" + "\n q2 = 0x%16.16llx%16.16llx" + "\n q3 = 0x%16.16llx%16.16llx" + "\n q4 = 0x%16.16llx%16.16llx" + "\n q5 = 0x%16.16llx%16.16llx" + "\n q6 = 0x%16.16llx%16.16llx" + "\n q7 = 0x%16.16llx%16.16llx" + "\n q8 = 0x%16.16llx%16.16llx" + "\n q9 = 0x%16.16llx%16.16llx" + "\n q10 = 0x%16.16llx%16.16llx" + "\n q11 = 0x%16.16llx%16.16llx" + "\n q12 = 0x%16.16llx%16.16llx" + "\n q13 = 0x%16.16llx%16.16llx" + "\n q14 = 0x%16.16llx%16.16llx" + "\n q15 = 0x%16.16llx%16.16llx" + "\n fpsr = 0x%8.8x" + "\n fpcr = 0x%8.8x\n\n", + m_thread->MachPortNumber(), ARM_NEON_STATE, ARM_NEON_STATE_COUNT, kret, + count, ((uint64_t *)&m_state.context.vfp.__v[0])[0], + ((uint64_t *)&m_state.context.vfp.__v[0])[1], + ((uint64_t *)&m_state.context.vfp.__v[1])[0], + ((uint64_t *)&m_state.context.vfp.__v[1])[1], + ((uint64_t *)&m_state.context.vfp.__v[2])[0], + ((uint64_t *)&m_state.context.vfp.__v[2])[1], + ((uint64_t *)&m_state.context.vfp.__v[3])[0], + ((uint64_t *)&m_state.context.vfp.__v[3])[1], + ((uint64_t *)&m_state.context.vfp.__v[4])[0], + ((uint64_t *)&m_state.context.vfp.__v[4])[1], + ((uint64_t *)&m_state.context.vfp.__v[5])[0], + ((uint64_t *)&m_state.context.vfp.__v[5])[1], + ((uint64_t *)&m_state.context.vfp.__v[6])[0], + ((uint64_t *)&m_state.context.vfp.__v[6])[1], + ((uint64_t *)&m_state.context.vfp.__v[7])[0], + ((uint64_t *)&m_state.context.vfp.__v[7])[1], + ((uint64_t *)&m_state.context.vfp.__v[8])[0], + ((uint64_t *)&m_state.context.vfp.__v[8])[1], + ((uint64_t *)&m_state.context.vfp.__v[9])[0], + ((uint64_t *)&m_state.context.vfp.__v[9])[1], + ((uint64_t *)&m_state.context.vfp.__v[10])[0], + ((uint64_t *)&m_state.context.vfp.__v[10])[1], + ((uint64_t *)&m_state.context.vfp.__v[11])[0], + ((uint64_t *)&m_state.context.vfp.__v[11])[1], + ((uint64_t *)&m_state.context.vfp.__v[12])[0], + ((uint64_t *)&m_state.context.vfp.__v[12])[1], + ((uint64_t *)&m_state.context.vfp.__v[13])[0], + ((uint64_t *)&m_state.context.vfp.__v[13])[1], + ((uint64_t *)&m_state.context.vfp.__v[14])[0], + ((uint64_t *)&m_state.context.vfp.__v[14])[1], + ((uint64_t *)&m_state.context.vfp.__v[15])[0], + ((uint64_t *)&m_state.context.vfp.__v[15])[1], + m_state.context.vfp.__fpsr, m_state.context.vfp.__fpcr); + } #else - // Read the registers from our thread - mach_msg_type_number_t count = ARM_VFP_STATE_COUNT; - kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_VFP_STATE, (thread_state_t)&m_state.context.vfp, &count); - - if (DNBLogEnabledForAny (LOG_THREAD)) - { - uint32_t *r = &m_state.context.vfp.__r[0]; - DNBLogThreaded ("thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count => %u)", - m_thread->MachPortNumber(), - ARM_THREAD_STATE, - ARM_THREAD_STATE_COUNT, - kret, - count); - DNBLogThreaded(" s0=%8.8x s1=%8.8x s2=%8.8x s3=%8.8x s4=%8.8x s5=%8.8x s6=%8.8x s7=%8.8x",r[ 0],r[ 1],r[ 2],r[ 3],r[ 4],r[ 5],r[ 6],r[ 7]); - DNBLogThreaded(" s8=%8.8x s9=%8.8x s10=%8.8x s11=%8.8x s12=%8.8x s13=%8.8x s14=%8.8x s15=%8.8x",r[ 8],r[ 9],r[10],r[11],r[12],r[13],r[14],r[15]); - DNBLogThreaded(" s16=%8.8x s17=%8.8x s18=%8.8x s19=%8.8x s20=%8.8x s21=%8.8x s22=%8.8x s23=%8.8x",r[16],r[17],r[18],r[19],r[20],r[21],r[22],r[23]); - DNBLogThreaded(" s24=%8.8x s25=%8.8x s26=%8.8x s27=%8.8x s28=%8.8x s29=%8.8x s30=%8.8x s31=%8.8x",r[24],r[25],r[26],r[27],r[28],r[29],r[30],r[31]); - DNBLogThreaded(" s32=%8.8x s33=%8.8x s34=%8.8x s35=%8.8x s36=%8.8x s37=%8.8x s38=%8.8x s39=%8.8x",r[32],r[33],r[34],r[35],r[36],r[37],r[38],r[39]); - DNBLogThreaded(" s40=%8.8x s41=%8.8x s42=%8.8x s43=%8.8x s44=%8.8x s45=%8.8x s46=%8.8x s47=%8.8x",r[40],r[41],r[42],r[43],r[44],r[45],r[46],r[47]); - DNBLogThreaded(" s48=%8.8x s49=%8.8x s50=%8.8x s51=%8.8x s52=%8.8x s53=%8.8x s54=%8.8x s55=%8.8x",r[48],r[49],r[50],r[51],r[52],r[53],r[54],r[55]); - DNBLogThreaded(" s56=%8.8x s57=%8.8x s58=%8.8x s59=%8.8x s60=%8.8x s61=%8.8x s62=%8.8x s63=%8.8x fpscr=%8.8x",r[56],r[57],r[58],r[59],r[60],r[61],r[62],r[63],r[64]); - } + // Read the registers from our thread + mach_msg_type_number_t count = ARM_VFP_STATE_COUNT; + kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_VFP_STATE, + (thread_state_t)&m_state.context.vfp, &count); + + if (DNBLogEnabledForAny(LOG_THREAD)) { + uint32_t *r = &m_state.context.vfp.__r[0]; + DNBLogThreaded( + "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count => %u)", + m_thread->MachPortNumber(), ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT, + kret, count); + DNBLogThreaded(" s0=%8.8x s1=%8.8x s2=%8.8x s3=%8.8x s4=%8.8x " + "s5=%8.8x s6=%8.8x s7=%8.8x", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + DNBLogThreaded(" s8=%8.8x s9=%8.8x s10=%8.8x s11=%8.8x s12=%8.8x " + "s13=%8.8x s14=%8.8x s15=%8.8x", + r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); + DNBLogThreaded(" s16=%8.8x s17=%8.8x s18=%8.8x s19=%8.8x s20=%8.8x " + "s21=%8.8x s22=%8.8x s23=%8.8x", + r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); + DNBLogThreaded(" s24=%8.8x s25=%8.8x s26=%8.8x s27=%8.8x s28=%8.8x " + "s29=%8.8x s30=%8.8x s31=%8.8x", + r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31]); + DNBLogThreaded(" s32=%8.8x s33=%8.8x s34=%8.8x s35=%8.8x s36=%8.8x " + "s37=%8.8x s38=%8.8x s39=%8.8x", + r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39]); + DNBLogThreaded(" s40=%8.8x s41=%8.8x s42=%8.8x s43=%8.8x s44=%8.8x " + "s45=%8.8x s46=%8.8x s47=%8.8x", + r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47]); + DNBLogThreaded(" s48=%8.8x s49=%8.8x s50=%8.8x s51=%8.8x s52=%8.8x " + "s53=%8.8x s54=%8.8x s55=%8.8x", + r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55]); + DNBLogThreaded(" s56=%8.8x s57=%8.8x s58=%8.8x s59=%8.8x s60=%8.8x " + "s61=%8.8x s62=%8.8x s63=%8.8x fpscr=%8.8x", + r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63], + r[64]); + } #endif - m_state.SetError(set, Read, kret); - return kret; + m_state.SetError(set, Read, kret); + return kret; } -kern_return_t -DNBArchMachARM::GetEXCState(bool force) -{ - int set = e_regSetEXC; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - // Read the registers from our thread - mach_msg_type_number_t count = ARM_EXCEPTION_STATE_COUNT; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, &count); - m_state.SetError(set, Read, kret); - return kret; +kern_return_t DNBArchMachARM::GetEXCState(bool force) { + int set = e_regSetEXC; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = ARM_EXCEPTION_STATE_COUNT; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, &count); + m_state.SetError(set, Read, kret); + return kret; } -static void -DumpDBGState(const DNBArchMachARM::DBG& dbg) -{ - uint32_t i = 0; - for (i=0; i<16; i++) - { - DNBLogThreadedIf(LOG_STEP, "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]); - } +static void DumpDBGState(const DNBArchMachARM::DBG &dbg) { + uint32_t i = 0; + for (i = 0; i < 16; i++) { + DNBLogThreadedIf(LOG_STEP, "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]); + } } -kern_return_t -DNBArchMachARM::GetDBGState(bool force) -{ - int set = e_regSetDBG; +kern_return_t DNBArchMachARM::GetDBGState(bool force) { + int set = e_regSetDBG; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; - // Read the registers from our thread -#if defined (ARM_DEBUG_STATE32) && (defined (__arm64__) || defined (__aarch64__)) - mach_msg_type_number_t count = ARM_DEBUG_STATE32_COUNT; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, &count); +// Read the registers from our thread +#if defined(ARM_DEBUG_STATE32) && (defined(__arm64__) || defined(__aarch64__)) + mach_msg_type_number_t count = ARM_DEBUG_STATE32_COUNT; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE32, + (thread_state_t)&m_state.dbg, &count); #else - mach_msg_type_number_t count = ARM_DEBUG_STATE_COUNT; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, &count); + mach_msg_type_number_t count = ARM_DEBUG_STATE_COUNT; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE, + (thread_state_t)&m_state.dbg, &count); #endif - m_state.SetError(set, Read, kret); + m_state.SetError(set, Read, kret); - return kret; + return kret; } -kern_return_t -DNBArchMachARM::SetGPRState() -{ - int set = e_regSetGPR; - kern_return_t kret = ::thread_set_state(m_thread->MachPortNumber(), ARM_THREAD_STATE, (thread_state_t)&m_state.context.gpr, ARM_THREAD_STATE_COUNT); - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code +kern_return_t DNBArchMachARM::SetGPRState() { + int set = e_regSetGPR; + kern_return_t kret = ::thread_set_state( + m_thread->MachPortNumber(), ARM_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, ARM_THREAD_STATE_COUNT); + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM::SetVFPState() -{ - int set = e_regSetVFP; - kern_return_t kret; - mach_msg_type_number_t count; +kern_return_t DNBArchMachARM::SetVFPState() { + int set = e_regSetVFP; + kern_return_t kret; + mach_msg_type_number_t count; -#if defined (__arm64__) || defined (__aarch64__) - count = ARM_NEON_STATE_COUNT; - kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_NEON_STATE, (thread_state_t)&m_state.context.vfp, count); +#if defined(__arm64__) || defined(__aarch64__) + count = ARM_NEON_STATE_COUNT; + kret = ::thread_set_state(m_thread->MachPortNumber(), ARM_NEON_STATE, + (thread_state_t)&m_state.context.vfp, count); #else - count = ARM_VFP_STATE_COUNT; - kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_VFP_STATE, (thread_state_t)&m_state.context.vfp, count); + count = ARM_VFP_STATE_COUNT; + kret = ::thread_set_state(m_thread->MachPortNumber(), ARM_VFP_STATE, + (thread_state_t)&m_state.context.vfp, count); #endif -#if defined (__arm64__) || defined (__aarch64__) - if (DNBLogEnabledForAny (LOG_THREAD)) - { - DNBLogThreaded("thread_set_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" - "\n q0 = 0x%16.16llx%16.16llx" - "\n q1 = 0x%16.16llx%16.16llx" - "\n q2 = 0x%16.16llx%16.16llx" - "\n q3 = 0x%16.16llx%16.16llx" - "\n q4 = 0x%16.16llx%16.16llx" - "\n q5 = 0x%16.16llx%16.16llx" - "\n q6 = 0x%16.16llx%16.16llx" - "\n q7 = 0x%16.16llx%16.16llx" - "\n q8 = 0x%16.16llx%16.16llx" - "\n q9 = 0x%16.16llx%16.16llx" - "\n q10 = 0x%16.16llx%16.16llx" - "\n q11 = 0x%16.16llx%16.16llx" - "\n q12 = 0x%16.16llx%16.16llx" - "\n q13 = 0x%16.16llx%16.16llx" - "\n q14 = 0x%16.16llx%16.16llx" - "\n q15 = 0x%16.16llx%16.16llx" - "\n fpsr = 0x%8.8x" - "\n fpcr = 0x%8.8x\n\n", - m_thread->MachPortNumber(), - ARM_NEON_STATE, - ARM_NEON_STATE_COUNT, - kret, - count, - ((uint64_t *)&m_state.context.vfp.__v[0])[0] , ((uint64_t *)&m_state.context.vfp.__v[0])[1], - ((uint64_t *)&m_state.context.vfp.__v[1])[0] , ((uint64_t *)&m_state.context.vfp.__v[1])[1], - ((uint64_t *)&m_state.context.vfp.__v[2])[0] , ((uint64_t *)&m_state.context.vfp.__v[2])[1], - ((uint64_t *)&m_state.context.vfp.__v[3])[0] , ((uint64_t *)&m_state.context.vfp.__v[3])[1], - ((uint64_t *)&m_state.context.vfp.__v[4])[0] , ((uint64_t *)&m_state.context.vfp.__v[4])[1], - ((uint64_t *)&m_state.context.vfp.__v[5])[0] , ((uint64_t *)&m_state.context.vfp.__v[5])[1], - ((uint64_t *)&m_state.context.vfp.__v[6])[0] , ((uint64_t *)&m_state.context.vfp.__v[6])[1], - ((uint64_t *)&m_state.context.vfp.__v[7])[0] , ((uint64_t *)&m_state.context.vfp.__v[7])[1], - ((uint64_t *)&m_state.context.vfp.__v[8])[0] , ((uint64_t *)&m_state.context.vfp.__v[8])[1], - ((uint64_t *)&m_state.context.vfp.__v[9])[0] , ((uint64_t *)&m_state.context.vfp.__v[9])[1], - ((uint64_t *)&m_state.context.vfp.__v[10])[0], ((uint64_t *)&m_state.context.vfp.__v[10])[1], - ((uint64_t *)&m_state.context.vfp.__v[11])[0], ((uint64_t *)&m_state.context.vfp.__v[11])[1], - ((uint64_t *)&m_state.context.vfp.__v[12])[0], ((uint64_t *)&m_state.context.vfp.__v[12])[1], - ((uint64_t *)&m_state.context.vfp.__v[13])[0], ((uint64_t *)&m_state.context.vfp.__v[13])[1], - ((uint64_t *)&m_state.context.vfp.__v[14])[0], ((uint64_t *)&m_state.context.vfp.__v[14])[1], - ((uint64_t *)&m_state.context.vfp.__v[15])[0], ((uint64_t *)&m_state.context.vfp.__v[15])[1], - m_state.context.vfp.__fpsr, - m_state.context.vfp.__fpcr); - } +#if defined(__arm64__) || defined(__aarch64__) + if (DNBLogEnabledForAny(LOG_THREAD)) { + DNBLogThreaded( + "thread_set_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" + "\n q0 = 0x%16.16llx%16.16llx" + "\n q1 = 0x%16.16llx%16.16llx" + "\n q2 = 0x%16.16llx%16.16llx" + "\n q3 = 0x%16.16llx%16.16llx" + "\n q4 = 0x%16.16llx%16.16llx" + "\n q5 = 0x%16.16llx%16.16llx" + "\n q6 = 0x%16.16llx%16.16llx" + "\n q7 = 0x%16.16llx%16.16llx" + "\n q8 = 0x%16.16llx%16.16llx" + "\n q9 = 0x%16.16llx%16.16llx" + "\n q10 = 0x%16.16llx%16.16llx" + "\n q11 = 0x%16.16llx%16.16llx" + "\n q12 = 0x%16.16llx%16.16llx" + "\n q13 = 0x%16.16llx%16.16llx" + "\n q14 = 0x%16.16llx%16.16llx" + "\n q15 = 0x%16.16llx%16.16llx" + "\n fpsr = 0x%8.8x" + "\n fpcr = 0x%8.8x\n\n", + m_thread->MachPortNumber(), ARM_NEON_STATE, ARM_NEON_STATE_COUNT, kret, + count, ((uint64_t *)&m_state.context.vfp.__v[0])[0], + ((uint64_t *)&m_state.context.vfp.__v[0])[1], + ((uint64_t *)&m_state.context.vfp.__v[1])[0], + ((uint64_t *)&m_state.context.vfp.__v[1])[1], + ((uint64_t *)&m_state.context.vfp.__v[2])[0], + ((uint64_t *)&m_state.context.vfp.__v[2])[1], + ((uint64_t *)&m_state.context.vfp.__v[3])[0], + ((uint64_t *)&m_state.context.vfp.__v[3])[1], + ((uint64_t *)&m_state.context.vfp.__v[4])[0], + ((uint64_t *)&m_state.context.vfp.__v[4])[1], + ((uint64_t *)&m_state.context.vfp.__v[5])[0], + ((uint64_t *)&m_state.context.vfp.__v[5])[1], + ((uint64_t *)&m_state.context.vfp.__v[6])[0], + ((uint64_t *)&m_state.context.vfp.__v[6])[1], + ((uint64_t *)&m_state.context.vfp.__v[7])[0], + ((uint64_t *)&m_state.context.vfp.__v[7])[1], + ((uint64_t *)&m_state.context.vfp.__v[8])[0], + ((uint64_t *)&m_state.context.vfp.__v[8])[1], + ((uint64_t *)&m_state.context.vfp.__v[9])[0], + ((uint64_t *)&m_state.context.vfp.__v[9])[1], + ((uint64_t *)&m_state.context.vfp.__v[10])[0], + ((uint64_t *)&m_state.context.vfp.__v[10])[1], + ((uint64_t *)&m_state.context.vfp.__v[11])[0], + ((uint64_t *)&m_state.context.vfp.__v[11])[1], + ((uint64_t *)&m_state.context.vfp.__v[12])[0], + ((uint64_t *)&m_state.context.vfp.__v[12])[1], + ((uint64_t *)&m_state.context.vfp.__v[13])[0], + ((uint64_t *)&m_state.context.vfp.__v[13])[1], + ((uint64_t *)&m_state.context.vfp.__v[14])[0], + ((uint64_t *)&m_state.context.vfp.__v[14])[1], + ((uint64_t *)&m_state.context.vfp.__v[15])[0], + ((uint64_t *)&m_state.context.vfp.__v[15])[1], + m_state.context.vfp.__fpsr, m_state.context.vfp.__fpcr); + } #else - if (DNBLogEnabledForAny (LOG_THREAD)) - { - uint32_t *r = &m_state.context.vfp.__r[0]; - DNBLogThreaded ("thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count => %u)", - m_thread->MachPortNumber(), - ARM_THREAD_STATE, - ARM_THREAD_STATE_COUNT, - kret, - count); - DNBLogThreaded(" s0=%8.8x s1=%8.8x s2=%8.8x s3=%8.8x s4=%8.8x s5=%8.8x s6=%8.8x s7=%8.8x",r[ 0],r[ 1],r[ 2],r[ 3],r[ 4],r[ 5],r[ 6],r[ 7]); - DNBLogThreaded(" s8=%8.8x s9=%8.8x s10=%8.8x s11=%8.8x s12=%8.8x s13=%8.8x s14=%8.8x s15=%8.8x",r[ 8],r[ 9],r[10],r[11],r[12],r[13],r[14],r[15]); - DNBLogThreaded(" s16=%8.8x s17=%8.8x s18=%8.8x s19=%8.8x s20=%8.8x s21=%8.8x s22=%8.8x s23=%8.8x",r[16],r[17],r[18],r[19],r[20],r[21],r[22],r[23]); - DNBLogThreaded(" s24=%8.8x s25=%8.8x s26=%8.8x s27=%8.8x s28=%8.8x s29=%8.8x s30=%8.8x s31=%8.8x",r[24],r[25],r[26],r[27],r[28],r[29],r[30],r[31]); - DNBLogThreaded(" s32=%8.8x s33=%8.8x s34=%8.8x s35=%8.8x s36=%8.8x s37=%8.8x s38=%8.8x s39=%8.8x",r[32],r[33],r[34],r[35],r[36],r[37],r[38],r[39]); - DNBLogThreaded(" s40=%8.8x s41=%8.8x s42=%8.8x s43=%8.8x s44=%8.8x s45=%8.8x s46=%8.8x s47=%8.8x",r[40],r[41],r[42],r[43],r[44],r[45],r[46],r[47]); - DNBLogThreaded(" s48=%8.8x s49=%8.8x s50=%8.8x s51=%8.8x s52=%8.8x s53=%8.8x s54=%8.8x s55=%8.8x",r[48],r[49],r[50],r[51],r[52],r[53],r[54],r[55]); - DNBLogThreaded(" s56=%8.8x s57=%8.8x s58=%8.8x s59=%8.8x s60=%8.8x s61=%8.8x s62=%8.8x s63=%8.8x fpscr=%8.8x",r[56],r[57],r[58],r[59],r[60],r[61],r[62],r[63],r[64]); - } + if (DNBLogEnabledForAny(LOG_THREAD)) { + uint32_t *r = &m_state.context.vfp.__r[0]; + DNBLogThreaded( + "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count => %u)", + m_thread->MachPortNumber(), ARM_THREAD_STATE, ARM_THREAD_STATE_COUNT, + kret, count); + DNBLogThreaded(" s0=%8.8x s1=%8.8x s2=%8.8x s3=%8.8x s4=%8.8x " + "s5=%8.8x s6=%8.8x s7=%8.8x", + r[0], r[1], r[2], r[3], r[4], r[5], r[6], r[7]); + DNBLogThreaded(" s8=%8.8x s9=%8.8x s10=%8.8x s11=%8.8x s12=%8.8x " + "s13=%8.8x s14=%8.8x s15=%8.8x", + r[8], r[9], r[10], r[11], r[12], r[13], r[14], r[15]); + DNBLogThreaded(" s16=%8.8x s17=%8.8x s18=%8.8x s19=%8.8x s20=%8.8x " + "s21=%8.8x s22=%8.8x s23=%8.8x", + r[16], r[17], r[18], r[19], r[20], r[21], r[22], r[23]); + DNBLogThreaded(" s24=%8.8x s25=%8.8x s26=%8.8x s27=%8.8x s28=%8.8x " + "s29=%8.8x s30=%8.8x s31=%8.8x", + r[24], r[25], r[26], r[27], r[28], r[29], r[30], r[31]); + DNBLogThreaded(" s32=%8.8x s33=%8.8x s34=%8.8x s35=%8.8x s36=%8.8x " + "s37=%8.8x s38=%8.8x s39=%8.8x", + r[32], r[33], r[34], r[35], r[36], r[37], r[38], r[39]); + DNBLogThreaded(" s40=%8.8x s41=%8.8x s42=%8.8x s43=%8.8x s44=%8.8x " + "s45=%8.8x s46=%8.8x s47=%8.8x", + r[40], r[41], r[42], r[43], r[44], r[45], r[46], r[47]); + DNBLogThreaded(" s48=%8.8x s49=%8.8x s50=%8.8x s51=%8.8x s52=%8.8x " + "s53=%8.8x s54=%8.8x s55=%8.8x", + r[48], r[49], r[50], r[51], r[52], r[53], r[54], r[55]); + DNBLogThreaded(" s56=%8.8x s57=%8.8x s58=%8.8x s59=%8.8x s60=%8.8x " + "s61=%8.8x s62=%8.8x s63=%8.8x fpscr=%8.8x", + r[56], r[57], r[58], r[59], r[60], r[61], r[62], r[63], + r[64]); + } #endif - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM::SetEXCState() -{ - int set = e_regSetEXC; - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, ARM_EXCEPTION_STATE_COUNT); - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code +kern_return_t DNBArchMachARM::SetEXCState() { + int set = e_regSetEXC; + kern_return_t kret = ::thread_set_state( + m_thread->MachPortNumber(), ARM_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, ARM_EXCEPTION_STATE_COUNT); + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM::SetDBGState(bool also_set_on_task) -{ - int set = e_regSetDBG; -#if defined (ARM_DEBUG_STATE32) && (defined (__arm64__) || defined (__aarch64__)) - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); - if (also_set_on_task) - { - kern_return_t task_kret = ::task_set_state (m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE32, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); - if (task_kret != KERN_SUCCESS) - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); - } +kern_return_t DNBArchMachARM::SetDBGState(bool also_set_on_task) { + int set = e_regSetDBG; +#if defined(ARM_DEBUG_STATE32) && (defined(__arm64__) || defined(__aarch64__)) + kern_return_t kret = + ::thread_set_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE32, + (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); + if (also_set_on_task) { + kern_return_t task_kret = ::task_set_state( + m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE32, + (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE32_COUNT); + if (task_kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to " + "set debug control register state: " + "0x%8.8x.", + kret); + } #else - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT); - if (also_set_on_task) - { - kern_return_t task_kret = ::task_set_state (m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE, (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT); - if (task_kret != KERN_SUCCESS) - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); - } + kern_return_t kret = + ::thread_set_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE, + (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT); + if (also_set_on_task) { + kern_return_t task_kret = ::task_set_state( + m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE, + (thread_state_t)&m_state.dbg, ARM_DEBUG_STATE_COUNT); + if (task_kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::SetDBGState failed to " + "set debug control register state: " + "0x%8.8x.", + kret); + } #endif - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -void -DNBArchMachARM::ThreadWillResume() -{ - // Do we need to step this thread? If so, let the mach thread tell us so. - if (m_thread->IsStepping()) - { - // This is the primary thread, let the arch do anything it needs - if (NumSupportedHardwareBreakpoints() > 0) - { - if (EnableHardwareSingleStep(true) != KERN_SUCCESS) - { - DNBLogThreaded("DNBArchMachARM::ThreadWillResume() failed to enable hardware single step"); - } - } +void DNBArchMachARM::ThreadWillResume() { + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) { + // This is the primary thread, let the arch do anything it needs + if (NumSupportedHardwareBreakpoints() > 0) { + if (EnableHardwareSingleStep(true) != KERN_SUCCESS) { + DNBLogThreaded("DNBArchMachARM::ThreadWillResume() failed to enable " + "hardware single step"); + } } - - // Disable the triggered watchpoint temporarily before we resume. - // Plus, we try to enable hardware single step to execute past the instruction which triggered our watchpoint. - if (m_watchpoint_did_occur) - { - if (m_watchpoint_hw_index >= 0) - { - kern_return_t kret = GetDBGState(false); - if (kret == KERN_SUCCESS && !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { - // The watchpoint might have been disabled by the user. We don't need to do anything at all - // to enable hardware single stepping. - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - return; - } - - DisableHardwareWatchpoint(m_watchpoint_hw_index, false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called", - m_watchpoint_hw_index); - - // Enable hardware single step to move past the watchpoint-triggering instruction. - m_watchpoint_resume_single_step_enabled = (EnableHardwareSingleStep(true) == KERN_SUCCESS); - - // If we are not able to enable single step to move past the watchpoint-triggering instruction, - // at least we should reset the two watchpoint member variables so that the next time around - // this callback function is invoked, the enclosing logical branch is skipped. - if (!m_watchpoint_resume_single_step_enabled) { - // Reset the two watchpoint member variables. - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() failed to enable single step"); - } - else - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() succeeded to enable single step"); - } + } + + // Disable the triggered watchpoint temporarily before we resume. + // Plus, we try to enable hardware single step to execute past the instruction + // which triggered our watchpoint. + if (m_watchpoint_did_occur) { + if (m_watchpoint_hw_index >= 0) { + kern_return_t kret = GetDBGState(false); + if (kret == KERN_SUCCESS && + !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { + // The watchpoint might have been disabled by the user. We don't need + // to do anything at all + // to enable hardware single stepping. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + return; + } + + DisableHardwareWatchpoint(m_watchpoint_hw_index, false); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() " + "DisableHardwareWatchpoint(%d) called", + m_watchpoint_hw_index); + + // Enable hardware single step to move past the watchpoint-triggering + // instruction. + m_watchpoint_resume_single_step_enabled = + (EnableHardwareSingleStep(true) == KERN_SUCCESS); + + // If we are not able to enable single step to move past the + // watchpoint-triggering instruction, + // at least we should reset the two watchpoint member variables so that + // the next time around + // this callback function is invoked, the enclosing logical branch is + // skipped. + if (!m_watchpoint_resume_single_step_enabled) { + // Reset the two watchpoint member variables. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchMachARM::ThreadWillResume() failed to enable single step"); + } else + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() " + "succeeded to enable single step"); } + } } -bool -DNBArchMachARM::ThreadDidStop() -{ - bool success = true; - - m_state.InvalidateRegisterSetState (e_regSetALL); - - if (m_watchpoint_resume_single_step_enabled) - { - // Great! We now disable the hardware single step as well as re-enable the hardware watchpoint. - // See also ThreadWillResume(). - if (EnableHardwareSingleStep(false) == KERN_SUCCESS) - { - if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) - { - ReenableHardwareWatchpoint(m_watchpoint_hw_index); - m_watchpoint_resume_single_step_enabled = false; - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - } - else - { - DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) does not hold!"); - } - } - else - { - DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but unable to disable single step!"); - } +bool DNBArchMachARM::ThreadDidStop() { + bool success = true; + + m_state.InvalidateRegisterSetState(e_regSetALL); + + if (m_watchpoint_resume_single_step_enabled) { + // Great! We now disable the hardware single step as well as re-enable the + // hardware watchpoint. + // See also ThreadWillResume(). + if (EnableHardwareSingleStep(false) == KERN_SUCCESS) { + if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) { + ReenableHardwareWatchpoint(m_watchpoint_hw_index); + m_watchpoint_resume_single_step_enabled = false; + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + } else { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " + "is true but (m_watchpoint_did_occur && " + "m_watchpoint_hw_index >= 0) does not hold!"); + } + } else { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " + "is true but unable to disable single step!"); } - - // Are we stepping a single instruction? - if (GetGPRState(true) == KERN_SUCCESS) - { - // We are single stepping, was this the primary thread? - if (m_thread->IsStepping()) - { - success = EnableHardwareSingleStep(false) == KERN_SUCCESS; - } - else - { - // The MachThread will automatically restore the suspend count - // in ThreadDidStop(), so we don't need to do anything here if - // we weren't the primary thread the last time - } + } + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) { + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } else { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time } - return success; + } + return success; } -bool -DNBArchMachARM::NotifyException(MachException::Data& exc) -{ - switch (exc.exc_type) - { - default: - break; - case EXC_BREAKPOINT: - if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) - { - // The data break address is passed as exc_data[1]. - nub_addr_t addr = exc.exc_data[1]; - // Find the hardware index with the side effect of possibly massaging the - // addr to return the starting address as seen from the debugger side. - uint32_t hw_index = GetHardwareWatchpointHit(addr); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException watchpoint %d was hit on address 0x%llx", hw_index, (uint64_t) addr); - const int num_watchpoints = NumSupportedHardwareWatchpoints (); - for (int i = 0; i < num_watchpoints; i++) - { - if (LoHi[i] != 0 - && LoHi[i] == hw_index - && LoHi[i] != i - && GetWatchpointAddressByIndex (i) != INVALID_NUB_ADDRESS) - { - addr = GetWatchpointAddressByIndex (i); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException It is a linked watchpoint; rewritten to index %d addr 0x%llx", LoHi[i], (uint64_t) addr); - } - } - if (hw_index != INVALID_NUB_HW_INDEX) - { - m_watchpoint_did_occur = true; - m_watchpoint_hw_index = hw_index; - exc.exc_data[1] = addr; - // Piggyback the hw_index in the exc.data. - exc.exc_data.push_back(hw_index); - } - - return true; - } - break; +bool DNBArchMachARM::NotifyException(MachException::Data &exc) { + switch (exc.exc_type) { + default: + break; + case EXC_BREAKPOINT: + if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) { + // The data break address is passed as exc_data[1]. + nub_addr_t addr = exc.exc_data[1]; + // Find the hardware index with the side effect of possibly massaging the + // addr to return the starting address as seen from the debugger side. + uint32_t hw_index = GetHardwareWatchpointHit(addr); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException " + "watchpoint %d was hit on address " + "0x%llx", + hw_index, (uint64_t)addr); + const int num_watchpoints = NumSupportedHardwareWatchpoints(); + for (int i = 0; i < num_watchpoints; i++) { + if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i && + GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) { + addr = GetWatchpointAddressByIndex(i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException " + "It is a linked watchpoint; " + "rewritten to index %d addr 0x%llx", + LoHi[i], (uint64_t)addr); + } + } + if (hw_index != INVALID_NUB_HW_INDEX) { + m_watchpoint_did_occur = true; + m_watchpoint_hw_index = hw_index; + exc.exc_data[1] = addr; + // Piggyback the hw_index in the exc.data. + exc.exc_data.push_back(hw_index); + } + + return true; } - return false; + break; + } + return false; } -bool -DNBArchMachARM::StepNotComplete () -{ - if (m_hw_single_chained_step_addr != INVALID_NUB_ADDRESS) - { - kern_return_t kret = KERN_INVALID_ARGUMENT; - kret = GetGPRState(false); - if (kret == KERN_SUCCESS) - { - if (m_state.context.gpr.__pc == m_hw_single_chained_step_addr) - { - DNBLogThreadedIf(LOG_STEP, "Need to step some more at 0x%8.8llx", (uint64_t) m_hw_single_chained_step_addr); - return true; - } - } +bool DNBArchMachARM::StepNotComplete() { + if (m_hw_single_chained_step_addr != INVALID_NUB_ADDRESS) { + kern_return_t kret = KERN_INVALID_ARGUMENT; + kret = GetGPRState(false); + if (kret == KERN_SUCCESS) { + if (m_state.context.gpr.__pc == m_hw_single_chained_step_addr) { + DNBLogThreadedIf(LOG_STEP, "Need to step some more at 0x%8.8llx", + (uint64_t)m_hw_single_chained_step_addr); + return true; + } } + } - m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS; - return false; + m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS; + return false; } // Set the single step bit in the processor status register. -kern_return_t -DNBArchMachARM::EnableHardwareSingleStep (bool enable) -{ - DNBError err; - DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); - - err = GetGPRState(false); - - if (err.Fail()) - { - err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); - return err.Error(); - } +kern_return_t DNBArchMachARM::EnableHardwareSingleStep(bool enable) { + DNBError err; + DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); - err = GetDBGState(false); + err = GetGPRState(false); - if (err.Fail()) - { - err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); - return err.Error(); - } + if (err.Fail()) { + err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); + return err.Error(); + } + + err = GetDBGState(false); + + if (err.Fail()) { + err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); + return err.Error(); + } // The use of __arm64__ here is not ideal. If debugserver is running on -// an armv8 device, regardless of whether it was built for arch arm or arch arm64, +// an armv8 device, regardless of whether it was built for arch arm or arch +// arm64, // it needs to use the MDSCR_EL1 SS bit to single instruction step. -#if defined (__arm64__) || defined (__aarch64__) - if (enable) - { - DNBLogThreadedIf(LOG_STEP, "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); - m_state.dbg.__mdscr_el1 |= 1; // Set bit 0 (single step, SS) in the MDSCR_EL1. - } - else - { - DNBLogThreadedIf(LOG_STEP, "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); - m_state.dbg.__mdscr_el1 &= ~(1ULL); // Clear bit 0 (single step, SS) in the MDSCR_EL1. - } +#if defined(__arm64__) || defined(__aarch64__) + if (enable) { + DNBLogThreadedIf(LOG_STEP, + "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", + __FUNCTION__, (uint64_t)m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 |= + 1; // Set bit 0 (single step, SS) in the MDSCR_EL1. + } else { + DNBLogThreadedIf(LOG_STEP, + "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", + __FUNCTION__, (uint64_t)m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 &= + ~(1ULL); // Clear bit 0 (single step, SS) in the MDSCR_EL1. + } #else - const uint32_t i = 0; - if (enable) - { - m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS; - - // Save our previous state - m_dbg_save = m_state.dbg; - // Set a breakpoint that will stop when the PC doesn't match the current one! - m_state.dbg.__bvr[i] = m_state.context.gpr.__pc & 0xFFFFFFFCu; // Set the current PC as the breakpoint address - m_state.dbg.__bcr[i] = BCR_M_IMVA_MISMATCH | // Stop on address mismatch - S_USER | // Stop only in user mode - BCR_ENABLE; // Enable this breakpoint - if (m_state.context.gpr.__cpsr & 0x20) - { - // Thumb breakpoint - if (m_state.context.gpr.__pc & 2) - m_state.dbg.__bcr[i] |= BAS_IMVA_2_3; - else - m_state.dbg.__bcr[i] |= BAS_IMVA_0_1; - - uint16_t opcode; - if (sizeof(opcode) == m_thread->Process()->Task().ReadMemory(m_state.context.gpr.__pc, sizeof(opcode), &opcode)) - { - if (IsThumb32Opcode(opcode)) - { - // 32 bit thumb opcode... - if (m_state.context.gpr.__pc & 2) - { - // We can't take care of a 32 bit thumb instruction single step - // with just IVA mismatching. We will need to chain an extra - // hardware single step in order to complete this single step... - m_hw_single_chained_step_addr = m_state.context.gpr.__pc + 2; - } - else - { - // Extend the number of bits to ignore for the mismatch - m_state.dbg.__bcr[i] |= BAS_IMVA_ALL; - } - } - } - } - else - { - // ARM breakpoint - m_state.dbg.__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change - } - - DNBLogThreadedIf(LOG_STEP, "%s: BVR%u=0x%8.8x BCR%u=0x%8.8x", __FUNCTION__, i, m_state.dbg.__bvr[i], i, m_state.dbg.__bcr[i]); + const uint32_t i = 0; + if (enable) { + m_hw_single_chained_step_addr = INVALID_NUB_ADDRESS; - for (uint32_t j=i+1; j<16; ++j) - { - // Disable all others - m_state.dbg.__bvr[j] = 0; - m_state.dbg.__bcr[j] = 0; + // Save our previous state + m_dbg_save = m_state.dbg; + // Set a breakpoint that will stop when the PC doesn't match the current + // one! + m_state.dbg.__bvr[i] = + m_state.context.gpr.__pc & + 0xFFFFFFFCu; // Set the current PC as the breakpoint address + m_state.dbg.__bcr[i] = BCR_M_IMVA_MISMATCH | // Stop on address mismatch + S_USER | // Stop only in user mode + BCR_ENABLE; // Enable this breakpoint + if (m_state.context.gpr.__cpsr & 0x20) { + // Thumb breakpoint + if (m_state.context.gpr.__pc & 2) + m_state.dbg.__bcr[i] |= BAS_IMVA_2_3; + else + m_state.dbg.__bcr[i] |= BAS_IMVA_0_1; + + uint16_t opcode; + if (sizeof(opcode) == + m_thread->Process()->Task().ReadMemory(m_state.context.gpr.__pc, + sizeof(opcode), &opcode)) { + if (IsThumb32Opcode(opcode)) { + // 32 bit thumb opcode... + if (m_state.context.gpr.__pc & 2) { + // We can't take care of a 32 bit thumb instruction single step + // with just IVA mismatching. We will need to chain an extra + // hardware single step in order to complete this single step... + m_hw_single_chained_step_addr = m_state.context.gpr.__pc + 2; + } else { + // Extend the number of bits to ignore for the mismatch + m_state.dbg.__bcr[i] |= BAS_IMVA_ALL; + } } + } + } else { + // ARM breakpoint + m_state.dbg.__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change } - else - { - // Just restore the state we had before we did single stepping - m_state.dbg = m_dbg_save; + + DNBLogThreadedIf(LOG_STEP, "%s: BVR%u=0x%8.8x BCR%u=0x%8.8x", __FUNCTION__, + i, m_state.dbg.__bvr[i], i, m_state.dbg.__bcr[i]); + + for (uint32_t j = i + 1; j < 16; ++j) { + // Disable all others + m_state.dbg.__bvr[j] = 0; + m_state.dbg.__bcr[j] = 0; } + } else { + // Just restore the state we had before we did single stepping + m_state.dbg = m_dbg_save; + } #endif - return SetDBGState(false); + return SetDBGState(false); } // return 1 if bit "BIT" is set in "value" -static inline uint32_t bit(uint32_t value, uint32_t bit) -{ - return (value >> bit) & 1u; +static inline uint32_t bit(uint32_t value, uint32_t bit) { + return (value >> bit) & 1u; } // return the bitfield "value[msbit:lsbit]". -static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit) -{ - assert(msbit >= lsbit); - uint32_t shift_left = sizeof(value) * 8 - 1 - msbit; - value <<= shift_left; // shift anything above the msbit off of the unsigned edge - value >>= (shift_left + lsbit); // shift it back again down to the lsbit (including undoing any shift from above) - return value; // return our result +static inline uint32_t bits(uint32_t value, uint32_t msbit, uint32_t lsbit) { + assert(msbit >= lsbit); + uint32_t shift_left = sizeof(value) * 8 - 1 - msbit; + value <<= + shift_left; // shift anything above the msbit off of the unsigned edge + value >>= (shift_left + lsbit); // shift it back again down to the lsbit + // (including undoing any shift from above) + return value; // return our result } -bool -DNBArchMachARM::ConditionPassed(uint8_t condition, uint32_t cpsr) -{ - uint32_t cpsr_n = bit(cpsr, 31); // Negative condition code flag - uint32_t cpsr_z = bit(cpsr, 30); // Zero condition code flag - uint32_t cpsr_c = bit(cpsr, 29); // Carry condition code flag - uint32_t cpsr_v = bit(cpsr, 28); // Overflow condition code flag - - switch (condition) { - case COND_EQ: // (0x0) - if (cpsr_z == 1) return true; - break; - case COND_NE: // (0x1) - if (cpsr_z == 0) return true; - break; - case COND_CS: // (0x2) - if (cpsr_c == 1) return true; - break; - case COND_CC: // (0x3) - if (cpsr_c == 0) return true; - break; - case COND_MI: // (0x4) - if (cpsr_n == 1) return true; - break; - case COND_PL: // (0x5) - if (cpsr_n == 0) return true; - break; - case COND_VS: // (0x6) - if (cpsr_v == 1) return true; - break; - case COND_VC: // (0x7) - if (cpsr_v == 0) return true; - break; - case COND_HI: // (0x8) - if ((cpsr_c == 1) && (cpsr_z == 0)) return true; - break; - case COND_LS: // (0x9) - if ((cpsr_c == 0) || (cpsr_z == 1)) return true; - break; - case COND_GE: // (0xA) - if (cpsr_n == cpsr_v) return true; - break; - case COND_LT: // (0xB) - if (cpsr_n != cpsr_v) return true; - break; - case COND_GT: // (0xC) - if ((cpsr_z == 0) && (cpsr_n == cpsr_v)) return true; - break; - case COND_LE: // (0xD) - if ((cpsr_z == 1) || (cpsr_n != cpsr_v)) return true; - break; - default: - return true; - break; - } - - return false; +bool DNBArchMachARM::ConditionPassed(uint8_t condition, uint32_t cpsr) { + uint32_t cpsr_n = bit(cpsr, 31); // Negative condition code flag + uint32_t cpsr_z = bit(cpsr, 30); // Zero condition code flag + uint32_t cpsr_c = bit(cpsr, 29); // Carry condition code flag + uint32_t cpsr_v = bit(cpsr, 28); // Overflow condition code flag + + switch (condition) { + case COND_EQ: // (0x0) + if (cpsr_z == 1) + return true; + break; + case COND_NE: // (0x1) + if (cpsr_z == 0) + return true; + break; + case COND_CS: // (0x2) + if (cpsr_c == 1) + return true; + break; + case COND_CC: // (0x3) + if (cpsr_c == 0) + return true; + break; + case COND_MI: // (0x4) + if (cpsr_n == 1) + return true; + break; + case COND_PL: // (0x5) + if (cpsr_n == 0) + return true; + break; + case COND_VS: // (0x6) + if (cpsr_v == 1) + return true; + break; + case COND_VC: // (0x7) + if (cpsr_v == 0) + return true; + break; + case COND_HI: // (0x8) + if ((cpsr_c == 1) && (cpsr_z == 0)) + return true; + break; + case COND_LS: // (0x9) + if ((cpsr_c == 0) || (cpsr_z == 1)) + return true; + break; + case COND_GE: // (0xA) + if (cpsr_n == cpsr_v) + return true; + break; + case COND_LT: // (0xB) + if (cpsr_n != cpsr_v) + return true; + break; + case COND_GT: // (0xC) + if ((cpsr_z == 0) && (cpsr_n == cpsr_v)) + return true; + break; + case COND_LE: // (0xD) + if ((cpsr_z == 1) || (cpsr_n != cpsr_v)) + return true; + break; + default: + return true; + break; + } + + return false; } -uint32_t -DNBArchMachARM::NumSupportedHardwareBreakpoints() -{ - // 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 = UINT_MAX; - if (g_num_supported_hw_breakpoints == UINT_MAX) - { - // Set this to zero in case we can't tell if there are any HW breakpoints - g_num_supported_hw_breakpoints = 0; - - size_t len; - uint32_t n = 0; - len = sizeof (n); - if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) - { - g_num_supported_hw_breakpoints = n; - DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n); +uint32_t DNBArchMachARM::NumSupportedHardwareBreakpoints() { + // 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 = UINT_MAX; + if (g_num_supported_hw_breakpoints == UINT_MAX) { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_breakpoints = 0; + + size_t len; + uint32_t n = 0; + len = sizeof(n); + if (::sysctlbyname("hw.optional.breakpoint", &n, &len, NULL, 0) == 0) { + g_num_supported_hw_breakpoints = n; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.breakpoint=%u", n); + } else { +#if !defined(__arm64__) && !defined(__aarch64__) + // Read the DBGDIDR to get the number of available hardware breakpoints + // However, in some of our current armv7 processors, hardware + // breakpoints/watchpoints were not properly connected. So detect those + // cases using a field in a sysctl. For now we are using "hw.cpusubtype" + // field to distinguish CPU architectures. This is a hack until we can + // get <rdar://problem/6372672> fixed, at which point we will switch to + // using a different sysctl string that will tell us how many BRPs + // are available to us directly without having to read DBGDIDR. + uint32_t register_DBGDIDR; + + asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); + uint32_t numBRPs = bits(register_DBGDIDR, 27, 24); + // Zero is reserved for the BRP count, so don't increment it if it is zero + if (numBRPs > 0) + numBRPs++; + DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", + register_DBGDIDR, numBRPs); + + if (numBRPs > 0) { + uint32_t cpusubtype; + len = sizeof(cpusubtype); + // TODO: remove this hack and change to using hw.optional.xx when + // implmented + if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) { + DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=%d", cpusubtype); + if (cpusubtype == CPU_SUBTYPE_ARM_V7) + DNBLogThreadedIf(LOG_THREAD, "Hardware breakpoints disabled for " + "armv7 (rdar://problem/6372672)"); + else + g_num_supported_hw_breakpoints = numBRPs; } - else - { -#if !defined (__arm64__) && !defined (__aarch64__) - // Read the DBGDIDR to get the number of available hardware breakpoints - // However, in some of our current armv7 processors, hardware - // breakpoints/watchpoints were not properly connected. So detect those - // cases using a field in a sysctl. For now we are using "hw.cpusubtype" - // field to distinguish CPU architectures. This is a hack until we can - // get <rdar://problem/6372672> fixed, at which point we will switch to - // using a different sysctl string that will tell us how many BRPs - // are available to us directly without having to read DBGDIDR. - uint32_t register_DBGDIDR; - - asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); - uint32_t numBRPs = bits(register_DBGDIDR, 27, 24); - // Zero is reserved for the BRP count, so don't increment it if it is zero - if (numBRPs > 0) - numBRPs++; - DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, numBRPs); - - if (numBRPs > 0) - { - uint32_t cpusubtype; - len = sizeof(cpusubtype); - // TODO: remove this hack and change to using hw.optional.xx when implmented - if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) - { - DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=%d", cpusubtype); - if (cpusubtype == CPU_SUBTYPE_ARM_V7) - DNBLogThreadedIf(LOG_THREAD, "Hardware breakpoints disabled for armv7 (rdar://problem/6372672)"); - else - g_num_supported_hw_breakpoints = numBRPs; - } - } + } #endif - } } - return g_num_supported_hw_breakpoints; + } + return g_num_supported_hw_breakpoints; } - -uint32_t -DNBArchMachARM::NumSupportedHardwareWatchpoints() -{ - // 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 = UINT_MAX; - if (g_num_supported_hw_watchpoints == UINT_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 DNBArchMachARM::NumSupportedHardwareWatchpoints() { + // 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 = UINT_MAX; + if (g_num_supported_hw_watchpoints == UINT_MAX) { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_watchpoints = 0; + + 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; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); + } else { +#if !defined(__arm64__) && !defined(__aarch64__) + // Read the DBGDIDR to get the number of available hardware breakpoints + // However, in some of our current armv7 processors, hardware + // breakpoints/watchpoints were not properly connected. So detect those + // cases using a field in a sysctl. For now we are using "hw.cpusubtype" + // field to distinguish CPU architectures. This is a hack until we can + // get <rdar://problem/6372672> fixed, at which point we will switch to + // using a different sysctl string that will tell us how many WRPs + // are available to us directly without having to read DBGDIDR. + + uint32_t register_DBGDIDR; + asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); + uint32_t numWRPs = bits(register_DBGDIDR, 31, 28) + 1; + DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", + register_DBGDIDR, numWRPs); + + if (numWRPs > 0) { + uint32_t cpusubtype; 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; - DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); + len = sizeof(cpusubtype); + // TODO: remove this hack and change to using hw.optional.xx when + // implmented + if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) { + DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype); + + if (cpusubtype == CPU_SUBTYPE_ARM_V7) + DNBLogThreadedIf(LOG_THREAD, "Hardware watchpoints disabled for " + "armv7 (rdar://problem/6372672)"); + else + g_num_supported_hw_watchpoints = numWRPs; } - else - { -#if !defined (__arm64__) && !defined (__aarch64__) - // Read the DBGDIDR to get the number of available hardware breakpoints - // However, in some of our current armv7 processors, hardware - // breakpoints/watchpoints were not properly connected. So detect those - // cases using a field in a sysctl. For now we are using "hw.cpusubtype" - // field to distinguish CPU architectures. This is a hack until we can - // get <rdar://problem/6372672> fixed, at which point we will switch to - // using a different sysctl string that will tell us how many WRPs - // are available to us directly without having to read DBGDIDR. - - uint32_t register_DBGDIDR; - asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); - uint32_t numWRPs = bits(register_DBGDIDR, 31, 28) + 1; - DNBLogThreadedIf(LOG_THREAD, "DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, numWRPs); - - if (numWRPs > 0) - { - uint32_t cpusubtype; - size_t len; - len = sizeof(cpusubtype); - // TODO: remove this hack and change to using hw.optional.xx when implmented - if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0) - { - DNBLogThreadedIf(LOG_THREAD, "hw.cpusubtype=0x%d", cpusubtype); - - if (cpusubtype == CPU_SUBTYPE_ARM_V7) - DNBLogThreadedIf(LOG_THREAD, "Hardware watchpoints disabled for armv7 (rdar://problem/6372672)"); - else - g_num_supported_hw_watchpoints = numWRPs; - } - } + } #endif - } } - return g_num_supported_hw_watchpoints; + } + return g_num_supported_hw_watchpoints; } +uint32_t DNBArchMachARM::EnableHardwareBreakpoint(nub_addr_t addr, + nub_size_t size) { + // Make sure our address isn't bogus + if (addr & 1) + return INVALID_NUB_HW_INDEX; -uint32_t -DNBArchMachARM::EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size) -{ - // Make sure our address isn't bogus - if (addr & 1) - return INVALID_NUB_HW_INDEX; - - kern_return_t kret = GetDBGState(false); + kern_return_t kret = GetDBGState(false); - if (kret == KERN_SUCCESS) - { - const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); - uint32_t i; - for (i=0; i<num_hw_breakpoints; ++i) - { - if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0) - break; // We found an available hw breakpoint slot (in i) - } + if (kret == KERN_SUCCESS) { + const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints(); + uint32_t i; + for (i = 0; i < num_hw_breakpoints; ++i) { + if ((m_state.dbg.__bcr[i] & BCR_ENABLE) == 0) + break; // We found an available hw breakpoint slot (in i) + } - // See if we found an available hw breakpoint slot above - if (i < num_hw_breakpoints) - { - // Make sure bits 1:0 are clear in our address - m_state.dbg.__bvr[i] = addr & ~((nub_addr_t)3); - - if (size == 2 || addr & 2) - { - uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1; - - // We have a thumb breakpoint - // We have an ARM breakpoint - m_state.dbg.__bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch - byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode - S_USER | // Which modes should this breakpoint stop in? - BCR_ENABLE; // Enable this hardware breakpoint - DNBLogThreadedIf (LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint( addr = 0x%8.8llx, size = %llu ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)", - (uint64_t)addr, - (uint64_t)size, - i, - i, - m_state.dbg.__bvr[i], - m_state.dbg.__bcr[i]); - } - else if (size == 4) - { - // We have an ARM breakpoint - m_state.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 - DNBLogThreadedIf (LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint( addr = 0x%8.8llx, size = %llu ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)", - (uint64_t)addr, - (uint64_t)size, - i, - i, - m_state.dbg.__bvr[i], - m_state.dbg.__bcr[i]); - } - - kret = SetDBGState(false); - DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint() SetDBGState() => 0x%8.8x.", kret); - - if (kret == KERN_SUCCESS) - return i; - } - else - { - DNBLogThreadedIf (LOG_BREAKPOINTS, "DNBArchMachARM::EnableHardwareBreakpoint(addr = 0x%8.8llx, size = %llu) => all hardware breakpoint resources are being used.", (uint64_t)addr, (uint64_t)size); - } + // See if we found an available hw breakpoint slot above + if (i < num_hw_breakpoints) { + // Make sure bits 1:0 are clear in our address + m_state.dbg.__bvr[i] = addr & ~((nub_addr_t)3); + + if (size == 2 || addr & 2) { + uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1; + + // We have a thumb breakpoint + // We have an ARM breakpoint + m_state.dbg.__bcr[i] = + BCR_M_IMVA_MATCH | // Stop on address mismatch + byte_addr_select | // Set the correct byte address select so we only + // trigger on the correct opcode + S_USER | // Which modes should this breakpoint stop in? + BCR_ENABLE; // Enable this hardware breakpoint + DNBLogThreadedIf(LOG_BREAKPOINTS, + "DNBArchMachARM::EnableHardwareBreakpoint( addr = " + "0x%8.8llx, size = %llu ) - BVR%u/BCR%u = 0x%8.8x / " + "0x%8.8x (Thumb)", + (uint64_t)addr, (uint64_t)size, i, i, + m_state.dbg.__bvr[i], m_state.dbg.__bcr[i]); + } else if (size == 4) { + // We have an ARM breakpoint + m_state.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 + DNBLogThreadedIf(LOG_BREAKPOINTS, + "DNBArchMachARM::EnableHardwareBreakpoint( addr = " + "0x%8.8llx, size = %llu ) - BVR%u/BCR%u = 0x%8.8x / " + "0x%8.8x (ARM)", + (uint64_t)addr, (uint64_t)size, i, i, + m_state.dbg.__bvr[i], m_state.dbg.__bcr[i]); + } + + kret = SetDBGState(false); + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::" + "EnableHardwareBreakpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + } else { + DNBLogThreadedIf(LOG_BREAKPOINTS, + "DNBArchMachARM::EnableHardwareBreakpoint(addr = " + "0x%8.8llx, size = %llu) => all hardware breakpoint " + "resources are being used.", + (uint64_t)addr, (uint64_t)size); } + } - return INVALID_NUB_HW_INDEX; + return INVALID_NUB_HW_INDEX; } -bool -DNBArchMachARM::DisableHardwareBreakpoint (uint32_t hw_index) -{ - kern_return_t kret = GetDBGState(false); - - const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); - if (kret == KERN_SUCCESS) - { - if (hw_index < num_hw_points) - { - m_state.dbg.__bcr[hw_index] = 0; - DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x", - hw_index, - hw_index, - m_state.dbg.__bvr[hw_index], - hw_index, - m_state.dbg.__bcr[hw_index]); - - kret = SetDBGState(false); - - if (kret == KERN_SUCCESS) - return true; - } +bool DNBArchMachARM::DisableHardwareBreakpoint(uint32_t hw_index) { + kern_return_t kret = GetDBGState(false); + + const uint32_t num_hw_points = NumSupportedHardwareBreakpoints(); + if (kret == KERN_SUCCESS) { + if (hw_index < num_hw_points) { + m_state.dbg.__bcr[hw_index] = 0; + DNBLogThreadedIf(LOG_BREAKPOINTS, "DNBArchMachARM::SetHardwareBreakpoint(" + " %u ) - BVR%u = 0x%8.8x BCR%u = " + "0x%8.8x", + hw_index, hw_index, m_state.dbg.__bvr[hw_index], + hw_index, m_state.dbg.__bcr[hw_index]); + + kret = SetDBGState(false); + + if (kret == KERN_SUCCESS) + return true; } - return false; + } + return false; } // ARM v7 watchpoints may be either word-size or double-word-size. @@ -1071,1092 +1080,1115 @@ DNBArchMachARM::DisableHardwareBreakpoint (uint32_t hw_index) // armv8 device, armv7 processes can watch dwords. But on a genuine armv7 // device I tried, only word watchpoints are supported. -#if defined (__arm64__) || defined (__aarch64__) +#if defined(__arm64__) || defined(__aarch64__) #define WATCHPOINTS_ARE_DWORD 1 #else #undef WATCHPOINTS_ARE_DWORD #endif -uint32_t -DNBArchMachARM::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) -{ - - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu, read = %u, write = %u)", (uint64_t)addr, size, read, write); - - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - - // Can't watch zero bytes - if (size == 0) - return INVALID_NUB_HW_INDEX; +uint32_t DNBArchMachARM::EnableHardwareWatchpoint(nub_addr_t addr, + nub_size_t size, bool read, + bool write, + bool also_set_on_task) { - // We must watch for either read or write - if (read == false && write == false) - return INVALID_NUB_HW_INDEX; + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(" + "addr = 0x%8.8llx, size = %zu, read = %u, " + "write = %u)", + (uint64_t)addr, size, read, write); - // Otherwise, can't watch more than 8 bytes per WVR/WCR pair - if (size > 8) - return INVALID_NUB_HW_INDEX; + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - // Treat arm watchpoints as having an 8-byte alignment requirement. You can put a watchpoint on a 4-byte - // offset address but you can only watch 4 bytes with that watchpoint. + // Can't watch zero bytes + if (size == 0) + return INVALID_NUB_HW_INDEX; - // arm watchpoints on an 8-byte (double word) aligned addr can watch any bytes in that - // 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, 3rd byte, etc, or any - // combination therein by setting the bits in the BAS [12:5] (Byte Address Select) field of - // the DBGWCRn_EL1 reg for the watchpoint. + // We must watch for either read or write + if (read == false && write == false) + return INVALID_NUB_HW_INDEX; - // If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to monitor a larger region - // of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield then selects a larger - // range of bytes, instead of individual bytes. See the ARMv8 Debug Architecture manual for details. - // This implementation does not currently use the MASK bits; the largest single region watched by a single - // watchpoint right now is 8-bytes. + // Otherwise, can't watch more than 8 bytes per WVR/WCR pair + if (size > 8) + return INVALID_NUB_HW_INDEX; -#if defined (WATCHPOINTS_ARE_DWORD) - nub_addr_t aligned_wp_address = addr & ~0x7; - uint32_t addr_dword_offset = addr & 0x7; - const int max_watchpoint_size = 8; +// Treat arm watchpoints as having an 8-byte alignment requirement. You can put +// a watchpoint on a 4-byte +// offset address but you can only watch 4 bytes with that watchpoint. + +// arm watchpoints on an 8-byte (double word) aligned addr can watch any bytes +// in that +// 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, 3rd +// byte, etc, or any +// combination therein by setting the bits in the BAS [12:5] (Byte Address +// Select) field of +// the DBGWCRn_EL1 reg for the watchpoint. + +// If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to +// monitor a larger region +// of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield +// then selects a larger +// range of bytes, instead of individual bytes. See the ARMv8 Debug +// Architecture manual for details. +// This implementation does not currently use the MASK bits; the largest single +// region watched by a single +// watchpoint right now is 8-bytes. + +#if defined(WATCHPOINTS_ARE_DWORD) + nub_addr_t aligned_wp_address = addr & ~0x7; + uint32_t addr_dword_offset = addr & 0x7; + const int max_watchpoint_size = 8; #else - nub_addr_t aligned_wp_address = addr & ~0x3; - uint32_t addr_dword_offset = addr & 0x3; - const int max_watchpoint_size = 4; + nub_addr_t aligned_wp_address = addr & ~0x3; + uint32_t addr_dword_offset = addr & 0x3; + const int max_watchpoint_size = 4; #endif - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint aligned_wp_address is 0x%llx and addr_dword_offset is 0x%x", (uint64_t)aligned_wp_address, addr_dword_offset); - - // Do we need to split up this logical watchpoint into two hardware watchpoint - // registers? - // e.g. a watchpoint of length 4 on address 6. We need do this with - // one watchpoint on address 0 with bytes 6 & 7 being monitored - // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored - - if (addr_dword_offset + size > max_watchpoint_size) - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu) needs two hardware watchpoints slots to monitor", (uint64_t)addr, size); - int low_watchpoint_size = max_watchpoint_size - addr_dword_offset; - int high_watchpoint_size = addr_dword_offset + size - max_watchpoint_size; - - uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, write, also_set_on_task); - if (lo == INVALID_NUB_HW_INDEX) - return INVALID_NUB_HW_INDEX; - uint32_t hi = EnableHardwareWatchpoint (aligned_wp_address + max_watchpoint_size, high_watchpoint_size, read, write, also_set_on_task); - if (hi == INVALID_NUB_HW_INDEX) - { - DisableHardwareWatchpoint (lo, also_set_on_task); - return INVALID_NUB_HW_INDEX; - } - // Tag this lo->hi mapping in our database. - LoHi[lo] = hi; - return lo; + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint " + "aligned_wp_address is 0x%llx and " + "addr_dword_offset is 0x%x", + (uint64_t)aligned_wp_address, addr_dword_offset); + + // Do we need to split up this logical watchpoint into two hardware watchpoint + // registers? + // e.g. a watchpoint of length 4 on address 6. We need do this with + // one watchpoint on address 0 with bytes 6 & 7 being monitored + // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored + + if (addr_dword_offset + size > max_watchpoint_size) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::" + "EnableHardwareWatchpoint(addr = " + "0x%8.8llx, size = %zu) needs two " + "hardware watchpoints slots to monitor", + (uint64_t)addr, size); + int low_watchpoint_size = max_watchpoint_size - addr_dword_offset; + int high_watchpoint_size = addr_dword_offset + size - max_watchpoint_size; + + uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, + write, also_set_on_task); + if (lo == INVALID_NUB_HW_INDEX) + return INVALID_NUB_HW_INDEX; + uint32_t hi = EnableHardwareWatchpoint( + aligned_wp_address + max_watchpoint_size, high_watchpoint_size, read, + write, also_set_on_task); + if (hi == INVALID_NUB_HW_INDEX) { + DisableHardwareWatchpoint(lo, also_set_on_task); + return INVALID_NUB_HW_INDEX; } + // Tag this lo->hi mapping in our database. + LoHi[lo] = hi; + return lo; + } + + // At this point + // 1 aligned_wp_address is the requested address rounded down to 8-byte + // alignment + // 2 addr_dword_offset is the offset into that double word (8-byte) region + // that we are watching + // 3 size is the number of bytes within that 8-byte region that we are + // watching + + // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the + // above. + // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, + // etc, up to 0b11111111 for 8. + // then we shift those bits left by the offset into this dword that we are + // interested in. + // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of + // 0b11110000. + uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; + + // Read the debug state + kern_return_t kret = GetDBGState(true); + + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; - // At this point - // 1 aligned_wp_address is the requested address rounded down to 8-byte alignment - // 2 addr_dword_offset is the offset into that double word (8-byte) region that we are watching - // 3 size is the number of bytes within that 8-byte region that we are watching - - // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the above. - // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, etc, up to 0b11111111 for 8. - // then we shift those bits left by the offset into this dword that we are interested in. - // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of 0b11110000. - uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; - - // Read the debug state - kern_return_t kret = GetDBGState(true); - - if (kret == KERN_SUCCESS) - { - // Check to make sure we have the needed hardware support - uint32_t i = 0; - - for (i=0; i<num_hw_watchpoints; ++i) - { - if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) - break; // We found an available hw watchpoint slot (in i) - } - - // See if we found an available hw watchpoint slot above - if (i < num_hw_watchpoints) - { - //DumpDBGState(m_state.dbg); - - // Clear any previous LoHi joined-watchpoint that may have been in use - LoHi[i] = 0; - - // shift our Byte Address Select bits up to the correct bit range for the DBGWCRn_EL1 - byte_address_select = byte_address_select << 5; - - // Make sure bits 1:0 are clear in our address - m_state.dbg.__wvr[i] = aligned_wp_address; // DVA (Data Virtual Address) - m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow the DVA that we will watch - S_USER | // Stop only in user mode - (read ? WCR_LOAD : 0) | // Stop on read access? - (write ? WCR_STORE : 0) | // Stop on write access? - WCR_ENABLE; // Enable this watchpoint; - - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() adding watchpoint on address 0x%llx with control register value 0x%x", (uint64_t) m_state.dbg.__wvr[i], (uint32_t) m_state.dbg.__wcr[i]); - - // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. - - kret = SetDBGState(also_set_on_task); - //DumpDBGState(m_state.dbg); - - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); + for (i = 0; i < num_hw_watchpoints; ++i) { + if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) + break; // We found an available hw watchpoint slot (in i) + } - if (kret == KERN_SUCCESS) - return i; - } - else - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); - } + // See if we found an available hw watchpoint slot above + if (i < num_hw_watchpoints) { + // DumpDBGState(m_state.dbg); + + // Clear any previous LoHi joined-watchpoint that may have been in use + LoHi[i] = 0; + + // shift our Byte Address Select bits up to the correct bit range for the + // DBGWCRn_EL1 + byte_address_select = byte_address_select << 5; + + // Make sure bits 1:0 are clear in our address + m_state.dbg.__wvr[i] = aligned_wp_address; // DVA (Data Virtual Address) + m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow + // the DVA that we will watch + S_USER | // Stop only in user mode + (read ? WCR_LOAD : 0) | // Stop on read access? + (write ? WCR_STORE : 0) | // Stop on write access? + WCR_ENABLE; // Enable this watchpoint; + + DNBLogThreadedIf( + LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint() adding " + "watchpoint on address 0x%llx with control register " + "value 0x%x", + (uint64_t)m_state.dbg.__wvr[i], (uint32_t)m_state.dbg.__wcr[i]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. + + kret = SetDBGState(also_set_on_task); + // DumpDBGState(m_state.dbg); + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::" + "EnableHardwareWatchpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::" + "EnableHardwareWatchpoint(): All " + "hardware resources (%u) are in use.", + num_hw_watchpoints); } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -bool -DNBArchMachARM::ReenableHardwareWatchpoint (uint32_t hw_index) -{ - // If this logical watchpoint # is actually implemented using - // two hardware watchpoint registers, re-enable both of them. +bool DNBArchMachARM::ReenableHardwareWatchpoint(uint32_t hw_index) { + // If this logical watchpoint # is actually implemented using + // two hardware watchpoint registers, re-enable both of them. - if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) - { - return ReenableHardwareWatchpoint_helper (hw_index) && ReenableHardwareWatchpoint_helper (LoHi[hw_index]); - } - else - { - return ReenableHardwareWatchpoint_helper (hw_index); - } + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { + return ReenableHardwareWatchpoint_helper(hw_index) && + ReenableHardwareWatchpoint_helper(LoHi[hw_index]); + } else { + return ReenableHardwareWatchpoint_helper(hw_index); + } } -bool -DNBArchMachARM::ReenableHardwareWatchpoint_helper (uint32_t hw_index) -{ - kern_return_t kret = GetDBGState(false); - if (kret != KERN_SUCCESS) - return false; - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (hw_index >= num_hw_points) - return false; +bool DNBArchMachARM::ReenableHardwareWatchpoint_helper(uint32_t hw_index) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; - m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; - m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; + m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; + m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", - hw_index, - hw_index, - (uint64_t) m_state.dbg.__wvr[hw_index], - hw_index, - (uint64_t) m_state.dbg.__wcr[hw_index]); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::EnableHardwareWatchpoint( " + "%u ) - WVR%u = 0x%8.8llx WCR%u = " + "0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); - // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. - kret = SetDBGState(false); + kret = SetDBGState(false); - return (kret == KERN_SUCCESS); + return (kret == KERN_SUCCESS); } -bool -DNBArchMachARM::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) -{ - if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) - { - return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task) && DisableHardwareWatchpoint_helper (LoHi[hw_index], also_set_on_task); - } - else - { - return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task); - } +bool DNBArchMachARM::DisableHardwareWatchpoint(uint32_t hw_index, + bool also_set_on_task) { + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { + return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task) && + DisableHardwareWatchpoint_helper(LoHi[hw_index], also_set_on_task); + } else { + return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task); + } } -bool -DNBArchMachARM::DisableHardwareWatchpoint_helper (uint32_t hw_index, bool also_set_on_task) -{ - kern_return_t kret = GetDBGState(false); - if (kret != KERN_SUCCESS) - return false; +bool DNBArchMachARM::DisableHardwareWatchpoint_helper(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (hw_index >= num_hw_points) - return false; + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; - m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; - m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; + m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; + m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; - m_state.dbg.__wvr[hw_index] = 0; - m_state.dbg.__wcr[hw_index] = 0; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", - hw_index, - hw_index, - (uint64_t) m_state.dbg.__wvr[hw_index], - hw_index, - (uint64_t) m_state.dbg.__wcr[hw_index]); + m_state.dbg.__wvr[hw_index] = 0; + m_state.dbg.__wcr[hw_index] = 0; + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::DisableHardwareWatchpoint(" + " %u ) - WVR%u = 0x%8.8llx WCR%u = " + "0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); - kret = SetDBGState(also_set_on_task); + kret = SetDBGState(also_set_on_task); - return (kret == KERN_SUCCESS); + return (kret == KERN_SUCCESS); } // Returns -1 if the trailing bit patterns are not one of: // { 0b???1, 0b??10, 0b?100, 0b1000 }. -static inline -int32_t -LowestBitSet(uint32_t val) -{ - for (unsigned i = 0; i < 4; ++i) { - if (bit(val, i)) - return i; - } - return -1; +static inline int32_t LowestBitSet(uint32_t val) { + for (unsigned i = 0; i < 4; ++i) { + if (bit(val, i)) + return i; + } + return -1; } -// Iterate through the debug registers; return the index of the first watchpoint whose address matches. -// As a side effect, the starting address as understood by the debugger is returned which could be +// Iterate through the debug registers; return the index of the first watchpoint +// whose address matches. +// As a side effect, the starting address as understood by the debugger is +// returned which could be // different from 'addr' passed as an in/out argument. -uint32_t -DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr) -{ - // Read the debug state - kern_return_t kret = GetDBGState(true); - //DumpDBGState(m_state.dbg); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); - - // This is the watchpoint value to match against, i.e., word address. -#if defined (WATCHPOINTS_ARE_DWORD) - nub_addr_t wp_val = addr & ~((nub_addr_t)7); +uint32_t DNBArchMachARM::GetHardwareWatchpointHit(nub_addr_t &addr) { + // Read the debug state + kern_return_t kret = GetDBGState(true); + // DumpDBGState(m_state.dbg); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchMachARM::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", + kret); + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM::GetHardwareWatchpointHit() addr = 0x%llx", + (uint64_t)addr); + +// This is the watchpoint value to match against, i.e., word address. +#if defined(WATCHPOINTS_ARE_DWORD) + nub_addr_t wp_val = addr & ~((nub_addr_t)7); #else - nub_addr_t wp_val = addr & ~((nub_addr_t)3); + nub_addr_t wp_val = addr & ~((nub_addr_t)3); #endif - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.dbg; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - { - nub_addr_t wp_addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, - "DNBArchMachARM::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).", - i, (uint64_t)wp_addr); - if (wp_val == wp_addr) { -#if defined (WATCHPOINTS_ARE_DWORD) - uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.dbg; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) { + nub_addr_t wp_addr = GetWatchAddress(debug_state, i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::" + "GetHardwareWatchpointHit() slot: %u " + "(addr = 0x%llx).", + i, (uint64_t)wp_addr); + if (wp_val == wp_addr) { +#if defined(WATCHPOINTS_ARE_DWORD) + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); #else - uint32_t byte_mask = bits(debug_state.__wcr[i], 8, 5); + uint32_t byte_mask = bits(debug_state.__wcr[i], 8, 5); #endif - // Sanity check the byte_mask, first. - if (LowestBitSet(byte_mask) < 0) - continue; + // Sanity check the byte_mask, first. + if (LowestBitSet(byte_mask) < 0) + continue; - // Compute the starting address (from the point of view of the debugger). - addr = wp_addr + LowestBitSet(byte_mask); - return i; - } - } + // Compute the starting address (from the point of view of the + // debugger). + addr = wp_addr + LowestBitSet(byte_mask); + return i; + } } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -nub_addr_t -DNBArchMachARM::GetWatchpointAddressByIndex (uint32_t hw_index) -{ - kern_return_t kret = GetDBGState(true); - if (kret != KERN_SUCCESS) - return INVALID_NUB_ADDRESS; - const uint32_t num = NumSupportedHardwareWatchpoints(); - if (hw_index >= num) - return INVALID_NUB_ADDRESS; - if (IsWatchpointEnabled (m_state.dbg, hw_index)) - return GetWatchAddress (m_state.dbg, hw_index); +nub_addr_t DNBArchMachARM::GetWatchpointAddressByIndex(uint32_t hw_index) { + kern_return_t kret = GetDBGState(true); + if (kret != KERN_SUCCESS) return INVALID_NUB_ADDRESS; + const uint32_t num = NumSupportedHardwareWatchpoints(); + if (hw_index >= num) + return INVALID_NUB_ADDRESS; + if (IsWatchpointEnabled(m_state.dbg, hw_index)) + return GetWatchAddress(m_state.dbg, hw_index); + return INVALID_NUB_ADDRESS; } -bool -DNBArchMachARM::IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index) -{ - // Watchpoint Control Registers, bitfield definitions - // ... - // Bits Value Description - // [0] 0 Watchpoint disabled - // 1 Watchpoint enabled. - return (debug_state.__wcr[hw_index] & 1u); +bool DNBArchMachARM::IsWatchpointEnabled(const DBG &debug_state, + uint32_t hw_index) { + // Watchpoint Control Registers, bitfield definitions + // ... + // Bits Value Description + // [0] 0 Watchpoint disabled + // 1 Watchpoint enabled. + return (debug_state.__wcr[hw_index] & 1u); } -nub_addr_t -DNBArchMachARM::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) -{ - // Watchpoint Value Registers, bitfield definitions - // Bits Description - // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) - // [1:0] RAZ/SBZP - return bits(debug_state.__wvr[hw_index], 31, 0); +nub_addr_t DNBArchMachARM::GetWatchAddress(const DBG &debug_state, + uint32_t hw_index) { + // Watchpoint Value Registers, bitfield definitions + // Bits Description + // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) + // [1:0] RAZ/SBZP + return bits(debug_state.__wvr[hw_index], 31, 0); } //---------------------------------------------------------------------- // Register information definitions for 32 bit ARMV7. //---------------------------------------------------------------------- -enum gpr_regnums -{ - 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_sp, - gpr_lr, - gpr_pc, - gpr_cpsr +enum gpr_regnums { + 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_sp, + gpr_lr, + gpr_pc, + gpr_cpsr }; -enum -{ - vfp_s0 = 0, - vfp_s1, - vfp_s2, - vfp_s3, - vfp_s4, - vfp_s5, - vfp_s6, - vfp_s7, - vfp_s8, - vfp_s9, - vfp_s10, - vfp_s11, - vfp_s12, - vfp_s13, - vfp_s14, - vfp_s15, - vfp_s16, - vfp_s17, - vfp_s18, - vfp_s19, - vfp_s20, - vfp_s21, - vfp_s22, - vfp_s23, - vfp_s24, - vfp_s25, - vfp_s26, - vfp_s27, - vfp_s28, - vfp_s29, - vfp_s30, - vfp_s31, - vfp_d0, - vfp_d1, - vfp_d2, - vfp_d3, - vfp_d4, - vfp_d5, - vfp_d6, - vfp_d7, - vfp_d8, - vfp_d9, - vfp_d10, - vfp_d11, - vfp_d12, - vfp_d13, - vfp_d14, - vfp_d15, - vfp_d16, - vfp_d17, - vfp_d18, - vfp_d19, - vfp_d20, - vfp_d21, - vfp_d22, - vfp_d23, - vfp_d24, - vfp_d25, - vfp_d26, - vfp_d27, - vfp_d28, - vfp_d29, - vfp_d30, - vfp_d31, - vfp_q0, - vfp_q1, - vfp_q2, - vfp_q3, - vfp_q4, - vfp_q5, - vfp_q6, - vfp_q7, - vfp_q8, - vfp_q9, - vfp_q10, - vfp_q11, - vfp_q12, - vfp_q13, - vfp_q14, - vfp_q15, -#if defined (__arm64__) || defined (__aarch64__) - vfp_fpsr, - vfp_fpcr, +enum { + vfp_s0 = 0, + vfp_s1, + vfp_s2, + vfp_s3, + vfp_s4, + vfp_s5, + vfp_s6, + vfp_s7, + vfp_s8, + vfp_s9, + vfp_s10, + vfp_s11, + vfp_s12, + vfp_s13, + vfp_s14, + vfp_s15, + vfp_s16, + vfp_s17, + vfp_s18, + vfp_s19, + vfp_s20, + vfp_s21, + vfp_s22, + vfp_s23, + vfp_s24, + vfp_s25, + vfp_s26, + vfp_s27, + vfp_s28, + vfp_s29, + vfp_s30, + vfp_s31, + vfp_d0, + vfp_d1, + vfp_d2, + vfp_d3, + vfp_d4, + vfp_d5, + vfp_d6, + vfp_d7, + vfp_d8, + vfp_d9, + vfp_d10, + vfp_d11, + vfp_d12, + vfp_d13, + vfp_d14, + vfp_d15, + vfp_d16, + vfp_d17, + vfp_d18, + vfp_d19, + vfp_d20, + vfp_d21, + vfp_d22, + vfp_d23, + vfp_d24, + vfp_d25, + vfp_d26, + vfp_d27, + vfp_d28, + vfp_d29, + vfp_d30, + vfp_d31, + vfp_q0, + vfp_q1, + vfp_q2, + vfp_q3, + vfp_q4, + vfp_q5, + vfp_q6, + vfp_q7, + vfp_q8, + vfp_q9, + vfp_q10, + vfp_q11, + vfp_q12, + vfp_q13, + vfp_q14, + vfp_q15, +#if defined(__arm64__) || defined(__aarch64__) + vfp_fpsr, + vfp_fpcr, #else - vfp_fpscr + vfp_fpscr #endif }; -enum -{ - exc_exception, - exc_fsr, - exc_far, +enum { + exc_exception, + exc_fsr, + exc_far, }; -#define GPR_OFFSET_IDX(idx) (offsetof (DNBArchMachARM::GPR, __r[idx])) -#define GPR_OFFSET_NAME(reg) (offsetof (DNBArchMachARM::GPR, __##reg)) +#define GPR_OFFSET_IDX(idx) (offsetof(DNBArchMachARM::GPR, __r[idx])) +#define GPR_OFFSET_NAME(reg) (offsetof(DNBArchMachARM::GPR, __##reg)) -#define EXC_OFFSET(reg) (offsetof (DNBArchMachARM::EXC, __##reg) + offsetof (DNBArchMachARM::Context, exc)) +#define EXC_OFFSET(reg) \ + (offsetof(DNBArchMachARM::EXC, __##reg) + \ + offsetof(DNBArchMachARM::Context, exc)) // These macros will auto define the register name, alt name, register size, // register offset, encoding, format and native register. This ensures that // the register state structures are defined correctly and have the correct // sizes and offsets. -#define DEFINE_GPR_IDX(idx, reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 4, GPR_OFFSET_IDX(idx), ehframe_##reg, dwarf_##reg, gen, INVALID_NUB_REGNUM, NULL, NULL} -#define DEFINE_GPR_NAME(reg, alt, gen, inval) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 4, GPR_OFFSET_NAME(reg), ehframe_##reg, dwarf_##reg, gen, INVALID_NUB_REGNUM, NULL, inval} +#define DEFINE_GPR_IDX(idx, reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 4, GPR_OFFSET_IDX(idx), \ + ehframe_##reg, dwarf_##reg, gen, INVALID_NUB_REGNUM, NULL, NULL \ + } +#define DEFINE_GPR_NAME(reg, alt, gen, inval) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 4, GPR_OFFSET_NAME(reg), \ + ehframe_##reg, dwarf_##reg, gen, INVALID_NUB_REGNUM, NULL, inval \ + } // In case we are debugging to a debug target that the ability to // change into the protected modes with folded registers (ABT, IRQ, // FIQ, SYS, USR, etc..), we should invalidate r8-r14 if the CPSR // gets modified. -const char * g_invalidate_cpsr[] = { "r8", "r9", "r10", "r11", "r12", "sp", "lr", NULL }; +const char *g_invalidate_cpsr[] = {"r8", "r9", "r10", "r11", + "r12", "sp", "lr", NULL}; // General purpose registers -const DNBRegisterInfo -DNBArchMachARM::g_gpr_registers[] = -{ - DEFINE_GPR_IDX ( 0, r0,"arg1", GENERIC_REGNUM_ARG1 ), - DEFINE_GPR_IDX ( 1, r1,"arg2", GENERIC_REGNUM_ARG2 ), - DEFINE_GPR_IDX ( 2, r2,"arg3", GENERIC_REGNUM_ARG3 ), - DEFINE_GPR_IDX ( 3, r3,"arg4", GENERIC_REGNUM_ARG4 ), - DEFINE_GPR_IDX ( 4, r4, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX ( 5, r5, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX ( 6, r6, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX ( 7, r7, "fp", GENERIC_REGNUM_FP ), - DEFINE_GPR_IDX ( 8, r8, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX ( 9, r9, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (10, r10, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (11, r11, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (12, r12, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_NAME (sp, "r13", GENERIC_REGNUM_SP, NULL), - DEFINE_GPR_NAME (lr, "r14", GENERIC_REGNUM_RA, NULL), - DEFINE_GPR_NAME (pc, "r15", GENERIC_REGNUM_PC, NULL), - DEFINE_GPR_NAME (cpsr, "flags", GENERIC_REGNUM_FLAGS, g_invalidate_cpsr) -}; - -const char *g_contained_q0 [] { "q0", NULL }; -const char *g_contained_q1 [] { "q1", NULL }; -const char *g_contained_q2 [] { "q2", NULL }; -const char *g_contained_q3 [] { "q3", NULL }; -const char *g_contained_q4 [] { "q4", NULL }; -const char *g_contained_q5 [] { "q5", NULL }; -const char *g_contained_q6 [] { "q6", NULL }; -const char *g_contained_q7 [] { "q7", NULL }; -const char *g_contained_q8 [] { "q8", NULL }; -const char *g_contained_q9 [] { "q9", NULL }; -const char *g_contained_q10[] { "q10", NULL }; -const char *g_contained_q11[] { "q11", NULL }; -const char *g_contained_q12[] { "q12", NULL }; -const char *g_contained_q13[] { "q13", NULL }; -const char *g_contained_q14[] { "q14", NULL }; -const char *g_contained_q15[] { "q15", NULL }; - -const char *g_invalidate_q0[] { "q0", "d0" , "d1" , "s0" , "s1" , "s2" , "s3" , NULL }; -const char *g_invalidate_q1[] { "q1", "d2" , "d3" , "s4" , "s5" , "s6" , "s7" , NULL }; -const char *g_invalidate_q2[] { "q2", "d4" , "d5" , "s8" , "s9" , "s10", "s11", NULL }; -const char *g_invalidate_q3[] { "q3", "d6" , "d7" , "s12", "s13", "s14", "s15", NULL }; -const char *g_invalidate_q4[] { "q4", "d8" , "d9" , "s16", "s17", "s18", "s19", NULL }; -const char *g_invalidate_q5[] { "q5", "d10", "d11", "s20", "s21", "s22", "s23", NULL }; -const char *g_invalidate_q6[] { "q6", "d12", "d13", "s24", "s25", "s26", "s27", NULL }; -const char *g_invalidate_q7[] { "q7", "d14", "d15", "s28", "s29", "s30", "s31", NULL }; -const char *g_invalidate_q8[] { "q8", "d16", "d17", NULL }; -const char *g_invalidate_q9[] { "q9", "d18", "d19", NULL }; -const char *g_invalidate_q10[] { "q10", "d20", "d21", NULL }; -const char *g_invalidate_q11[] { "q11", "d22", "d23", NULL }; -const char *g_invalidate_q12[] { "q12", "d24", "d25", NULL }; -const char *g_invalidate_q13[] { "q13", "d26", "d27", NULL }; -const char *g_invalidate_q14[] { "q14", "d28", "d29", NULL }; -const char *g_invalidate_q15[] { "q15", "d30", "d31", NULL }; - -#define VFP_S_OFFSET_IDX(idx) (((idx) % 4) * 4) // offset into q reg: 0, 4, 8, 12 -#define VFP_D_OFFSET_IDX(idx) (((idx) % 2) * 8) // offset into q reg: 0, 8 -#define VFP_Q_OFFSET_IDX(idx) (VFP_S_OFFSET_IDX ((idx) * 4)) - -#define VFP_OFFSET_NAME(reg) (offsetof (DNBArchMachARM::FPU, __##reg) + offsetof (DNBArchMachARM::Context, vfp)) +const DNBRegisterInfo DNBArchMachARM::g_gpr_registers[] = { + DEFINE_GPR_IDX(0, r0, "arg1", GENERIC_REGNUM_ARG1), + DEFINE_GPR_IDX(1, r1, "arg2", GENERIC_REGNUM_ARG2), + DEFINE_GPR_IDX(2, r2, "arg3", GENERIC_REGNUM_ARG3), + DEFINE_GPR_IDX(3, r3, "arg4", GENERIC_REGNUM_ARG4), + DEFINE_GPR_IDX(4, r4, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(5, r5, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(6, r6, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(7, r7, "fp", GENERIC_REGNUM_FP), + DEFINE_GPR_IDX(8, r8, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(9, r9, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(10, r10, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(11, r11, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(12, r12, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_NAME(sp, "r13", GENERIC_REGNUM_SP, NULL), + DEFINE_GPR_NAME(lr, "r14", GENERIC_REGNUM_RA, NULL), + DEFINE_GPR_NAME(pc, "r15", GENERIC_REGNUM_PC, NULL), + DEFINE_GPR_NAME(cpsr, "flags", GENERIC_REGNUM_FLAGS, g_invalidate_cpsr)}; + +const char *g_contained_q0[]{"q0", NULL}; +const char *g_contained_q1[]{"q1", NULL}; +const char *g_contained_q2[]{"q2", NULL}; +const char *g_contained_q3[]{"q3", NULL}; +const char *g_contained_q4[]{"q4", NULL}; +const char *g_contained_q5[]{"q5", NULL}; +const char *g_contained_q6[]{"q6", NULL}; +const char *g_contained_q7[]{"q7", NULL}; +const char *g_contained_q8[]{"q8", NULL}; +const char *g_contained_q9[]{"q9", NULL}; +const char *g_contained_q10[]{"q10", NULL}; +const char *g_contained_q11[]{"q11", NULL}; +const char *g_contained_q12[]{"q12", NULL}; +const char *g_contained_q13[]{"q13", NULL}; +const char *g_contained_q14[]{"q14", NULL}; +const char *g_contained_q15[]{"q15", NULL}; + +const char *g_invalidate_q0[]{"q0", "d0", "d1", "s0", "s1", "s2", "s3", NULL}; +const char *g_invalidate_q1[]{"q1", "d2", "d3", "s4", "s5", "s6", "s7", NULL}; +const char *g_invalidate_q2[]{"q2", "d4", "d5", "s8", "s9", "s10", "s11", NULL}; +const char *g_invalidate_q3[]{"q3", "d6", "d7", "s12", + "s13", "s14", "s15", NULL}; +const char *g_invalidate_q4[]{"q4", "d8", "d9", "s16", + "s17", "s18", "s19", NULL}; +const char *g_invalidate_q5[]{"q5", "d10", "d11", "s20", + "s21", "s22", "s23", NULL}; +const char *g_invalidate_q6[]{"q6", "d12", "d13", "s24", + "s25", "s26", "s27", NULL}; +const char *g_invalidate_q7[]{"q7", "d14", "d15", "s28", + "s29", "s30", "s31", NULL}; +const char *g_invalidate_q8[]{"q8", "d16", "d17", NULL}; +const char *g_invalidate_q9[]{"q9", "d18", "d19", NULL}; +const char *g_invalidate_q10[]{"q10", "d20", "d21", NULL}; +const char *g_invalidate_q11[]{"q11", "d22", "d23", NULL}; +const char *g_invalidate_q12[]{"q12", "d24", "d25", NULL}; +const char *g_invalidate_q13[]{"q13", "d26", "d27", NULL}; +const char *g_invalidate_q14[]{"q14", "d28", "d29", NULL}; +const char *g_invalidate_q15[]{"q15", "d30", "d31", NULL}; + +#define VFP_S_OFFSET_IDX(idx) \ + (((idx) % 4) * 4) // offset into q reg: 0, 4, 8, 12 +#define VFP_D_OFFSET_IDX(idx) (((idx) % 2) * 8) // offset into q reg: 0, 8 +#define VFP_Q_OFFSET_IDX(idx) (VFP_S_OFFSET_IDX((idx)*4)) + +#define VFP_OFFSET_NAME(reg) \ + (offsetof(DNBArchMachARM::FPU, __##reg) + \ + offsetof(DNBArchMachARM::Context, vfp)) #define FLOAT_FORMAT Float -#define DEFINE_VFP_S_IDX(idx) e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, FLOAT_FORMAT, 4, VFP_S_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_s##idx, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM -#define DEFINE_VFP_D_IDX(idx) e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, FLOAT_FORMAT, 8, VFP_D_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_d##idx, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM -#define DEFINE_VFP_Q_IDX(idx) e_regSetVFP, vfp_q##idx, "q" #idx, NULL, Vector, VectorOfUInt8, 16, VFP_Q_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_q##idx, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM +#define DEFINE_VFP_S_IDX(idx) \ + e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, FLOAT_FORMAT, 4, \ + VFP_S_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_s##idx, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM +#define DEFINE_VFP_D_IDX(idx) \ + e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, FLOAT_FORMAT, 8, \ + VFP_D_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_d##idx, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM +#define DEFINE_VFP_Q_IDX(idx) \ + e_regSetVFP, vfp_q##idx, "q" #idx, NULL, Vector, VectorOfUInt8, 16, \ + VFP_Q_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_q##idx, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM // Floating point registers -const DNBRegisterInfo -DNBArchMachARM::g_vfp_registers[] = -{ - { DEFINE_VFP_S_IDX ( 0), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_S_IDX ( 1), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_S_IDX ( 2), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_S_IDX ( 3), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_S_IDX ( 4), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_S_IDX ( 5), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_S_IDX ( 6), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_S_IDX ( 7), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_S_IDX ( 8), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_S_IDX ( 9), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_S_IDX (10), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_S_IDX (11), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_S_IDX (12), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_S_IDX (13), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_S_IDX (14), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_S_IDX (15), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_S_IDX (16), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_S_IDX (17), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_S_IDX (18), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_S_IDX (19), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_S_IDX (20), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_S_IDX (21), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_S_IDX (22), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_S_IDX (23), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_S_IDX (24), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_S_IDX (25), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_S_IDX (26), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_S_IDX (27), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_S_IDX (28), g_contained_q7, g_invalidate_q7 }, - { DEFINE_VFP_S_IDX (29), g_contained_q7, g_invalidate_q7 }, - { DEFINE_VFP_S_IDX (30), g_contained_q7, g_invalidate_q7 }, - { DEFINE_VFP_S_IDX (31), g_contained_q7, g_invalidate_q7 }, - - { DEFINE_VFP_D_IDX (0), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_D_IDX (1), g_contained_q0, g_invalidate_q0 }, - { DEFINE_VFP_D_IDX (2), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_D_IDX (3), g_contained_q1, g_invalidate_q1 }, - { DEFINE_VFP_D_IDX (4), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_D_IDX (5), g_contained_q2, g_invalidate_q2 }, - { DEFINE_VFP_D_IDX (6), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_D_IDX (7), g_contained_q3, g_invalidate_q3 }, - { DEFINE_VFP_D_IDX (8), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_D_IDX (9), g_contained_q4, g_invalidate_q4 }, - { DEFINE_VFP_D_IDX (10), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_D_IDX (11), g_contained_q5, g_invalidate_q5 }, - { DEFINE_VFP_D_IDX (12), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_D_IDX (13), g_contained_q6, g_invalidate_q6 }, - { DEFINE_VFP_D_IDX (14), g_contained_q7, g_invalidate_q7 }, - { DEFINE_VFP_D_IDX (15), g_contained_q7, g_invalidate_q7 }, - { DEFINE_VFP_D_IDX (16), g_contained_q8, g_invalidate_q8 }, - { DEFINE_VFP_D_IDX (17), g_contained_q8, g_invalidate_q8 }, - { DEFINE_VFP_D_IDX (18), g_contained_q9, g_invalidate_q9 }, - { DEFINE_VFP_D_IDX (19), g_contained_q9, g_invalidate_q9 }, - { DEFINE_VFP_D_IDX (20), g_contained_q10, g_invalidate_q10 }, - { DEFINE_VFP_D_IDX (21), g_contained_q10, g_invalidate_q10 }, - { DEFINE_VFP_D_IDX (22), g_contained_q11, g_invalidate_q11 }, - { DEFINE_VFP_D_IDX (23), g_contained_q11, g_invalidate_q11 }, - { DEFINE_VFP_D_IDX (24), g_contained_q12, g_invalidate_q12 }, - { DEFINE_VFP_D_IDX (25), g_contained_q12, g_invalidate_q12 }, - { DEFINE_VFP_D_IDX (26), g_contained_q13, g_invalidate_q13 }, - { DEFINE_VFP_D_IDX (27), g_contained_q13, g_invalidate_q13 }, - { DEFINE_VFP_D_IDX (28), g_contained_q14, g_invalidate_q14 }, - { DEFINE_VFP_D_IDX (29), g_contained_q14, g_invalidate_q14 }, - { DEFINE_VFP_D_IDX (30), g_contained_q15, g_invalidate_q15 }, - { DEFINE_VFP_D_IDX (31), g_contained_q15, g_invalidate_q15 }, - - { DEFINE_VFP_Q_IDX (0), NULL, g_invalidate_q0 }, - { DEFINE_VFP_Q_IDX (1), NULL, g_invalidate_q1 }, - { DEFINE_VFP_Q_IDX (2), NULL, g_invalidate_q2 }, - { DEFINE_VFP_Q_IDX (3), NULL, g_invalidate_q3 }, - { DEFINE_VFP_Q_IDX (4), NULL, g_invalidate_q4 }, - { DEFINE_VFP_Q_IDX (5), NULL, g_invalidate_q5 }, - { DEFINE_VFP_Q_IDX (6), NULL, g_invalidate_q6 }, - { DEFINE_VFP_Q_IDX (7), NULL, g_invalidate_q7 }, - { DEFINE_VFP_Q_IDX (8), NULL, g_invalidate_q8 }, - { DEFINE_VFP_Q_IDX (9), NULL, g_invalidate_q9 }, - { DEFINE_VFP_Q_IDX (10), NULL, g_invalidate_q10 }, - { DEFINE_VFP_Q_IDX (11), NULL, g_invalidate_q11 }, - { DEFINE_VFP_Q_IDX (12), NULL, g_invalidate_q12 }, - { DEFINE_VFP_Q_IDX (13), NULL, g_invalidate_q13 }, - { DEFINE_VFP_Q_IDX (14), NULL, g_invalidate_q14 }, - { DEFINE_VFP_Q_IDX (15), NULL, g_invalidate_q15 }, - -#if defined (__arm64__) || defined (__aarch64__) - { e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, VFP_OFFSET_NAME(fpsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - { e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, VFP_OFFSET_NAME(fpcr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL } +const DNBRegisterInfo DNBArchMachARM::g_vfp_registers[] = { + {DEFINE_VFP_S_IDX(0), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_S_IDX(1), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_S_IDX(2), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_S_IDX(3), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_S_IDX(4), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_S_IDX(5), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_S_IDX(6), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_S_IDX(7), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_S_IDX(8), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_S_IDX(9), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_S_IDX(10), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_S_IDX(11), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_S_IDX(12), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_S_IDX(13), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_S_IDX(14), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_S_IDX(15), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_S_IDX(16), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_S_IDX(17), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_S_IDX(18), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_S_IDX(19), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_S_IDX(20), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_S_IDX(21), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_S_IDX(22), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_S_IDX(23), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_S_IDX(24), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_S_IDX(25), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_S_IDX(26), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_S_IDX(27), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_S_IDX(28), g_contained_q7, g_invalidate_q7}, + {DEFINE_VFP_S_IDX(29), g_contained_q7, g_invalidate_q7}, + {DEFINE_VFP_S_IDX(30), g_contained_q7, g_invalidate_q7}, + {DEFINE_VFP_S_IDX(31), g_contained_q7, g_invalidate_q7}, + + {DEFINE_VFP_D_IDX(0), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_D_IDX(1), g_contained_q0, g_invalidate_q0}, + {DEFINE_VFP_D_IDX(2), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_D_IDX(3), g_contained_q1, g_invalidate_q1}, + {DEFINE_VFP_D_IDX(4), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_D_IDX(5), g_contained_q2, g_invalidate_q2}, + {DEFINE_VFP_D_IDX(6), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_D_IDX(7), g_contained_q3, g_invalidate_q3}, + {DEFINE_VFP_D_IDX(8), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_D_IDX(9), g_contained_q4, g_invalidate_q4}, + {DEFINE_VFP_D_IDX(10), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_D_IDX(11), g_contained_q5, g_invalidate_q5}, + {DEFINE_VFP_D_IDX(12), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_D_IDX(13), g_contained_q6, g_invalidate_q6}, + {DEFINE_VFP_D_IDX(14), g_contained_q7, g_invalidate_q7}, + {DEFINE_VFP_D_IDX(15), g_contained_q7, g_invalidate_q7}, + {DEFINE_VFP_D_IDX(16), g_contained_q8, g_invalidate_q8}, + {DEFINE_VFP_D_IDX(17), g_contained_q8, g_invalidate_q8}, + {DEFINE_VFP_D_IDX(18), g_contained_q9, g_invalidate_q9}, + {DEFINE_VFP_D_IDX(19), g_contained_q9, g_invalidate_q9}, + {DEFINE_VFP_D_IDX(20), g_contained_q10, g_invalidate_q10}, + {DEFINE_VFP_D_IDX(21), g_contained_q10, g_invalidate_q10}, + {DEFINE_VFP_D_IDX(22), g_contained_q11, g_invalidate_q11}, + {DEFINE_VFP_D_IDX(23), g_contained_q11, g_invalidate_q11}, + {DEFINE_VFP_D_IDX(24), g_contained_q12, g_invalidate_q12}, + {DEFINE_VFP_D_IDX(25), g_contained_q12, g_invalidate_q12}, + {DEFINE_VFP_D_IDX(26), g_contained_q13, g_invalidate_q13}, + {DEFINE_VFP_D_IDX(27), g_contained_q13, g_invalidate_q13}, + {DEFINE_VFP_D_IDX(28), g_contained_q14, g_invalidate_q14}, + {DEFINE_VFP_D_IDX(29), g_contained_q14, g_invalidate_q14}, + {DEFINE_VFP_D_IDX(30), g_contained_q15, g_invalidate_q15}, + {DEFINE_VFP_D_IDX(31), g_contained_q15, g_invalidate_q15}, + + {DEFINE_VFP_Q_IDX(0), NULL, g_invalidate_q0}, + {DEFINE_VFP_Q_IDX(1), NULL, g_invalidate_q1}, + {DEFINE_VFP_Q_IDX(2), NULL, g_invalidate_q2}, + {DEFINE_VFP_Q_IDX(3), NULL, g_invalidate_q3}, + {DEFINE_VFP_Q_IDX(4), NULL, g_invalidate_q4}, + {DEFINE_VFP_Q_IDX(5), NULL, g_invalidate_q5}, + {DEFINE_VFP_Q_IDX(6), NULL, g_invalidate_q6}, + {DEFINE_VFP_Q_IDX(7), NULL, g_invalidate_q7}, + {DEFINE_VFP_Q_IDX(8), NULL, g_invalidate_q8}, + {DEFINE_VFP_Q_IDX(9), NULL, g_invalidate_q9}, + {DEFINE_VFP_Q_IDX(10), NULL, g_invalidate_q10}, + {DEFINE_VFP_Q_IDX(11), NULL, g_invalidate_q11}, + {DEFINE_VFP_Q_IDX(12), NULL, g_invalidate_q12}, + {DEFINE_VFP_Q_IDX(13), NULL, g_invalidate_q13}, + {DEFINE_VFP_Q_IDX(14), NULL, g_invalidate_q14}, + {DEFINE_VFP_Q_IDX(15), NULL, g_invalidate_q15}, + +#if defined(__arm64__) || defined(__aarch64__) + {e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, VFP_OFFSET_NAME(fpsr), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, VFP_OFFSET_NAME(fpcr), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL} #else - { e_regSetVFP, vfp_fpscr, "fpscr", NULL, Uint, Hex, 4, VFP_OFFSET_NAME(fpscr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL } + {e_regSetVFP, vfp_fpscr, "fpscr", NULL, Uint, Hex, 4, + VFP_OFFSET_NAME(fpscr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL} #endif }; // Exception registers -const DNBRegisterInfo -DNBArchMachARM::g_exc_registers[] = -{ - { e_regSetVFP, exc_exception , "exception" , NULL, Uint, Hex, 4, EXC_OFFSET(exception) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM }, - { e_regSetVFP, exc_fsr , "fsr" , NULL, Uint, Hex, 4, EXC_OFFSET(fsr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM }, - { e_regSetVFP, exc_far , "far" , NULL, Uint, Hex, 4, EXC_OFFSET(far) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM } -}; +const DNBRegisterInfo DNBArchMachARM::g_exc_registers[] = { + {e_regSetVFP, exc_exception, "exception", NULL, Uint, Hex, 4, + EXC_OFFSET(exception), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM}, + {e_regSetVFP, exc_fsr, "fsr", NULL, Uint, Hex, 4, EXC_OFFSET(fsr), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM}, + {e_regSetVFP, exc_far, "far", NULL, Uint, Hex, 4, EXC_OFFSET(far), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM}}; // Number of registers in each register set -const size_t DNBArchMachARM::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM::k_num_vfp_registers = sizeof(g_vfp_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM::k_num_all_registers = k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers; +const size_t DNBArchMachARM::k_num_gpr_registers = + sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM::k_num_vfp_registers = + sizeof(g_vfp_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM::k_num_exc_registers = + sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM::k_num_all_registers = + k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers; //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index // of zero is for all registers, followed by other registers sets. The // register information for the all register set need not be filled in. //---------------------------------------------------------------------- -const DNBRegisterSetInfo -DNBArchMachARM::g_reg_sets[] = -{ - { "ARM Registers", NULL, k_num_all_registers }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_vfp_registers, k_num_vfp_registers }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; +const DNBRegisterSetInfo DNBArchMachARM::g_reg_sets[] = { + {"ARM Registers", NULL, k_num_all_registers}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_vfp_registers, k_num_vfp_registers}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; // Total number of register sets for this architecture -const size_t DNBArchMachARM::k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo); - +const size_t DNBArchMachARM::k_num_register_sets = + sizeof(g_reg_sets) / sizeof(DNBRegisterSetInfo); const DNBRegisterSetInfo * -DNBArchMachARM::GetRegisterSetInfo(nub_size_t *num_reg_sets) -{ - *num_reg_sets = k_num_register_sets; - return g_reg_sets; +DNBArchMachARM::GetRegisterSetInfo(nub_size_t *num_reg_sets) { + *num_reg_sets = k_num_register_sets; + return g_reg_sets; } -bool -DNBArchMachARM::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_pc; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_sp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_r7; // is this the right reg? - break; - - case GENERIC_REGNUM_RA: // Return Address - set = e_regSetGPR; - reg = gpr_lr; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_cpsr; - break; - - default: - return false; - } +bool DNBArchMachARM::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_pc; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_sp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_r7; // is this the right reg? + break; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = gpr_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_cpsr; + break; + + default: + return false; } + } + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - value->info = *regInfo; - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - value->value.uint32 = m_state.context.gpr.__r[reg]; - return true; - } - break; - - case e_regSetVFP: - // "reg" is an index into the floating point register set at this point. - // We need to translate it up so entry 0 in the fp reg set is the same as vfp_s0 - // in the enumerated values for case statement below. - if (reg >= vfp_s0 && reg <= vfp_s31) - { -#if defined (__arm64__) || defined (__aarch64__) - uint32_t *s_reg = ((uint32_t *) &m_state.context.vfp.__v[0]) + (reg - vfp_s0); - memcpy (&value->value.v_uint8, s_reg, 4); + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + value->info = *regInfo; + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + value->value.uint32 = m_state.context.gpr.__r[reg]; + return true; + } + break; + + case e_regSetVFP: + // "reg" is an index into the floating point register set at this point. + // We need to translate it up so entry 0 in the fp reg set is the same as + // vfp_s0 + // in the enumerated values for case statement below. + if (reg >= vfp_s0 && reg <= vfp_s31) { +#if defined(__arm64__) || defined(__aarch64__) + uint32_t *s_reg = + ((uint32_t *)&m_state.context.vfp.__v[0]) + (reg - vfp_s0); + memcpy(&value->value.v_uint8, s_reg, 4); #else - value->value.uint32 = m_state.context.vfp.__r[reg]; + value->value.uint32 = m_state.context.vfp.__r[reg]; #endif - return true; - } - else if (reg >= vfp_d0 && reg <= vfp_d31) - { -#if defined (__arm64__) || defined (__aarch64__) - uint64_t *d_reg = ((uint64_t *) &m_state.context.vfp.__v[0]) + (reg - vfp_d0); - memcpy (&value->value.v_uint8, d_reg, 8); + return true; + } else if (reg >= vfp_d0 && reg <= vfp_d31) { +#if defined(__arm64__) || defined(__aarch64__) + uint64_t *d_reg = + ((uint64_t *)&m_state.context.vfp.__v[0]) + (reg - vfp_d0); + memcpy(&value->value.v_uint8, d_reg, 8); #else - uint32_t d_reg_idx = reg - vfp_d0; - uint32_t s_reg_idx = d_reg_idx * 2; - value->value.v_sint32[0] = m_state.context.vfp.__r[s_reg_idx + 0]; - value->value.v_sint32[1] = m_state.context.vfp.__r[s_reg_idx + 1]; + uint32_t d_reg_idx = reg - vfp_d0; + uint32_t s_reg_idx = d_reg_idx * 2; + value->value.v_sint32[0] = m_state.context.vfp.__r[s_reg_idx + 0]; + value->value.v_sint32[1] = m_state.context.vfp.__r[s_reg_idx + 1]; #endif - return true; - } - else if (reg >= vfp_q0 && reg <= vfp_q15) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.v_uint8, (uint8_t *) &m_state.context.vfp.__v[reg - vfp_q0], 16); + return true; + } else if (reg >= vfp_q0 && reg <= vfp_q15) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.v_uint8, + (uint8_t *)&m_state.context.vfp.__v[reg - vfp_q0], 16); #else - uint32_t s_reg_idx = (reg - vfp_q0) * 4; - memcpy (&value->value.v_uint8, (uint8_t *) &m_state.context.vfp.__r[s_reg_idx], 16); + uint32_t s_reg_idx = (reg - vfp_q0) * 4; + memcpy(&value->value.v_uint8, + (uint8_t *)&m_state.context.vfp.__r[s_reg_idx], 16); #endif - return true; - } -#if defined (__arm64__) || defined (__aarch64__) - else if (reg == vfp_fpsr) - { - value->value.uint32 = m_state.context.vfp.__fpsr; - return true; - } - else if (reg == vfp_fpcr) - { - value->value.uint32 = m_state.context.vfp.__fpcr; - return true; - } + return true; + } +#if defined(__arm64__) || defined(__aarch64__) + else if (reg == vfp_fpsr) { + value->value.uint32 = m_state.context.vfp.__fpsr; + return true; + } else if (reg == vfp_fpcr) { + value->value.uint32 = m_state.context.vfp.__fpcr; + return true; + } #else - else if (reg == vfp_fpscr) - { - value->value.uint32 = m_state.context.vfp.__fpscr; - return true; - } + else if (reg == vfp_fpscr) { + value->value.uint32 = m_state.context.vfp.__fpscr; + return true; + } #endif - break; - - case e_regSetEXC: - if (reg < k_num_exc_registers) - { - value->value.uint32 = (&m_state.context.exc.__exception)[reg]; - return true; - } - break; - } + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) { + value->value.uint32 = (&m_state.context.exc.__exception)[reg]; + return true; + } + break; } - return false; + } + return false; } -bool -DNBArchMachARM::SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_pc; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_sp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_r7; - break; - - case GENERIC_REGNUM_RA: // Return Address - set = e_regSetGPR; - reg = gpr_lr; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_cpsr; - break; - - default: - return false; - } +bool DNBArchMachARM::SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_pc; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_sp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_r7; + break; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = gpr_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_cpsr; + break; + + default: + return false; } + } - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - bool success = false; - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - m_state.context.gpr.__r[reg] = value->value.uint32; - success = true; - } - break; - - case e_regSetVFP: - // "reg" is an index into the floating point register set at this point. - // We need to translate it up so entry 0 in the fp reg set is the same as vfp_s0 - // in the enumerated values for case statement below. - if (reg >= vfp_s0 && reg <= vfp_s31) - { -#if defined (__arm64__) || defined (__aarch64__) - uint32_t *s_reg = ((uint32_t *) &m_state.context.vfp.__v[0]) + (reg - vfp_s0); - memcpy (s_reg, &value->value.v_uint8, 4); + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + bool success = false; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + m_state.context.gpr.__r[reg] = value->value.uint32; + success = true; + } + break; + + case e_regSetVFP: + // "reg" is an index into the floating point register set at this point. + // We need to translate it up so entry 0 in the fp reg set is the same as + // vfp_s0 + // in the enumerated values for case statement below. + if (reg >= vfp_s0 && reg <= vfp_s31) { +#if defined(__arm64__) || defined(__aarch64__) + uint32_t *s_reg = + ((uint32_t *)&m_state.context.vfp.__v[0]) + (reg - vfp_s0); + memcpy(s_reg, &value->value.v_uint8, 4); #else - m_state.context.vfp.__r[reg] = value->value.uint32; + m_state.context.vfp.__r[reg] = value->value.uint32; #endif - success = true; - } - else if (reg >= vfp_d0 && reg <= vfp_d31) - { -#if defined (__arm64__) || defined (__aarch64__) - uint64_t *d_reg = ((uint64_t *) &m_state.context.vfp.__v[0]) + (reg - vfp_d0); - memcpy (d_reg, &value->value.v_uint8, 8); + success = true; + } else if (reg >= vfp_d0 && reg <= vfp_d31) { +#if defined(__arm64__) || defined(__aarch64__) + uint64_t *d_reg = + ((uint64_t *)&m_state.context.vfp.__v[0]) + (reg - vfp_d0); + memcpy(d_reg, &value->value.v_uint8, 8); #else - uint32_t d_reg_idx = reg - vfp_d0; - uint32_t s_reg_idx = d_reg_idx * 2; - m_state.context.vfp.__r[s_reg_idx + 0] = value->value.v_sint32[0]; - m_state.context.vfp.__r[s_reg_idx + 1] = value->value.v_sint32[1]; + uint32_t d_reg_idx = reg - vfp_d0; + uint32_t s_reg_idx = d_reg_idx * 2; + m_state.context.vfp.__r[s_reg_idx + 0] = value->value.v_sint32[0]; + m_state.context.vfp.__r[s_reg_idx + 1] = value->value.v_sint32[1]; #endif - success = true; - } - else if (reg >= vfp_q0 && reg <= vfp_q15) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy ((uint8_t *) &m_state.context.vfp.__v[reg - vfp_q0], &value->value.v_uint8, 16); + success = true; + } else if (reg >= vfp_q0 && reg <= vfp_q15) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy((uint8_t *)&m_state.context.vfp.__v[reg - vfp_q0], + &value->value.v_uint8, 16); #else - uint32_t s_reg_idx = (reg - vfp_q0) * 4; - memcpy ((uint8_t *) &m_state.context.vfp.__r[s_reg_idx], &value->value.v_uint8, 16); + uint32_t s_reg_idx = (reg - vfp_q0) * 4; + memcpy((uint8_t *)&m_state.context.vfp.__r[s_reg_idx], + &value->value.v_uint8, 16); #endif - success = true; - } -#if defined (__arm64__) || defined (__aarch64__) - else if (reg == vfp_fpsr) - { - m_state.context.vfp.__fpsr = value->value.uint32; - success = true; - } - else if (reg == vfp_fpcr) - { - m_state.context.vfp.__fpcr = value->value.uint32; - success = true; - } + success = true; + } +#if defined(__arm64__) || defined(__aarch64__) + else if (reg == vfp_fpsr) { + m_state.context.vfp.__fpsr = value->value.uint32; + success = true; + } else if (reg == vfp_fpcr) { + m_state.context.vfp.__fpcr = value->value.uint32; + success = true; + } #else - else if (reg == vfp_fpscr) - { - m_state.context.vfp.__fpscr = value->value.uint32; - success = true; - } + else if (reg == vfp_fpscr) { + m_state.context.vfp.__fpscr = value->value.uint32; + success = true; + } #endif - break; - - case e_regSetEXC: - if (reg < k_num_exc_registers) - { - (&m_state.context.exc.__exception)[reg] = value->value.uint32; - success = true; - } - break; - } - + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) { + (&m_state.context.exc.__exception)[reg] = value->value.uint32; + success = true; + } + break; } - if (success) - return SetRegisterState(set) == KERN_SUCCESS; - return false; + } + if (success) + return SetRegisterState(set) == KERN_SUCCESS; + return false; } -kern_return_t -DNBArchMachARM::GetRegisterState(int set, bool force) -{ - switch (set) - { - case e_regSetALL: return GetGPRState(force) | - GetVFPState(force) | - GetEXCState(force) | - GetDBGState(force); - case e_regSetGPR: return GetGPRState(force); - case e_regSetVFP: return GetVFPState(force); - case e_regSetEXC: return GetEXCState(force); - case e_regSetDBG: return GetDBGState(force); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachARM::GetRegisterState(int set, bool force) { + switch (set) { + case e_regSetALL: + return GetGPRState(force) | GetVFPState(force) | GetEXCState(force) | + GetDBGState(force); + case e_regSetGPR: + return GetGPRState(force); + case e_regSetVFP: + return GetVFPState(force); + case e_regSetEXC: + return GetEXCState(force); + case e_regSetDBG: + return GetDBGState(force); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -kern_return_t -DNBArchMachARM::SetRegisterState(int set) -{ - // Make sure we have a valid context to set. - kern_return_t err = GetRegisterState(set, false); - if (err != KERN_SUCCESS) - return err; - - switch (set) - { - case e_regSetALL: return SetGPRState() | - SetVFPState() | - SetEXCState() | - SetDBGState(false); - case e_regSetGPR: return SetGPRState(); - case e_regSetVFP: return SetVFPState(); - case e_regSetEXC: return SetEXCState(); - case e_regSetDBG: return SetDBGState(false); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachARM::SetRegisterState(int set) { + // Make sure we have a valid context to set. + kern_return_t err = GetRegisterState(set, false); + if (err != KERN_SUCCESS) + return err; + + switch (set) { + case e_regSetALL: + return SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false); + case e_regSetGPR: + return SetGPRState(); + case e_regSetVFP: + return SetVFPState(); + case e_regSetEXC: + return SetEXCState(); + case e_regSetDBG: + return SetDBGState(false); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -bool -DNBArchMachARM::RegisterSetStateIsValid (int set) const -{ - return m_state.RegsAreValid(set); +bool DNBArchMachARM::RegisterSetStateIsValid(int set) const { + return m_state.RegsAreValid(set); } - -nub_size_t -DNBArchMachARM::GetRegisterContext (void *buf, nub_size_t buf_len) -{ - nub_size_t size = sizeof (m_state.context.gpr) + - sizeof (m_state.context.vfp) + - sizeof (m_state.context.exc); - - if (buf && buf_len) - { - if (size > buf_len) - size = buf_len; - - bool force = false; - if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) - return 0; - - // Copy each struct individually to avoid any padding that might be between the structs in m_state.context - uint8_t *p = (uint8_t *)buf; - ::memcpy (p, &m_state.context.gpr, sizeof(m_state.context.gpr)); - p += sizeof(m_state.context.gpr); - ::memcpy (p, &m_state.context.vfp, sizeof(m_state.context.vfp)); - p += sizeof(m_state.context.vfp); - ::memcpy (p, &m_state.context.exc, sizeof(m_state.context.exc)); - p += sizeof(m_state.context.exc); - - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::GetRegisterContext (buf = %p, len = %llu) => %llu", buf, (uint64_t)buf_len, (uint64_t)size); - // Return the size of the register context even if NULL was passed in - return size; +nub_size_t DNBArchMachARM::GetRegisterContext(void *buf, nub_size_t buf_len) { + nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + + sizeof(m_state.context.exc); + + if (buf && buf_len) { + if (size > buf_len) + size = buf_len; + + bool force = false; + if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) + return 0; + + // Copy each struct individually to avoid any padding that might be between + // the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy(p, &m_state.context.gpr, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy(p, &m_state.context.vfp, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy(p, &m_state.context.exc, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchMachARM::GetRegisterContext (buf = %p, len = %llu) => %llu", buf, + (uint64_t)buf_len, (uint64_t)size); + // Return the size of the register context even if NULL was passed in + return size; } -nub_size_t -DNBArchMachARM::SetRegisterContext (const void *buf, nub_size_t buf_len) -{ - nub_size_t size = sizeof (m_state.context.gpr) + - sizeof (m_state.context.vfp) + - sizeof (m_state.context.exc); - - if (buf == NULL || buf_len == 0) - size = 0; - - if (size) - { - if (size > buf_len) - size = buf_len; - - // Copy each struct individually to avoid any padding that might be between the structs in m_state.context - uint8_t *p = (uint8_t *)buf; - ::memcpy (&m_state.context.gpr, p, sizeof(m_state.context.gpr)); - p += sizeof(m_state.context.gpr); - ::memcpy (&m_state.context.vfp, p, sizeof(m_state.context.vfp)); - p += sizeof(m_state.context.vfp); - ::memcpy (&m_state.context.exc, p, sizeof(m_state.context.exc)); - p += sizeof(m_state.context.exc); - - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - - if (SetGPRState() | SetVFPState() | SetEXCState()) - return 0; - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SetRegisterContext (buf = %p, len = %llu) => %llu", buf, (uint64_t)buf_len, (uint64_t)size); - return size; +nub_size_t DNBArchMachARM::SetRegisterContext(const void *buf, + nub_size_t buf_len) { + nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + + sizeof(m_state.context.exc); + + if (buf == NULL || buf_len == 0) + size = 0; + + if (size) { + if (size > buf_len) + size = buf_len; + + // Copy each struct individually to avoid any padding that might be between + // the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + + if (SetGPRState() | SetVFPState() | SetEXCState()) + return 0; + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchMachARM::SetRegisterContext (buf = %p, len = %llu) => %llu", buf, + (uint64_t)buf_len, (uint64_t)size); + return size; } - -uint32_t -DNBArchMachARM::SaveRegisterState () -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); - - // Always re-read the registers because above we call thread_abort_safely(); - bool force = true; - - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: GPR regs failed to read: %u ", kret); - } - else if ((kret = GetVFPState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: %s regs failed to read: %u", "VFP", kret); - } - else - { - const uint32_t save_id = GetNextRegisterStateSaveID (); - m_saved_register_states[save_id] = m_state.context; - return save_id; - } - return UINT32_MAX; +uint32_t DNBArchMachARM::SaveRegisterState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: " + "GPR regs failed to read: %u ", + kret); + } else if ((kret = GetVFPState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM::SaveRegisterState () error: " + "%s regs failed to read: %u", + "VFP", kret); + } else { + const uint32_t save_id = GetNextRegisterStateSaveID(); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return UINT32_MAX; } -bool -DNBArchMachARM::RestoreRegisterState (uint32_t save_id) -{ - SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); - if (pos != m_saved_register_states.end()) - { - m_state.context.gpr = pos->second.gpr; - m_state.context.vfp = pos->second.vfp; - kern_return_t kret; - bool success = true; - if ((kret = SetGPRState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); - success = false; - } - else if ((kret = SetVFPState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, "VFP", kret); - success = false; - } - m_saved_register_states.erase(pos); - return success; +bool DNBArchMachARM::RestoreRegisterState(uint32_t save_id) { + SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) { + m_state.context.gpr = pos->second.gpr; + m_state.context.vfp = pos->second.vfp; + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM::RestoreRegisterState " + "(save_id = %u) error: GPR regs failed to " + "write: %u", + save_id, kret); + success = false; + } else if ((kret = SetVFPState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM::RestoreRegisterState " + "(save_id = %u) error: %s regs failed to " + "write: %u", + save_id, "VFP", kret); + success = false; } - return false; + m_saved_register_states.erase(pos); + return success; + } + return false; } - -#endif // #if defined (__arm__) - +#endif // #if defined (__arm__) diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h index ae897485523..e8622c4ec7e 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -14,7 +14,7 @@ #ifndef __DebugNubArchMachARM_h__ #define __DebugNubArchMachARM_h__ -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #include "DNBArch.h" @@ -22,261 +22,254 @@ class MachThread; -class DNBArchMachARM : public DNBArchProtocol -{ +class DNBArchMachARM : public DNBArchProtocol { public: - enum { kMaxNumThumbITBreakpoints = 4 }; + enum { kMaxNumThumbITBreakpoints = 4 }; - DNBArchMachARM(MachThread *thread) : - m_thread(thread), - m_state(), - m_disabled_watchpoints(), + DNBArchMachARM(MachThread *thread) + : m_thread(thread), m_state(), m_disabled_watchpoints(), m_hw_single_chained_step_addr(INVALID_NUB_ADDRESS), - m_last_decode_pc(INVALID_NUB_ADDRESS), - m_watchpoint_hw_index(-1), + m_last_decode_pc(INVALID_NUB_ADDRESS), m_watchpoint_hw_index(-1), m_watchpoint_did_occur(false), m_watchpoint_resume_single_step_enabled(false), - m_saved_register_states() - { - m_disabled_watchpoints.resize (16); - memset(&m_dbg_save, 0, sizeof(m_dbg_save)); -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - ThumbStaticsInit(&m_last_decode_thumb); + m_saved_register_states() { + m_disabled_watchpoints.resize(16); + memset(&m_dbg_save, 0, sizeof(m_dbg_save)); +#if defined(USE_ARM_DISASSEMBLER_FRAMEWORK) + ThumbStaticsInit(&m_last_decode_thumb); #endif - } - - virtual ~DNBArchMachARM() - { - } - - static void Initialize(); - static const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets); - - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState (); - virtual bool RestoreRegisterState (uint32_t save_id); - - virtual kern_return_t GetRegisterState (int set, bool force); - virtual kern_return_t SetRegisterState (int set); - virtual bool RegisterSetStateIsValid (int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data& exc); - - static DNBArchProtocol *Create (MachThread *thread); - static const uint8_t * SoftwareBreakpointOpcode (nub_size_t byte_size); - static uint32_t GetCPUType(); - - virtual uint32_t NumSupportedHardwareBreakpoints(); - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareBreakpoint (nub_addr_t addr, nub_size_t size); - virtual bool DisableHardwareBreakpoint (uint32_t hw_break_index); - - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint_helper (uint32_t hw_break_index, bool also_set_on_task); - virtual bool ReenableHardwareWatchpoint (uint32_t hw_break_index); - virtual bool ReenableHardwareWatchpoint_helper (uint32_t hw_break_index); - - virtual bool StepNotComplete (); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); - -#if defined (ARM_DEBUG_STATE32) && (defined (__arm64__) || defined (__aarch64__)) - typedef arm_debug_state32_t DBG; + } + + virtual ~DNBArchMachARM() {} + + static void Initialize(); + static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); + + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value); + virtual bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value); + virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); + virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState(); + virtual bool RestoreRegisterState(uint32_t save_id); + + virtual kern_return_t GetRegisterState(int set, bool force); + virtual kern_return_t SetRegisterState(int set); + virtual bool RegisterSetStateIsValid(int set) const; + + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual void ThreadWillResume(); + virtual bool ThreadDidStop(); + virtual bool NotifyException(MachException::Data &exc); + + static DNBArchProtocol *Create(MachThread *thread); + static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); + static uint32_t GetCPUType(); + + virtual uint32_t NumSupportedHardwareBreakpoints(); + virtual uint32_t NumSupportedHardwareWatchpoints(); + virtual uint32_t EnableHardwareBreakpoint(nub_addr_t addr, nub_size_t size); + virtual bool DisableHardwareBreakpoint(uint32_t hw_break_index); + + virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index, + bool also_set_on_task); + virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index); + virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index); + + virtual bool StepNotComplete(); + virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + +#if defined(ARM_DEBUG_STATE32) && (defined(__arm64__) || defined(__aarch64__)) + typedef arm_debug_state32_t DBG; #else - typedef arm_debug_state_t DBG; + typedef arm_debug_state_t DBG; #endif protected: - - - kern_return_t EnableHardwareSingleStep (bool enable); - kern_return_t SetSingleStepSoftwareBreakpoints (); - - bool ConditionPassed(uint8_t condition, uint32_t cpsr); -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - bool ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC); - arm_error_t DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc); - void DecodeITBlockInstructions(nub_addr_t curr_pc); + kern_return_t EnableHardwareSingleStep(bool enable); + kern_return_t SetSingleStepSoftwareBreakpoints(); + + bool ConditionPassed(uint8_t condition, uint32_t cpsr); +#if defined(USE_ARM_DISASSEMBLER_FRAMEWORK) + bool ComputeNextPC(nub_addr_t currentPC, + arm_decoded_instruction_t decodedInstruction, + bool currentPCIsThumb, nub_addr_t *targetPC); + arm_error_t DecodeInstructionUsingDisassembler( + nub_addr_t curr_pc, uint32_t curr_cpsr, + arm_decoded_instruction_t *decodedInstruction, + thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc); + void DecodeITBlockInstructions(nub_addr_t curr_pc); #endif - void EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb); - - - typedef enum RegisterSetTag - { - e_regSetALL = REGISTER_SET_ALL, - e_regSetGPR, // ARM_THREAD_STATE - e_regSetVFP, // ARM_VFP_STATE (ARM_NEON_STATE if defined __arm64__) - e_regSetEXC, // ARM_EXCEPTION_STATE - e_regSetDBG, // ARM_DEBUG_STATE (ARM_DEBUG_STATE32 if defined __arm64__) - kNumRegisterSets - } RegisterSet; - - enum - { - Read = 0, - Write = 1, - kNumErrors = 2 - }; - - typedef arm_thread_state_t GPR; -#if defined (__arm64__) || defined (__aarch64__) - typedef arm_neon_state_t FPU; + void EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, + uint32_t cpsr, + bool currentPCIsThumb, + nub_addr_t *nextPC, + bool *nextPCIsThumb); + + typedef enum RegisterSetTag { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, // ARM_THREAD_STATE + e_regSetVFP, // ARM_VFP_STATE (ARM_NEON_STATE if defined __arm64__) + e_regSetEXC, // ARM_EXCEPTION_STATE + e_regSetDBG, // ARM_DEBUG_STATE (ARM_DEBUG_STATE32 if defined __arm64__) + kNumRegisterSets + } RegisterSet; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + typedef arm_thread_state_t GPR; +#if defined(__arm64__) || defined(__aarch64__) + typedef arm_neon_state_t FPU; #else - typedef arm_vfp_state_t FPU; + typedef arm_vfp_state_t FPU; #endif - typedef arm_exception_state_t EXC; - - static const DNBRegisterInfo g_gpr_registers[]; - static const DNBRegisterInfo g_vfp_registers[]; - static const DNBRegisterInfo g_exc_registers[]; - static const DNBRegisterSetInfo g_reg_sets[]; - - static const size_t k_num_gpr_registers; - static const size_t k_num_vfp_registers; - static const size_t k_num_exc_registers; - static const size_t k_num_all_registers; - static const size_t k_num_register_sets; - - struct Context - { - GPR gpr; - FPU vfp; - EXC exc; - }; - - struct State - { - Context context; - DBG dbg; - kern_return_t gpr_errs[2]; // Read/Write errors - kern_return_t vfp_errs[2]; // Read/Write errors - kern_return_t exc_errs[2]; // Read/Write errors - kern_return_t dbg_errs[2]; // Read/Write errors - State() - { - uint32_t i; - for (i=0; i<kNumErrors; i++) - { - gpr_errs[i] = -1; - vfp_errs[i] = -1; - exc_errs[i] = -1; - dbg_errs[i] = -1; - } - } - void InvalidateRegisterSetState(int set) - { - SetError (set, Read, -1); - } - kern_return_t GetError (int set, uint32_t err_idx) const - { - if (err_idx < kNumErrors) - { - switch (set) - { - // When getting all errors, just OR all values together to see if - // we got any kind of error. - case e_regSetALL: return gpr_errs[err_idx] | - vfp_errs[err_idx] | - exc_errs[err_idx] | - dbg_errs[err_idx] ; - case e_regSetGPR: return gpr_errs[err_idx]; - case e_regSetVFP: return vfp_errs[err_idx]; - case e_regSetEXC: return exc_errs[err_idx]; - case e_regSetDBG: return dbg_errs[err_idx]; - default: break; - } - } - return -1; - } - bool SetError (int set, uint32_t err_idx, kern_return_t err) - { - if (err_idx < kNumErrors) - { - switch (set) - { - case e_regSetALL: - gpr_errs[err_idx] = err; - vfp_errs[err_idx] = err; - dbg_errs[err_idx] = err; - exc_errs[err_idx] = err; - return true; - - case e_regSetGPR: - gpr_errs[err_idx] = err; - return true; - - case e_regSetVFP: - vfp_errs[err_idx] = err; - return true; - - case e_regSetEXC: - exc_errs[err_idx] = err; - return true; - - case e_regSetDBG: - dbg_errs[err_idx] = err; - return true; - default: break; - } - } - return false; + typedef arm_exception_state_t EXC; + + static const DNBRegisterInfo g_gpr_registers[]; + static const DNBRegisterInfo g_vfp_registers[]; + static const DNBRegisterInfo g_exc_registers[]; + static const DNBRegisterSetInfo g_reg_sets[]; + + static const size_t k_num_gpr_registers; + static const size_t k_num_vfp_registers; + static const size_t k_num_exc_registers; + static const size_t k_num_all_registers; + static const size_t k_num_register_sets; + + struct Context { + GPR gpr; + FPU vfp; + EXC exc; + }; + + struct State { + Context context; + DBG dbg; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t vfp_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t dbg_errs[2]; // Read/Write errors + State() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + vfp_errs[i] = -1; + exc_errs[i] = -1; + dbg_errs[i] = -1; + } + } + void InvalidateRegisterSetState(int set) { SetError(set, Read, -1); } + kern_return_t GetError(int set, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (set) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case e_regSetALL: + return gpr_errs[err_idx] | vfp_errs[err_idx] | exc_errs[err_idx] | + dbg_errs[err_idx]; + case e_regSetGPR: + return gpr_errs[err_idx]; + case e_regSetVFP: + return vfp_errs[err_idx]; + case e_regSetEXC: + return exc_errs[err_idx]; + case e_regSetDBG: + return dbg_errs[err_idx]; + default: + break; } - bool RegsAreValid (int set) const - { - return GetError(set, Read) == KERN_SUCCESS; + } + return -1; + } + bool SetError(int set, uint32_t err_idx, kern_return_t err) { + if (err_idx < kNumErrors) { + switch (set) { + case e_regSetALL: + gpr_errs[err_idx] = err; + vfp_errs[err_idx] = err; + dbg_errs[err_idx] = err; + exc_errs[err_idx] = err; + return true; + + case e_regSetGPR: + gpr_errs[err_idx] = err; + return true; + + case e_regSetVFP: + vfp_errs[err_idx] = err; + return true; + + case e_regSetEXC: + exc_errs[err_idx] = err; + return true; + + case e_regSetDBG: + dbg_errs[err_idx] = err; + return true; + default: + break; } - }; - - kern_return_t GetGPRState (bool force); - kern_return_t GetVFPState (bool force); - kern_return_t GetEXCState (bool force); - kern_return_t GetDBGState (bool force); - - kern_return_t SetGPRState (); - kern_return_t SetVFPState (); - kern_return_t SetEXCState (); - kern_return_t SetDBGState (bool also_set_on_task); - - bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); - nub_addr_t GetWatchpointAddressByIndex (uint32_t hw_index); - nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - - class disabled_watchpoint { - public: - disabled_watchpoint () { addr = 0; control = 0; } - nub_addr_t addr; - uint32_t control; - }; + } + return false; + } + bool RegsAreValid(int set) const { + return GetError(set, Read) == KERN_SUCCESS; + } + }; + + kern_return_t GetGPRState(bool force); + kern_return_t GetVFPState(bool force); + kern_return_t GetEXCState(bool force); + kern_return_t GetDBGState(bool force); + + kern_return_t SetGPRState(); + kern_return_t SetVFPState(); + kern_return_t SetEXCState(); + kern_return_t SetDBGState(bool also_set_on_task); + + bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); + nub_addr_t GetWatchpointAddressByIndex(uint32_t hw_index); + nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + + class disabled_watchpoint { + public: + disabled_watchpoint() { + addr = 0; + control = 0; + } + nub_addr_t addr; + uint32_t control; + }; protected: - MachThread * m_thread; - State m_state; - DBG m_dbg_save; + MachThread *m_thread; + State m_state; + DBG m_dbg_save; - // armv8 doesn't keep the disabled watchpoint values in the debug register context like armv7; - // we need to save them aside when we disable them temporarily. - std::vector<disabled_watchpoint> m_disabled_watchpoints; + // armv8 doesn't keep the disabled watchpoint values in the debug register + // context like armv7; + // we need to save them aside when we disable them temporarily. + std::vector<disabled_watchpoint> m_disabled_watchpoints; - nub_addr_t m_hw_single_chained_step_addr; - nub_addr_t m_last_decode_pc; + nub_addr_t m_hw_single_chained_step_addr; + nub_addr_t m_last_decode_pc; - // The following member variables should be updated atomically. - int32_t m_watchpoint_hw_index; - bool m_watchpoint_did_occur; - bool m_watchpoint_resume_single_step_enabled; + // The following member variables should be updated atomically. + int32_t m_watchpoint_hw_index; + bool m_watchpoint_did_occur; + bool m_watchpoint_resume_single_step_enabled; - typedef std::map<uint32_t, Context> SaveRegisterStates; - SaveRegisterStates m_saved_register_states; + typedef std::map<uint32_t, Context> SaveRegisterStates; + SaveRegisterStates m_saved_register_states; }; -#endif // #if defined (__arm__) -#endif // #ifndef __DebugNubArchMachARM_h__ +#endif // #if defined (__arm__) +#endif // #ifndef __DebugNubArchMachARM_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp index e79d3d52e8f..7d04170623d 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp @@ -11,1349 +11,1359 @@ // //===----------------------------------------------------------------------===// -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) #include "MacOSX/arm64/DNBArchImplARM64.h" -#if defined (ARM_THREAD_STATE64_COUNT) +#if defined(ARM_THREAD_STATE64_COUNT) -#include "MacOSX/MachProcess.h" -#include "MacOSX/MachThread.h" +#include "DNB.h" #include "DNBBreakpoint.h" #include "DNBLog.h" #include "DNBRegisterInfo.h" -#include "DNB.h" +#include "MacOSX/MachProcess.h" +#include "MacOSX/MachThread.h" #include <inttypes.h> #include <sys/sysctl.h> // Break only in privileged or user mode // (PAC bits in the DBGWVRn_EL1 watchpoint control register) -#define S_USER ((uint32_t)(2u << 1)) +#define S_USER ((uint32_t)(2u << 1)) -#define BCR_ENABLE ((uint32_t)(1u)) -#define WCR_ENABLE ((uint32_t)(1u)) +#define BCR_ENABLE ((uint32_t)(1u)) +#define WCR_ENABLE ((uint32_t)(1u)) // Watchpoint load/store // (LSC bits in the DBGWVRn_EL1 watchpoint control register) -#define WCR_LOAD ((uint32_t)(1u << 3)) -#define WCR_STORE ((uint32_t)(1u << 4)) +#define WCR_LOAD ((uint32_t)(1u << 3)) +#define WCR_STORE ((uint32_t)(1u << 4)) // Enable breakpoint, watchpoint, and vector catch debug exceptions. -// (MDE bit in the MDSCR_EL1 register. Equivalent to the MDBGen bit in DBGDSCRext in Aarch32) +// (MDE bit in the MDSCR_EL1 register. Equivalent to the MDBGen bit in +// DBGDSCRext in Aarch32) #define MDE_ENABLE ((uint32_t)(1u << 15)) // Single instruction step // (SS bit in the MDSCR_EL1 register) #define SS_ENABLE ((uint32_t)(1u)) -static const uint8_t g_arm64_breakpoint_opcode[] = { 0x00, 0x00, 0x20, 0xD4 }; // "brk #0", 0xd4200000 in BE byte order -static const uint8_t g_arm_breakpoint_opcode[] = { 0xFE, 0xDE, 0xFF, 0xE7 }; // this armv7 insn also works in arm64 +static const uint8_t g_arm64_breakpoint_opcode[] = { + 0x00, 0x00, 0x20, 0xD4}; // "brk #0", 0xd4200000 in BE byte order +static const uint8_t g_arm_breakpoint_opcode[] = { + 0xFE, 0xDE, 0xFF, 0xE7}; // this armv7 insn also works in arm64 // If we need to set one logical watchpoint by using // two hardware watchpoint registers, the watchpoint // will be split into a "high" and "low" watchpoint. // Record both of them in the LoHi array. -// It's safe to initialize to all 0's since +// It's safe to initialize to all 0's since // hi > lo and therefore LoHi[i] cannot be 0. -static uint32_t LoHi[16] = { 0 }; - - -void -DNBArchMachARM64::Initialize() -{ - DNBArchPluginInfo arch_plugin_info = - { - CPU_TYPE_ARM64, - DNBArchMachARM64::Create, - DNBArchMachARM64::GetRegisterSetInfo, - DNBArchMachARM64::SoftwareBreakpointOpcode - }; - - // Register this arch plug-in with the main protocol class - DNBArchProtocol::RegisterArchPlugin (arch_plugin_info); -} +static uint32_t LoHi[16] = {0}; +void DNBArchMachARM64::Initialize() { + DNBArchPluginInfo arch_plugin_info = { + CPU_TYPE_ARM64, DNBArchMachARM64::Create, + DNBArchMachARM64::GetRegisterSetInfo, + DNBArchMachARM64::SoftwareBreakpointOpcode}; -DNBArchProtocol * -DNBArchMachARM64::Create (MachThread *thread) -{ - DNBArchMachARM64 *obj = new DNBArchMachARM64 (thread); + // Register this arch plug-in with the main protocol class + DNBArchProtocol::RegisterArchPlugin(arch_plugin_info); +} + +DNBArchProtocol *DNBArchMachARM64::Create(MachThread *thread) { + DNBArchMachARM64 *obj = new DNBArchMachARM64(thread); - return obj; + return obj; } const uint8_t * -DNBArchMachARM64::SoftwareBreakpointOpcode (nub_size_t byte_size) -{ - return g_arm_breakpoint_opcode; +DNBArchMachARM64::SoftwareBreakpointOpcode(nub_size_t byte_size) { + return g_arm_breakpoint_opcode; } -uint32_t -DNBArchMachARM64::GetCPUType() -{ - return CPU_TYPE_ARM64; -} +uint32_t DNBArchMachARM64::GetCPUType() { return CPU_TYPE_ARM64; } -uint64_t -DNBArchMachARM64::GetPC(uint64_t failValue) -{ - // Get program counter - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__pc; - return failValue; +uint64_t DNBArchMachARM64::GetPC(uint64_t failValue) { + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__pc; + return failValue; } -kern_return_t -DNBArchMachARM64::SetPC(uint64_t value) -{ - // Get program counter - kern_return_t err = GetGPRState(false); - if (err == KERN_SUCCESS) - { - m_state.context.gpr.__pc = value; - err = SetGPRState(); - } - return err == KERN_SUCCESS; +kern_return_t DNBArchMachARM64::SetPC(uint64_t value) { + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) { + m_state.context.gpr.__pc = value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; } -uint64_t -DNBArchMachARM64::GetSP(uint64_t failValue) -{ - // Get stack pointer - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__sp; - return failValue; +uint64_t DNBArchMachARM64::GetSP(uint64_t failValue) { + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__sp; + return failValue; } -kern_return_t -DNBArchMachARM64::GetGPRState(bool force) -{ - int set = e_regSetGPR; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - // Read the registers from our thread - mach_msg_type_number_t count = e_regSetGPRCount; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, &count); - if (DNBLogEnabledForAny (LOG_THREAD)) - { - uint64_t *x = &m_state.context.gpr.__x[0]; - DNBLogThreaded("thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs" - "\n x0=%16.16llx" - "\n x1=%16.16llx" - "\n x2=%16.16llx" - "\n x3=%16.16llx" - "\n x4=%16.16llx" - "\n x5=%16.16llx" - "\n x6=%16.16llx" - "\n x7=%16.16llx" - "\n x8=%16.16llx" - "\n x9=%16.16llx" - "\n x10=%16.16llx" - "\n x11=%16.16llx" - "\n x12=%16.16llx" - "\n x13=%16.16llx" - "\n x14=%16.16llx" - "\n x15=%16.16llx" - "\n x16=%16.16llx" - "\n x17=%16.16llx" - "\n x18=%16.16llx" - "\n x19=%16.16llx" - "\n x20=%16.16llx" - "\n x21=%16.16llx" - "\n x22=%16.16llx" - "\n x23=%16.16llx" - "\n x24=%16.16llx" - "\n x25=%16.16llx" - "\n x26=%16.16llx" - "\n x27=%16.16llx" - "\n x28=%16.16llx" - "\n fp=%16.16llx" - "\n lr=%16.16llx" - "\n sp=%16.16llx" - "\n pc=%16.16llx" - "\n cpsr=%8.8x", - m_thread->MachPortNumber(), - e_regSetGPR, - e_regSetGPRCount, - kret, - count, - x[0], - x[1], - x[2], - x[3], - x[4], - x[5], - x[6], - x[7], - x[8], - x[9], - x[0], - x[11], - x[12], - x[13], - x[14], - x[15], - x[16], - x[17], - x[18], - x[19], - x[20], - x[21], - x[22], - x[23], - x[24], - x[25], - x[26], - x[27], - x[28], - m_state.context.gpr.__fp, - m_state.context.gpr.__lr, - m_state.context.gpr.__sp, - m_state.context.gpr.__pc, - m_state.context.gpr.__cpsr); - } - m_state.SetError(set, Read, kret); - return kret; +kern_return_t DNBArchMachARM64::GetGPRState(bool force) { + int set = e_regSetGPR; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetGPRCount; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, + (thread_state_t)&m_state.context.gpr, &count); + if (DNBLogEnabledForAny(LOG_THREAD)) { + uint64_t *x = &m_state.context.gpr.__x[0]; + DNBLogThreaded( + "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x (count = %u) regs" + "\n x0=%16.16llx" + "\n x1=%16.16llx" + "\n x2=%16.16llx" + "\n x3=%16.16llx" + "\n x4=%16.16llx" + "\n x5=%16.16llx" + "\n x6=%16.16llx" + "\n x7=%16.16llx" + "\n x8=%16.16llx" + "\n x9=%16.16llx" + "\n x10=%16.16llx" + "\n x11=%16.16llx" + "\n x12=%16.16llx" + "\n x13=%16.16llx" + "\n x14=%16.16llx" + "\n x15=%16.16llx" + "\n x16=%16.16llx" + "\n x17=%16.16llx" + "\n x18=%16.16llx" + "\n x19=%16.16llx" + "\n x20=%16.16llx" + "\n x21=%16.16llx" + "\n x22=%16.16llx" + "\n x23=%16.16llx" + "\n x24=%16.16llx" + "\n x25=%16.16llx" + "\n x26=%16.16llx" + "\n x27=%16.16llx" + "\n x28=%16.16llx" + "\n fp=%16.16llx" + "\n lr=%16.16llx" + "\n sp=%16.16llx" + "\n pc=%16.16llx" + "\n cpsr=%8.8x", + m_thread->MachPortNumber(), e_regSetGPR, e_regSetGPRCount, kret, count, + x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7], x[8], x[9], x[0], x[11], + x[12], x[13], x[14], x[15], x[16], x[17], x[18], x[19], x[20], x[21], + x[22], x[23], x[24], x[25], x[26], x[27], x[28], + m_state.context.gpr.__fp, m_state.context.gpr.__lr, + m_state.context.gpr.__sp, m_state.context.gpr.__pc, + m_state.context.gpr.__cpsr); + } + m_state.SetError(set, Read, kret); + return kret; } -kern_return_t -DNBArchMachARM64::GetVFPState(bool force) -{ - int set = e_regSetVFP; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - // Read the registers from our thread - mach_msg_type_number_t count = e_regSetVFPCount; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE64, (thread_state_t)&m_state.context.vfp, &count); - if (DNBLogEnabledForAny (LOG_THREAD)) - { -#if defined (__arm64__) || defined (__aarch64__) - DNBLogThreaded("thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" - "\n q0 = 0x%16.16llx%16.16llx" - "\n q1 = 0x%16.16llx%16.16llx" - "\n q2 = 0x%16.16llx%16.16llx" - "\n q3 = 0x%16.16llx%16.16llx" - "\n q4 = 0x%16.16llx%16.16llx" - "\n q5 = 0x%16.16llx%16.16llx" - "\n q6 = 0x%16.16llx%16.16llx" - "\n q7 = 0x%16.16llx%16.16llx" - "\n q8 = 0x%16.16llx%16.16llx" - "\n q9 = 0x%16.16llx%16.16llx" - "\n q10 = 0x%16.16llx%16.16llx" - "\n q11 = 0x%16.16llx%16.16llx" - "\n q12 = 0x%16.16llx%16.16llx" - "\n q13 = 0x%16.16llx%16.16llx" - "\n q14 = 0x%16.16llx%16.16llx" - "\n q15 = 0x%16.16llx%16.16llx" - "\n q16 = 0x%16.16llx%16.16llx" - "\n q17 = 0x%16.16llx%16.16llx" - "\n q18 = 0x%16.16llx%16.16llx" - "\n q19 = 0x%16.16llx%16.16llx" - "\n q20 = 0x%16.16llx%16.16llx" - "\n q21 = 0x%16.16llx%16.16llx" - "\n q22 = 0x%16.16llx%16.16llx" - "\n q23 = 0x%16.16llx%16.16llx" - "\n q24 = 0x%16.16llx%16.16llx" - "\n q25 = 0x%16.16llx%16.16llx" - "\n q26 = 0x%16.16llx%16.16llx" - "\n q27 = 0x%16.16llx%16.16llx" - "\n q28 = 0x%16.16llx%16.16llx" - "\n q29 = 0x%16.16llx%16.16llx" - "\n q30 = 0x%16.16llx%16.16llx" - "\n q31 = 0x%16.16llx%16.16llx" - "\n fpsr = 0x%8.8x" - "\n fpcr = 0x%8.8x\n\n", - m_thread->MachPortNumber(), - e_regSetVFP, - e_regSetVFPCount, - kret, - count, - ((uint64_t *)&m_state.context.vfp.__v[0])[0] , ((uint64_t *)&m_state.context.vfp.__v[0])[1], - ((uint64_t *)&m_state.context.vfp.__v[1])[0] , ((uint64_t *)&m_state.context.vfp.__v[1])[1], - ((uint64_t *)&m_state.context.vfp.__v[2])[0] , ((uint64_t *)&m_state.context.vfp.__v[2])[1], - ((uint64_t *)&m_state.context.vfp.__v[3])[0] , ((uint64_t *)&m_state.context.vfp.__v[3])[1], - ((uint64_t *)&m_state.context.vfp.__v[4])[0] , ((uint64_t *)&m_state.context.vfp.__v[4])[1], - ((uint64_t *)&m_state.context.vfp.__v[5])[0] , ((uint64_t *)&m_state.context.vfp.__v[5])[1], - ((uint64_t *)&m_state.context.vfp.__v[6])[0] , ((uint64_t *)&m_state.context.vfp.__v[6])[1], - ((uint64_t *)&m_state.context.vfp.__v[7])[0] , ((uint64_t *)&m_state.context.vfp.__v[7])[1], - ((uint64_t *)&m_state.context.vfp.__v[8])[0] , ((uint64_t *)&m_state.context.vfp.__v[8])[1], - ((uint64_t *)&m_state.context.vfp.__v[9])[0] , ((uint64_t *)&m_state.context.vfp.__v[9])[1], - ((uint64_t *)&m_state.context.vfp.__v[10])[0], ((uint64_t *)&m_state.context.vfp.__v[10])[1], - ((uint64_t *)&m_state.context.vfp.__v[11])[0], ((uint64_t *)&m_state.context.vfp.__v[11])[1], - ((uint64_t *)&m_state.context.vfp.__v[12])[0], ((uint64_t *)&m_state.context.vfp.__v[12])[1], - ((uint64_t *)&m_state.context.vfp.__v[13])[0], ((uint64_t *)&m_state.context.vfp.__v[13])[1], - ((uint64_t *)&m_state.context.vfp.__v[14])[0], ((uint64_t *)&m_state.context.vfp.__v[14])[1], - ((uint64_t *)&m_state.context.vfp.__v[15])[0], ((uint64_t *)&m_state.context.vfp.__v[15])[1], - ((uint64_t *)&m_state.context.vfp.__v[16])[0], ((uint64_t *)&m_state.context.vfp.__v[16])[1], - ((uint64_t *)&m_state.context.vfp.__v[17])[0], ((uint64_t *)&m_state.context.vfp.__v[17])[1], - ((uint64_t *)&m_state.context.vfp.__v[18])[0], ((uint64_t *)&m_state.context.vfp.__v[18])[1], - ((uint64_t *)&m_state.context.vfp.__v[19])[0], ((uint64_t *)&m_state.context.vfp.__v[19])[1], - ((uint64_t *)&m_state.context.vfp.__v[20])[0], ((uint64_t *)&m_state.context.vfp.__v[20])[1], - ((uint64_t *)&m_state.context.vfp.__v[21])[0], ((uint64_t *)&m_state.context.vfp.__v[21])[1], - ((uint64_t *)&m_state.context.vfp.__v[22])[0], ((uint64_t *)&m_state.context.vfp.__v[22])[1], - ((uint64_t *)&m_state.context.vfp.__v[23])[0], ((uint64_t *)&m_state.context.vfp.__v[23])[1], - ((uint64_t *)&m_state.context.vfp.__v[24])[0], ((uint64_t *)&m_state.context.vfp.__v[24])[1], - ((uint64_t *)&m_state.context.vfp.__v[25])[0], ((uint64_t *)&m_state.context.vfp.__v[25])[1], - ((uint64_t *)&m_state.context.vfp.__v[26])[0], ((uint64_t *)&m_state.context.vfp.__v[26])[1], - ((uint64_t *)&m_state.context.vfp.__v[27])[0], ((uint64_t *)&m_state.context.vfp.__v[27])[1], - ((uint64_t *)&m_state.context.vfp.__v[28])[0], ((uint64_t *)&m_state.context.vfp.__v[28])[1], - ((uint64_t *)&m_state.context.vfp.__v[29])[0], ((uint64_t *)&m_state.context.vfp.__v[29])[1], - ((uint64_t *)&m_state.context.vfp.__v[30])[0], ((uint64_t *)&m_state.context.vfp.__v[30])[1], - ((uint64_t *)&m_state.context.vfp.__v[31])[0], ((uint64_t *)&m_state.context.vfp.__v[31])[1], - m_state.context.vfp.__fpsr, - m_state.context.vfp.__fpcr); +kern_return_t DNBArchMachARM64::GetVFPState(bool force) { + int set = e_regSetVFP; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetVFPCount; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_NEON_STATE64, + (thread_state_t)&m_state.context.vfp, &count); + if (DNBLogEnabledForAny(LOG_THREAD)) { +#if defined(__arm64__) || defined(__aarch64__) + DNBLogThreaded( + "thread_get_state(0x%4.4x, %u, &vfp, %u) => 0x%8.8x (count = %u) regs" + "\n q0 = 0x%16.16llx%16.16llx" + "\n q1 = 0x%16.16llx%16.16llx" + "\n q2 = 0x%16.16llx%16.16llx" + "\n q3 = 0x%16.16llx%16.16llx" + "\n q4 = 0x%16.16llx%16.16llx" + "\n q5 = 0x%16.16llx%16.16llx" + "\n q6 = 0x%16.16llx%16.16llx" + "\n q7 = 0x%16.16llx%16.16llx" + "\n q8 = 0x%16.16llx%16.16llx" + "\n q9 = 0x%16.16llx%16.16llx" + "\n q10 = 0x%16.16llx%16.16llx" + "\n q11 = 0x%16.16llx%16.16llx" + "\n q12 = 0x%16.16llx%16.16llx" + "\n q13 = 0x%16.16llx%16.16llx" + "\n q14 = 0x%16.16llx%16.16llx" + "\n q15 = 0x%16.16llx%16.16llx" + "\n q16 = 0x%16.16llx%16.16llx" + "\n q17 = 0x%16.16llx%16.16llx" + "\n q18 = 0x%16.16llx%16.16llx" + "\n q19 = 0x%16.16llx%16.16llx" + "\n q20 = 0x%16.16llx%16.16llx" + "\n q21 = 0x%16.16llx%16.16llx" + "\n q22 = 0x%16.16llx%16.16llx" + "\n q23 = 0x%16.16llx%16.16llx" + "\n q24 = 0x%16.16llx%16.16llx" + "\n q25 = 0x%16.16llx%16.16llx" + "\n q26 = 0x%16.16llx%16.16llx" + "\n q27 = 0x%16.16llx%16.16llx" + "\n q28 = 0x%16.16llx%16.16llx" + "\n q29 = 0x%16.16llx%16.16llx" + "\n q30 = 0x%16.16llx%16.16llx" + "\n q31 = 0x%16.16llx%16.16llx" + "\n fpsr = 0x%8.8x" + "\n fpcr = 0x%8.8x\n\n", + m_thread->MachPortNumber(), e_regSetVFP, e_regSetVFPCount, kret, count, + ((uint64_t *)&m_state.context.vfp.__v[0])[0], + ((uint64_t *)&m_state.context.vfp.__v[0])[1], + ((uint64_t *)&m_state.context.vfp.__v[1])[0], + ((uint64_t *)&m_state.context.vfp.__v[1])[1], + ((uint64_t *)&m_state.context.vfp.__v[2])[0], + ((uint64_t *)&m_state.context.vfp.__v[2])[1], + ((uint64_t *)&m_state.context.vfp.__v[3])[0], + ((uint64_t *)&m_state.context.vfp.__v[3])[1], + ((uint64_t *)&m_state.context.vfp.__v[4])[0], + ((uint64_t *)&m_state.context.vfp.__v[4])[1], + ((uint64_t *)&m_state.context.vfp.__v[5])[0], + ((uint64_t *)&m_state.context.vfp.__v[5])[1], + ((uint64_t *)&m_state.context.vfp.__v[6])[0], + ((uint64_t *)&m_state.context.vfp.__v[6])[1], + ((uint64_t *)&m_state.context.vfp.__v[7])[0], + ((uint64_t *)&m_state.context.vfp.__v[7])[1], + ((uint64_t *)&m_state.context.vfp.__v[8])[0], + ((uint64_t *)&m_state.context.vfp.__v[8])[1], + ((uint64_t *)&m_state.context.vfp.__v[9])[0], + ((uint64_t *)&m_state.context.vfp.__v[9])[1], + ((uint64_t *)&m_state.context.vfp.__v[10])[0], + ((uint64_t *)&m_state.context.vfp.__v[10])[1], + ((uint64_t *)&m_state.context.vfp.__v[11])[0], + ((uint64_t *)&m_state.context.vfp.__v[11])[1], + ((uint64_t *)&m_state.context.vfp.__v[12])[0], + ((uint64_t *)&m_state.context.vfp.__v[12])[1], + ((uint64_t *)&m_state.context.vfp.__v[13])[0], + ((uint64_t *)&m_state.context.vfp.__v[13])[1], + ((uint64_t *)&m_state.context.vfp.__v[14])[0], + ((uint64_t *)&m_state.context.vfp.__v[14])[1], + ((uint64_t *)&m_state.context.vfp.__v[15])[0], + ((uint64_t *)&m_state.context.vfp.__v[15])[1], + ((uint64_t *)&m_state.context.vfp.__v[16])[0], + ((uint64_t *)&m_state.context.vfp.__v[16])[1], + ((uint64_t *)&m_state.context.vfp.__v[17])[0], + ((uint64_t *)&m_state.context.vfp.__v[17])[1], + ((uint64_t *)&m_state.context.vfp.__v[18])[0], + ((uint64_t *)&m_state.context.vfp.__v[18])[1], + ((uint64_t *)&m_state.context.vfp.__v[19])[0], + ((uint64_t *)&m_state.context.vfp.__v[19])[1], + ((uint64_t *)&m_state.context.vfp.__v[20])[0], + ((uint64_t *)&m_state.context.vfp.__v[20])[1], + ((uint64_t *)&m_state.context.vfp.__v[21])[0], + ((uint64_t *)&m_state.context.vfp.__v[21])[1], + ((uint64_t *)&m_state.context.vfp.__v[22])[0], + ((uint64_t *)&m_state.context.vfp.__v[22])[1], + ((uint64_t *)&m_state.context.vfp.__v[23])[0], + ((uint64_t *)&m_state.context.vfp.__v[23])[1], + ((uint64_t *)&m_state.context.vfp.__v[24])[0], + ((uint64_t *)&m_state.context.vfp.__v[24])[1], + ((uint64_t *)&m_state.context.vfp.__v[25])[0], + ((uint64_t *)&m_state.context.vfp.__v[25])[1], + ((uint64_t *)&m_state.context.vfp.__v[26])[0], + ((uint64_t *)&m_state.context.vfp.__v[26])[1], + ((uint64_t *)&m_state.context.vfp.__v[27])[0], + ((uint64_t *)&m_state.context.vfp.__v[27])[1], + ((uint64_t *)&m_state.context.vfp.__v[28])[0], + ((uint64_t *)&m_state.context.vfp.__v[28])[1], + ((uint64_t *)&m_state.context.vfp.__v[29])[0], + ((uint64_t *)&m_state.context.vfp.__v[29])[1], + ((uint64_t *)&m_state.context.vfp.__v[30])[0], + ((uint64_t *)&m_state.context.vfp.__v[30])[1], + ((uint64_t *)&m_state.context.vfp.__v[31])[0], + ((uint64_t *)&m_state.context.vfp.__v[31])[1], + m_state.context.vfp.__fpsr, m_state.context.vfp.__fpcr); #endif - } - m_state.SetError(set, Read, kret); - return kret; + } + m_state.SetError(set, Read, kret); + return kret; } -kern_return_t -DNBArchMachARM64::GetEXCState(bool force) -{ - int set = e_regSetEXC; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; - - // Read the registers from our thread - mach_msg_type_number_t count = e_regSetEXCCount; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, &count); - m_state.SetError(set, Read, kret); - return kret; +kern_return_t DNBArchMachARM64::GetEXCState(bool force) { + int set = e_regSetEXC; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; + + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetEXCCount; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, + (thread_state_t)&m_state.context.exc, &count); + m_state.SetError(set, Read, kret); + return kret; } -static void -DumpDBGState(const arm_debug_state_t& dbg) -{ - uint32_t i = 0; - for (i=0; i<16; i++) - DNBLogThreadedIf(LOG_STEP, "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]); +static void DumpDBGState(const arm_debug_state_t &dbg) { + uint32_t i = 0; + for (i = 0; i < 16; i++) + DNBLogThreadedIf(LOG_STEP, "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]); } -kern_return_t -DNBArchMachARM64::GetDBGState(bool force) -{ - int set = e_regSetDBG; +kern_return_t DNBArchMachARM64::GetDBGState(bool force) { + int set = e_regSetDBG; - // Check if we have valid cached registers - if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) - return KERN_SUCCESS; + // Check if we have valid cached registers + if (!force && m_state.GetError(set, Read) == KERN_SUCCESS) + return KERN_SUCCESS; - // Read the registers from our thread - mach_msg_type_number_t count = e_regSetDBGCount; - kern_return_t kret = ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, &count); - m_state.SetError(set, Read, kret); + // Read the registers from our thread + mach_msg_type_number_t count = e_regSetDBGCount; + kern_return_t kret = + ::thread_get_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, + (thread_state_t)&m_state.dbg, &count); + m_state.SetError(set, Read, kret); - return kret; + return kret; } -kern_return_t -DNBArchMachARM64::SetGPRState() -{ - int set = e_regSetGPR; - kern_return_t kret = ::thread_set_state(m_thread->MachPortNumber(), ARM_THREAD_STATE64, (thread_state_t)&m_state.context.gpr, e_regSetGPRCount); - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code +kern_return_t DNBArchMachARM64::SetGPRState() { + int set = e_regSetGPR; + kern_return_t kret = ::thread_set_state( + m_thread->MachPortNumber(), ARM_THREAD_STATE64, + (thread_state_t)&m_state.context.gpr, e_regSetGPRCount); + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM64::SetVFPState() -{ - int set = e_regSetVFP; - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_NEON_STATE64, (thread_state_t)&m_state.context.vfp, e_regSetVFPCount); - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code +kern_return_t DNBArchMachARM64::SetVFPState() { + int set = e_regSetVFP; + kern_return_t kret = ::thread_set_state( + m_thread->MachPortNumber(), ARM_NEON_STATE64, + (thread_state_t)&m_state.context.vfp, e_regSetVFPCount); + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM64::SetEXCState() -{ - int set = e_regSetEXC; - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, (thread_state_t)&m_state.context.exc, e_regSetEXCCount); - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - return kret; // Return the error code +kern_return_t DNBArchMachARM64::SetEXCState() { + int set = e_regSetEXC; + kern_return_t kret = ::thread_set_state( + m_thread->MachPortNumber(), ARM_EXCEPTION_STATE64, + (thread_state_t)&m_state.context.exc, e_regSetEXCCount); + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + return kret; // Return the error code } -kern_return_t -DNBArchMachARM64::SetDBGState(bool also_set_on_task) -{ - int set = e_regSetDBG; - kern_return_t kret = ::thread_set_state (m_thread->MachPortNumber(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, e_regSetDBGCount); - if (also_set_on_task) - { - kern_return_t task_kret = task_set_state (m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE64, (thread_state_t)&m_state.dbg, e_regSetDBGCount); - if (task_kret != KERN_SUCCESS) - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::SetDBGState failed to set debug control register state: 0x%8.8x.", task_kret); - } - m_state.SetError(set, Write, kret); // Set the current write error for this register set - m_state.InvalidateRegisterSetState(set); // Invalidate the current register state in case registers are read back differently - - return kret; // Return the error code +kern_return_t DNBArchMachARM64::SetDBGState(bool also_set_on_task) { + int set = e_regSetDBG; + kern_return_t kret = + ::thread_set_state(m_thread->MachPortNumber(), ARM_DEBUG_STATE64, + (thread_state_t)&m_state.dbg, e_regSetDBGCount); + if (also_set_on_task) { + kern_return_t task_kret = task_set_state( + m_thread->Process()->Task().TaskPort(), ARM_DEBUG_STATE64, + (thread_state_t)&m_state.dbg, e_regSetDBGCount); + if (task_kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::SetDBGState failed " + "to set debug control register state: " + "0x%8.8x.", + task_kret); + } + m_state.SetError(set, Write, + kret); // Set the current write error for this register set + m_state.InvalidateRegisterSetState(set); // Invalidate the current register + // state in case registers are read + // back differently + + return kret; // Return the error code } -void -DNBArchMachARM64::ThreadWillResume() -{ - // Do we need to step this thread? If so, let the mach thread tell us so. - if (m_thread->IsStepping()) - { - EnableHardwareSingleStep(true); +void DNBArchMachARM64::ThreadWillResume() { + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) { + EnableHardwareSingleStep(true); + } + + // Disable the triggered watchpoint temporarily before we resume. + // Plus, we try to enable hardware single step to execute past the instruction + // which triggered our watchpoint. + if (m_watchpoint_did_occur) { + if (m_watchpoint_hw_index >= 0) { + kern_return_t kret = GetDBGState(false); + if (kret == KERN_SUCCESS && + !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { + // The watchpoint might have been disabled by the user. We don't need + // to do anything at all + // to enable hardware single stepping. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + return; + } + + DisableHardwareWatchpoint(m_watchpoint_hw_index, false); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() " + "DisableHardwareWatchpoint(%d) called", + m_watchpoint_hw_index); + + // Enable hardware single step to move past the watchpoint-triggering + // instruction. + m_watchpoint_resume_single_step_enabled = + (EnableHardwareSingleStep(true) == KERN_SUCCESS); + + // If we are not able to enable single step to move past the + // watchpoint-triggering instruction, + // at least we should reset the two watchpoint member variables so that + // the next time around + // this callback function is invoked, the enclosing logical branch is + // skipped. + if (!m_watchpoint_resume_single_step_enabled) { + // Reset the two watchpoint member variables. + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchMachARM::ThreadWillResume() failed to enable single step"); + } else + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() " + "succeeded to enable single step"); } + } +} - // Disable the triggered watchpoint temporarily before we resume. - // Plus, we try to enable hardware single step to execute past the instruction which triggered our watchpoint. - if (m_watchpoint_did_occur) - { - if (m_watchpoint_hw_index >= 0) - { - kern_return_t kret = GetDBGState(false); - if (kret == KERN_SUCCESS && !IsWatchpointEnabled(m_state.dbg, m_watchpoint_hw_index)) { - // The watchpoint might have been disabled by the user. We don't need to do anything at all - // to enable hardware single stepping. - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - return; - } - - DisableHardwareWatchpoint(m_watchpoint_hw_index, false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() DisableHardwareWatchpoint(%d) called", - m_watchpoint_hw_index); - - // Enable hardware single step to move past the watchpoint-triggering instruction. - m_watchpoint_resume_single_step_enabled = (EnableHardwareSingleStep(true) == KERN_SUCCESS); - - // If we are not able to enable single step to move past the watchpoint-triggering instruction, - // at least we should reset the two watchpoint member variables so that the next time around - // this callback function is invoked, the enclosing logical branch is skipped. - if (!m_watchpoint_resume_single_step_enabled) { - // Reset the two watchpoint member variables. - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() failed to enable single step"); - } - else - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::ThreadWillResume() succeeded to enable single step"); +bool DNBArchMachARM64::NotifyException(MachException::Data &exc) { + + switch (exc.exc_type) { + default: + break; + case EXC_BREAKPOINT: + if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) { + // The data break address is passed as exc_data[1]. + nub_addr_t addr = exc.exc_data[1]; + // Find the hardware index with the side effect of possibly massaging the + // addr to return the starting address as seen from the debugger side. + uint32_t hw_index = GetHardwareWatchpointHit(addr); + + // One logical watchpoint was split into two watchpoint locations because + // it was too big. If the watchpoint exception is indicating the 2nd half + // of the two-parter, find the address of the 1st half and report that -- + // that's what lldb is going to expect to see. + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException " + "watchpoint %d was hit on address " + "0x%llx", + hw_index, (uint64_t)addr); + const int num_watchpoints = NumSupportedHardwareWatchpoints(); + for (int i = 0; i < num_watchpoints; i++) { + if (LoHi[i] != 0 && LoHi[i] == hw_index && LoHi[i] != i && + GetWatchpointAddressByIndex(i) != INVALID_NUB_ADDRESS) { + addr = GetWatchpointAddressByIndex(i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException " + "It is a linked watchpoint; " + "rewritten to index %d addr 0x%llx", + LoHi[i], (uint64_t)addr); } - } -} + } + + if (hw_index != INVALID_NUB_HW_INDEX) { + m_watchpoint_did_occur = true; + m_watchpoint_hw_index = hw_index; + exc.exc_data[1] = addr; + // Piggyback the hw_index in the exc.data. + exc.exc_data.push_back(hw_index); + } -bool -DNBArchMachARM64::NotifyException(MachException::Data& exc) -{ - - switch (exc.exc_type) - { - default: - break; - case EXC_BREAKPOINT: - if (exc.exc_data.size() == 2 && exc.exc_data[0] == EXC_ARM_DA_DEBUG) - { - // The data break address is passed as exc_data[1]. - nub_addr_t addr = exc.exc_data[1]; - // Find the hardware index with the side effect of possibly massaging the - // addr to return the starting address as seen from the debugger side. - uint32_t hw_index = GetHardwareWatchpointHit(addr); - - // One logical watchpoint was split into two watchpoint locations because - // it was too big. If the watchpoint exception is indicating the 2nd half - // of the two-parter, find the address of the 1st half and report that -- - // that's what lldb is going to expect to see. - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException watchpoint %d was hit on address 0x%llx", hw_index, (uint64_t) addr); - const int num_watchpoints = NumSupportedHardwareWatchpoints (); - for (int i = 0; i < num_watchpoints; i++) - { - if (LoHi[i] != 0 - && LoHi[i] == hw_index - && LoHi[i] != i - && GetWatchpointAddressByIndex (i) != INVALID_NUB_ADDRESS) - { - addr = GetWatchpointAddressByIndex (i); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM::NotifyException It is a linked watchpoint; rewritten to index %d addr 0x%llx", LoHi[i], (uint64_t) addr); - } - } - - if (hw_index != INVALID_NUB_HW_INDEX) - { - m_watchpoint_did_occur = true; - m_watchpoint_hw_index = hw_index; - exc.exc_data[1] = addr; - // Piggyback the hw_index in the exc.data. - exc.exc_data.push_back(hw_index); - } - - return true; - } - break; + return true; } - return false; + break; + } + return false; } -bool -DNBArchMachARM64::ThreadDidStop() -{ - bool success = true; - - m_state.InvalidateAllRegisterStates(); - - if (m_watchpoint_resume_single_step_enabled) - { - // Great! We now disable the hardware single step as well as re-enable the hardware watchpoint. - // See also ThreadWillResume(). - if (EnableHardwareSingleStep(false) == KERN_SUCCESS) - { - if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) - { - ReenableHardwareWatchpoint(m_watchpoint_hw_index); - m_watchpoint_resume_single_step_enabled = false; - m_watchpoint_did_occur = false; - m_watchpoint_hw_index = -1; - } - else - { - DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) does not hold!"); - } - } - else - { - DNBLogError("internal error detected: m_watchpoint_resume_step_enabled is true but unable to disable single step!"); - } +bool DNBArchMachARM64::ThreadDidStop() { + bool success = true; + + m_state.InvalidateAllRegisterStates(); + + if (m_watchpoint_resume_single_step_enabled) { + // Great! We now disable the hardware single step as well as re-enable the + // hardware watchpoint. + // See also ThreadWillResume(). + if (EnableHardwareSingleStep(false) == KERN_SUCCESS) { + if (m_watchpoint_did_occur && m_watchpoint_hw_index >= 0) { + ReenableHardwareWatchpoint(m_watchpoint_hw_index); + m_watchpoint_resume_single_step_enabled = false; + m_watchpoint_did_occur = false; + m_watchpoint_hw_index = -1; + } else { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " + "is true but (m_watchpoint_did_occur && " + "m_watchpoint_hw_index >= 0) does not hold!"); + } + } else { + DNBLogError("internal error detected: m_watchpoint_resume_step_enabled " + "is true but unable to disable single step!"); } - - // Are we stepping a single instruction? - if (GetGPRState(true) == KERN_SUCCESS) - { - // We are single stepping, was this the primary thread? - if (m_thread->IsStepping()) - { - // This was the primary thread, we need to clear the trace - // bit if so. - success = EnableHardwareSingleStep(false) == KERN_SUCCESS; - } - else - { - // The MachThread will automatically restore the suspend count - // in ThreadDidStop(), so we don't need to do anything here if - // we weren't the primary thread the last time - } + } + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } else { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time } - return success; + } + return success; } // Set the single step bit in the processor status register. -kern_return_t -DNBArchMachARM64::EnableHardwareSingleStep (bool enable) -{ - DNBError err; - DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); - - err = GetGPRState(false); - - if (err.Fail()) - { - err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); - return err.Error(); - } - - err = GetDBGState(false); - - if (err.Fail()) - { - err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); - return err.Error(); - } - - if (enable) - { - DNBLogThreadedIf(LOG_STEP, "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); - m_state.dbg.__mdscr_el1 |= SS_ENABLE; - } - else - { - DNBLogThreadedIf(LOG_STEP, "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", __FUNCTION__, (uint64_t) m_state.context.gpr.__pc); - m_state.dbg.__mdscr_el1 &= ~(SS_ENABLE); - } - - return SetDBGState(false); +kern_return_t DNBArchMachARM64::EnableHardwareSingleStep(bool enable) { + DNBError err; + DNBLogThreadedIf(LOG_STEP, "%s( enable = %d )", __FUNCTION__, enable); + + err = GetGPRState(false); + + if (err.Fail()) { + err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); + return err.Error(); + } + + err = GetDBGState(false); + + if (err.Fail()) { + err.LogThreaded("%s: failed to read the DBG registers", __FUNCTION__); + return err.Error(); + } + + if (enable) { + DNBLogThreadedIf(LOG_STEP, + "%s: Setting MDSCR_EL1 Single Step bit at pc 0x%llx", + __FUNCTION__, (uint64_t)m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 |= SS_ENABLE; + } else { + DNBLogThreadedIf(LOG_STEP, + "%s: Clearing MDSCR_EL1 Single Step bit at pc 0x%llx", + __FUNCTION__, (uint64_t)m_state.context.gpr.__pc); + m_state.dbg.__mdscr_el1 &= ~(SS_ENABLE); + } + + return SetDBGState(false); } // return 1 if bit "BIT" is set in "value" -static inline uint32_t bit(uint32_t value, uint32_t bit) -{ - return (value >> bit) & 1u; +static inline uint32_t bit(uint32_t value, uint32_t bit) { + return (value >> bit) & 1u; } // return the bitfield "value[msbit:lsbit]". -static inline uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) -{ - assert(msbit >= lsbit); - uint64_t shift_left = sizeof(value) * 8 - 1 - msbit; - value <<= shift_left; // shift anything above the msbit off of the unsigned edge - value >>= shift_left + lsbit; // shift it back again down to the lsbit (including undoing any shift from above) - return value; // return our result +static inline uint64_t bits(uint64_t value, uint32_t msbit, uint32_t lsbit) { + assert(msbit >= lsbit); + uint64_t shift_left = sizeof(value) * 8 - 1 - msbit; + value <<= + shift_left; // shift anything above the msbit off of the unsigned edge + value >>= shift_left + lsbit; // shift it back again down to the lsbit + // (including undoing any shift from above) + return value; // return our result } -uint32_t -DNBArchMachARM64::NumSupportedHardwareWatchpoints() -{ - // 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 = UINT_MAX; - if (g_num_supported_hw_watchpoints == UINT_MAX) - { - // Set this to zero in case we can't tell if there are any HW breakpoints - g_num_supported_hw_watchpoints = 0; - - - 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; - DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); - } - else - { - // For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in EL0 so it can't - // access that reg. The kernel should have filled in the sysctls based on it though. -#if defined (__arm__) - uint32_t register_DBGDIDR; - - asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR)); - uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); - // Zero is reserved for the WRP count, so don't increment it if it is zero - if (numWRPs > 0) - numWRPs++; - g_num_supported_hw_watchpoints = numWRPs; - DNBLogThreadedIf(LOG_THREAD, "Number of supported hw watchpoints via asm(): %d", g_num_supported_hw_watchpoints); +uint32_t DNBArchMachARM64::NumSupportedHardwareWatchpoints() { + // 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 = UINT_MAX; + if (g_num_supported_hw_watchpoints == UINT_MAX) { + // Set this to zero in case we can't tell if there are any HW breakpoints + g_num_supported_hw_watchpoints = 0; + + 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; + DNBLogThreadedIf(LOG_THREAD, "hw.optional.watchpoint=%u", n); + } else { +// For AArch64 we would need to look at ID_AA64DFR0_EL1 but debugserver runs in +// EL0 so it can't +// access that reg. The kernel should have filled in the sysctls based on it +// though. +#if defined(__arm__) + uint32_t register_DBGDIDR; + + asm("mrc p14, 0, %0, c0, c0, 0" : "=r"(register_DBGDIDR)); + uint32_t numWRPs = bits(register_DBGDIDR, 31, 28); + // Zero is reserved for the WRP count, so don't increment it if it is zero + if (numWRPs > 0) + numWRPs++; + g_num_supported_hw_watchpoints = numWRPs; + DNBLogThreadedIf(LOG_THREAD, + "Number of supported hw watchpoints via asm(): %d", + g_num_supported_hw_watchpoints); #endif - } } - return g_num_supported_hw_watchpoints; + } + return g_num_supported_hw_watchpoints; } -uint32_t -DNBArchMachARM64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu, read = %u, write = %u)", (uint64_t)addr, size, read, write); - - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - - // Can't watch zero bytes - if (size == 0) - return INVALID_NUB_HW_INDEX; - - // We must watch for either read or write - if (read == false && write == false) - return INVALID_NUB_HW_INDEX; - - // Otherwise, can't watch more than 8 bytes per WVR/WCR pair - if (size > 8) - return INVALID_NUB_HW_INDEX; - - // arm64 watchpoints really have an 8-byte alignment requirement. You can put a watchpoint on a 4-byte - // offset address but you can only watch 4 bytes with that watchpoint. - - // arm64 watchpoints on an 8-byte (double word) aligned addr can watch any bytes in that - // 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, 3rd byte, etc, or any - // combination therein by setting the bits in the BAS [12:5] (Byte Address Select) field of - // the DBGWCRn_EL1 reg for the watchpoint. - - // If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to monitor a larger region - // of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield then selects a larger - // range of bytes, instead of individual bytes. See the ARMv8 Debug Architecture manual for details. - // This implementation does not currently use the MASK bits; the largest single region watched by a single - // watchpoint right now is 8-bytes. - - nub_addr_t aligned_wp_address = addr & ~0x7; - uint32_t addr_dword_offset = addr & 0x7; - - // Do we need to split up this logical watchpoint into two hardware watchpoint - // registers? - // e.g. a watchpoint of length 4 on address 6. We need do this with - // one watchpoint on address 0 with bytes 6 & 7 being monitored - // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored - - if (addr_dword_offset + size > 8) - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(addr = 0x%8.8llx, size = %zu) needs two hardware watchpoints slots to monitor", (uint64_t)addr, size); - int low_watchpoint_size = 8 - addr_dword_offset; - int high_watchpoint_size = addr_dword_offset + size - 8; - - uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, write, also_set_on_task); - if (lo == INVALID_NUB_HW_INDEX) - return INVALID_NUB_HW_INDEX; - uint32_t hi = EnableHardwareWatchpoint (aligned_wp_address + 8, high_watchpoint_size, read, write, also_set_on_task); - if (hi == INVALID_NUB_HW_INDEX) - { - DisableHardwareWatchpoint (lo, also_set_on_task); - return INVALID_NUB_HW_INDEX; - } - // Tag this lo->hi mapping in our database. - LoHi[lo] = hi; - return lo; - } - - // At this point - // 1 aligned_wp_address is the requested address rounded down to 8-byte alignment - // 2 addr_dword_offset is the offset into that double word (8-byte) region that we are watching - // 3 size is the number of bytes within that 8-byte region that we are watching - - // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the above. - // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, etc, up to 0b11111111 for 8. - // then we shift those bits left by the offset into this dword that we are interested in. - // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of 0b11110000. - uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; - - // Read the debug state - kern_return_t kret = GetDBGState(false); - - if (kret == KERN_SUCCESS) - { - // Check to make sure we have the needed hardware support - uint32_t i = 0; - - for (i=0; i<num_hw_watchpoints; ++i) - { - if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) - break; // We found an available hw watchpoint slot (in i) - } +uint32_t DNBArchMachARM64::EnableHardwareWatchpoint(nub_addr_t addr, + nub_size_t size, bool read, + bool write, + bool also_set_on_task) { + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::EnableHardwareWatchpoint(addr = " + "0x%8.8llx, size = %zu, read = %u, write = %u)", + (uint64_t)addr, size, read, write); - // See if we found an available hw watchpoint slot above - if (i < num_hw_watchpoints) - { - //DumpDBGState(m_state.dbg); + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - // Clear any previous LoHi joined-watchpoint that may have been in use - LoHi[i] = 0; - - // shift our Byte Address Select bits up to the correct bit range for the DBGWCRn_EL1 - byte_address_select = byte_address_select << 5; - - // Make sure bits 1:0 are clear in our address - m_state.dbg.__wvr[i] = aligned_wp_address; // DVA (Data Virtual Address) - m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow the DVA that we will watch - S_USER | // Stop only in user mode - (read ? WCR_LOAD : 0) | // Stop on read access? - (write ? WCR_STORE : 0) | // Stop on write access? - WCR_ENABLE; // Enable this watchpoint; + // Can't watch zero bytes + if (size == 0) + return INVALID_NUB_HW_INDEX; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint() adding watchpoint on address 0x%llx with control register value 0x%x", (uint64_t) m_state.dbg.__wvr[i], (uint32_t) m_state.dbg.__wcr[i]); + // We must watch for either read or write + if (read == false && write == false) + return INVALID_NUB_HW_INDEX; - // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. + // Otherwise, can't watch more than 8 bytes per WVR/WCR pair + if (size > 8) + return INVALID_NUB_HW_INDEX; - kret = SetDBGState(also_set_on_task); - //DumpDBGState(m_state.dbg); + // arm64 watchpoints really have an 8-byte alignment requirement. You can put + // a watchpoint on a 4-byte + // offset address but you can only watch 4 bytes with that watchpoint. + + // arm64 watchpoints on an 8-byte (double word) aligned addr can watch any + // bytes in that + // 8-byte long region of memory. They can watch the 1st byte, the 2nd byte, + // 3rd byte, etc, or any + // combination therein by setting the bits in the BAS [12:5] (Byte Address + // Select) field of + // the DBGWCRn_EL1 reg for the watchpoint. + + // If the MASK [28:24] bits in the DBGWCRn_EL1 allow a single watchpoint to + // monitor a larger region + // of memory (16 bytes, 32 bytes, or 2GB) but the Byte Address Select bitfield + // then selects a larger + // range of bytes, instead of individual bytes. See the ARMv8 Debug + // Architecture manual for details. + // This implementation does not currently use the MASK bits; the largest + // single region watched by a single + // watchpoint right now is 8-bytes. + + nub_addr_t aligned_wp_address = addr & ~0x7; + uint32_t addr_dword_offset = addr & 0x7; + + // Do we need to split up this logical watchpoint into two hardware watchpoint + // registers? + // e.g. a watchpoint of length 4 on address 6. We need do this with + // one watchpoint on address 0 with bytes 6 & 7 being monitored + // one watchpoint on address 8 with bytes 0, 1, 2, 3 being monitored + + if (addr_dword_offset + size > 8) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "EnableHardwareWatchpoint(addr = " + "0x%8.8llx, size = %zu) needs two " + "hardware watchpoints slots to monitor", + (uint64_t)addr, size); + int low_watchpoint_size = 8 - addr_dword_offset; + int high_watchpoint_size = addr_dword_offset + size - 8; + + uint32_t lo = EnableHardwareWatchpoint(addr, low_watchpoint_size, read, + write, also_set_on_task); + if (lo == INVALID_NUB_HW_INDEX) + return INVALID_NUB_HW_INDEX; + uint32_t hi = + EnableHardwareWatchpoint(aligned_wp_address + 8, high_watchpoint_size, + read, write, also_set_on_task); + if (hi == INVALID_NUB_HW_INDEX) { + DisableHardwareWatchpoint(lo, also_set_on_task); + return INVALID_NUB_HW_INDEX; + } + // Tag this lo->hi mapping in our database. + LoHi[lo] = hi; + return lo; + } + + // At this point + // 1 aligned_wp_address is the requested address rounded down to 8-byte + // alignment + // 2 addr_dword_offset is the offset into that double word (8-byte) region + // that we are watching + // 3 size is the number of bytes within that 8-byte region that we are + // watching + + // Set the Byte Address Selects bits DBGWCRn_EL1 bits [12:5] based on the + // above. + // The bit shift and negation operation will give us 0b11 for 2, 0b1111 for 4, + // etc, up to 0b11111111 for 8. + // then we shift those bits left by the offset into this dword that we are + // interested in. + // e.g. if we are watching bytes 4,5,6,7 in a dword we want a BAS of + // 0b11110000. + uint32_t byte_address_select = ((1 << size) - 1) << addr_dword_offset; + + // Read the debug state + kern_return_t kret = GetDBGState(false); + + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); + for (i = 0; i < num_hw_watchpoints; ++i) { + if ((m_state.dbg.__wcr[i] & WCR_ENABLE) == 0) + break; // We found an available hw watchpoint slot (in i) + } - if (kret == KERN_SUCCESS) - return i; - } - else - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); - } + // See if we found an available hw watchpoint slot above + if (i < num_hw_watchpoints) { + // DumpDBGState(m_state.dbg); + + // Clear any previous LoHi joined-watchpoint that may have been in use + LoHi[i] = 0; + + // shift our Byte Address Select bits up to the correct bit range for the + // DBGWCRn_EL1 + byte_address_select = byte_address_select << 5; + + // Make sure bits 1:0 are clear in our address + m_state.dbg.__wvr[i] = aligned_wp_address; // DVA (Data Virtual Address) + m_state.dbg.__wcr[i] = byte_address_select | // Which bytes that follow + // the DVA that we will watch + S_USER | // Stop only in user mode + (read ? WCR_LOAD : 0) | // Stop on read access? + (write ? WCR_STORE : 0) | // Stop on write access? + WCR_ENABLE; // Enable this watchpoint; + + DNBLogThreadedIf( + LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint() " + "adding watchpoint on address 0x%llx with control " + "register value 0x%x", + (uint64_t)m_state.dbg.__wvr[i], (uint32_t)m_state.dbg.__wcr[i]); + + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. + + kret = SetDBGState(also_set_on_task); + // DumpDBGState(m_state.dbg); + + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "EnableHardwareWatchpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "EnableHardwareWatchpoint(): All " + "hardware resources (%u) are in use.", + num_hw_watchpoints); } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -bool -DNBArchMachARM64::ReenableHardwareWatchpoint (uint32_t hw_index) -{ - // If this logical watchpoint # is actually implemented using - // two hardware watchpoint registers, re-enable both of them. +bool DNBArchMachARM64::ReenableHardwareWatchpoint(uint32_t hw_index) { + // If this logical watchpoint # is actually implemented using + // two hardware watchpoint registers, re-enable both of them. - if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) - { - return ReenableHardwareWatchpoint_helper (hw_index) && ReenableHardwareWatchpoint_helper (LoHi[hw_index]); - } - else - { - return ReenableHardwareWatchpoint_helper (hw_index); - } + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { + return ReenableHardwareWatchpoint_helper(hw_index) && + ReenableHardwareWatchpoint_helper(LoHi[hw_index]); + } else { + return ReenableHardwareWatchpoint_helper(hw_index); + } } -bool -DNBArchMachARM64::ReenableHardwareWatchpoint_helper (uint32_t hw_index) -{ - kern_return_t kret = GetDBGState(false); - if (kret != KERN_SUCCESS) - return false; +bool DNBArchMachARM64::ReenableHardwareWatchpoint_helper(uint32_t hw_index) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (hw_index >= num_hw_points) - return false; + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; - m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; - m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; + m_state.dbg.__wvr[hw_index] = m_disabled_watchpoints[hw_index].addr; + m_state.dbg.__wcr[hw_index] = m_disabled_watchpoints[hw_index].control; - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::EnableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", - hw_index, - hw_index, - (uint64_t) m_state.dbg.__wvr[hw_index], - hw_index, - (uint64_t) m_state.dbg.__wcr[hw_index]); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "EnableHardwareWatchpoint( %u ) - WVR%u = " + "0x%8.8llx WCR%u = 0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); - // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us automatically, don't need to do it here. + // The kernel will set the MDE_ENABLE bit in the MDSCR_EL1 for us + // automatically, don't need to do it here. - kret = SetDBGState(false); + kret = SetDBGState(false); - return (kret == KERN_SUCCESS); + return (kret == KERN_SUCCESS); } -bool -DNBArchMachARM64::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) -{ - if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) - { - return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task) && DisableHardwareWatchpoint_helper (LoHi[hw_index], also_set_on_task); - } - else - { - return DisableHardwareWatchpoint_helper (hw_index, also_set_on_task); - } +bool DNBArchMachARM64::DisableHardwareWatchpoint(uint32_t hw_index, + bool also_set_on_task) { + if (hw_index < NumSupportedHardwareWatchpoints() && LoHi[hw_index]) { + return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task) && + DisableHardwareWatchpoint_helper(LoHi[hw_index], also_set_on_task); + } else { + return DisableHardwareWatchpoint_helper(hw_index, also_set_on_task); + } } -bool -DNBArchMachARM64::DisableHardwareWatchpoint_helper (uint32_t hw_index, bool also_set_on_task) -{ - kern_return_t kret = GetDBGState(false); - if (kret != KERN_SUCCESS) - return false; +bool DNBArchMachARM64::DisableHardwareWatchpoint_helper(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + if (kret != KERN_SUCCESS) + return false; - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (hw_index >= num_hw_points) - return false; + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (hw_index >= num_hw_points) + return false; - m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; - m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; + m_disabled_watchpoints[hw_index].addr = m_state.dbg.__wvr[hw_index]; + m_disabled_watchpoints[hw_index].control = m_state.dbg.__wcr[hw_index]; - m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::DisableHardwareWatchpoint( %u ) - WVR%u = 0x%8.8llx WCR%u = 0x%8.8llx", - hw_index, - hw_index, - (uint64_t) m_state.dbg.__wvr[hw_index], - hw_index, - (uint64_t) m_state.dbg.__wcr[hw_index]); + m_state.dbg.__wcr[hw_index] &= ~((nub_addr_t)WCR_ENABLE); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "DisableHardwareWatchpoint( %u ) - WVR%u = " + "0x%8.8llx WCR%u = 0x%8.8llx", + hw_index, hw_index, (uint64_t)m_state.dbg.__wvr[hw_index], + hw_index, (uint64_t)m_state.dbg.__wcr[hw_index]); - kret = SetDBGState(also_set_on_task); + kret = SetDBGState(also_set_on_task); - return (kret == KERN_SUCCESS); + return (kret == KERN_SUCCESS); } -// This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control register. +// This is for checking the Byte Address Select bits in the DBRWCRn_EL1 control +// register. // Returns -1 if the trailing bit patterns are not one of: -// { 0b???????1, 0b??????10, 0b?????100, 0b????1000, 0b???10000, 0b??100000, 0b?1000000, 0b10000000 }. -static inline -int32_t -LowestBitSet(uint32_t val) -{ - for (unsigned i = 0; i < 8; ++i) { - if (bit(val, i)) - return i; - } - return -1; +// { 0b???????1, 0b??????10, 0b?????100, 0b????1000, 0b???10000, 0b??100000, +// 0b?1000000, 0b10000000 }. +static inline int32_t LowestBitSet(uint32_t val) { + for (unsigned i = 0; i < 8; ++i) { + if (bit(val, i)) + return i; + } + return -1; } -// Iterate through the debug registers; return the index of the first watchpoint whose address matches. -// As a side effect, the starting address as understood by the debugger is returned which could be +// Iterate through the debug registers; return the index of the first watchpoint +// whose address matches. +// As a side effect, the starting address as understood by the debugger is +// returned which could be // different from 'addr' passed as an in/out argument. -uint32_t -DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) -{ - // Read the debug state - kern_return_t kret = GetDBGState(true); - //DumpDBGState(m_state.dbg); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", (uint64_t)addr); - - // This is the watchpoint value to match against, i.e., word address. - nub_addr_t wp_val = addr & ~((nub_addr_t)3); - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.dbg; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - { - nub_addr_t wp_addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, - "DNBArchMachARM64::GetHardwareWatchpointHit() slot: %u (addr = 0x%llx).", - i, (uint64_t)wp_addr); - if (wp_val == wp_addr) { - uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); - - // Sanity check the byte_mask, first. - if (LowestBitSet(byte_mask) < 0) - continue; - - // Check that the watchpoint is enabled. - if (!IsWatchpointEnabled(debug_state, i)) - continue; - - // Compute the starting address (from the point of view of the debugger). - addr = wp_addr + LowestBitSet(byte_mask); - return i; - } - } +uint32_t DNBArchMachARM64::GetHardwareWatchpointHit(nub_addr_t &addr) { + // Read the debug state + kern_return_t kret = GetDBGState(true); + // DumpDBGState(m_state.dbg); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchMachARM64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", + kret); + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchMachARM64::GetHardwareWatchpointHit() addr = 0x%llx", + (uint64_t)addr); + + // This is the watchpoint value to match against, i.e., word address. + nub_addr_t wp_val = addr & ~((nub_addr_t)3); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.dbg; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) { + nub_addr_t wp_addr = GetWatchAddress(debug_state, i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchMachARM64::" + "GetHardwareWatchpointHit() slot: %u " + "(addr = 0x%llx).", + i, (uint64_t)wp_addr); + if (wp_val == wp_addr) { + uint32_t byte_mask = bits(debug_state.__wcr[i], 12, 5); + + // Sanity check the byte_mask, first. + if (LowestBitSet(byte_mask) < 0) + continue; + + // Check that the watchpoint is enabled. + if (!IsWatchpointEnabled(debug_state, i)) + continue; + + // Compute the starting address (from the point of view of the + // debugger). + addr = wp_addr + LowestBitSet(byte_mask); + return i; + } } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -nub_addr_t -DNBArchMachARM64::GetWatchpointAddressByIndex (uint32_t hw_index) -{ - kern_return_t kret = GetDBGState(true); - if (kret != KERN_SUCCESS) - return INVALID_NUB_ADDRESS; - const uint32_t num = NumSupportedHardwareWatchpoints(); - if (hw_index >= num) - return INVALID_NUB_ADDRESS; - if (IsWatchpointEnabled (m_state.dbg, hw_index)) - return GetWatchAddress (m_state.dbg, hw_index); +nub_addr_t DNBArchMachARM64::GetWatchpointAddressByIndex(uint32_t hw_index) { + kern_return_t kret = GetDBGState(true); + if (kret != KERN_SUCCESS) + return INVALID_NUB_ADDRESS; + const uint32_t num = NumSupportedHardwareWatchpoints(); + if (hw_index >= num) return INVALID_NUB_ADDRESS; + if (IsWatchpointEnabled(m_state.dbg, hw_index)) + return GetWatchAddress(m_state.dbg, hw_index); + return INVALID_NUB_ADDRESS; } -bool -DNBArchMachARM64::IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index) -{ - // Watchpoint Control Registers, bitfield definitions - // ... - // Bits Value Description - // [0] 0 Watchpoint disabled - // 1 Watchpoint enabled. - return (debug_state.__wcr[hw_index] & 1u); +bool DNBArchMachARM64::IsWatchpointEnabled(const DBG &debug_state, + uint32_t hw_index) { + // Watchpoint Control Registers, bitfield definitions + // ... + // Bits Value Description + // [0] 0 Watchpoint disabled + // 1 Watchpoint enabled. + return (debug_state.__wcr[hw_index] & 1u); } -nub_addr_t -DNBArchMachARM64::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) -{ - // Watchpoint Value Registers, bitfield definitions - // Bits Description - // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) - // [1:0] RAZ/SBZP - return bits(debug_state.__wvr[hw_index], 63, 0); +nub_addr_t DNBArchMachARM64::GetWatchAddress(const DBG &debug_state, + uint32_t hw_index) { + // Watchpoint Value Registers, bitfield definitions + // Bits Description + // [31:2] Watchpoint value (word address, i.e., 4-byte aligned) + // [1:0] RAZ/SBZP + return bits(debug_state.__wvr[hw_index], 63, 0); } //---------------------------------------------------------------------- // Register information definitions for 64 bit ARMv8. //---------------------------------------------------------------------- -enum gpr_regnums -{ - 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_fp, gpr_x29 = gpr_fp, - gpr_lr, gpr_x30 = gpr_lr, - gpr_sp, gpr_x31 = gpr_sp, - gpr_pc, - gpr_cpsr, - gpr_w0, - gpr_w1, - gpr_w2, - gpr_w3, - gpr_w4, - gpr_w5, - gpr_w6, - gpr_w7, - gpr_w8, - gpr_w9, - gpr_w10, - gpr_w11, - gpr_w12, - gpr_w13, - gpr_w14, - gpr_w15, - gpr_w16, - gpr_w17, - gpr_w18, - gpr_w19, - gpr_w20, - gpr_w21, - gpr_w22, - gpr_w23, - gpr_w24, - gpr_w25, - gpr_w26, - gpr_w27, - gpr_w28 +enum gpr_regnums { + 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_fp, + gpr_x29 = gpr_fp, + gpr_lr, + gpr_x30 = gpr_lr, + gpr_sp, + gpr_x31 = gpr_sp, + gpr_pc, + gpr_cpsr, + gpr_w0, + gpr_w1, + gpr_w2, + gpr_w3, + gpr_w4, + gpr_w5, + gpr_w6, + gpr_w7, + gpr_w8, + gpr_w9, + gpr_w10, + gpr_w11, + gpr_w12, + gpr_w13, + gpr_w14, + gpr_w15, + gpr_w16, + gpr_w17, + gpr_w18, + gpr_w19, + gpr_w20, + gpr_w21, + gpr_w22, + gpr_w23, + gpr_w24, + gpr_w25, + gpr_w26, + gpr_w27, + gpr_w28 }; -enum -{ - vfp_v0 = 0, - vfp_v1, - vfp_v2, - vfp_v3, - vfp_v4, - vfp_v5, - vfp_v6, - vfp_v7, - vfp_v8, - vfp_v9, - vfp_v10, - vfp_v11, - vfp_v12, - vfp_v13, - vfp_v14, - vfp_v15, - vfp_v16, - vfp_v17, - vfp_v18, - vfp_v19, - vfp_v20, - vfp_v21, - vfp_v22, - vfp_v23, - vfp_v24, - vfp_v25, - vfp_v26, - vfp_v27, - vfp_v28, - vfp_v29, - vfp_v30, - vfp_v31, - vfp_fpsr, - vfp_fpcr, - - // lower 32 bits of the corresponding vfp_v<n> reg. - vfp_s0, - vfp_s1, - vfp_s2, - vfp_s3, - vfp_s4, - vfp_s5, - vfp_s6, - vfp_s7, - vfp_s8, - vfp_s9, - vfp_s10, - vfp_s11, - vfp_s12, - vfp_s13, - vfp_s14, - vfp_s15, - vfp_s16, - vfp_s17, - vfp_s18, - vfp_s19, - vfp_s20, - vfp_s21, - vfp_s22, - vfp_s23, - vfp_s24, - vfp_s25, - vfp_s26, - vfp_s27, - vfp_s28, - vfp_s29, - vfp_s30, - vfp_s31, - - // lower 64 bits of the corresponding vfp_v<n> reg. - vfp_d0, - vfp_d1, - vfp_d2, - vfp_d3, - vfp_d4, - vfp_d5, - vfp_d6, - vfp_d7, - vfp_d8, - vfp_d9, - vfp_d10, - vfp_d11, - vfp_d12, - vfp_d13, - vfp_d14, - vfp_d15, - vfp_d16, - vfp_d17, - vfp_d18, - vfp_d19, - vfp_d20, - vfp_d21, - vfp_d22, - vfp_d23, - vfp_d24, - vfp_d25, - vfp_d26, - vfp_d27, - vfp_d28, - vfp_d29, - vfp_d30, - vfp_d31 +enum { + vfp_v0 = 0, + vfp_v1, + vfp_v2, + vfp_v3, + vfp_v4, + vfp_v5, + vfp_v6, + vfp_v7, + vfp_v8, + vfp_v9, + vfp_v10, + vfp_v11, + vfp_v12, + vfp_v13, + vfp_v14, + vfp_v15, + vfp_v16, + vfp_v17, + vfp_v18, + vfp_v19, + vfp_v20, + vfp_v21, + vfp_v22, + vfp_v23, + vfp_v24, + vfp_v25, + vfp_v26, + vfp_v27, + vfp_v28, + vfp_v29, + vfp_v30, + vfp_v31, + vfp_fpsr, + vfp_fpcr, + + // lower 32 bits of the corresponding vfp_v<n> reg. + vfp_s0, + vfp_s1, + vfp_s2, + vfp_s3, + vfp_s4, + vfp_s5, + vfp_s6, + vfp_s7, + vfp_s8, + vfp_s9, + vfp_s10, + vfp_s11, + vfp_s12, + vfp_s13, + vfp_s14, + vfp_s15, + vfp_s16, + vfp_s17, + vfp_s18, + vfp_s19, + vfp_s20, + vfp_s21, + vfp_s22, + vfp_s23, + vfp_s24, + vfp_s25, + vfp_s26, + vfp_s27, + vfp_s28, + vfp_s29, + vfp_s30, + vfp_s31, + + // lower 64 bits of the corresponding vfp_v<n> reg. + vfp_d0, + vfp_d1, + vfp_d2, + vfp_d3, + vfp_d4, + vfp_d5, + vfp_d6, + vfp_d7, + vfp_d8, + vfp_d9, + vfp_d10, + vfp_d11, + vfp_d12, + vfp_d13, + vfp_d14, + vfp_d15, + vfp_d16, + vfp_d17, + vfp_d18, + vfp_d19, + vfp_d20, + vfp_d21, + vfp_d22, + vfp_d23, + vfp_d24, + vfp_d25, + vfp_d26, + vfp_d27, + vfp_d28, + vfp_d29, + vfp_d30, + vfp_d31 }; -enum -{ - exc_far = 0, - exc_esr, - exc_exception +enum { exc_far = 0, exc_esr, exc_exception }; + +// These numbers from the "DWARF for the ARM 64-bit Architecture (AArch64)" +// document. + +enum { + dwarf_x0 = 0, + dwarf_x1, + dwarf_x2, + dwarf_x3, + dwarf_x4, + dwarf_x5, + dwarf_x6, + dwarf_x7, + dwarf_x8, + dwarf_x9, + dwarf_x10, + dwarf_x11, + dwarf_x12, + dwarf_x13, + dwarf_x14, + dwarf_x15, + dwarf_x16, + dwarf_x17, + dwarf_x18, + dwarf_x19, + dwarf_x20, + dwarf_x21, + dwarf_x22, + dwarf_x23, + dwarf_x24, + dwarf_x25, + dwarf_x26, + dwarf_x27, + dwarf_x28, + dwarf_x29, + dwarf_x30, + dwarf_x31, + dwarf_pc = 32, + dwarf_elr_mode = 33, + dwarf_fp = dwarf_x29, + dwarf_lr = dwarf_x30, + dwarf_sp = dwarf_x31, + // 34-63 reserved + + // V0-V31 (128 bit vector registers) + dwarf_v0 = 64, + dwarf_v1, + dwarf_v2, + dwarf_v3, + dwarf_v4, + dwarf_v5, + dwarf_v6, + dwarf_v7, + dwarf_v8, + dwarf_v9, + dwarf_v10, + dwarf_v11, + dwarf_v12, + dwarf_v13, + dwarf_v14, + dwarf_v15, + dwarf_v16, + dwarf_v17, + dwarf_v18, + dwarf_v19, + dwarf_v20, + dwarf_v21, + dwarf_v22, + dwarf_v23, + dwarf_v24, + dwarf_v25, + dwarf_v26, + dwarf_v27, + dwarf_v28, + dwarf_v29, + dwarf_v30, + dwarf_v31 + + // 96-127 reserved }; -// These numbers from the "DWARF for the ARM 64-bit Architecture (AArch64)" document. - -enum -{ - dwarf_x0 = 0, - dwarf_x1, - dwarf_x2, - dwarf_x3, - dwarf_x4, - dwarf_x5, - dwarf_x6, - dwarf_x7, - dwarf_x8, - dwarf_x9, - dwarf_x10, - dwarf_x11, - dwarf_x12, - dwarf_x13, - dwarf_x14, - dwarf_x15, - dwarf_x16, - dwarf_x17, - dwarf_x18, - dwarf_x19, - dwarf_x20, - dwarf_x21, - dwarf_x22, - dwarf_x23, - dwarf_x24, - dwarf_x25, - dwarf_x26, - dwarf_x27, - dwarf_x28, - dwarf_x29, - dwarf_x30, - dwarf_x31, - dwarf_pc = 32, - dwarf_elr_mode = 33, - dwarf_fp = dwarf_x29, - dwarf_lr = dwarf_x30, - dwarf_sp = dwarf_x31, - // 34-63 reserved - - // V0-V31 (128 bit vector registers) - dwarf_v0 = 64, - dwarf_v1, - dwarf_v2, - dwarf_v3, - dwarf_v4, - dwarf_v5, - dwarf_v6, - dwarf_v7, - dwarf_v8, - dwarf_v9, - dwarf_v10, - dwarf_v11, - dwarf_v12, - dwarf_v13, - dwarf_v14, - dwarf_v15, - dwarf_v16, - dwarf_v17, - dwarf_v18, - dwarf_v19, - dwarf_v20, - dwarf_v21, - dwarf_v22, - dwarf_v23, - dwarf_v24, - dwarf_v25, - dwarf_v26, - dwarf_v27, - dwarf_v28, - dwarf_v29, - dwarf_v30, - dwarf_v31 - - // 96-127 reserved +enum { + debugserver_gpr_x0 = 0, + debugserver_gpr_x1, + debugserver_gpr_x2, + debugserver_gpr_x3, + debugserver_gpr_x4, + debugserver_gpr_x5, + debugserver_gpr_x6, + debugserver_gpr_x7, + debugserver_gpr_x8, + debugserver_gpr_x9, + debugserver_gpr_x10, + debugserver_gpr_x11, + debugserver_gpr_x12, + debugserver_gpr_x13, + debugserver_gpr_x14, + debugserver_gpr_x15, + debugserver_gpr_x16, + debugserver_gpr_x17, + debugserver_gpr_x18, + debugserver_gpr_x19, + debugserver_gpr_x20, + debugserver_gpr_x21, + debugserver_gpr_x22, + debugserver_gpr_x23, + debugserver_gpr_x24, + debugserver_gpr_x25, + debugserver_gpr_x26, + debugserver_gpr_x27, + debugserver_gpr_x28, + debugserver_gpr_fp, // x29 + debugserver_gpr_lr, // x30 + debugserver_gpr_sp, // sp aka xsp + debugserver_gpr_pc, + debugserver_gpr_cpsr, + debugserver_vfp_v0, + debugserver_vfp_v1, + debugserver_vfp_v2, + debugserver_vfp_v3, + debugserver_vfp_v4, + debugserver_vfp_v5, + debugserver_vfp_v6, + debugserver_vfp_v7, + debugserver_vfp_v8, + debugserver_vfp_v9, + debugserver_vfp_v10, + debugserver_vfp_v11, + debugserver_vfp_v12, + debugserver_vfp_v13, + debugserver_vfp_v14, + debugserver_vfp_v15, + debugserver_vfp_v16, + debugserver_vfp_v17, + debugserver_vfp_v18, + debugserver_vfp_v19, + debugserver_vfp_v20, + debugserver_vfp_v21, + debugserver_vfp_v22, + debugserver_vfp_v23, + debugserver_vfp_v24, + debugserver_vfp_v25, + debugserver_vfp_v26, + debugserver_vfp_v27, + debugserver_vfp_v28, + debugserver_vfp_v29, + debugserver_vfp_v30, + debugserver_vfp_v31, + debugserver_vfp_fpsr, + debugserver_vfp_fpcr }; -enum -{ - debugserver_gpr_x0 = 0, - debugserver_gpr_x1, - debugserver_gpr_x2, - debugserver_gpr_x3, - debugserver_gpr_x4, - debugserver_gpr_x5, - debugserver_gpr_x6, - debugserver_gpr_x7, - debugserver_gpr_x8, - debugserver_gpr_x9, - debugserver_gpr_x10, - debugserver_gpr_x11, - debugserver_gpr_x12, - debugserver_gpr_x13, - debugserver_gpr_x14, - debugserver_gpr_x15, - debugserver_gpr_x16, - debugserver_gpr_x17, - debugserver_gpr_x18, - debugserver_gpr_x19, - debugserver_gpr_x20, - debugserver_gpr_x21, - debugserver_gpr_x22, - debugserver_gpr_x23, - debugserver_gpr_x24, - debugserver_gpr_x25, - debugserver_gpr_x26, - debugserver_gpr_x27, - debugserver_gpr_x28, - debugserver_gpr_fp, // x29 - debugserver_gpr_lr, // x30 - debugserver_gpr_sp, // sp aka xsp - debugserver_gpr_pc, - debugserver_gpr_cpsr, - debugserver_vfp_v0, - debugserver_vfp_v1, - debugserver_vfp_v2, - debugserver_vfp_v3, - debugserver_vfp_v4, - debugserver_vfp_v5, - debugserver_vfp_v6, - debugserver_vfp_v7, - debugserver_vfp_v8, - debugserver_vfp_v9, - debugserver_vfp_v10, - debugserver_vfp_v11, - debugserver_vfp_v12, - debugserver_vfp_v13, - debugserver_vfp_v14, - debugserver_vfp_v15, - debugserver_vfp_v16, - debugserver_vfp_v17, - debugserver_vfp_v18, - debugserver_vfp_v19, - debugserver_vfp_v20, - debugserver_vfp_v21, - debugserver_vfp_v22, - debugserver_vfp_v23, - debugserver_vfp_v24, - debugserver_vfp_v25, - debugserver_vfp_v26, - debugserver_vfp_v27, - debugserver_vfp_v28, - debugserver_vfp_v29, - debugserver_vfp_v30, - debugserver_vfp_v31, - debugserver_vfp_fpsr, - debugserver_vfp_fpcr -}; - -const char *g_contained_x0[] {"x0", NULL }; -const char *g_contained_x1[] {"x1", NULL }; -const char *g_contained_x2[] {"x2", NULL }; -const char *g_contained_x3[] {"x3", NULL }; -const char *g_contained_x4[] {"x4", NULL }; -const char *g_contained_x5[] {"x5", NULL }; -const char *g_contained_x6[] {"x6", NULL }; -const char *g_contained_x7[] {"x7", NULL }; -const char *g_contained_x8[] {"x8", NULL }; -const char *g_contained_x9[] {"x9", NULL }; -const char *g_contained_x10[] {"x10", NULL }; -const char *g_contained_x11[] {"x11", NULL }; -const char *g_contained_x12[] {"x12", NULL }; -const char *g_contained_x13[] {"x13", NULL }; -const char *g_contained_x14[] {"x14", NULL }; -const char *g_contained_x15[] {"x15", NULL }; -const char *g_contained_x16[] {"x16", NULL }; -const char *g_contained_x17[] {"x17", NULL }; -const char *g_contained_x18[] {"x18", NULL }; -const char *g_contained_x19[] {"x19", NULL }; -const char *g_contained_x20[] {"x20", NULL }; -const char *g_contained_x21[] {"x21", NULL }; -const char *g_contained_x22[] {"x22", NULL }; -const char *g_contained_x23[] {"x23", NULL }; -const char *g_contained_x24[] {"x24", NULL }; -const char *g_contained_x25[] {"x25", NULL }; -const char *g_contained_x26[] {"x26", NULL }; -const char *g_contained_x27[] {"x27", NULL }; -const char *g_contained_x28[] {"x28", NULL }; - -const char *g_invalidate_x0[] {"x0", "w0", NULL }; -const char *g_invalidate_x1[] {"x1", "w1", NULL }; -const char *g_invalidate_x2[] {"x2", "w2", NULL }; -const char *g_invalidate_x3[] {"x3", "w3", NULL }; -const char *g_invalidate_x4[] {"x4", "w4", NULL }; -const char *g_invalidate_x5[] {"x5", "w5", NULL }; -const char *g_invalidate_x6[] {"x6", "w6", NULL }; -const char *g_invalidate_x7[] {"x7", "w7", NULL }; -const char *g_invalidate_x8[] {"x8", "w8", NULL }; -const char *g_invalidate_x9[] {"x9", "w9", NULL }; -const char *g_invalidate_x10[] {"x10", "w10", NULL }; -const char *g_invalidate_x11[] {"x11", "w11", NULL }; -const char *g_invalidate_x12[] {"x12", "w12", NULL }; -const char *g_invalidate_x13[] {"x13", "w13", NULL }; -const char *g_invalidate_x14[] {"x14", "w14", NULL }; -const char *g_invalidate_x15[] {"x15", "w15", NULL }; -const char *g_invalidate_x16[] {"x16", "w16", NULL }; -const char *g_invalidate_x17[] {"x17", "w17", NULL }; -const char *g_invalidate_x18[] {"x18", "w18", NULL }; -const char *g_invalidate_x19[] {"x19", "w19", NULL }; -const char *g_invalidate_x20[] {"x20", "w20", NULL }; -const char *g_invalidate_x21[] {"x21", "w21", NULL }; -const char *g_invalidate_x22[] {"x22", "w22", NULL }; -const char *g_invalidate_x23[] {"x23", "w23", NULL }; -const char *g_invalidate_x24[] {"x24", "w24", NULL }; -const char *g_invalidate_x25[] {"x25", "w25", NULL }; -const char *g_invalidate_x26[] {"x26", "w26", NULL }; -const char *g_invalidate_x27[] {"x27", "w27", NULL }; -const char *g_invalidate_x28[] {"x28", "w28", NULL }; - -#define GPR_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::GPR, __x[idx])) - -#define GPR_OFFSET_NAME(reg) (offsetof (DNBArchMachARM64::GPR , __##reg)) +const char *g_contained_x0[]{"x0", NULL}; +const char *g_contained_x1[]{"x1", NULL}; +const char *g_contained_x2[]{"x2", NULL}; +const char *g_contained_x3[]{"x3", NULL}; +const char *g_contained_x4[]{"x4", NULL}; +const char *g_contained_x5[]{"x5", NULL}; +const char *g_contained_x6[]{"x6", NULL}; +const char *g_contained_x7[]{"x7", NULL}; +const char *g_contained_x8[]{"x8", NULL}; +const char *g_contained_x9[]{"x9", NULL}; +const char *g_contained_x10[]{"x10", NULL}; +const char *g_contained_x11[]{"x11", NULL}; +const char *g_contained_x12[]{"x12", NULL}; +const char *g_contained_x13[]{"x13", NULL}; +const char *g_contained_x14[]{"x14", NULL}; +const char *g_contained_x15[]{"x15", NULL}; +const char *g_contained_x16[]{"x16", NULL}; +const char *g_contained_x17[]{"x17", NULL}; +const char *g_contained_x18[]{"x18", NULL}; +const char *g_contained_x19[]{"x19", NULL}; +const char *g_contained_x20[]{"x20", NULL}; +const char *g_contained_x21[]{"x21", NULL}; +const char *g_contained_x22[]{"x22", NULL}; +const char *g_contained_x23[]{"x23", NULL}; +const char *g_contained_x24[]{"x24", NULL}; +const char *g_contained_x25[]{"x25", NULL}; +const char *g_contained_x26[]{"x26", NULL}; +const char *g_contained_x27[]{"x27", NULL}; +const char *g_contained_x28[]{"x28", NULL}; + +const char *g_invalidate_x0[]{"x0", "w0", NULL}; +const char *g_invalidate_x1[]{"x1", "w1", NULL}; +const char *g_invalidate_x2[]{"x2", "w2", NULL}; +const char *g_invalidate_x3[]{"x3", "w3", NULL}; +const char *g_invalidate_x4[]{"x4", "w4", NULL}; +const char *g_invalidate_x5[]{"x5", "w5", NULL}; +const char *g_invalidate_x6[]{"x6", "w6", NULL}; +const char *g_invalidate_x7[]{"x7", "w7", NULL}; +const char *g_invalidate_x8[]{"x8", "w8", NULL}; +const char *g_invalidate_x9[]{"x9", "w9", NULL}; +const char *g_invalidate_x10[]{"x10", "w10", NULL}; +const char *g_invalidate_x11[]{"x11", "w11", NULL}; +const char *g_invalidate_x12[]{"x12", "w12", NULL}; +const char *g_invalidate_x13[]{"x13", "w13", NULL}; +const char *g_invalidate_x14[]{"x14", "w14", NULL}; +const char *g_invalidate_x15[]{"x15", "w15", NULL}; +const char *g_invalidate_x16[]{"x16", "w16", NULL}; +const char *g_invalidate_x17[]{"x17", "w17", NULL}; +const char *g_invalidate_x18[]{"x18", "w18", NULL}; +const char *g_invalidate_x19[]{"x19", "w19", NULL}; +const char *g_invalidate_x20[]{"x20", "w20", NULL}; +const char *g_invalidate_x21[]{"x21", "w21", NULL}; +const char *g_invalidate_x22[]{"x22", "w22", NULL}; +const char *g_invalidate_x23[]{"x23", "w23", NULL}; +const char *g_invalidate_x24[]{"x24", "w24", NULL}; +const char *g_invalidate_x25[]{"x25", "w25", NULL}; +const char *g_invalidate_x26[]{"x26", "w26", NULL}; +const char *g_invalidate_x27[]{"x27", "w27", NULL}; +const char *g_invalidate_x28[]{"x28", "w28", NULL}; + +#define GPR_OFFSET_IDX(idx) (offsetof(DNBArchMachARM64::GPR, __x[idx])) + +#define GPR_OFFSET_NAME(reg) (offsetof(DNBArchMachARM64::GPR, __##reg)) // These macros will auto define the register name, alt name, register size, // register offset, encoding, format and native register. This ensures that // the register state structures are defined correctly and have the correct // sizes and offsets. -#define DEFINE_GPR_IDX(idx, reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_IDX(idx) , dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, g_invalidate_x##idx } -#define DEFINE_GPR_NAME(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_NAME(reg), dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, NULL } -#define DEFINE_PSEUDO_GPR_IDX(idx, reg) { e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_x##idx, g_invalidate_x##idx } +#define DEFINE_GPR_IDX(idx, reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_IDX(idx), \ + dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, \ + g_invalidate_x##idx \ + } +#define DEFINE_GPR_NAME(reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, 8, GPR_OFFSET_NAME(reg), \ + dwarf_##reg, dwarf_##reg, gen, debugserver_gpr_##reg, NULL, NULL \ + } +#define DEFINE_PSEUDO_GPR_IDX(idx, reg) \ + { \ + e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, 4, 0, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + g_contained_x##idx, g_invalidate_x##idx \ + } //_STRUCT_ARM_THREAD_STATE64 //{ @@ -1365,268 +1375,292 @@ const char *g_invalidate_x28[] {"x28", "w28", NULL }; // uint32_t cpsr; /* Current program status register */ //}; - // General purpose registers -const DNBRegisterInfo -DNBArchMachARM64::g_gpr_registers[] = -{ - DEFINE_GPR_IDX ( 0, x0, "arg1", GENERIC_REGNUM_ARG1 ), - DEFINE_GPR_IDX ( 1, x1, "arg2", GENERIC_REGNUM_ARG2 ), - DEFINE_GPR_IDX ( 2, x2, "arg3", GENERIC_REGNUM_ARG3 ), - DEFINE_GPR_IDX ( 3, x3, "arg4", GENERIC_REGNUM_ARG4 ), - DEFINE_GPR_IDX ( 4, x4, "arg5", GENERIC_REGNUM_ARG5 ), - DEFINE_GPR_IDX ( 5, x5, "arg6", GENERIC_REGNUM_ARG6 ), - DEFINE_GPR_IDX ( 6, x6, "arg7", GENERIC_REGNUM_ARG7 ), - DEFINE_GPR_IDX ( 7, x7, "arg8", GENERIC_REGNUM_ARG8 ), - DEFINE_GPR_IDX ( 8, x8, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX ( 9, x9, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (10, x10, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (11, x11, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (12, x12, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (13, x13, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (14, x14, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (15, x15, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (16, x16, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (17, x17, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (18, x18, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (19, x19, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (20, x20, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (21, x21, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (22, x22, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (23, x23, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (24, x24, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (25, x25, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (26, x26, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (27, x27, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_IDX (28, x28, NULL, INVALID_NUB_REGNUM ), - DEFINE_GPR_NAME (fp, "x29", GENERIC_REGNUM_FP), - DEFINE_GPR_NAME (lr, "x30", GENERIC_REGNUM_RA), - DEFINE_GPR_NAME (sp, "xsp", GENERIC_REGNUM_SP), - DEFINE_GPR_NAME (pc, NULL, GENERIC_REGNUM_PC), - - // in armv7 we specify that writing to the CPSR should invalidate r8-12, sp, lr. - // this should be specified for arm64 too even though debugserver is only used for +const DNBRegisterInfo DNBArchMachARM64::g_gpr_registers[] = { + DEFINE_GPR_IDX(0, x0, "arg1", GENERIC_REGNUM_ARG1), + DEFINE_GPR_IDX(1, x1, "arg2", GENERIC_REGNUM_ARG2), + DEFINE_GPR_IDX(2, x2, "arg3", GENERIC_REGNUM_ARG3), + DEFINE_GPR_IDX(3, x3, "arg4", GENERIC_REGNUM_ARG4), + DEFINE_GPR_IDX(4, x4, "arg5", GENERIC_REGNUM_ARG5), + DEFINE_GPR_IDX(5, x5, "arg6", GENERIC_REGNUM_ARG6), + DEFINE_GPR_IDX(6, x6, "arg7", GENERIC_REGNUM_ARG7), + DEFINE_GPR_IDX(7, x7, "arg8", GENERIC_REGNUM_ARG8), + DEFINE_GPR_IDX(8, x8, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(9, x9, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(10, x10, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(11, x11, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(12, x12, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(13, x13, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(14, x14, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(15, x15, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(16, x16, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(17, x17, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(18, x18, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(19, x19, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(20, x20, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(21, x21, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(22, x22, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(23, x23, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(24, x24, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(25, x25, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(26, x26, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(27, x27, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_IDX(28, x28, NULL, INVALID_NUB_REGNUM), + DEFINE_GPR_NAME(fp, "x29", GENERIC_REGNUM_FP), + DEFINE_GPR_NAME(lr, "x30", GENERIC_REGNUM_RA), + DEFINE_GPR_NAME(sp, "xsp", GENERIC_REGNUM_SP), + DEFINE_GPR_NAME(pc, NULL, GENERIC_REGNUM_PC), + + // in armv7 we specify that writing to the CPSR should invalidate r8-12, sp, + // lr. + // this should be specified for arm64 too even though debugserver is only + // used for // userland debugging. - { e_regSetGPR, gpr_cpsr, "cpsr", "flags", Uint, Hex, 4, GPR_OFFSET_NAME(cpsr), dwarf_elr_mode, dwarf_elr_mode, INVALID_NUB_REGNUM, debugserver_gpr_cpsr, NULL, NULL }, - - DEFINE_PSEUDO_GPR_IDX ( 0, w0), - DEFINE_PSEUDO_GPR_IDX ( 1, w1), - DEFINE_PSEUDO_GPR_IDX ( 2, w2), - DEFINE_PSEUDO_GPR_IDX ( 3, w3), - DEFINE_PSEUDO_GPR_IDX ( 4, w4), - DEFINE_PSEUDO_GPR_IDX ( 5, w5), - DEFINE_PSEUDO_GPR_IDX ( 6, w6), - DEFINE_PSEUDO_GPR_IDX ( 7, w7), - DEFINE_PSEUDO_GPR_IDX ( 8, w8), - DEFINE_PSEUDO_GPR_IDX ( 9, w9), - DEFINE_PSEUDO_GPR_IDX (10, w10), - DEFINE_PSEUDO_GPR_IDX (11, w11), - DEFINE_PSEUDO_GPR_IDX (12, w12), - DEFINE_PSEUDO_GPR_IDX (13, w13), - DEFINE_PSEUDO_GPR_IDX (14, w14), - DEFINE_PSEUDO_GPR_IDX (15, w15), - DEFINE_PSEUDO_GPR_IDX (16, w16), - DEFINE_PSEUDO_GPR_IDX (17, w17), - DEFINE_PSEUDO_GPR_IDX (18, w18), - DEFINE_PSEUDO_GPR_IDX (19, w19), - DEFINE_PSEUDO_GPR_IDX (20, w20), - DEFINE_PSEUDO_GPR_IDX (21, w21), - DEFINE_PSEUDO_GPR_IDX (22, w22), - DEFINE_PSEUDO_GPR_IDX (23, w23), - DEFINE_PSEUDO_GPR_IDX (24, w24), - DEFINE_PSEUDO_GPR_IDX (25, w25), - DEFINE_PSEUDO_GPR_IDX (26, w26), - DEFINE_PSEUDO_GPR_IDX (27, w27), - DEFINE_PSEUDO_GPR_IDX (28, w28) -}; - -const char *g_contained_v0[] {"v0", NULL }; -const char *g_contained_v1[] {"v1", NULL }; -const char *g_contained_v2[] {"v2", NULL }; -const char *g_contained_v3[] {"v3", NULL }; -const char *g_contained_v4[] {"v4", NULL }; -const char *g_contained_v5[] {"v5", NULL }; -const char *g_contained_v6[] {"v6", NULL }; -const char *g_contained_v7[] {"v7", NULL }; -const char *g_contained_v8[] {"v8", NULL }; -const char *g_contained_v9[] {"v9", NULL }; -const char *g_contained_v10[] {"v10", NULL }; -const char *g_contained_v11[] {"v11", NULL }; -const char *g_contained_v12[] {"v12", NULL }; -const char *g_contained_v13[] {"v13", NULL }; -const char *g_contained_v14[] {"v14", NULL }; -const char *g_contained_v15[] {"v15", NULL }; -const char *g_contained_v16[] {"v16", NULL }; -const char *g_contained_v17[] {"v17", NULL }; -const char *g_contained_v18[] {"v18", NULL }; -const char *g_contained_v19[] {"v19", NULL }; -const char *g_contained_v20[] {"v20", NULL }; -const char *g_contained_v21[] {"v21", NULL }; -const char *g_contained_v22[] {"v22", NULL }; -const char *g_contained_v23[] {"v23", NULL }; -const char *g_contained_v24[] {"v24", NULL }; -const char *g_contained_v25[] {"v25", NULL }; -const char *g_contained_v26[] {"v26", NULL }; -const char *g_contained_v27[] {"v27", NULL }; -const char *g_contained_v28[] {"v28", NULL }; -const char *g_contained_v29[] {"v29", NULL }; -const char *g_contained_v30[] {"v30", NULL }; -const char *g_contained_v31[] {"v31", NULL }; - -const char *g_invalidate_v0[] {"v0", "d0", "s0", NULL }; -const char *g_invalidate_v1[] {"v1", "d1", "s1", NULL }; -const char *g_invalidate_v2[] {"v2", "d2", "s2", NULL }; -const char *g_invalidate_v3[] {"v3", "d3", "s3", NULL }; -const char *g_invalidate_v4[] {"v4", "d4", "s4", NULL }; -const char *g_invalidate_v5[] {"v5", "d5", "s5", NULL }; -const char *g_invalidate_v6[] {"v6", "d6", "s6", NULL }; -const char *g_invalidate_v7[] {"v7", "d7", "s7", NULL }; -const char *g_invalidate_v8[] {"v8", "d8", "s8", NULL }; -const char *g_invalidate_v9[] {"v9", "d9", "s9", NULL }; -const char *g_invalidate_v10[] {"v10", "d10", "s10", NULL }; -const char *g_invalidate_v11[] {"v11", "d11", "s11", NULL }; -const char *g_invalidate_v12[] {"v12", "d12", "s12", NULL }; -const char *g_invalidate_v13[] {"v13", "d13", "s13", NULL }; -const char *g_invalidate_v14[] {"v14", "d14", "s14", NULL }; -const char *g_invalidate_v15[] {"v15", "d15", "s15", NULL }; -const char *g_invalidate_v16[] {"v16", "d16", "s16", NULL }; -const char *g_invalidate_v17[] {"v17", "d17", "s17", NULL }; -const char *g_invalidate_v18[] {"v18", "d18", "s18", NULL }; -const char *g_invalidate_v19[] {"v19", "d19", "s19", NULL }; -const char *g_invalidate_v20[] {"v20", "d20", "s20", NULL }; -const char *g_invalidate_v21[] {"v21", "d21", "s21", NULL }; -const char *g_invalidate_v22[] {"v22", "d22", "s22", NULL }; -const char *g_invalidate_v23[] {"v23", "d23", "s23", NULL }; -const char *g_invalidate_v24[] {"v24", "d24", "s24", NULL }; -const char *g_invalidate_v25[] {"v25", "d25", "s25", NULL }; -const char *g_invalidate_v26[] {"v26", "d26", "s26", NULL }; -const char *g_invalidate_v27[] {"v27", "d27", "s27", NULL }; -const char *g_invalidate_v28[] {"v28", "d28", "s28", NULL }; -const char *g_invalidate_v29[] {"v29", "d29", "s29", NULL }; -const char *g_invalidate_v30[] {"v30", "d30", "s30", NULL }; -const char *g_invalidate_v31[] {"v31", "d31", "s31", NULL }; - -#if defined (__arm64__) || defined (__aarch64__) -#define VFP_V_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::FPU, __v) + (idx * 16) + offsetof (DNBArchMachARM64::Context, vfp)) + {e_regSetGPR, gpr_cpsr, "cpsr", "flags", Uint, Hex, 4, + GPR_OFFSET_NAME(cpsr), dwarf_elr_mode, dwarf_elr_mode, INVALID_NUB_REGNUM, + debugserver_gpr_cpsr, NULL, NULL}, + + DEFINE_PSEUDO_GPR_IDX(0, w0), + DEFINE_PSEUDO_GPR_IDX(1, w1), + DEFINE_PSEUDO_GPR_IDX(2, w2), + DEFINE_PSEUDO_GPR_IDX(3, w3), + DEFINE_PSEUDO_GPR_IDX(4, w4), + DEFINE_PSEUDO_GPR_IDX(5, w5), + DEFINE_PSEUDO_GPR_IDX(6, w6), + DEFINE_PSEUDO_GPR_IDX(7, w7), + DEFINE_PSEUDO_GPR_IDX(8, w8), + DEFINE_PSEUDO_GPR_IDX(9, w9), + DEFINE_PSEUDO_GPR_IDX(10, w10), + DEFINE_PSEUDO_GPR_IDX(11, w11), + DEFINE_PSEUDO_GPR_IDX(12, w12), + DEFINE_PSEUDO_GPR_IDX(13, w13), + DEFINE_PSEUDO_GPR_IDX(14, w14), + DEFINE_PSEUDO_GPR_IDX(15, w15), + DEFINE_PSEUDO_GPR_IDX(16, w16), + DEFINE_PSEUDO_GPR_IDX(17, w17), + DEFINE_PSEUDO_GPR_IDX(18, w18), + DEFINE_PSEUDO_GPR_IDX(19, w19), + DEFINE_PSEUDO_GPR_IDX(20, w20), + DEFINE_PSEUDO_GPR_IDX(21, w21), + DEFINE_PSEUDO_GPR_IDX(22, w22), + DEFINE_PSEUDO_GPR_IDX(23, w23), + DEFINE_PSEUDO_GPR_IDX(24, w24), + DEFINE_PSEUDO_GPR_IDX(25, w25), + DEFINE_PSEUDO_GPR_IDX(26, w26), + DEFINE_PSEUDO_GPR_IDX(27, w27), + DEFINE_PSEUDO_GPR_IDX(28, w28)}; + +const char *g_contained_v0[]{"v0", NULL}; +const char *g_contained_v1[]{"v1", NULL}; +const char *g_contained_v2[]{"v2", NULL}; +const char *g_contained_v3[]{"v3", NULL}; +const char *g_contained_v4[]{"v4", NULL}; +const char *g_contained_v5[]{"v5", NULL}; +const char *g_contained_v6[]{"v6", NULL}; +const char *g_contained_v7[]{"v7", NULL}; +const char *g_contained_v8[]{"v8", NULL}; +const char *g_contained_v9[]{"v9", NULL}; +const char *g_contained_v10[]{"v10", NULL}; +const char *g_contained_v11[]{"v11", NULL}; +const char *g_contained_v12[]{"v12", NULL}; +const char *g_contained_v13[]{"v13", NULL}; +const char *g_contained_v14[]{"v14", NULL}; +const char *g_contained_v15[]{"v15", NULL}; +const char *g_contained_v16[]{"v16", NULL}; +const char *g_contained_v17[]{"v17", NULL}; +const char *g_contained_v18[]{"v18", NULL}; +const char *g_contained_v19[]{"v19", NULL}; +const char *g_contained_v20[]{"v20", NULL}; +const char *g_contained_v21[]{"v21", NULL}; +const char *g_contained_v22[]{"v22", NULL}; +const char *g_contained_v23[]{"v23", NULL}; +const char *g_contained_v24[]{"v24", NULL}; +const char *g_contained_v25[]{"v25", NULL}; +const char *g_contained_v26[]{"v26", NULL}; +const char *g_contained_v27[]{"v27", NULL}; +const char *g_contained_v28[]{"v28", NULL}; +const char *g_contained_v29[]{"v29", NULL}; +const char *g_contained_v30[]{"v30", NULL}; +const char *g_contained_v31[]{"v31", NULL}; + +const char *g_invalidate_v0[]{"v0", "d0", "s0", NULL}; +const char *g_invalidate_v1[]{"v1", "d1", "s1", NULL}; +const char *g_invalidate_v2[]{"v2", "d2", "s2", NULL}; +const char *g_invalidate_v3[]{"v3", "d3", "s3", NULL}; +const char *g_invalidate_v4[]{"v4", "d4", "s4", NULL}; +const char *g_invalidate_v5[]{"v5", "d5", "s5", NULL}; +const char *g_invalidate_v6[]{"v6", "d6", "s6", NULL}; +const char *g_invalidate_v7[]{"v7", "d7", "s7", NULL}; +const char *g_invalidate_v8[]{"v8", "d8", "s8", NULL}; +const char *g_invalidate_v9[]{"v9", "d9", "s9", NULL}; +const char *g_invalidate_v10[]{"v10", "d10", "s10", NULL}; +const char *g_invalidate_v11[]{"v11", "d11", "s11", NULL}; +const char *g_invalidate_v12[]{"v12", "d12", "s12", NULL}; +const char *g_invalidate_v13[]{"v13", "d13", "s13", NULL}; +const char *g_invalidate_v14[]{"v14", "d14", "s14", NULL}; +const char *g_invalidate_v15[]{"v15", "d15", "s15", NULL}; +const char *g_invalidate_v16[]{"v16", "d16", "s16", NULL}; +const char *g_invalidate_v17[]{"v17", "d17", "s17", NULL}; +const char *g_invalidate_v18[]{"v18", "d18", "s18", NULL}; +const char *g_invalidate_v19[]{"v19", "d19", "s19", NULL}; +const char *g_invalidate_v20[]{"v20", "d20", "s20", NULL}; +const char *g_invalidate_v21[]{"v21", "d21", "s21", NULL}; +const char *g_invalidate_v22[]{"v22", "d22", "s22", NULL}; +const char *g_invalidate_v23[]{"v23", "d23", "s23", NULL}; +const char *g_invalidate_v24[]{"v24", "d24", "s24", NULL}; +const char *g_invalidate_v25[]{"v25", "d25", "s25", NULL}; +const char *g_invalidate_v26[]{"v26", "d26", "s26", NULL}; +const char *g_invalidate_v27[]{"v27", "d27", "s27", NULL}; +const char *g_invalidate_v28[]{"v28", "d28", "s28", NULL}; +const char *g_invalidate_v29[]{"v29", "d29", "s29", NULL}; +const char *g_invalidate_v30[]{"v30", "d30", "s30", NULL}; +const char *g_invalidate_v31[]{"v31", "d31", "s31", NULL}; + +#if defined(__arm64__) || defined(__aarch64__) +#define VFP_V_OFFSET_IDX(idx) \ + (offsetof(DNBArchMachARM64::FPU, __v) + (idx * 16) + \ + offsetof(DNBArchMachARM64::Context, vfp)) #else -#define VFP_V_OFFSET_IDX(idx) (offsetof (DNBArchMachARM64::FPU, opaque) + (idx * 16) + offsetof (DNBArchMachARM64::Context, vfp)) +#define VFP_V_OFFSET_IDX(idx) \ + (offsetof(DNBArchMachARM64::FPU, opaque) + (idx * 16) + \ + offsetof(DNBArchMachARM64::Context, vfp)) #endif -#define VFP_OFFSET_NAME(reg) (offsetof (DNBArchMachARM64::FPU, reg) + offsetof (DNBArchMachARM64::Context, vfp)) -#define EXC_OFFSET(reg) (offsetof (DNBArchMachARM64::EXC, reg) + offsetof (DNBArchMachARM64::Context, exc)) +#define VFP_OFFSET_NAME(reg) \ + (offsetof(DNBArchMachARM64::FPU, reg) + \ + offsetof(DNBArchMachARM64::Context, vfp)) +#define EXC_OFFSET(reg) \ + (offsetof(DNBArchMachARM64::EXC, reg) + \ + offsetof(DNBArchMachARM64::Context, exc)) //#define FLOAT_FORMAT Float -#define DEFINE_VFP_V_IDX(idx) { e_regSetVFP, vfp_v##idx, "v" #idx, "q" #idx, Vector, VectorOfUInt8, 16, VFP_V_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_v##idx, INVALID_NUB_REGNUM, debugserver_vfp_v##idx, NULL, g_invalidate_v##idx } -#define DEFINE_PSEUDO_VFP_S_IDX(idx) { e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, Float, 4, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx } -#define DEFINE_PSEUDO_VFP_D_IDX(idx) { e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, Float, 8, 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx } +#define DEFINE_VFP_V_IDX(idx) \ + { \ + e_regSetVFP, vfp_v##idx, "v" #idx, "q" #idx, Vector, VectorOfUInt8, 16, \ + VFP_V_OFFSET_IDX(idx), INVALID_NUB_REGNUM, dwarf_v##idx, \ + INVALID_NUB_REGNUM, debugserver_vfp_v##idx, NULL, g_invalidate_v##idx \ + } +#define DEFINE_PSEUDO_VFP_S_IDX(idx) \ + { \ + e_regSetVFP, vfp_s##idx, "s" #idx, NULL, IEEE754, Float, 4, 0, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx \ + } +#define DEFINE_PSEUDO_VFP_D_IDX(idx) \ + { \ + e_regSetVFP, vfp_d##idx, "d" #idx, NULL, IEEE754, Float, 8, 0, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, g_contained_v##idx, g_invalidate_v##idx \ + } // Floating point registers -const DNBRegisterInfo -DNBArchMachARM64::g_vfp_registers[] = -{ - DEFINE_VFP_V_IDX ( 0), - DEFINE_VFP_V_IDX ( 1), - DEFINE_VFP_V_IDX ( 2), - DEFINE_VFP_V_IDX ( 3), - DEFINE_VFP_V_IDX ( 4), - DEFINE_VFP_V_IDX ( 5), - DEFINE_VFP_V_IDX ( 6), - DEFINE_VFP_V_IDX ( 7), - DEFINE_VFP_V_IDX ( 8), - DEFINE_VFP_V_IDX ( 9), - DEFINE_VFP_V_IDX (10), - DEFINE_VFP_V_IDX (11), - DEFINE_VFP_V_IDX (12), - DEFINE_VFP_V_IDX (13), - DEFINE_VFP_V_IDX (14), - DEFINE_VFP_V_IDX (15), - DEFINE_VFP_V_IDX (16), - DEFINE_VFP_V_IDX (17), - DEFINE_VFP_V_IDX (18), - DEFINE_VFP_V_IDX (19), - DEFINE_VFP_V_IDX (20), - DEFINE_VFP_V_IDX (21), - DEFINE_VFP_V_IDX (22), - DEFINE_VFP_V_IDX (23), - DEFINE_VFP_V_IDX (24), - DEFINE_VFP_V_IDX (25), - DEFINE_VFP_V_IDX (26), - DEFINE_VFP_V_IDX (27), - DEFINE_VFP_V_IDX (28), - DEFINE_VFP_V_IDX (29), - DEFINE_VFP_V_IDX (30), - DEFINE_VFP_V_IDX (31), - { e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, VFP_V_OFFSET_IDX (32) + 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - { e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, VFP_V_OFFSET_IDX (32) + 4, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - - DEFINE_PSEUDO_VFP_S_IDX (0), - DEFINE_PSEUDO_VFP_S_IDX (1), - DEFINE_PSEUDO_VFP_S_IDX (2), - DEFINE_PSEUDO_VFP_S_IDX (3), - DEFINE_PSEUDO_VFP_S_IDX (4), - DEFINE_PSEUDO_VFP_S_IDX (5), - DEFINE_PSEUDO_VFP_S_IDX (6), - DEFINE_PSEUDO_VFP_S_IDX (7), - DEFINE_PSEUDO_VFP_S_IDX (8), - DEFINE_PSEUDO_VFP_S_IDX (9), - DEFINE_PSEUDO_VFP_S_IDX (10), - DEFINE_PSEUDO_VFP_S_IDX (11), - DEFINE_PSEUDO_VFP_S_IDX (12), - DEFINE_PSEUDO_VFP_S_IDX (13), - DEFINE_PSEUDO_VFP_S_IDX (14), - DEFINE_PSEUDO_VFP_S_IDX (15), - DEFINE_PSEUDO_VFP_S_IDX (16), - DEFINE_PSEUDO_VFP_S_IDX (17), - DEFINE_PSEUDO_VFP_S_IDX (18), - DEFINE_PSEUDO_VFP_S_IDX (19), - DEFINE_PSEUDO_VFP_S_IDX (20), - DEFINE_PSEUDO_VFP_S_IDX (21), - DEFINE_PSEUDO_VFP_S_IDX (22), - DEFINE_PSEUDO_VFP_S_IDX (23), - DEFINE_PSEUDO_VFP_S_IDX (24), - DEFINE_PSEUDO_VFP_S_IDX (25), - DEFINE_PSEUDO_VFP_S_IDX (26), - DEFINE_PSEUDO_VFP_S_IDX (27), - DEFINE_PSEUDO_VFP_S_IDX (28), - DEFINE_PSEUDO_VFP_S_IDX (29), - DEFINE_PSEUDO_VFP_S_IDX (30), - DEFINE_PSEUDO_VFP_S_IDX (31), - - DEFINE_PSEUDO_VFP_D_IDX (0), - DEFINE_PSEUDO_VFP_D_IDX (1), - DEFINE_PSEUDO_VFP_D_IDX (2), - DEFINE_PSEUDO_VFP_D_IDX (3), - DEFINE_PSEUDO_VFP_D_IDX (4), - DEFINE_PSEUDO_VFP_D_IDX (5), - DEFINE_PSEUDO_VFP_D_IDX (6), - DEFINE_PSEUDO_VFP_D_IDX (7), - DEFINE_PSEUDO_VFP_D_IDX (8), - DEFINE_PSEUDO_VFP_D_IDX (9), - DEFINE_PSEUDO_VFP_D_IDX (10), - DEFINE_PSEUDO_VFP_D_IDX (11), - DEFINE_PSEUDO_VFP_D_IDX (12), - DEFINE_PSEUDO_VFP_D_IDX (13), - DEFINE_PSEUDO_VFP_D_IDX (14), - DEFINE_PSEUDO_VFP_D_IDX (15), - DEFINE_PSEUDO_VFP_D_IDX (16), - DEFINE_PSEUDO_VFP_D_IDX (17), - DEFINE_PSEUDO_VFP_D_IDX (18), - DEFINE_PSEUDO_VFP_D_IDX (19), - DEFINE_PSEUDO_VFP_D_IDX (20), - DEFINE_PSEUDO_VFP_D_IDX (21), - DEFINE_PSEUDO_VFP_D_IDX (22), - DEFINE_PSEUDO_VFP_D_IDX (23), - DEFINE_PSEUDO_VFP_D_IDX (24), - DEFINE_PSEUDO_VFP_D_IDX (25), - DEFINE_PSEUDO_VFP_D_IDX (26), - DEFINE_PSEUDO_VFP_D_IDX (27), - DEFINE_PSEUDO_VFP_D_IDX (28), - DEFINE_PSEUDO_VFP_D_IDX (29), - DEFINE_PSEUDO_VFP_D_IDX (30), - DEFINE_PSEUDO_VFP_D_IDX (31) +const DNBRegisterInfo DNBArchMachARM64::g_vfp_registers[] = { + DEFINE_VFP_V_IDX(0), + DEFINE_VFP_V_IDX(1), + DEFINE_VFP_V_IDX(2), + DEFINE_VFP_V_IDX(3), + DEFINE_VFP_V_IDX(4), + DEFINE_VFP_V_IDX(5), + DEFINE_VFP_V_IDX(6), + DEFINE_VFP_V_IDX(7), + DEFINE_VFP_V_IDX(8), + DEFINE_VFP_V_IDX(9), + DEFINE_VFP_V_IDX(10), + DEFINE_VFP_V_IDX(11), + DEFINE_VFP_V_IDX(12), + DEFINE_VFP_V_IDX(13), + DEFINE_VFP_V_IDX(14), + DEFINE_VFP_V_IDX(15), + DEFINE_VFP_V_IDX(16), + DEFINE_VFP_V_IDX(17), + DEFINE_VFP_V_IDX(18), + DEFINE_VFP_V_IDX(19), + DEFINE_VFP_V_IDX(20), + DEFINE_VFP_V_IDX(21), + DEFINE_VFP_V_IDX(22), + DEFINE_VFP_V_IDX(23), + DEFINE_VFP_V_IDX(24), + DEFINE_VFP_V_IDX(25), + DEFINE_VFP_V_IDX(26), + DEFINE_VFP_V_IDX(27), + DEFINE_VFP_V_IDX(28), + DEFINE_VFP_V_IDX(29), + DEFINE_VFP_V_IDX(30), + DEFINE_VFP_V_IDX(31), + {e_regSetVFP, vfp_fpsr, "fpsr", NULL, Uint, Hex, 4, + VFP_V_OFFSET_IDX(32) + 0, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetVFP, vfp_fpcr, "fpcr", NULL, Uint, Hex, 4, + VFP_V_OFFSET_IDX(32) + 4, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + + DEFINE_PSEUDO_VFP_S_IDX(0), + DEFINE_PSEUDO_VFP_S_IDX(1), + DEFINE_PSEUDO_VFP_S_IDX(2), + DEFINE_PSEUDO_VFP_S_IDX(3), + DEFINE_PSEUDO_VFP_S_IDX(4), + DEFINE_PSEUDO_VFP_S_IDX(5), + DEFINE_PSEUDO_VFP_S_IDX(6), + DEFINE_PSEUDO_VFP_S_IDX(7), + DEFINE_PSEUDO_VFP_S_IDX(8), + DEFINE_PSEUDO_VFP_S_IDX(9), + DEFINE_PSEUDO_VFP_S_IDX(10), + DEFINE_PSEUDO_VFP_S_IDX(11), + DEFINE_PSEUDO_VFP_S_IDX(12), + DEFINE_PSEUDO_VFP_S_IDX(13), + DEFINE_PSEUDO_VFP_S_IDX(14), + DEFINE_PSEUDO_VFP_S_IDX(15), + DEFINE_PSEUDO_VFP_S_IDX(16), + DEFINE_PSEUDO_VFP_S_IDX(17), + DEFINE_PSEUDO_VFP_S_IDX(18), + DEFINE_PSEUDO_VFP_S_IDX(19), + DEFINE_PSEUDO_VFP_S_IDX(20), + DEFINE_PSEUDO_VFP_S_IDX(21), + DEFINE_PSEUDO_VFP_S_IDX(22), + DEFINE_PSEUDO_VFP_S_IDX(23), + DEFINE_PSEUDO_VFP_S_IDX(24), + DEFINE_PSEUDO_VFP_S_IDX(25), + DEFINE_PSEUDO_VFP_S_IDX(26), + DEFINE_PSEUDO_VFP_S_IDX(27), + DEFINE_PSEUDO_VFP_S_IDX(28), + DEFINE_PSEUDO_VFP_S_IDX(29), + DEFINE_PSEUDO_VFP_S_IDX(30), + DEFINE_PSEUDO_VFP_S_IDX(31), + + DEFINE_PSEUDO_VFP_D_IDX(0), + DEFINE_PSEUDO_VFP_D_IDX(1), + DEFINE_PSEUDO_VFP_D_IDX(2), + DEFINE_PSEUDO_VFP_D_IDX(3), + DEFINE_PSEUDO_VFP_D_IDX(4), + DEFINE_PSEUDO_VFP_D_IDX(5), + DEFINE_PSEUDO_VFP_D_IDX(6), + DEFINE_PSEUDO_VFP_D_IDX(7), + DEFINE_PSEUDO_VFP_D_IDX(8), + DEFINE_PSEUDO_VFP_D_IDX(9), + DEFINE_PSEUDO_VFP_D_IDX(10), + DEFINE_PSEUDO_VFP_D_IDX(11), + DEFINE_PSEUDO_VFP_D_IDX(12), + DEFINE_PSEUDO_VFP_D_IDX(13), + DEFINE_PSEUDO_VFP_D_IDX(14), + DEFINE_PSEUDO_VFP_D_IDX(15), + DEFINE_PSEUDO_VFP_D_IDX(16), + DEFINE_PSEUDO_VFP_D_IDX(17), + DEFINE_PSEUDO_VFP_D_IDX(18), + DEFINE_PSEUDO_VFP_D_IDX(19), + DEFINE_PSEUDO_VFP_D_IDX(20), + DEFINE_PSEUDO_VFP_D_IDX(21), + DEFINE_PSEUDO_VFP_D_IDX(22), + DEFINE_PSEUDO_VFP_D_IDX(23), + DEFINE_PSEUDO_VFP_D_IDX(24), + DEFINE_PSEUDO_VFP_D_IDX(25), + DEFINE_PSEUDO_VFP_D_IDX(26), + DEFINE_PSEUDO_VFP_D_IDX(27), + DEFINE_PSEUDO_VFP_D_IDX(28), + DEFINE_PSEUDO_VFP_D_IDX(29), + DEFINE_PSEUDO_VFP_D_IDX(30), + DEFINE_PSEUDO_VFP_D_IDX(31) }; - //_STRUCT_ARM_EXCEPTION_STATE64 //{ // uint64_t far; /* Virtual Fault Address */ @@ -1635,461 +1669,436 @@ DNBArchMachARM64::g_vfp_registers[] = //}; // Exception registers -const DNBRegisterInfo -DNBArchMachARM64::g_exc_registers[] = -{ - { e_regSetEXC, exc_far , "far" , NULL, Uint, Hex, 8, EXC_OFFSET(__far) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - { e_regSetEXC, exc_esr , "esr" , NULL, Uint, Hex, 4, EXC_OFFSET(__esr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - { e_regSetEXC, exc_exception , "exception" , NULL, Uint, Hex, 4, EXC_OFFSET(__exception) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL } -}; +const DNBRegisterInfo DNBArchMachARM64::g_exc_registers[] = { + {e_regSetEXC, exc_far, "far", NULL, Uint, Hex, 8, EXC_OFFSET(__far), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetEXC, exc_esr, "esr", NULL, Uint, Hex, 4, EXC_OFFSET(__esr), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetEXC, exc_exception, "exception", NULL, Uint, Hex, 4, + EXC_OFFSET(__exception), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}}; // Number of registers in each register set -const size_t DNBArchMachARM64::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM64::k_num_vfp_registers = sizeof(g_vfp_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM64::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchMachARM64::k_num_all_registers = k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers; +const size_t DNBArchMachARM64::k_num_gpr_registers = + sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_vfp_registers = + sizeof(g_vfp_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_exc_registers = + sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchMachARM64::k_num_all_registers = + k_num_gpr_registers + k_num_vfp_registers + k_num_exc_registers; //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index // of zero is for all registers, followed by other registers sets. The // register information for the all register set need not be filled in. //---------------------------------------------------------------------- -const DNBRegisterSetInfo -DNBArchMachARM64::g_reg_sets[] = -{ - { "ARM64 Registers", NULL, k_num_all_registers }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_vfp_registers, k_num_vfp_registers }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; +const DNBRegisterSetInfo DNBArchMachARM64::g_reg_sets[] = { + {"ARM64 Registers", NULL, k_num_all_registers}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_vfp_registers, k_num_vfp_registers}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; // Total number of register sets for this architecture -const size_t DNBArchMachARM64::k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo); - +const size_t DNBArchMachARM64::k_num_register_sets = + sizeof(g_reg_sets) / sizeof(DNBRegisterSetInfo); const DNBRegisterSetInfo * -DNBArchMachARM64::GetRegisterSetInfo(nub_size_t *num_reg_sets) -{ - *num_reg_sets = k_num_register_sets; - return g_reg_sets; +DNBArchMachARM64::GetRegisterSetInfo(nub_size_t *num_reg_sets) { + *num_reg_sets = k_num_register_sets; + return g_reg_sets; } -bool -DNBArchMachARM64::FixGenericRegisterNumber (uint32_t &set, uint32_t ®) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_pc; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_sp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_fp; - break; - - case GENERIC_REGNUM_RA: // Return Address - set = e_regSetGPR; - reg = gpr_lr; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_cpsr; - break; - - case GENERIC_REGNUM_ARG1: - case GENERIC_REGNUM_ARG2: - case GENERIC_REGNUM_ARG3: - case GENERIC_REGNUM_ARG4: - case GENERIC_REGNUM_ARG5: - case GENERIC_REGNUM_ARG6: - set = e_regSetGPR; - reg = gpr_x0 + reg - GENERIC_REGNUM_ARG1; - break; - - default: - return false; - } +bool DNBArchMachARM64::FixGenericRegisterNumber(uint32_t &set, uint32_t ®) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_pc; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_sp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_fp; + break; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = gpr_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_cpsr; + break; + + case GENERIC_REGNUM_ARG1: + case GENERIC_REGNUM_ARG2: + case GENERIC_REGNUM_ARG3: + case GENERIC_REGNUM_ARG4: + case GENERIC_REGNUM_ARG5: + case GENERIC_REGNUM_ARG6: + set = e_regSetGPR; + reg = gpr_x0 + reg - GENERIC_REGNUM_ARG1; + break; + + default: + return false; } - return true; + } + return true; } -bool -DNBArchMachARM64::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) -{ - if (!FixGenericRegisterNumber (set, reg)) - return false; - - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - value->info = *regInfo; - switch (set) - { - case e_regSetGPR: - if (reg <= gpr_pc) - { - value->value.uint64 = m_state.context.gpr.__x[reg]; - return true; - } - else if (reg == gpr_cpsr) - { - value->value.uint32 = m_state.context.gpr.__cpsr; - return true; - } - break; - - case e_regSetVFP: - - if (reg >= vfp_v0 && reg <= vfp_v31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_v0], 16); +bool DNBArchMachARM64::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + if (!FixGenericRegisterNumber(set, reg)) + return false; + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + value->info = *regInfo; + switch (set) { + case e_regSetGPR: + if (reg <= gpr_pc) { + value->value.uint64 = m_state.context.gpr.__x[reg]; + return true; + } else if (reg == gpr_cpsr) { + value->value.uint32 = m_state.context.gpr.__cpsr; + return true; + } + break; + + case e_regSetVFP: + + if (reg >= vfp_v0 && reg <= vfp_v31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_v0], + 16); #else - memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), 16); + memcpy(&value->value.v_uint8, + ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), + 16); #endif - return true; - } - else if (reg == vfp_fpsr) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.uint32, &m_state.context.vfp.__fpsr, 4); + return true; + } else if (reg == vfp_fpsr) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.uint32, &m_state.context.vfp.__fpsr, 4); #else - memcpy (&value->value.uint32, ((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 0, 4); + memcpy(&value->value.uint32, + ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0, 4); #endif - return true; - } - else if (reg == vfp_fpcr) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.uint32, &m_state.context.vfp.__fpcr, 4); + return true; + } else if (reg == vfp_fpcr) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.uint32, &m_state.context.vfp.__fpcr, 4); #else - memcpy (&value->value.uint32, ((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 4, 4); + memcpy(&value->value.uint32, + ((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 4, 4); #endif - return true; - } - else if (reg >= vfp_s0 && reg <= vfp_s31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_s0], 4); + return true; + } else if (reg >= vfp_s0 && reg <= vfp_s31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_s0], + 4); #else - memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), 4); + memcpy(&value->value.v_uint8, + ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), + 4); #endif - return true; - } - else if (reg >= vfp_d0 && reg <= vfp_d31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_d0], 8); + return true; + } else if (reg >= vfp_d0 && reg <= vfp_d31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&value->value.v_uint8, &m_state.context.vfp.__v[reg - vfp_d0], + 8); #else - memcpy (&value->value.v_uint8, ((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), 8); + memcpy(&value->value.v_uint8, + ((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), + 8); #endif - return true; - } - break; - - case e_regSetEXC: - if (reg == exc_far) - { - value->value.uint64 = m_state.context.exc.__far; - return true; - } - else if (reg == exc_esr) - { - value->value.uint32 = m_state.context.exc.__esr; - return true; - } - else if (reg == exc_exception) - { - value->value.uint32 = m_state.context.exc.__exception; - return true; - } - break; - } + return true; + } + break; + + case e_regSetEXC: + if (reg == exc_far) { + value->value.uint64 = m_state.context.exc.__far; + return true; + } else if (reg == exc_esr) { + value->value.uint32 = m_state.context.exc.__esr; + return true; + } else if (reg == exc_exception) { + value->value.uint32 = m_state.context.exc.__exception; + return true; + } + break; } - return false; + } + return false; } -bool -DNBArchMachARM64::SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value) -{ - if (!FixGenericRegisterNumber (set, reg)) - return false; - - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - bool success = false; - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - switch (set) - { - case e_regSetGPR: - if (reg <= gpr_pc) - { - m_state.context.gpr.__x[reg] = value->value.uint64; - success = true; - } - else if (reg == gpr_cpsr) - { - m_state.context.gpr.__cpsr = value->value.uint32; - success = true; - } - break; - - case e_regSetVFP: - if (reg >= vfp_v0 && reg <= vfp_v31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&m_state.context.vfp.__v[reg - vfp_v0], &value->value.v_uint8, 16); +bool DNBArchMachARM64::SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + if (!FixGenericRegisterNumber(set, reg)) + return false; + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + bool success = false; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + switch (set) { + case e_regSetGPR: + if (reg <= gpr_pc) { + m_state.context.gpr.__x[reg] = value->value.uint64; + success = true; + } else if (reg == gpr_cpsr) { + m_state.context.gpr.__cpsr = value->value.uint32; + success = true; + } + break; + + case e_regSetVFP: + if (reg >= vfp_v0 && reg <= vfp_v31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&m_state.context.vfp.__v[reg - vfp_v0], &value->value.v_uint8, + 16); #else - memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), &value->value.v_uint8, 16); + memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_v0) * 16), + &value->value.v_uint8, 16); #endif - success = true; - } - else if (reg == vfp_fpsr) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&m_state.context.vfp.__fpsr, &value->value.uint32, 4); + success = true; + } else if (reg == vfp_fpsr) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&m_state.context.vfp.__fpsr, &value->value.uint32, 4); #else - memcpy (((uint8_t *) &m_state.context.vfp.opaque) + (32 * 16) + 0, &value->value.uint32, 4); + memcpy(((uint8_t *)&m_state.context.vfp.opaque) + (32 * 16) + 0, + &value->value.uint32, 4); #endif - success = true; - } - else if (reg == vfp_fpcr) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&m_state.context.vfp.__fpcr, &value->value.uint32, 4); + success = true; + } else if (reg == vfp_fpcr) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&m_state.context.vfp.__fpcr, &value->value.uint32, 4); #else - memcpy (((uint8_t *) m_state.context.vfp.opaque) + (32 * 16) + 4, &value->value.uint32, 4); + memcpy(((uint8_t *)m_state.context.vfp.opaque) + (32 * 16) + 4, + &value->value.uint32, 4); #endif - success = true; - } - else if (reg >= vfp_s0 && reg <= vfp_s31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&m_state.context.vfp.__v[reg - vfp_s0], &value->value.v_uint8, 4); + success = true; + } else if (reg >= vfp_s0 && reg <= vfp_s31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&m_state.context.vfp.__v[reg - vfp_s0], &value->value.v_uint8, + 4); #else - memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), &value->value.v_uint8, 4); + memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_s0) * 16), + &value->value.v_uint8, 4); #endif - success = true; - } - else if (reg >= vfp_d0 && reg <= vfp_d31) - { -#if defined (__arm64__) || defined (__aarch64__) - memcpy (&m_state.context.vfp.__v[reg - vfp_d0], &value->value.v_uint8, 8); + success = true; + } else if (reg >= vfp_d0 && reg <= vfp_d31) { +#if defined(__arm64__) || defined(__aarch64__) + memcpy(&m_state.context.vfp.__v[reg - vfp_d0], &value->value.v_uint8, + 8); #else - memcpy (((uint8_t *) &m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), &value->value.v_uint8, 8); + memcpy(((uint8_t *)&m_state.context.vfp.opaque) + ((reg - vfp_d0) * 16), + &value->value.v_uint8, 8); #endif - success = true; - } - break; - - case e_regSetEXC: - if (reg == exc_far) - { - m_state.context.exc.__far = value->value.uint64; - success = true; - } - else if (reg == exc_esr) - { - m_state.context.exc.__esr = value->value.uint32; - success = true; - } - else if (reg == exc_exception) - { - m_state.context.exc.__exception = value->value.uint32; - success = true; - } - break; - } - + success = true; + } + break; + + case e_regSetEXC: + if (reg == exc_far) { + m_state.context.exc.__far = value->value.uint64; + success = true; + } else if (reg == exc_esr) { + m_state.context.exc.__esr = value->value.uint32; + success = true; + } else if (reg == exc_exception) { + m_state.context.exc.__exception = value->value.uint32; + success = true; + } + break; } - if (success) - return SetRegisterState(set) == KERN_SUCCESS; - return false; + } + if (success) + return SetRegisterState(set) == KERN_SUCCESS; + return false; } -kern_return_t -DNBArchMachARM64::GetRegisterState(int set, bool force) -{ - switch (set) - { - case e_regSetALL: return GetGPRState(force) | - GetVFPState(force) | - GetEXCState(force) | - GetDBGState(force); - case e_regSetGPR: return GetGPRState(force); - case e_regSetVFP: return GetVFPState(force); - case e_regSetEXC: return GetEXCState(force); - case e_regSetDBG: return GetDBGState(force); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachARM64::GetRegisterState(int set, bool force) { + switch (set) { + case e_regSetALL: + return GetGPRState(force) | GetVFPState(force) | GetEXCState(force) | + GetDBGState(force); + case e_regSetGPR: + return GetGPRState(force); + case e_regSetVFP: + return GetVFPState(force); + case e_regSetEXC: + return GetEXCState(force); + case e_regSetDBG: + return GetDBGState(force); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -kern_return_t -DNBArchMachARM64::SetRegisterState(int set) -{ - // Make sure we have a valid context to set. - kern_return_t err = GetRegisterState(set, false); - if (err != KERN_SUCCESS) - return err; - - switch (set) - { - case e_regSetALL: return SetGPRState() | - SetVFPState() | - SetEXCState() | - SetDBGState(false); - case e_regSetGPR: return SetGPRState(); - case e_regSetVFP: return SetVFPState(); - case e_regSetEXC: return SetEXCState(); - case e_regSetDBG: return SetDBGState(false); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachARM64::SetRegisterState(int set) { + // Make sure we have a valid context to set. + kern_return_t err = GetRegisterState(set, false); + if (err != KERN_SUCCESS) + return err; + + switch (set) { + case e_regSetALL: + return SetGPRState() | SetVFPState() | SetEXCState() | SetDBGState(false); + case e_regSetGPR: + return SetGPRState(); + case e_regSetVFP: + return SetVFPState(); + case e_regSetEXC: + return SetEXCState(); + case e_regSetDBG: + return SetDBGState(false); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -bool -DNBArchMachARM64::RegisterSetStateIsValid (int set) const -{ - return m_state.RegsAreValid(set); +bool DNBArchMachARM64::RegisterSetStateIsValid(int set) const { + return m_state.RegsAreValid(set); } - -nub_size_t -DNBArchMachARM64::GetRegisterContext (void *buf, nub_size_t buf_len) -{ - nub_size_t size = sizeof (m_state.context.gpr) + - sizeof (m_state.context.vfp) + - sizeof (m_state.context.exc); - - if (buf && buf_len) - { - if (size > buf_len) - size = buf_len; - - bool force = false; - if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) - return 0; - - // Copy each struct individually to avoid any padding that might be between the structs in m_state.context - uint8_t *p = (uint8_t *)buf; - ::memcpy (p, &m_state.context.gpr, sizeof(m_state.context.gpr)); - p += sizeof(m_state.context.gpr); - ::memcpy (p, &m_state.context.vfp, sizeof(m_state.context.vfp)); - p += sizeof(m_state.context.vfp); - ::memcpy (p, &m_state.context.exc, sizeof(m_state.context.exc)); - p += sizeof(m_state.context.exc); - - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size); - // Return the size of the register context even if NULL was passed in - return size; +nub_size_t DNBArchMachARM64::GetRegisterContext(void *buf, nub_size_t buf_len) { + nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + + sizeof(m_state.context.exc); + + if (buf && buf_len) { + if (size > buf_len) + size = buf_len; + + bool force = false; + if (GetGPRState(force) | GetVFPState(force) | GetEXCState(force)) + return 0; + + // Copy each struct individually to avoid any padding that might be between + // the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy(p, &m_state.context.gpr, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy(p, &m_state.context.vfp, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy(p, &m_state.context.exc, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchMachARM64::GetRegisterContext (buf = %p, len = %zu) => %zu", buf, + buf_len, size); + // Return the size of the register context even if NULL was passed in + return size; } -nub_size_t -DNBArchMachARM64::SetRegisterContext (const void *buf, nub_size_t buf_len) -{ - nub_size_t size = sizeof (m_state.context.gpr) + - sizeof (m_state.context.vfp) + - sizeof (m_state.context.exc); - - if (buf == NULL || buf_len == 0) - size = 0; - - if (size) - { - if (size > buf_len) - size = buf_len; - - // Copy each struct individually to avoid any padding that might be between the structs in m_state.context - uint8_t *p = (uint8_t *)buf; - ::memcpy (&m_state.context.gpr, p, sizeof(m_state.context.gpr)); - p += sizeof(m_state.context.gpr); - ::memcpy (&m_state.context.vfp, p, sizeof(m_state.context.vfp)); - p += sizeof(m_state.context.vfp); - ::memcpy (&m_state.context.exc, p, sizeof(m_state.context.exc)); - p += sizeof(m_state.context.exc); - - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - SetGPRState(); - SetVFPState(); - SetEXCState(); - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, buf_len, size); - return size; +nub_size_t DNBArchMachARM64::SetRegisterContext(const void *buf, + nub_size_t buf_len) { + nub_size_t size = sizeof(m_state.context.gpr) + sizeof(m_state.context.vfp) + + sizeof(m_state.context.exc); + + if (buf == NULL || buf_len == 0) + size = 0; + + if (size) { + if (size > buf_len) + size = buf_len; + + // Copy each struct individually to avoid any padding that might be between + // the structs in m_state.context + uint8_t *p = (uint8_t *)buf; + ::memcpy(&m_state.context.gpr, p, sizeof(m_state.context.gpr)); + p += sizeof(m_state.context.gpr); + ::memcpy(&m_state.context.vfp, p, sizeof(m_state.context.vfp)); + p += sizeof(m_state.context.vfp); + ::memcpy(&m_state.context.exc, p, sizeof(m_state.context.exc)); + p += sizeof(m_state.context.exc); + + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + SetGPRState(); + SetVFPState(); + SetEXCState(); + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchMachARM64::SetRegisterContext (buf = %p, len = %zu) => %zu", buf, + buf_len, size); + return size; } -uint32_t -DNBArchMachARM64::SaveRegisterState () -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); - - // Always re-read the registers because above we call thread_abort_safely(); - bool force = true; - - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () error: GPR regs failed to read: %u ", kret); - } - else if ((kret = GetVFPState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () error: %s regs failed to read: %u", "VFP", kret); - } - else - { - const uint32_t save_id = GetNextRegisterStateSaveID (); - m_saved_register_states[save_id] = m_state.context; - return save_id; - } - return UINT32_MAX; +uint32_t DNBArchMachARM64::SaveRegisterState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () " + "error: GPR regs failed to read: %u ", + kret); + } else if ((kret = GetVFPState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::SaveRegisterState () " + "error: %s regs failed to read: %u", + "VFP", kret); + } else { + const uint32_t save_id = GetNextRegisterStateSaveID(); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return UINT32_MAX; } -bool -DNBArchMachARM64::RestoreRegisterState (uint32_t save_id) -{ - SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); - if (pos != m_saved_register_states.end()) - { - m_state.context.gpr = pos->second.gpr; - m_state.context.vfp = pos->second.vfp; - kern_return_t kret; - bool success = true; - if ((kret = SetGPRState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); - success = false; - } - else if ((kret = SetVFPState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, "VFP", kret); - success = false; - } - m_saved_register_states.erase(pos); - return success; +bool DNBArchMachARM64::RestoreRegisterState(uint32_t save_id) { + SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) { + m_state.context.gpr = pos->second.gpr; + m_state.context.vfp = pos->second.vfp; + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState " + "(save_id = %u) error: GPR regs failed to " + "write: %u", + save_id, kret); + success = false; + } else if ((kret = SetVFPState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchMachARM64::RestoreRegisterState " + "(save_id = %u) error: %s regs failed to " + "write: %u", + save_id, "VFP", kret); + success = false; } - return false; + m_saved_register_states.erase(pos); + return success; + } + return false; } - -#endif // #if defined (ARM_THREAD_STATE64_COUNT) -#endif // #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) +#endif // #if defined (ARM_THREAD_STATE64_COUNT) +#endif // #if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) diff --git a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h index 7e68e411a76..cde0abf42d5 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h +++ b/lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.h @@ -7,266 +7,243 @@ // //===----------------------------------------------------------------------===// - #ifndef __DNBArchImplARM64_h__ #define __DNBArchImplARM64_h__ -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) -#include <map> #include <mach/thread_status.h> +#include <map> -#if defined (ARM_THREAD_STATE64_COUNT) +#if defined(ARM_THREAD_STATE64_COUNT) #include "DNBArch.h" class MachThread; -class DNBArchMachARM64 : public DNBArchProtocol -{ +class DNBArchMachARM64 : public DNBArchProtocol { public: - enum { kMaxNumThumbITBreakpoints = 4 }; - - DNBArchMachARM64(MachThread *thread) : - m_thread(thread), - m_state(), - m_disabled_watchpoints(), - m_watchpoint_hw_index(-1), - m_watchpoint_did_occur(false), - m_watchpoint_resume_single_step_enabled(false), - m_saved_register_states() - { - m_disabled_watchpoints.resize (16); - memset(&m_dbg_save, 0, sizeof(m_dbg_save)); - } - - virtual ~DNBArchMachARM64() - { - } + enum { kMaxNumThumbITBreakpoints = 4 }; - static void Initialize(); - static const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets); - - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState (); - virtual bool RestoreRegisterState (uint32_t save_id); - - virtual kern_return_t GetRegisterState (int set, bool force); - virtual kern_return_t SetRegisterState (int set); - virtual bool RegisterSetStateIsValid (int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data& exc); - - static DNBArchProtocol *Create (MachThread *thread); - static const uint8_t * SoftwareBreakpointOpcode (nub_size_t byte_size); - static uint32_t GetCPUType(); - - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint_helper (uint32_t hw_break_index, bool also_set_on_task); + DNBArchMachARM64(MachThread *thread) + : m_thread(thread), m_state(), m_disabled_watchpoints(), + m_watchpoint_hw_index(-1), m_watchpoint_did_occur(false), + m_watchpoint_resume_single_step_enabled(false), + m_saved_register_states() { + m_disabled_watchpoints.resize(16); + memset(&m_dbg_save, 0, sizeof(m_dbg_save)); + } + + virtual ~DNBArchMachARM64() {} + + static void Initialize(); + static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); + + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value); + virtual bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value); + virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); + virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState(); + virtual bool RestoreRegisterState(uint32_t save_id); + + virtual kern_return_t GetRegisterState(int set, bool force); + virtual kern_return_t SetRegisterState(int set); + virtual bool RegisterSetStateIsValid(int set) const; + + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual void ThreadWillResume(); + virtual bool ThreadDidStop(); + virtual bool NotifyException(MachException::Data &exc); + + static DNBArchProtocol *Create(MachThread *thread); + static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); + static uint32_t GetCPUType(); + + virtual uint32_t NumSupportedHardwareWatchpoints(); + virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint_helper(uint32_t hw_break_index, + bool also_set_on_task); protected: - - - kern_return_t EnableHardwareSingleStep (bool enable); - static bool FixGenericRegisterNumber (uint32_t &set, uint32_t ®); - - typedef enum RegisterSetTag - { - e_regSetALL = REGISTER_SET_ALL, - e_regSetGPR, // ARM_THREAD_STATE64, - e_regSetVFP, // ARM_NEON_STATE64, - e_regSetEXC, // ARM_EXCEPTION_STATE64, - e_regSetDBG, // ARM_DEBUG_STATE64, - kNumRegisterSets - } RegisterSet; - - enum - { - e_regSetGPRCount = ARM_THREAD_STATE64_COUNT, - e_regSetVFPCount = ARM_NEON_STATE64_COUNT, - e_regSetEXCCount = ARM_EXCEPTION_STATE64_COUNT, - e_regSetDBGCount = ARM_DEBUG_STATE64_COUNT, - }; - - enum - { - Read = 0, - Write = 1, - kNumErrors = 2 - }; - - typedef arm_thread_state64_t GPR; - typedef arm_neon_state64_t FPU; - typedef arm_exception_state64_t EXC; - - static const DNBRegisterInfo g_gpr_registers[]; - static const DNBRegisterInfo g_vfp_registers[]; - static const DNBRegisterInfo g_exc_registers[]; - static const DNBRegisterSetInfo g_reg_sets[]; - - static const size_t k_num_gpr_registers; - static const size_t k_num_vfp_registers; - static const size_t k_num_exc_registers; - static const size_t k_num_all_registers; - static const size_t k_num_register_sets; - - struct Context - { - GPR gpr; - FPU vfp; - EXC exc; - }; - - struct State - { - Context context; - arm_debug_state64_t dbg; - kern_return_t gpr_errs[2]; // Read/Write errors - kern_return_t vfp_errs[2]; // Read/Write errors - kern_return_t exc_errs[2]; // Read/Write errors - kern_return_t dbg_errs[2]; // Read/Write errors - State() - { - uint32_t i; - for (i=0; i<kNumErrors; i++) - { - gpr_errs[i] = -1; - vfp_errs[i] = -1; - exc_errs[i] = -1; - dbg_errs[i] = -1; - } - } - void InvalidateRegisterSetState(int set) - { - SetError (set, Read, -1); - } - - void - InvalidateAllRegisterStates() - { - SetError (e_regSetALL, Read, -1); - } - - kern_return_t GetError (int set, uint32_t err_idx) const - { - if (err_idx < kNumErrors) - { - switch (set) - { - // When getting all errors, just OR all values together to see if - // we got any kind of error. - case e_regSetALL: return gpr_errs[err_idx] | - vfp_errs[err_idx] | - exc_errs[err_idx] | - dbg_errs[err_idx] ; - case e_regSetGPR: return gpr_errs[err_idx]; - case e_regSetVFP: return vfp_errs[err_idx]; - case e_regSetEXC: return exc_errs[err_idx]; - //case e_regSetDBG: return dbg_errs[err_idx]; - default: break; - } - } - return -1; - } - bool SetError (int set, uint32_t err_idx, kern_return_t err) - { - if (err_idx < kNumErrors) - { - switch (set) - { - case e_regSetALL: - gpr_errs[err_idx] = err; - vfp_errs[err_idx] = err; - dbg_errs[err_idx] = err; - exc_errs[err_idx] = err; - return true; - - case e_regSetGPR: - gpr_errs[err_idx] = err; - return true; - - case e_regSetVFP: - vfp_errs[err_idx] = err; - return true; - - case e_regSetEXC: - exc_errs[err_idx] = err; - return true; - -// case e_regSetDBG: -// dbg_errs[err_idx] = err; -// return true; - default: break; - } - } - return false; + kern_return_t EnableHardwareSingleStep(bool enable); + static bool FixGenericRegisterNumber(uint32_t &set, uint32_t ®); + + typedef enum RegisterSetTag { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, // ARM_THREAD_STATE64, + e_regSetVFP, // ARM_NEON_STATE64, + e_regSetEXC, // ARM_EXCEPTION_STATE64, + e_regSetDBG, // ARM_DEBUG_STATE64, + kNumRegisterSets + } RegisterSet; + + enum { + e_regSetGPRCount = ARM_THREAD_STATE64_COUNT, + e_regSetVFPCount = ARM_NEON_STATE64_COUNT, + e_regSetEXCCount = ARM_EXCEPTION_STATE64_COUNT, + e_regSetDBGCount = ARM_DEBUG_STATE64_COUNT, + }; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + typedef arm_thread_state64_t GPR; + typedef arm_neon_state64_t FPU; + typedef arm_exception_state64_t EXC; + + static const DNBRegisterInfo g_gpr_registers[]; + static const DNBRegisterInfo g_vfp_registers[]; + static const DNBRegisterInfo g_exc_registers[]; + static const DNBRegisterSetInfo g_reg_sets[]; + + static const size_t k_num_gpr_registers; + static const size_t k_num_vfp_registers; + static const size_t k_num_exc_registers; + static const size_t k_num_all_registers; + static const size_t k_num_register_sets; + + struct Context { + GPR gpr; + FPU vfp; + EXC exc; + }; + + struct State { + Context context; + arm_debug_state64_t dbg; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t vfp_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t dbg_errs[2]; // Read/Write errors + State() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + vfp_errs[i] = -1; + exc_errs[i] = -1; + dbg_errs[i] = -1; + } + } + void InvalidateRegisterSetState(int set) { SetError(set, Read, -1); } + + void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); } + + kern_return_t GetError(int set, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (set) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case e_regSetALL: + return gpr_errs[err_idx] | vfp_errs[err_idx] | exc_errs[err_idx] | + dbg_errs[err_idx]; + case e_regSetGPR: + return gpr_errs[err_idx]; + case e_regSetVFP: + return vfp_errs[err_idx]; + case e_regSetEXC: + return exc_errs[err_idx]; + // case e_regSetDBG: return dbg_errs[err_idx]; + default: + break; } - bool RegsAreValid (int set) const - { - return GetError(set, Read) == KERN_SUCCESS; + } + return -1; + } + bool SetError(int set, uint32_t err_idx, kern_return_t err) { + if (err_idx < kNumErrors) { + switch (set) { + case e_regSetALL: + gpr_errs[err_idx] = err; + vfp_errs[err_idx] = err; + dbg_errs[err_idx] = err; + exc_errs[err_idx] = err; + return true; + + case e_regSetGPR: + gpr_errs[err_idx] = err; + return true; + + case e_regSetVFP: + vfp_errs[err_idx] = err; + return true; + + case e_regSetEXC: + exc_errs[err_idx] = err; + return true; + + // case e_regSetDBG: + // dbg_errs[err_idx] = err; + // return true; + default: + break; } - }; - - kern_return_t GetGPRState (bool force); - kern_return_t GetVFPState (bool force); - kern_return_t GetEXCState (bool force); - kern_return_t GetDBGState (bool force); - - kern_return_t SetGPRState (); - kern_return_t SetVFPState (); - kern_return_t SetEXCState (); - kern_return_t SetDBGState (bool also_set_on_task); - - // Helper functions for watchpoint implementaions. - - typedef arm_debug_state64_t DBG; - - void ClearWatchpointOccurred(); - bool HasWatchpointOccurred(); - bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); - nub_addr_t GetWatchpointAddressByIndex (uint32_t hw_index); - nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - virtual bool ReenableHardwareWatchpoint (uint32_t hw_break_index); - virtual bool ReenableHardwareWatchpoint_helper (uint32_t hw_break_index); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); - - - class disabled_watchpoint { - public: - disabled_watchpoint () { addr = 0; control = 0; } - nub_addr_t addr; - uint32_t control; - }; + } + return false; + } + bool RegsAreValid(int set) const { + return GetError(set, Read) == KERN_SUCCESS; + } + }; + + kern_return_t GetGPRState(bool force); + kern_return_t GetVFPState(bool force); + kern_return_t GetEXCState(bool force); + kern_return_t GetDBGState(bool force); + + kern_return_t SetGPRState(); + kern_return_t SetVFPState(); + kern_return_t SetEXCState(); + kern_return_t SetDBGState(bool also_set_on_task); + + // Helper functions for watchpoint implementaions. + + typedef arm_debug_state64_t DBG; + + void ClearWatchpointOccurred(); + bool HasWatchpointOccurred(); + bool IsWatchpointEnabled(const DBG &debug_state, uint32_t hw_index); + nub_addr_t GetWatchpointAddressByIndex(uint32_t hw_index); + nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + virtual bool ReenableHardwareWatchpoint(uint32_t hw_break_index); + virtual bool ReenableHardwareWatchpoint_helper(uint32_t hw_break_index); + virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + + class disabled_watchpoint { + public: + disabled_watchpoint() { + addr = 0; + control = 0; + } + nub_addr_t addr; + uint32_t control; + }; protected: - MachThread * m_thread; - State m_state; - arm_debug_state64_t m_dbg_save; - - // arm64 doesn't keep the disabled watchpoint values in the debug register context like armv7; - // we need to save them aside when we disable them temporarily. - std::vector<disabled_watchpoint> m_disabled_watchpoints; - - // The following member variables should be updated atomically. - int32_t m_watchpoint_hw_index; - bool m_watchpoint_did_occur; - bool m_watchpoint_resume_single_step_enabled; - - typedef std::map<uint32_t, Context> SaveRegisterStates; - SaveRegisterStates m_saved_register_states; + MachThread *m_thread; + State m_state; + arm_debug_state64_t m_dbg_save; + + // arm64 doesn't keep the disabled watchpoint values in the debug register + // context like armv7; + // we need to save them aside when we disable them temporarily. + std::vector<disabled_watchpoint> m_disabled_watchpoints; + + // The following member variables should be updated atomically. + int32_t m_watchpoint_hw_index; + bool m_watchpoint_did_occur; + bool m_watchpoint_resume_single_step_enabled; + + typedef std::map<uint32_t, Context> SaveRegisterStates; + SaveRegisterStates m_saved_register_states; }; -#endif // #if defined (ARM_THREAD_STATE64_COUNT) -#endif // #if defined (__arm__) -#endif // #ifndef __DNBArchImplARM64_h__ +#endif // #if defined (ARM_THREAD_STATE64_COUNT) +#endif // #if defined (__arm__) +#endif // #ifndef __DNBArchImplARM64_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp index 93d4d894300..0974b168326 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.cpp @@ -11,51 +11,43 @@ // //===----------------------------------------------------------------------===// -#if defined (__i386__) || defined (__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include <sys/cdefs.h> -#include "MacOSX/i386/DNBArchImplI386.h" #include "DNBLog.h" -#include "MachThread.h" +#include "MacOSX/i386/DNBArchImplI386.h" #include "MachProcess.h" +#include "MachThread.h" extern "C" bool CPUHasAVX(); // Defined over in DNBArchImplX86_64.cpp -#if defined (LLDB_DEBUGSERVER_RELEASE) || defined (LLDB_DEBUGSERVER_DEBUG) -enum debugState { - debugStateUnknown, - debugStateOff, - debugStateOn -}; +#if defined(LLDB_DEBUGSERVER_RELEASE) || defined(LLDB_DEBUGSERVER_DEBUG) +enum debugState { debugStateUnknown, debugStateOff, debugStateOn }; static debugState sFPUDebugState = debugStateUnknown; static debugState sAVXForceState = debugStateUnknown; -static bool DebugFPURegs () -{ - if (sFPUDebugState == debugStateUnknown) - { - if (getenv("DNB_DEBUG_FPU_REGS")) - sFPUDebugState = debugStateOn; - else - sFPUDebugState = debugStateOff; - } - - return (sFPUDebugState == debugStateOn); +static bool DebugFPURegs() { + if (sFPUDebugState == debugStateUnknown) { + if (getenv("DNB_DEBUG_FPU_REGS")) + sFPUDebugState = debugStateOn; + else + sFPUDebugState = debugStateOff; + } + + return (sFPUDebugState == debugStateOn); } -static bool ForceAVXRegs () -{ - if (sFPUDebugState == debugStateUnknown) - { - if (getenv("DNB_DEBUG_X86_FORCE_AVX_REGS")) - sAVXForceState = debugStateOn; - else - sAVXForceState = debugStateOff; - } - - return (sAVXForceState == debugStateOn); +static bool ForceAVXRegs() { + if (sFPUDebugState == debugStateUnknown) { + if (getenv("DNB_DEBUG_X86_FORCE_AVX_REGS")) + sAVXForceState = debugStateOn; + else + sAVXForceState = debugStateOff; + } + + return (sAVXForceState == debugStateOn); } #define DEBUG_FPU_REGS (DebugFPURegs()) @@ -65,1837 +57,2314 @@ static bool ForceAVXRegs () #define FORCE_AVX_REGS (0) #endif -enum -{ - gpr_eax = 0, - gpr_ebx = 1, - gpr_ecx = 2, - gpr_edx = 3, - gpr_edi = 4, - gpr_esi = 5, - gpr_ebp = 6, - gpr_esp = 7, - gpr_ss = 8, - gpr_eflags = 9, - gpr_eip = 10, - gpr_cs = 11, - gpr_ds = 12, - gpr_es = 13, - gpr_fs = 14, - gpr_gs = 15, - gpr_ax , - gpr_bx , - gpr_cx , - gpr_dx , - gpr_di , - gpr_si , - gpr_bp , - gpr_sp , - gpr_ah , - gpr_bh , - gpr_ch , - gpr_dh , - gpr_al , - gpr_bl , - gpr_cl , - gpr_dl , - gpr_dil, - gpr_sil, - gpr_bpl, - gpr_spl, - k_num_gpr_regs +enum { + gpr_eax = 0, + gpr_ebx = 1, + gpr_ecx = 2, + gpr_edx = 3, + gpr_edi = 4, + gpr_esi = 5, + gpr_ebp = 6, + gpr_esp = 7, + gpr_ss = 8, + gpr_eflags = 9, + gpr_eip = 10, + gpr_cs = 11, + gpr_ds = 12, + gpr_es = 13, + gpr_fs = 14, + gpr_gs = 15, + gpr_ax, + gpr_bx, + gpr_cx, + gpr_dx, + gpr_di, + gpr_si, + gpr_bp, + gpr_sp, + gpr_ah, + gpr_bh, + gpr_ch, + gpr_dh, + gpr_al, + gpr_bl, + gpr_cl, + gpr_dl, + gpr_dil, + gpr_sil, + gpr_bpl, + gpr_spl, + k_num_gpr_regs }; enum { - fpu_fcw, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_dp, - fpu_ds, - fpu_mxcsr, - fpu_mxcsrmask, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, - fpu_ymm0, - fpu_ymm1, - fpu_ymm2, - fpu_ymm3, - fpu_ymm4, - fpu_ymm5, - fpu_ymm6, - fpu_ymm7, - k_num_fpu_regs, - - // Aliases - fpu_fctrl = fpu_fcw, - fpu_fstat = fpu_fsw, - fpu_ftag = fpu_ftw, - fpu_fiseg = fpu_cs, - fpu_fioff = fpu_ip, - fpu_foseg = fpu_ds, - fpu_fooff = fpu_dp + fpu_fcw, + fpu_fsw, + fpu_ftw, + fpu_fop, + fpu_ip, + fpu_cs, + fpu_dp, + fpu_ds, + fpu_mxcsr, + fpu_mxcsrmask, + fpu_stmm0, + fpu_stmm1, + fpu_stmm2, + fpu_stmm3, + fpu_stmm4, + fpu_stmm5, + fpu_stmm6, + fpu_stmm7, + fpu_xmm0, + fpu_xmm1, + fpu_xmm2, + fpu_xmm3, + fpu_xmm4, + fpu_xmm5, + fpu_xmm6, + fpu_xmm7, + fpu_ymm0, + fpu_ymm1, + fpu_ymm2, + fpu_ymm3, + fpu_ymm4, + fpu_ymm5, + fpu_ymm6, + fpu_ymm7, + k_num_fpu_regs, + + // Aliases + fpu_fctrl = fpu_fcw, + fpu_fstat = fpu_fsw, + fpu_ftag = fpu_ftw, + fpu_fiseg = fpu_cs, + fpu_fioff = fpu_ip, + fpu_foseg = fpu_ds, + fpu_fooff = fpu_dp }; enum { - exc_trapno, - exc_err, - exc_faultvaddr, - k_num_exc_regs, + exc_trapno, + exc_err, + exc_faultvaddr, + k_num_exc_regs, }; - -enum -{ - ehframe_eax = 0, - ehframe_ecx, - ehframe_edx, - ehframe_ebx, - - // On i386 Darwin the eh_frame register numbers for ebp and esp are reversed from DWARF. - // It's due to an ancient compiler bug in the output of the eh_frame. - // Specifically, on i386 darwin eh_frame, 4 is ebp, 5 is esp. - // On i386 darwin debug_frame (and debug_info), 4 is esp, 5 is ebp. - ehframe_ebp, - ehframe_esp, - ehframe_esi, - ehframe_edi, - ehframe_eip, - ehframe_eflags +enum { + ehframe_eax = 0, + ehframe_ecx, + ehframe_edx, + ehframe_ebx, + + // On i386 Darwin the eh_frame register numbers for ebp and esp are reversed + // from DWARF. + // It's due to an ancient compiler bug in the output of the eh_frame. + // Specifically, on i386 darwin eh_frame, 4 is ebp, 5 is esp. + // On i386 darwin debug_frame (and debug_info), 4 is esp, 5 is ebp. + ehframe_ebp, + ehframe_esp, + ehframe_esi, + ehframe_edi, + ehframe_eip, + ehframe_eflags }; -enum -{ - dwarf_eax = 0, - dwarf_ecx, - dwarf_edx, - dwarf_ebx, - dwarf_esp, - dwarf_ebp, - dwarf_esi, - dwarf_edi, - dwarf_eip, - dwarf_eflags, - dwarf_stmm0 = 11, - dwarf_stmm1, - dwarf_stmm2, - dwarf_stmm3, - dwarf_stmm4, - dwarf_stmm5, - dwarf_stmm6, - dwarf_stmm7, - dwarf_xmm0 = 21, - dwarf_xmm1, - dwarf_xmm2, - dwarf_xmm3, - dwarf_xmm4, - dwarf_xmm5, - dwarf_xmm6, - dwarf_xmm7, - dwarf_ymm0 = dwarf_xmm0, - dwarf_ymm1 = dwarf_xmm1, - dwarf_ymm2 = dwarf_xmm2, - dwarf_ymm3 = dwarf_xmm3, - dwarf_ymm4 = dwarf_xmm4, - dwarf_ymm5 = dwarf_xmm5, - dwarf_ymm6 = dwarf_xmm6, - dwarf_ymm7 = dwarf_xmm7, +enum { + dwarf_eax = 0, + dwarf_ecx, + dwarf_edx, + dwarf_ebx, + dwarf_esp, + dwarf_ebp, + dwarf_esi, + dwarf_edi, + dwarf_eip, + dwarf_eflags, + dwarf_stmm0 = 11, + dwarf_stmm1, + dwarf_stmm2, + dwarf_stmm3, + dwarf_stmm4, + dwarf_stmm5, + dwarf_stmm6, + dwarf_stmm7, + dwarf_xmm0 = 21, + dwarf_xmm1, + dwarf_xmm2, + dwarf_xmm3, + dwarf_xmm4, + dwarf_xmm5, + dwarf_xmm6, + dwarf_xmm7, + dwarf_ymm0 = dwarf_xmm0, + dwarf_ymm1 = dwarf_xmm1, + dwarf_ymm2 = dwarf_xmm2, + dwarf_ymm3 = dwarf_xmm3, + dwarf_ymm4 = dwarf_xmm4, + dwarf_ymm5 = dwarf_xmm5, + dwarf_ymm6 = dwarf_xmm6, + dwarf_ymm7 = dwarf_xmm7, }; -enum -{ - debugserver_eax = 0, - debugserver_ecx = 1, - debugserver_edx = 2, - debugserver_ebx = 3, - debugserver_esp = 4, - debugserver_ebp = 5, - debugserver_esi = 6, - debugserver_edi = 7, - debugserver_eip = 8, - debugserver_eflags = 9, - debugserver_cs = 10, - debugserver_ss = 11, - debugserver_ds = 12, - debugserver_es = 13, - debugserver_fs = 14, - debugserver_gs = 15, - debugserver_stmm0 = 16, - debugserver_stmm1 = 17, - debugserver_stmm2 = 18, - debugserver_stmm3 = 19, - debugserver_stmm4 = 20, - debugserver_stmm5 = 21, - debugserver_stmm6 = 22, - debugserver_stmm7 = 23, - debugserver_fctrl = 24, debugserver_fcw = debugserver_fctrl, - debugserver_fstat = 25, debugserver_fsw = debugserver_fstat, - debugserver_ftag = 26, debugserver_ftw = debugserver_ftag, - debugserver_fiseg = 27, debugserver_fpu_cs = debugserver_fiseg, - debugserver_fioff = 28, debugserver_ip = debugserver_fioff, - debugserver_foseg = 29, debugserver_fpu_ds = debugserver_foseg, - debugserver_fooff = 30, debugserver_dp = debugserver_fooff, - debugserver_fop = 31, - debugserver_xmm0 = 32, - debugserver_xmm1 = 33, - debugserver_xmm2 = 34, - debugserver_xmm3 = 35, - debugserver_xmm4 = 36, - debugserver_xmm5 = 37, - debugserver_xmm6 = 38, - debugserver_xmm7 = 39, - debugserver_mxcsr = 40, - debugserver_mm0 = 41, - debugserver_mm1 = 42, - debugserver_mm2 = 43, - debugserver_mm3 = 44, - debugserver_mm4 = 45, - debugserver_mm5 = 46, - debugserver_mm6 = 47, - debugserver_mm7 = 48, - debugserver_ymm0 = debugserver_xmm0, - debugserver_ymm1 = debugserver_xmm1, - debugserver_ymm2 = debugserver_xmm2, - debugserver_ymm3 = debugserver_xmm3, - debugserver_ymm4 = debugserver_xmm4, - debugserver_ymm5 = debugserver_xmm5, - debugserver_ymm6 = debugserver_xmm6, - debugserver_ymm7 = debugserver_xmm7 +enum { + debugserver_eax = 0, + debugserver_ecx = 1, + debugserver_edx = 2, + debugserver_ebx = 3, + debugserver_esp = 4, + debugserver_ebp = 5, + debugserver_esi = 6, + debugserver_edi = 7, + debugserver_eip = 8, + debugserver_eflags = 9, + debugserver_cs = 10, + debugserver_ss = 11, + debugserver_ds = 12, + debugserver_es = 13, + debugserver_fs = 14, + debugserver_gs = 15, + debugserver_stmm0 = 16, + debugserver_stmm1 = 17, + debugserver_stmm2 = 18, + debugserver_stmm3 = 19, + debugserver_stmm4 = 20, + debugserver_stmm5 = 21, + debugserver_stmm6 = 22, + debugserver_stmm7 = 23, + debugserver_fctrl = 24, + debugserver_fcw = debugserver_fctrl, + debugserver_fstat = 25, + debugserver_fsw = debugserver_fstat, + debugserver_ftag = 26, + debugserver_ftw = debugserver_ftag, + debugserver_fiseg = 27, + debugserver_fpu_cs = debugserver_fiseg, + debugserver_fioff = 28, + debugserver_ip = debugserver_fioff, + debugserver_foseg = 29, + debugserver_fpu_ds = debugserver_foseg, + debugserver_fooff = 30, + debugserver_dp = debugserver_fooff, + debugserver_fop = 31, + debugserver_xmm0 = 32, + debugserver_xmm1 = 33, + debugserver_xmm2 = 34, + debugserver_xmm3 = 35, + debugserver_xmm4 = 36, + debugserver_xmm5 = 37, + debugserver_xmm6 = 38, + debugserver_xmm7 = 39, + debugserver_mxcsr = 40, + debugserver_mm0 = 41, + debugserver_mm1 = 42, + debugserver_mm2 = 43, + debugserver_mm3 = 44, + debugserver_mm4 = 45, + debugserver_mm5 = 46, + debugserver_mm6 = 47, + debugserver_mm7 = 48, + debugserver_ymm0 = debugserver_xmm0, + debugserver_ymm1 = debugserver_xmm1, + debugserver_ymm2 = debugserver_xmm2, + debugserver_ymm3 = debugserver_xmm3, + debugserver_ymm4 = debugserver_xmm4, + debugserver_ymm5 = debugserver_xmm5, + debugserver_ymm6 = debugserver_xmm6, + debugserver_ymm7 = debugserver_xmm7 }; -uint64_t -DNBArchImplI386::GetPC(uint64_t failValue) -{ - // Get program counter - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__eip; - return failValue; +uint64_t DNBArchImplI386::GetPC(uint64_t failValue) { + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__eip; + return failValue; } -kern_return_t -DNBArchImplI386::SetPC(uint64_t value) -{ - // Get program counter - kern_return_t err = GetGPRState(false); - if (err == KERN_SUCCESS) - { - m_state.context.gpr.__eip = static_cast<uint32_t>(value); - err = SetGPRState(); - } - return err == KERN_SUCCESS; +kern_return_t DNBArchImplI386::SetPC(uint64_t value) { + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) { + m_state.context.gpr.__eip = static_cast<uint32_t>(value); + err = SetGPRState(); + } + return err == KERN_SUCCESS; } -uint64_t -DNBArchImplI386::GetSP(uint64_t failValue) -{ - // Get stack pointer - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__esp; - return failValue; +uint64_t DNBArchImplI386::GetSP(uint64_t failValue) { + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__esp; + return failValue; } // Uncomment the value below to verify the values in the debugger. //#define DEBUG_GPR_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED //#define SET_GPR(reg) m_state.context.gpr.__##reg = gpr_##reg -kern_return_t -DNBArchImplI386::GetGPRState(bool force) -{ - if (force || m_state.GetError(e_regSetGPR, Read)) - { +kern_return_t DNBArchImplI386::GetGPRState(bool force) { + if (force || m_state.GetError(e_regSetGPR, Read)) { #if DEBUG_GPR_VALUES - SET_GPR(eax); - SET_GPR(ebx); - SET_GPR(ecx); - SET_GPR(edx); - SET_GPR(edi); - SET_GPR(esi); - SET_GPR(ebp); - SET_GPR(esp); - SET_GPR(ss); - SET_GPR(eflags); - SET_GPR(eip); - SET_GPR(cs); - SET_GPR(ds); - SET_GPR(es); - SET_GPR(fs); - SET_GPR(gs); - m_state.SetError(e_regSetGPR, Read, 0); + SET_GPR(eax); + SET_GPR(ebx); + SET_GPR(ecx); + SET_GPR(edx); + SET_GPR(edi); + SET_GPR(esi); + SET_GPR(ebp); + SET_GPR(esp); + SET_GPR(ss); + SET_GPR(eflags); + SET_GPR(eip); + SET_GPR(cs); + SET_GPR(ds); + SET_GPR(es); + SET_GPR(fs); + SET_GPR(gs); + m_state.SetError(e_regSetGPR, Read, 0); #else - mach_msg_type_number_t count = e_regSetWordSizeGPR; - m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->MachPortNumber(), __i386_THREAD_STATE, (thread_state_t)&m_state.context.gpr, &count)); + mach_msg_type_number_t count = e_regSetWordSizeGPR; + m_state.SetError( + e_regSetGPR, Read, + ::thread_get_state(m_thread->MachPortNumber(), __i386_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, &count)); #endif - } - return m_state.GetError(e_regSetGPR, Read); + } + return m_state.GetError(e_regSetGPR, Read); } // Uncomment the value below to verify the values in the debugger. //#define DEBUG_FPU_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED -kern_return_t -DNBArchImplI386::GetFPUState(bool force) -{ - if (force || m_state.GetError(e_regSetFPU, Read)) - { - if (DEBUG_FPU_REGS) - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - m_state.context.fpu.avx.__fpu_reserved[0] = -1; - m_state.context.fpu.avx.__fpu_reserved[1] = -1; - *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fcw) = 0x1234; - *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fsw) = 0x5678; - m_state.context.fpu.avx.__fpu_ftw = 1; - m_state.context.fpu.avx.__fpu_rsrv1 = UINT8_MAX; - m_state.context.fpu.avx.__fpu_fop = 2; - m_state.context.fpu.avx.__fpu_ip = 3; - m_state.context.fpu.avx.__fpu_cs = 4; - m_state.context.fpu.avx.__fpu_rsrv2 = 5; - m_state.context.fpu.avx.__fpu_dp = 6; - m_state.context.fpu.avx.__fpu_ds = 7; - m_state.context.fpu.avx.__fpu_rsrv3 = UINT16_MAX; - m_state.context.fpu.avx.__fpu_mxcsr = 8; - m_state.context.fpu.avx.__fpu_mxcsrmask = 9; - int i; - for (i=0; i<16; ++i) - { - if (i<10) - { - m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = 'a'; - m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = 'b'; - m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = 'c'; - m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = 'd'; - m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = 'e'; - m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = 'f'; - m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = 'g'; - m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = 'h'; - } - else - { - m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; - } - - m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg[i] = '0'; - m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg[i] = '1'; - m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg[i] = '2'; - m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg[i] = '3'; - m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg[i] = '4'; - m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg[i] = '5'; - m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg[i] = '6'; - m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg[i] = '7'; - } - for (i=0; i<sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) - m_state.context.fpu.avx.__fpu_rsrv4[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_reserved1 = -1; - for (i=0; i<sizeof(m_state.context.fpu.avx.__avx_reserved1); ++i) - m_state.context.fpu.avx.__avx_reserved1[i] = INT8_MIN; - - for (i = 0; i < 16; ++i) - { - m_state.context.fpu.avx.__fpu_ymmh0.__xmm_reg[i] = '0'; - m_state.context.fpu.avx.__fpu_ymmh1.__xmm_reg[i] = '1'; - m_state.context.fpu.avx.__fpu_ymmh2.__xmm_reg[i] = '2'; - m_state.context.fpu.avx.__fpu_ymmh3.__xmm_reg[i] = '3'; - m_state.context.fpu.avx.__fpu_ymmh4.__xmm_reg[i] = '4'; - m_state.context.fpu.avx.__fpu_ymmh5.__xmm_reg[i] = '5'; - m_state.context.fpu.avx.__fpu_ymmh6.__xmm_reg[i] = '6'; - m_state.context.fpu.avx.__fpu_ymmh7.__xmm_reg[i] = '7'; - } - } - else - { - m_state.context.fpu.no_avx.__fpu_reserved[0] = -1; - m_state.context.fpu.no_avx.__fpu_reserved[1] = -1; - *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fcw) = 0x1234; - *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fsw) = 0x5678; - m_state.context.fpu.no_avx.__fpu_ftw = 1; - m_state.context.fpu.no_avx.__fpu_rsrv1 = UINT8_MAX; - m_state.context.fpu.no_avx.__fpu_fop = 2; - m_state.context.fpu.no_avx.__fpu_ip = 3; - m_state.context.fpu.no_avx.__fpu_cs = 4; - m_state.context.fpu.no_avx.__fpu_rsrv2 = 5; - m_state.context.fpu.no_avx.__fpu_dp = 6; - m_state.context.fpu.no_avx.__fpu_ds = 7; - m_state.context.fpu.no_avx.__fpu_rsrv3 = UINT16_MAX; - m_state.context.fpu.no_avx.__fpu_mxcsr = 8; - m_state.context.fpu.no_avx.__fpu_mxcsrmask = 9; - int i; - for (i=0; i<16; ++i) - { - if (i<10) - { - m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = 'a'; - m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = 'b'; - m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = 'c'; - m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = 'd'; - m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = 'e'; - m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = 'f'; - m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = 'g'; - m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = 'h'; - } - else - { - m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; - } - - m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg[i] = '0'; - m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg[i] = '1'; - m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg[i] = '2'; - m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg[i] = '3'; - m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg[i] = '4'; - m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg[i] = '5'; - m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg[i] = '6'; - m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg[i] = '7'; - } - for (i=0; i<sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) - m_state.context.fpu.no_avx.__fpu_rsrv4[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_reserved1 = -1; - } - m_state.SetError(e_regSetFPU, Read, 0); +kern_return_t DNBArchImplI386::GetFPUState(bool force) { + if (force || m_state.GetError(e_regSetFPU, Read)) { + if (DEBUG_FPU_REGS) { + if (CPUHasAVX() || FORCE_AVX_REGS) { + m_state.context.fpu.avx.__fpu_reserved[0] = -1; + m_state.context.fpu.avx.__fpu_reserved[1] = -1; + *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fcw) = 0x1234; + *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fsw) = 0x5678; + m_state.context.fpu.avx.__fpu_ftw = 1; + m_state.context.fpu.avx.__fpu_rsrv1 = UINT8_MAX; + m_state.context.fpu.avx.__fpu_fop = 2; + m_state.context.fpu.avx.__fpu_ip = 3; + m_state.context.fpu.avx.__fpu_cs = 4; + m_state.context.fpu.avx.__fpu_rsrv2 = 5; + m_state.context.fpu.avx.__fpu_dp = 6; + m_state.context.fpu.avx.__fpu_ds = 7; + m_state.context.fpu.avx.__fpu_rsrv3 = UINT16_MAX; + m_state.context.fpu.avx.__fpu_mxcsr = 8; + m_state.context.fpu.avx.__fpu_mxcsrmask = 9; + int i; + for (i = 0; i < 16; ++i) { + if (i < 10) { + m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = 'a'; + m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = 'b'; + m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = 'c'; + m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = 'd'; + m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = 'e'; + m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = 'f'; + m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = 'g'; + m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = 'h'; + } else { + m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; + } + + m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg[i] = '0'; + m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg[i] = '1'; + m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg[i] = '2'; + m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg[i] = '3'; + m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg[i] = '4'; + m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg[i] = '5'; + m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg[i] = '6'; + m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg[i] = '7'; } - else - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - mach_msg_type_number_t count = e_regSetWordSizeAVX; - m_state.SetError (e_regSetFPU, Read, ::thread_get_state(m_thread->MachPortNumber(), __i386_AVX_STATE, (thread_state_t)&m_state.context.fpu.avx, &count)); - DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &avx, %u (%u passed in)) => 0x%8.8x", - m_thread->MachPortNumber(), __i386_AVX_STATE, count, e_regSetWordSizeAVX, - m_state.GetError(e_regSetFPU, Read)); - } - else - { - mach_msg_type_number_t count = e_regSetWordSizeFPU; - m_state.SetError(e_regSetFPU, Read, ::thread_get_state(m_thread->MachPortNumber(), __i386_FLOAT_STATE, (thread_state_t)&m_state.context.fpu.no_avx, &count)); - DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &fpu, %u (%u passed in) => 0x%8.8x", - m_thread->MachPortNumber(), __i386_FLOAT_STATE, count, e_regSetWordSizeFPU, - m_state.GetError(e_regSetFPU, Read)); - } + for (i = 0; i < sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) + m_state.context.fpu.avx.__fpu_rsrv4[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_reserved1 = -1; + for (i = 0; i < sizeof(m_state.context.fpu.avx.__avx_reserved1); ++i) + m_state.context.fpu.avx.__avx_reserved1[i] = INT8_MIN; + + for (i = 0; i < 16; ++i) { + m_state.context.fpu.avx.__fpu_ymmh0.__xmm_reg[i] = '0'; + m_state.context.fpu.avx.__fpu_ymmh1.__xmm_reg[i] = '1'; + m_state.context.fpu.avx.__fpu_ymmh2.__xmm_reg[i] = '2'; + m_state.context.fpu.avx.__fpu_ymmh3.__xmm_reg[i] = '3'; + m_state.context.fpu.avx.__fpu_ymmh4.__xmm_reg[i] = '4'; + m_state.context.fpu.avx.__fpu_ymmh5.__xmm_reg[i] = '5'; + m_state.context.fpu.avx.__fpu_ymmh6.__xmm_reg[i] = '6'; + m_state.context.fpu.avx.__fpu_ymmh7.__xmm_reg[i] = '7'; } + } else { + m_state.context.fpu.no_avx.__fpu_reserved[0] = -1; + m_state.context.fpu.no_avx.__fpu_reserved[1] = -1; + *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fcw) = 0x1234; + *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fsw) = 0x5678; + m_state.context.fpu.no_avx.__fpu_ftw = 1; + m_state.context.fpu.no_avx.__fpu_rsrv1 = UINT8_MAX; + m_state.context.fpu.no_avx.__fpu_fop = 2; + m_state.context.fpu.no_avx.__fpu_ip = 3; + m_state.context.fpu.no_avx.__fpu_cs = 4; + m_state.context.fpu.no_avx.__fpu_rsrv2 = 5; + m_state.context.fpu.no_avx.__fpu_dp = 6; + m_state.context.fpu.no_avx.__fpu_ds = 7; + m_state.context.fpu.no_avx.__fpu_rsrv3 = UINT16_MAX; + m_state.context.fpu.no_avx.__fpu_mxcsr = 8; + m_state.context.fpu.no_avx.__fpu_mxcsrmask = 9; + int i; + for (i = 0; i < 16; ++i) { + if (i < 10) { + m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = 'a'; + m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = 'b'; + m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = 'c'; + m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = 'd'; + m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = 'e'; + m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = 'f'; + m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = 'g'; + m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = 'h'; + } else { + m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; + } + + m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg[i] = '0'; + m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg[i] = '1'; + m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg[i] = '2'; + m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg[i] = '3'; + m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg[i] = '4'; + m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg[i] = '5'; + m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg[i] = '6'; + m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg[i] = '7'; + } + for (i = 0; i < sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) + m_state.context.fpu.no_avx.__fpu_rsrv4[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_reserved1 = -1; + } + m_state.SetError(e_regSetFPU, Read, 0); + } else { + if (CPUHasAVX() || FORCE_AVX_REGS) { + mach_msg_type_number_t count = e_regSetWordSizeAVX; + m_state.SetError(e_regSetFPU, Read, + ::thread_get_state( + m_thread->MachPortNumber(), __i386_AVX_STATE, + (thread_state_t)&m_state.context.fpu.avx, &count)); + DNBLogThreadedIf(LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &avx, " + "%u (%u passed in)) => 0x%8.8x", + m_thread->MachPortNumber(), __i386_AVX_STATE, count, + e_regSetWordSizeAVX, + m_state.GetError(e_regSetFPU, Read)); + } else { + mach_msg_type_number_t count = e_regSetWordSizeFPU; + m_state.SetError( + e_regSetFPU, Read, + ::thread_get_state(m_thread->MachPortNumber(), __i386_FLOAT_STATE, + (thread_state_t)&m_state.context.fpu.no_avx, + &count)); + DNBLogThreadedIf(LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &fpu, " + "%u (%u passed in) => 0x%8.8x", + m_thread->MachPortNumber(), __i386_FLOAT_STATE, count, + e_regSetWordSizeFPU, + m_state.GetError(e_regSetFPU, Read)); + } } - return m_state.GetError(e_regSetFPU, Read); + } + return m_state.GetError(e_regSetFPU, Read); } -kern_return_t -DNBArchImplI386::GetEXCState(bool force) -{ - if (force || m_state.GetError(e_regSetEXC, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeEXC; - m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->MachPortNumber(), __i386_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, &count)); - } - return m_state.GetError(e_regSetEXC, Read); +kern_return_t DNBArchImplI386::GetEXCState(bool force) { + if (force || m_state.GetError(e_regSetEXC, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeEXC; + m_state.SetError( + e_regSetEXC, Read, + ::thread_get_state(m_thread->MachPortNumber(), __i386_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, &count)); + } + return m_state.GetError(e_regSetEXC, Read); } -kern_return_t -DNBArchImplI386::SetGPRState() -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); - - - m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR)); - return m_state.GetError(e_regSetGPR, Write); +kern_return_t DNBArchImplI386::SetGPRState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + m_state.SetError(e_regSetGPR, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __i386_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, + e_regSetWordSizeGPR)); + return m_state.GetError(e_regSetGPR, Write); } -kern_return_t -DNBArchImplI386::SetFPUState() -{ - if (DEBUG_FPU_REGS) - { - m_state.SetError(e_regSetFPU, Write, 0); - return m_state.GetError(e_regSetFPU, Write); - } +kern_return_t DNBArchImplI386::SetFPUState() { + if (DEBUG_FPU_REGS) { + m_state.SetError(e_regSetFPU, Write, 0); + return m_state.GetError(e_regSetFPU, Write); + } else { + if (CPUHasAVX() || FORCE_AVX_REGS) + m_state.SetError( + e_regSetFPU, Write, + ::thread_set_state(m_thread->MachPortNumber(), __i386_AVX_STATE, + (thread_state_t)&m_state.context.fpu.avx, + e_regSetWordSizeAVX)); else - { - if (CPUHasAVX() || FORCE_AVX_REGS) - m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_AVX_STATE, (thread_state_t)&m_state.context.fpu.avx, e_regSetWordSizeAVX)); - else - m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_FLOAT_STATE, (thread_state_t)&m_state.context.fpu.no_avx, e_regSetWordSizeFPU)); - return m_state.GetError(e_regSetFPU, Write); - } + m_state.SetError( + e_regSetFPU, Write, + ::thread_set_state(m_thread->MachPortNumber(), __i386_FLOAT_STATE, + (thread_state_t)&m_state.context.fpu.no_avx, + e_regSetWordSizeFPU)); + return m_state.GetError(e_regSetFPU, Write); + } } -kern_return_t -DNBArchImplI386::SetEXCState() -{ - m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, e_regSetWordSizeEXC)); - return m_state.GetError(e_regSetEXC, Write); +kern_return_t DNBArchImplI386::SetEXCState() { + m_state.SetError(e_regSetEXC, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __i386_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, + e_regSetWordSizeEXC)); + return m_state.GetError(e_regSetEXC, Write); } -kern_return_t -DNBArchImplI386::GetDBGState(bool force) -{ - if (force || m_state.GetError(e_regSetDBG, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeDBG; - m_state.SetError(e_regSetDBG, Read, ::thread_get_state(m_thread->MachPortNumber(), __i386_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, &count)); - } - return m_state.GetError(e_regSetDBG, Read); +kern_return_t DNBArchImplI386::GetDBGState(bool force) { + if (force || m_state.GetError(e_regSetDBG, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeDBG; + m_state.SetError( + e_regSetDBG, Read, + ::thread_get_state(m_thread->MachPortNumber(), __i386_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, &count)); + } + return m_state.GetError(e_regSetDBG, Read); } -kern_return_t -DNBArchImplI386::SetDBGState(bool also_set_on_task) -{ - m_state.SetError(e_regSetDBG, Write, ::thread_set_state(m_thread->MachPortNumber(), __i386_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG)); - if (also_set_on_task) - { - kern_return_t kret = ::task_set_state(m_thread->Process()->Task().TaskPort(), __i386_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG); - if (kret != KERN_SUCCESS) - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); - - } - return m_state.GetError(e_regSetDBG, Write); +kern_return_t DNBArchImplI386::SetDBGState(bool also_set_on_task) { + m_state.SetError(e_regSetDBG, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __i386_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, + e_regSetWordSizeDBG)); + if (also_set_on_task) { + kern_return_t kret = ::task_set_state( + m_thread->Process()->Task().TaskPort(), __i386_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG); + if (kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::SetDBGState failed " + "to set debug control register state: " + "0x%8.8x.", + kret); + } + return m_state.GetError(e_regSetDBG, Write); } -void -DNBArchImplI386::ThreadWillResume() -{ - // Do we need to step this thread? If so, let the mach thread tell us so. - if (m_thread->IsStepping()) - { - // This is the primary thread, let the arch do anything it needs - EnableHardwareSingleStep(true); - } - - // Reset the debug status register, if necessary, before we resume. - kern_return_t kret = GetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret); - if (kret != KERN_SUCCESS) - return; +void DNBArchImplI386::ThreadWillResume() { + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) { + // This is the primary thread, let the arch do anything it needs + EnableHardwareSingleStep(true); + } + + // Reset the debug status register, if necessary, before we resume. + kern_return_t kret = GetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplI386::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret); + if (kret != KERN_SUCCESS) + return; - DBG &debug_state = m_state.context.dbg; - bool need_reset = false; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - if (IsWatchpointHit(debug_state, i)) - need_reset = true; - - if (need_reset) - { - ClearWatchpointHits(debug_state); - kret = SetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS,"DNBArchImplI386::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret); - } + DBG &debug_state = m_state.context.dbg; + bool need_reset = false; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) + if (IsWatchpointHit(debug_state, i)) + need_reset = true; + + if (need_reset) { + ClearWatchpointHits(debug_state); + kret = SetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplI386::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret); + } } -bool -DNBArchImplI386::ThreadDidStop() -{ - bool success = true; +bool DNBArchImplI386::ThreadDidStop() { + bool success = true; - m_state.InvalidateAllRegisterStates(); - - // Are we stepping a single instruction? - if (GetGPRState(true) == KERN_SUCCESS) - { - // We are single stepping, was this the primary thread? - if (m_thread->IsStepping()) - { - // This was the primary thread, we need to clear the trace - // bit if so. - success = EnableHardwareSingleStep(false) == KERN_SUCCESS; - } - else - { - // The MachThread will automatically restore the suspend count - // in ThreadDidStop(), so we don't need to do anything here if - // we weren't the primary thread the last time - } + m_state.InvalidateAllRegisterStates(); + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } else { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time } - return success; + } + return success; } -bool -DNBArchImplI386::NotifyException(MachException::Data& exc) -{ - switch (exc.exc_type) - { - case EXC_BAD_ACCESS: - break; - case EXC_BAD_INSTRUCTION: - break; - case EXC_ARITHMETIC: - break; - case EXC_EMULATION: - break; - case EXC_SOFTWARE: - break; - case EXC_BREAKPOINT: - if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2) - { - // exc_code = EXC_I386_BPT - // - nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); - if (pc != INVALID_NUB_ADDRESS && pc > 0) - { - pc -= 1; - // Check for a breakpoint at one byte prior to the current PC value - // since the PC will be just past the trap. - - DNBBreakpoint *bp = m_thread->Process()->Breakpoints().FindByAddress(pc); - if (bp) - { - // Backup the PC for i386 since the trap was taken and the PC - // is at the address following the single byte trap instruction. - if (m_state.context.gpr.__eip > 0) - { - m_state.context.gpr.__eip = static_cast<uint32_t>(pc); - // Write the new PC back out - SetGPRState (); - } - } - return true; - } +bool DNBArchImplI386::NotifyException(MachException::Data &exc) { + switch (exc.exc_type) { + case EXC_BAD_ACCESS: + break; + case EXC_BAD_INSTRUCTION: + break; + case EXC_ARITHMETIC: + break; + case EXC_EMULATION: + break; + case EXC_SOFTWARE: + break; + case EXC_BREAKPOINT: + if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2) { + // exc_code = EXC_I386_BPT + // + nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); + if (pc != INVALID_NUB_ADDRESS && pc > 0) { + pc -= 1; + // Check for a breakpoint at one byte prior to the current PC value + // since the PC will be just past the trap. + + DNBBreakpoint *bp = + m_thread->Process()->Breakpoints().FindByAddress(pc); + if (bp) { + // Backup the PC for i386 since the trap was taken and the PC + // is at the address following the single byte trap instruction. + if (m_state.context.gpr.__eip > 0) { + m_state.context.gpr.__eip = static_cast<uint32_t>(pc); + // Write the new PC back out + SetGPRState(); + } } - else if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1) - { - // exc_code = EXC_I386_SGL - // - // Check whether this corresponds to a watchpoint hit event. - // If yes, set the exc_sub_code to the data break address. - nub_addr_t addr = 0; - uint32_t hw_index = GetHardwareWatchpointHit(addr); - if (hw_index != INVALID_NUB_HW_INDEX) - { - exc.exc_data[1] = addr; - // Piggyback the hw_index in the exc.data. - exc.exc_data.push_back(hw_index); - } - - return true; - } - break; - case EXC_SYSCALL: - break; - case EXC_MACH_SYSCALL: - break; - case EXC_RPC_ALERT: - break; + return true; + } + } else if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1) { + // exc_code = EXC_I386_SGL + // + // Check whether this corresponds to a watchpoint hit event. + // If yes, set the exc_sub_code to the data break address. + nub_addr_t addr = 0; + uint32_t hw_index = GetHardwareWatchpointHit(addr); + if (hw_index != INVALID_NUB_HW_INDEX) { + exc.exc_data[1] = addr; + // Piggyback the hw_index in the exc.data. + exc.exc_data.push_back(hw_index); + } + + return true; } - return false; + break; + case EXC_SYSCALL: + break; + case EXC_MACH_SYSCALL: + break; + case EXC_RPC_ALERT: + break; + } + return false; } -uint32_t -DNBArchImplI386::NumSupportedHardwareWatchpoints() -{ - // Available debug address registers: dr0, dr1, dr2, dr3. - return 4; +uint32_t DNBArchImplI386::NumSupportedHardwareWatchpoints() { + // Available debug address registers: dr0, dr1, dr2, dr3. + return 4; } -static uint32_t -size_and_rw_bits(nub_size_t size, bool read, bool write) -{ - uint32_t rw; - if (read) { - rw = 0x3; // READ or READ/WRITE - } else if (write) { - rw = 0x1; // WRITE - } else { - assert(0 && "read and write cannot both be false"); - } - - switch (size) { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - } - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - return 0; +static uint32_t size_and_rw_bits(nub_size_t size, bool read, bool write) { + uint32_t rw; + if (read) { + rw = 0x3; // READ or READ/WRITE + } else if (write) { + rw = 0x1; // WRITE + } else { + assert(0 && "read and write cannot both be false"); + } + + switch (size) { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + } + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + return 0; } -void -DNBArchImplI386::SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write) -{ - // Set both dr7 (debug control register) and dri (debug address register). - - // dr7{7-0} encodes the local/gloabl enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - // - // dr7{31-16} encodes the rw/len bits: - // b_x+3, b_x+2, b_x+1, b_x - // where bits{x+1, x} => rw - // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io read-or-write (unused) - // and bits{x+3, x+2} => len - // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte - // - // dr0 -> bits{19-16} - // dr1 -> bits{23-20} - // dr2 -> bits{27-24} - // dr3 -> bits{31-28} - debug_state.__dr7 |= (1 << (2*hw_index) | - size_and_rw_bits(size, read, write) << (16+4*hw_index)); - uint32_t addr_32 = addr & 0xffffffff; - switch (hw_index) { - case 0: - debug_state.__dr0 = addr_32; break; - case 1: - debug_state.__dr1 = addr_32; break; - case 2: - debug_state.__dr2 = addr_32; break; - case 3: - debug_state.__dr3 = addr_32; break; - default: - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - } - return; +void DNBArchImplI386::SetWatchpoint(DBG &debug_state, uint32_t hw_index, + nub_addr_t addr, nub_size_t size, bool read, + bool write) { + // Set both dr7 (debug control register) and dri (debug address register). + + // dr7{7-0} encodes the local/gloabl enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + // + // dr7{31-16} encodes the rw/len bits: + // b_x+3, b_x+2, b_x+1, b_x + // where bits{x+1, x} => rw + // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io + // read-or-write (unused) + // and bits{x+3, x+2} => len + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte + // + // dr0 -> bits{19-16} + // dr1 -> bits{23-20} + // dr2 -> bits{27-24} + // dr3 -> bits{31-28} + debug_state.__dr7 |= + (1 << (2 * hw_index) | + size_and_rw_bits(size, read, write) << (16 + 4 * hw_index)); + uint32_t addr_32 = addr & 0xffffffff; + switch (hw_index) { + case 0: + debug_state.__dr0 = addr_32; + break; + case 1: + debug_state.__dr1 = addr_32; + break; + case 2: + debug_state.__dr2 = addr_32; + break; + case 3: + debug_state.__dr3 = addr_32; + break; + default: + assert(0 && + "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; } -void -DNBArchImplI386::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) -{ - debug_state.__dr7 &= ~(3 << (2*hw_index)); - switch (hw_index) { - case 0: - debug_state.__dr0 = 0; break; - case 1: - debug_state.__dr1 = 0; break; - case 2: - debug_state.__dr2 = 0; break; - case 3: - debug_state.__dr3 = 0; break; - default: - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - } - return; +void DNBArchImplI386::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) { + debug_state.__dr7 &= ~(3 << (2 * hw_index)); + switch (hw_index) { + case 0: + debug_state.__dr0 = 0; + break; + case 1: + debug_state.__dr1 = 0; + break; + case 2: + debug_state.__dr2 = 0; + break; + case 3: + debug_state.__dr3 = 0; + break; + default: + assert(0 && + "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; } -bool -DNBArchImplI386::IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index) -{ - // Check dr7 (debug control register) for local/global enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - return (debug_state.__dr7 & (3 << (2*hw_index))) == 0; +bool DNBArchImplI386::IsWatchpointVacant(const DBG &debug_state, + uint32_t hw_index) { + // Check dr7 (debug control register) for local/global enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + return (debug_state.__dr7 & (3 << (2 * hw_index))) == 0; } -// Resets local copy of debug status register to wait for the next debug exception. -void -DNBArchImplI386::ClearWatchpointHits(DBG &debug_state) -{ - // See also IsWatchpointHit(). - debug_state.__dr6 = 0; - return; +// Resets local copy of debug status register to wait for the next debug +// exception. +void DNBArchImplI386::ClearWatchpointHits(DBG &debug_state) { + // See also IsWatchpointHit(). + debug_state.__dr6 = 0; + return; } -bool -DNBArchImplI386::IsWatchpointHit(const DBG &debug_state, uint32_t hw_index) -{ - // Check dr6 (debug status register) whether a watchpoint hits: - // is watchpoint hit? - // | - // v - // dr0 -> bits{0} - // dr1 -> bits{1} - // dr2 -> bits{2} - // dr3 -> bits{3} - return (debug_state.__dr6 & (1 << hw_index)); +bool DNBArchImplI386::IsWatchpointHit(const DBG &debug_state, + uint32_t hw_index) { + // Check dr6 (debug status register) whether a watchpoint hits: + // is watchpoint hit? + // | + // v + // dr0 -> bits{0} + // dr1 -> bits{1} + // dr2 -> bits{2} + // dr3 -> bits{3} + return (debug_state.__dr6 & (1 << hw_index)); } -nub_addr_t -DNBArchImplI386::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) -{ - switch (hw_index) { - case 0: - return debug_state.__dr0; - case 1: - return debug_state.__dr1; - case 2: - return debug_state.__dr2; - case 3: - return debug_state.__dr3; - } - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - return 0; +nub_addr_t DNBArchImplI386::GetWatchAddress(const DBG &debug_state, + uint32_t hw_index) { + switch (hw_index) { + case 0: + return debug_state.__dr0; + case 1: + return debug_state.__dr1; + case 2: + return debug_state.__dr2; + case 3: + return debug_state.__dr3; + } + assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); + return 0; } -bool -DNBArchImplI386::StartTransForHWP() -{ - if (m_2pc_trans_state != Trans_Done && m_2pc_trans_state != Trans_Rolled_Back) - DNBLogError ("%s inconsistent state detected, expected %d or %d, got: %d", __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); - m_2pc_dbg_checkpoint = m_state.context.dbg; - m_2pc_trans_state = Trans_Pending; - return true; -} -bool -DNBArchImplI386::RollbackTransForHWP() -{ - m_state.context.dbg = m_2pc_dbg_checkpoint; - if (m_2pc_trans_state != Trans_Pending) - DNBLogError ("%s inconsistent state detected, expected %d, got: %d", __FUNCTION__, Trans_Pending, m_2pc_trans_state); - m_2pc_trans_state = Trans_Rolled_Back; - kern_return_t kret = SetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret); - - if (kret == KERN_SUCCESS) - return true; - else - return false; +bool DNBArchImplI386::StartTransForHWP() { + if (m_2pc_trans_state != Trans_Done && m_2pc_trans_state != Trans_Rolled_Back) + DNBLogError("%s inconsistent state detected, expected %d or %d, got: %d", + __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); + m_2pc_dbg_checkpoint = m_state.context.dbg; + m_2pc_trans_state = Trans_Pending; + return true; } -bool -DNBArchImplI386::FinishTransForHWP() -{ - m_2pc_trans_state = Trans_Done; +bool DNBArchImplI386::RollbackTransForHWP() { + m_state.context.dbg = m_2pc_dbg_checkpoint; + if (m_2pc_trans_state != Trans_Pending) + DNBLogError("%s inconsistent state detected, expected %d, got: %d", + __FUNCTION__, Trans_Pending, m_2pc_trans_state); + m_2pc_trans_state = Trans_Rolled_Back; + kern_return_t kret = SetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplI386::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret); + + if (kret == KERN_SUCCESS) return true; + else + return false; +} +bool DNBArchImplI386::FinishTransForHWP() { + m_2pc_trans_state = Trans_Done; + return true; } -DNBArchImplI386::DBG -DNBArchImplI386::GetDBGCheckpoint() -{ - return m_2pc_dbg_checkpoint; +DNBArchImplI386::DBG DNBArchImplI386::GetDBGCheckpoint() { + return m_2pc_dbg_checkpoint; } -uint32_t -DNBArchImplI386::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint(addr = 0x%llx, size = %llu, read = %u, write = %u)", (uint64_t)addr, (uint64_t)size, read, write); +uint32_t DNBArchImplI386::EnableHardwareWatchpoint(nub_addr_t addr, + nub_size_t size, bool read, + bool write, + bool also_set_on_task) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint(" + "addr = 0x%llx, size = %llu, read = %u, " + "write = %u)", + (uint64_t)addr, (uint64_t)size, read, write); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - // Can only watch 1, 2, 4, or 8 bytes. - if (!(size == 1 || size == 2 || size == 4 || size == 8)) - return INVALID_NUB_HW_INDEX; + // Can only watch 1, 2, 4, or 8 bytes. + if (!(size == 1 || size == 2 || size == 4 || size == 8)) + return INVALID_NUB_HW_INDEX; - // We must watch for either read or write - if (read == false && write == false) - return INVALID_NUB_HW_INDEX; + // We must watch for either read or write + if (read == false && write == false) + return INVALID_NUB_HW_INDEX; - // Read the debug state - kern_return_t kret = GetDBGState(false); + // Read the debug state + kern_return_t kret = GetDBGState(false); - if (kret == KERN_SUCCESS) - { - // Check to make sure we have the needed hardware support - uint32_t i = 0; + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; - DBG &debug_state = m_state.context.dbg; - for (i = 0; i < num_hw_watchpoints; ++i) - { - if (IsWatchpointVacant(debug_state, i)) - break; - } + DBG &debug_state = m_state.context.dbg; + for (i = 0; i < num_hw_watchpoints; ++i) { + if (IsWatchpointVacant(debug_state, i)) + break; + } - // See if we found an available hw breakpoint slot above - if (i < num_hw_watchpoints) - { - StartTransForHWP(); - - // Modify our local copy of the debug state, first. - SetWatchpoint(debug_state, i, addr, size, read, write); - // Now set the watch point in the inferior. - kret = SetDBGState(also_set_on_task); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); - - if (kret == KERN_SUCCESS) - return i; - else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. - m_state.context.dbg = GetDBGCheckpoint(); - } - else - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); - } + // See if we found an available hw breakpoint slot above + if (i < num_hw_watchpoints) { + StartTransForHWP(); + + // Modify our local copy of the debug state, first. + SetWatchpoint(debug_state, i, addr, size, read, write); + // Now set the watch point in the inferior. + kret = SetDBGState(also_set_on_task); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::" + "EnableHardwareWatchpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + else // Revert to the previous debug state voluntarily. The transaction + // coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::" + "EnableHardwareWatchpoint(): All " + "hardware resources (%u) are in use.", + num_hw_watchpoints); } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -bool -DNBArchImplI386::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) -{ - kern_return_t kret = GetDBGState(false); - - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.context.dbg; - if (hw_index < num_hw_points && !IsWatchpointVacant(debug_state, hw_index)) - { - StartTransForHWP(); - - // Modify our local copy of the debug state, first. - ClearWatchpoint(debug_state, hw_index); - // Now disable the watch point in the inferior. - kret = SetDBGState(also_set_on_task); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::DisableHardwareWatchpoint( %u )", - hw_index); - - if (kret == KERN_SUCCESS) - return true; - else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. - m_state.context.dbg = GetDBGCheckpoint(); - } +bool DNBArchImplI386::DisableHardwareWatchpoint(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.context.dbg; + if (hw_index < num_hw_points && + !IsWatchpointVacant(debug_state, hw_index)) { + StartTransForHWP(); + + // Modify our local copy of the debug state, first. + ClearWatchpoint(debug_state, hw_index); + // Now disable the watch point in the inferior. + kret = SetDBGState(also_set_on_task); + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchImplI386::DisableHardwareWatchpoint( %u )", + hw_index); + + if (kret == KERN_SUCCESS) + return true; + else // Revert to the previous debug state voluntarily. The transaction + // coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } - return false; + } + return false; } // Iterate through the debug status register; return the index of the first hit. -uint32_t -DNBArchImplI386::GetHardwareWatchpointHit(nub_addr_t &addr) -{ - // Read the debug state - kern_return_t kret = GetDBGState(true); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret); - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.context.dbg; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - { - if (IsWatchpointHit(debug_state, i)) - { - addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, - "DNBArchImplI386::GetHardwareWatchpointHit() found => %u (addr = 0x%llx).", - i, (uint64_t)addr); - return i; - } - } +uint32_t DNBArchImplI386::GetHardwareWatchpointHit(nub_addr_t &addr) { + // Read the debug state + kern_return_t kret = GetDBGState(true); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplI386::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", + kret); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.context.dbg; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) { + if (IsWatchpointHit(debug_state, i)) { + addr = GetWatchAddress(debug_state, i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplI386::" + "GetHardwareWatchpointHit() found => " + "%u (addr = 0x%llx).", + i, (uint64_t)addr); + return i; + } } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } // Set the single step bit in the processor status register. -kern_return_t -DNBArchImplI386::EnableHardwareSingleStep (bool enable) -{ - if (GetGPRState(false) == KERN_SUCCESS) - { - const uint32_t trace_bit = 0x100u; - if (enable) - m_state.context.gpr.__eflags |= trace_bit; - else - m_state.context.gpr.__eflags &= ~trace_bit; - return SetGPRState(); - } - return m_state.GetError(e_regSetGPR, Read); +kern_return_t DNBArchImplI386::EnableHardwareSingleStep(bool enable) { + if (GetGPRState(false) == KERN_SUCCESS) { + const uint32_t trace_bit = 0x100u; + if (enable) + m_state.context.gpr.__eflags |= trace_bit; + else + m_state.context.gpr.__eflags &= ~trace_bit; + return SetGPRState(); + } + return m_state.GetError(e_regSetGPR, Read); } - //---------------------------------------------------------------------- // Register information definitions //---------------------------------------------------------------------- -#define DEFINE_GPR_PSEUDO_16(reg16,reg32) { e_regSetGPR, gpr_##reg16, #reg16, NULL, Uint, Hex, 2, 0,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg32, g_invalidate_##reg32 } -#define DEFINE_GPR_PSEUDO_8H(reg8,reg32) { e_regSetGPR, gpr_##reg8 , #reg8 , NULL, Uint, Hex, 1, 1,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg32, g_invalidate_##reg32 } -#define DEFINE_GPR_PSEUDO_8L(reg8,reg32) { e_regSetGPR, gpr_##reg8 , #reg8 , NULL, Uint, Hex, 1, 0,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg32, g_invalidate_##reg32 } - - -#define GPR_OFFSET(reg) (offsetof (DNBArchImplI386::GPR, __##reg)) -#define FPU_OFFSET(reg) (offsetof (DNBArchImplI386::FPU, __fpu_##reg) + offsetof (DNBArchImplI386::Context, fpu.no_avx)) -#define AVX_OFFSET(reg) (offsetof (DNBArchImplI386::AVX, __fpu_##reg) + offsetof (DNBArchImplI386::Context, fpu.avx)) -#define EXC_OFFSET(reg) (offsetof (DNBArchImplI386::EXC, __##reg) + offsetof (DNBArchImplI386::Context, exc)) - -#define GPR_SIZE(reg) (sizeof(((DNBArchImplI386::GPR *)NULL)->__##reg)) -#define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg)) -#define FPU_SIZE_MMST(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__mmst_reg)) -#define FPU_SIZE_XMM(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__xmm_reg)) -#define FPU_SIZE_YMM(reg) (32) -#define EXC_SIZE(reg) (sizeof(((DNBArchImplI386::EXC *)NULL)->__##reg)) - -// This does not accurately identify the location of ymm0...7 in +#define DEFINE_GPR_PSEUDO_16(reg16, reg32) \ + { \ + e_regSetGPR, gpr_##reg16, #reg16, NULL, Uint, Hex, 2, 0, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, g_contained_##reg32, g_invalidate_##reg32 \ + } +#define DEFINE_GPR_PSEUDO_8H(reg8, reg32) \ + { \ + e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 1, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + g_contained_##reg32, g_invalidate_##reg32 \ + } +#define DEFINE_GPR_PSEUDO_8L(reg8, reg32) \ + { \ + e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 0, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + g_contained_##reg32, g_invalidate_##reg32 \ + } + +#define GPR_OFFSET(reg) (offsetof(DNBArchImplI386::GPR, __##reg)) +#define FPU_OFFSET(reg) \ + (offsetof(DNBArchImplI386::FPU, __fpu_##reg) + \ + offsetof(DNBArchImplI386::Context, fpu.no_avx)) +#define AVX_OFFSET(reg) \ + (offsetof(DNBArchImplI386::AVX, __fpu_##reg) + \ + offsetof(DNBArchImplI386::Context, fpu.avx)) +#define EXC_OFFSET(reg) \ + (offsetof(DNBArchImplI386::EXC, __##reg) + \ + offsetof(DNBArchImplI386::Context, exc)) + +#define GPR_SIZE(reg) (sizeof(((DNBArchImplI386::GPR *)NULL)->__##reg)) +#define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg)) +#define FPU_SIZE_MMST(reg) \ + (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__mmst_reg)) +#define FPU_SIZE_XMM(reg) \ + (sizeof(((DNBArchImplI386::FPU *)NULL)->__fpu_##reg.__xmm_reg)) +#define FPU_SIZE_YMM(reg) (32) +#define EXC_SIZE(reg) (sizeof(((DNBArchImplI386::EXC *)NULL)->__##reg)) + +// This does not accurately identify the location of ymm0...7 in // Context.fpu.avx. That is because there is a bunch of padding // in Context.fpu.avx that we don't need. Offset macros lay out // the register state that Debugserver transmits to the debugger // -- not to interpret the thread_get_state info. -#define AVX_OFFSET_YMM(n) (AVX_OFFSET(xmm7) + FPU_SIZE_XMM(xmm7) + (32 * n)) +#define AVX_OFFSET_YMM(n) (AVX_OFFSET(xmm7) + FPU_SIZE_XMM(xmm7) + (32 * n)) // These macros will auto define the register name, alt name, register size, // register offset, encoding, format and native register. This ensures that // the register state structures are defined correctly and have the correct // sizes and offsets. -const char * g_contained_eax[] = { "eax", NULL }; -const char * g_contained_ebx[] = { "ebx", NULL }; -const char * g_contained_ecx[] = { "ecx", NULL }; -const char * g_contained_edx[] = { "edx", NULL }; -const char * g_contained_edi[] = { "edi", NULL }; -const char * g_contained_esi[] = { "esi", NULL }; -const char * g_contained_ebp[] = { "ebp", NULL }; -const char * g_contained_esp[] = { "esp", NULL }; - -const char * g_invalidate_eax[] = { "eax", "ax", "ah", "al", NULL }; -const char * g_invalidate_ebx[] = { "ebx", "bx", "bh", "bl", NULL }; -const char * g_invalidate_ecx[] = { "ecx", "cx", "ch", "cl", NULL }; -const char * g_invalidate_edx[] = { "edx", "dx", "dh", "dl", NULL }; -const char * g_invalidate_edi[] = { "edi", "di", "dil", NULL }; -const char * g_invalidate_esi[] = { "esi", "si", "sil", NULL }; -const char * g_invalidate_ebp[] = { "ebp", "bp", "bpl", NULL }; -const char * g_invalidate_esp[] = { "esp", "sp", "spl", NULL }; +const char *g_contained_eax[] = {"eax", NULL}; +const char *g_contained_ebx[] = {"ebx", NULL}; +const char *g_contained_ecx[] = {"ecx", NULL}; +const char *g_contained_edx[] = {"edx", NULL}; +const char *g_contained_edi[] = {"edi", NULL}; +const char *g_contained_esi[] = {"esi", NULL}; +const char *g_contained_ebp[] = {"ebp", NULL}; +const char *g_contained_esp[] = {"esp", NULL}; + +const char *g_invalidate_eax[] = {"eax", "ax", "ah", "al", NULL}; +const char *g_invalidate_ebx[] = {"ebx", "bx", "bh", "bl", NULL}; +const char *g_invalidate_ecx[] = {"ecx", "cx", "ch", "cl", NULL}; +const char *g_invalidate_edx[] = {"edx", "dx", "dh", "dl", NULL}; +const char *g_invalidate_edi[] = {"edi", "di", "dil", NULL}; +const char *g_invalidate_esi[] = {"esi", "si", "sil", NULL}; +const char *g_invalidate_ebp[] = {"ebp", "bp", "bpl", NULL}; +const char *g_invalidate_esp[] = {"esp", "sp", "spl", NULL}; // General purpose registers for 64 bit -const DNBRegisterInfo -DNBArchImplI386::g_gpr_registers[] = -{ -{ e_regSetGPR, gpr_eax, "eax" , NULL , Uint, Hex, GPR_SIZE(eax), GPR_OFFSET(eax) , ehframe_eax , dwarf_eax , INVALID_NUB_REGNUM , debugserver_eax , NULL, g_invalidate_eax }, -{ e_regSetGPR, gpr_ebx, "ebx" , NULL , Uint, Hex, GPR_SIZE(ebx), GPR_OFFSET(ebx) , ehframe_ebx , dwarf_ebx , INVALID_NUB_REGNUM , debugserver_ebx , NULL, g_invalidate_ebx }, -{ e_regSetGPR, gpr_ecx, "ecx" , NULL , Uint, Hex, GPR_SIZE(ecx), GPR_OFFSET(ecx) , ehframe_ecx , dwarf_ecx , INVALID_NUB_REGNUM , debugserver_ecx , NULL, g_invalidate_ecx }, -{ e_regSetGPR, gpr_edx, "edx" , NULL , Uint, Hex, GPR_SIZE(edx), GPR_OFFSET(edx) , ehframe_edx , dwarf_edx , INVALID_NUB_REGNUM , debugserver_edx , NULL, g_invalidate_edx }, -{ e_regSetGPR, gpr_edi, "edi" , NULL , Uint, Hex, GPR_SIZE(edi), GPR_OFFSET(edi) , ehframe_edi , dwarf_edi , INVALID_NUB_REGNUM , debugserver_edi , NULL, g_invalidate_edi }, -{ e_regSetGPR, gpr_esi, "esi" , NULL , Uint, Hex, GPR_SIZE(esi), GPR_OFFSET(esi) , ehframe_esi , dwarf_esi , INVALID_NUB_REGNUM , debugserver_esi , NULL, g_invalidate_esi }, -{ e_regSetGPR, gpr_ebp, "ebp" , "fp" , Uint, Hex, GPR_SIZE(ebp), GPR_OFFSET(ebp) , ehframe_ebp , dwarf_ebp , GENERIC_REGNUM_FP , debugserver_ebp , NULL, g_invalidate_ebp }, -{ e_regSetGPR, gpr_esp, "esp" , "sp" , Uint, Hex, GPR_SIZE(esp), GPR_OFFSET(esp) , ehframe_esp , dwarf_esp , GENERIC_REGNUM_SP , debugserver_esp , NULL, g_invalidate_esp }, -{ e_regSetGPR, gpr_ss, "ss" , NULL , Uint, Hex, GPR_SIZE(ss), GPR_OFFSET(ss) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_ss , NULL, NULL}, -{ e_regSetGPR, gpr_eflags, "eflags", "flags" , Uint, Hex, GPR_SIZE(eflags), GPR_OFFSET(eflags) , ehframe_eflags , dwarf_eflags , GENERIC_REGNUM_FLAGS , debugserver_eflags, NULL, NULL}, -{ e_regSetGPR, gpr_eip, "eip" , "pc" , Uint, Hex, GPR_SIZE(eip), GPR_OFFSET(eip) , ehframe_eip , dwarf_eip , GENERIC_REGNUM_PC , debugserver_eip , NULL, NULL}, -{ e_regSetGPR, gpr_cs, "cs" , NULL , Uint, Hex, GPR_SIZE(cs), GPR_OFFSET(cs) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_cs , NULL, NULL}, -{ e_regSetGPR, gpr_ds, "ds" , NULL , Uint, Hex, GPR_SIZE(ds), GPR_OFFSET(ds) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_ds , NULL, NULL}, -{ e_regSetGPR, gpr_es, "es" , NULL , Uint, Hex, GPR_SIZE(es), GPR_OFFSET(es) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_es , NULL, NULL}, -{ e_regSetGPR, gpr_fs, "fs" , NULL , Uint, Hex, GPR_SIZE(fs), GPR_OFFSET(fs) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_fs , NULL, NULL}, -{ e_regSetGPR, gpr_gs, "gs" , NULL , Uint, Hex, GPR_SIZE(gs), GPR_OFFSET(gs) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM , debugserver_gs , NULL, NULL}, -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), -DEFINE_GPR_PSEUDO_8L (dil, edi), -DEFINE_GPR_PSEUDO_8L (sil, esi), -DEFINE_GPR_PSEUDO_8L (bpl, ebp), -DEFINE_GPR_PSEUDO_8L (spl, esp) -}; - - -const DNBRegisterInfo -DNBArchImplI386::g_fpu_registers_no_avx[] = -{ -{ e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , FPU_OFFSET(fcw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , FPU_OFFSET(fsw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , FPU_OFFSET(ftw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , FPU_OFFSET(fop) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , FPU_OFFSET(ip) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , FPU_OFFSET(cs) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , FPU_OFFSET(dp) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , FPU_OFFSET(ds) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , FPU_OFFSET(mxcsr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , FPU_OFFSET(mxcsrmask) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - -{ e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL }, -{ e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL }, -{ e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL }, -{ e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL }, -{ e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL }, -{ e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL }, -{ e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL }, -{ e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL }, - -{ e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0), FPU_OFFSET(xmm0), INVALID_NUB_REGNUM, dwarf_xmm0, INVALID_NUB_REGNUM, debugserver_xmm0, NULL, NULL }, -{ e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1), FPU_OFFSET(xmm1), INVALID_NUB_REGNUM, dwarf_xmm1, INVALID_NUB_REGNUM, debugserver_xmm1, NULL, NULL }, -{ e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2), FPU_OFFSET(xmm2), INVALID_NUB_REGNUM, dwarf_xmm2, INVALID_NUB_REGNUM, debugserver_xmm2, NULL, NULL }, -{ e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3), FPU_OFFSET(xmm3), INVALID_NUB_REGNUM, dwarf_xmm3, INVALID_NUB_REGNUM, debugserver_xmm3, NULL, NULL }, -{ e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4), FPU_OFFSET(xmm4), INVALID_NUB_REGNUM, dwarf_xmm4, INVALID_NUB_REGNUM, debugserver_xmm4, NULL, NULL }, -{ e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5), FPU_OFFSET(xmm5), INVALID_NUB_REGNUM, dwarf_xmm5, INVALID_NUB_REGNUM, debugserver_xmm5, NULL, NULL }, -{ e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6), FPU_OFFSET(xmm6), INVALID_NUB_REGNUM, dwarf_xmm6, INVALID_NUB_REGNUM, debugserver_xmm6, NULL, NULL }, -{ e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7), FPU_OFFSET(xmm7), INVALID_NUB_REGNUM, dwarf_xmm7, INVALID_NUB_REGNUM, debugserver_xmm7, NULL, NULL } -}; - - -static const char *g_contained_ymm0 [] = { "ymm0", NULL }; -static const char *g_contained_ymm1 [] = { "ymm1", NULL }; -static const char *g_contained_ymm2 [] = { "ymm2", NULL }; -static const char *g_contained_ymm3 [] = { "ymm3", NULL }; -static const char *g_contained_ymm4 [] = { "ymm4", NULL }; -static const char *g_contained_ymm5 [] = { "ymm5", NULL }; -static const char *g_contained_ymm6 [] = { "ymm6", NULL }; -static const char *g_contained_ymm7 [] = { "ymm7", NULL }; - - -const DNBRegisterInfo -DNBArchImplI386::g_fpu_registers_avx[] = -{ -{ e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , AVX_OFFSET(fcw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , AVX_OFFSET(fsw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , AVX_OFFSET(ftw) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , AVX_OFFSET(fop) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , AVX_OFFSET(ip) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , AVX_OFFSET(cs) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , AVX_OFFSET(dp) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , AVX_OFFSET(ds) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , AVX_OFFSET(mxcsr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , AVX_OFFSET(mxcsrmask) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, - -{ e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL }, -{ e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL }, -{ e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL }, -{ e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL }, -{ e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL }, -{ e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL }, -{ e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL }, -{ e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL }, - -{ e_regSetFPU, fpu_ymm0, "ymm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm0), AVX_OFFSET_YMM(0), INVALID_NUB_REGNUM, dwarf_ymm0, INVALID_NUB_REGNUM, debugserver_ymm0, NULL, NULL }, -{ e_regSetFPU, fpu_ymm1, "ymm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm1), AVX_OFFSET_YMM(1), INVALID_NUB_REGNUM, dwarf_ymm1, INVALID_NUB_REGNUM, debugserver_ymm1, NULL, NULL }, -{ e_regSetFPU, fpu_ymm2, "ymm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm2), AVX_OFFSET_YMM(2), INVALID_NUB_REGNUM, dwarf_ymm2, INVALID_NUB_REGNUM, debugserver_ymm2, NULL, NULL }, -{ e_regSetFPU, fpu_ymm3, "ymm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm3), AVX_OFFSET_YMM(3), INVALID_NUB_REGNUM, dwarf_ymm3, INVALID_NUB_REGNUM, debugserver_ymm3, NULL, NULL }, -{ e_regSetFPU, fpu_ymm4, "ymm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm4), AVX_OFFSET_YMM(4), INVALID_NUB_REGNUM, dwarf_ymm4, INVALID_NUB_REGNUM, debugserver_ymm4, NULL, NULL }, -{ e_regSetFPU, fpu_ymm5, "ymm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm5), AVX_OFFSET_YMM(5), INVALID_NUB_REGNUM, dwarf_ymm5, INVALID_NUB_REGNUM, debugserver_ymm5, NULL, NULL }, -{ e_regSetFPU, fpu_ymm6, "ymm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm6), AVX_OFFSET_YMM(6), INVALID_NUB_REGNUM, dwarf_ymm6, INVALID_NUB_REGNUM, debugserver_ymm6, NULL, NULL }, -{ e_regSetFPU, fpu_ymm7, "ymm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm7), AVX_OFFSET_YMM(7), INVALID_NUB_REGNUM, dwarf_ymm7, INVALID_NUB_REGNUM, debugserver_ymm7, NULL, NULL }, - -{ e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0), 0, INVALID_NUB_REGNUM, dwarf_xmm0, INVALID_NUB_REGNUM, debugserver_xmm0, g_contained_ymm0, NULL }, -{ e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1), 0, INVALID_NUB_REGNUM, dwarf_xmm1, INVALID_NUB_REGNUM, debugserver_xmm1, g_contained_ymm1, NULL }, -{ e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2), 0, INVALID_NUB_REGNUM, dwarf_xmm2, INVALID_NUB_REGNUM, debugserver_xmm2, g_contained_ymm2, NULL }, -{ e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3), 0, INVALID_NUB_REGNUM, dwarf_xmm3, INVALID_NUB_REGNUM, debugserver_xmm3, g_contained_ymm3, NULL }, -{ e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4), 0, INVALID_NUB_REGNUM, dwarf_xmm4, INVALID_NUB_REGNUM, debugserver_xmm4, g_contained_ymm4, NULL }, -{ e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5), 0, INVALID_NUB_REGNUM, dwarf_xmm5, INVALID_NUB_REGNUM, debugserver_xmm5, g_contained_ymm5, NULL }, -{ e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6), 0, INVALID_NUB_REGNUM, dwarf_xmm6, INVALID_NUB_REGNUM, debugserver_xmm6, g_contained_ymm6, NULL }, -{ e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7), 0, INVALID_NUB_REGNUM, dwarf_xmm7, INVALID_NUB_REGNUM, debugserver_xmm7, g_contained_ymm7, NULL }, +const DNBRegisterInfo DNBArchImplI386::g_gpr_registers[] = { + {e_regSetGPR, gpr_eax, "eax", NULL, Uint, Hex, GPR_SIZE(eax), + GPR_OFFSET(eax), ehframe_eax, dwarf_eax, INVALID_NUB_REGNUM, + debugserver_eax, NULL, g_invalidate_eax}, + {e_regSetGPR, gpr_ebx, "ebx", NULL, Uint, Hex, GPR_SIZE(ebx), + GPR_OFFSET(ebx), ehframe_ebx, dwarf_ebx, INVALID_NUB_REGNUM, + debugserver_ebx, NULL, g_invalidate_ebx}, + {e_regSetGPR, gpr_ecx, "ecx", NULL, Uint, Hex, GPR_SIZE(ecx), + GPR_OFFSET(ecx), ehframe_ecx, dwarf_ecx, INVALID_NUB_REGNUM, + debugserver_ecx, NULL, g_invalidate_ecx}, + {e_regSetGPR, gpr_edx, "edx", NULL, Uint, Hex, GPR_SIZE(edx), + GPR_OFFSET(edx), ehframe_edx, dwarf_edx, INVALID_NUB_REGNUM, + debugserver_edx, NULL, g_invalidate_edx}, + {e_regSetGPR, gpr_edi, "edi", NULL, Uint, Hex, GPR_SIZE(edi), + GPR_OFFSET(edi), ehframe_edi, dwarf_edi, INVALID_NUB_REGNUM, + debugserver_edi, NULL, g_invalidate_edi}, + {e_regSetGPR, gpr_esi, "esi", NULL, Uint, Hex, GPR_SIZE(esi), + GPR_OFFSET(esi), ehframe_esi, dwarf_esi, INVALID_NUB_REGNUM, + debugserver_esi, NULL, g_invalidate_esi}, + {e_regSetGPR, gpr_ebp, "ebp", "fp", Uint, Hex, GPR_SIZE(ebp), + GPR_OFFSET(ebp), ehframe_ebp, dwarf_ebp, GENERIC_REGNUM_FP, + debugserver_ebp, NULL, g_invalidate_ebp}, + {e_regSetGPR, gpr_esp, "esp", "sp", Uint, Hex, GPR_SIZE(esp), + GPR_OFFSET(esp), ehframe_esp, dwarf_esp, GENERIC_REGNUM_SP, + debugserver_esp, NULL, g_invalidate_esp}, + {e_regSetGPR, gpr_ss, "ss", NULL, Uint, Hex, GPR_SIZE(ss), GPR_OFFSET(ss), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_ss, + NULL, NULL}, + {e_regSetGPR, gpr_eflags, "eflags", "flags", Uint, Hex, GPR_SIZE(eflags), + GPR_OFFSET(eflags), ehframe_eflags, dwarf_eflags, GENERIC_REGNUM_FLAGS, + debugserver_eflags, NULL, NULL}, + {e_regSetGPR, gpr_eip, "eip", "pc", Uint, Hex, GPR_SIZE(eip), + GPR_OFFSET(eip), ehframe_eip, dwarf_eip, GENERIC_REGNUM_PC, + debugserver_eip, NULL, NULL}, + {e_regSetGPR, gpr_cs, "cs", NULL, Uint, Hex, GPR_SIZE(cs), GPR_OFFSET(cs), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_cs, + NULL, NULL}, + {e_regSetGPR, gpr_ds, "ds", NULL, Uint, Hex, GPR_SIZE(ds), GPR_OFFSET(ds), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_ds, + NULL, NULL}, + {e_regSetGPR, gpr_es, "es", NULL, Uint, Hex, GPR_SIZE(es), GPR_OFFSET(es), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_es, + NULL, NULL}, + {e_regSetGPR, gpr_fs, "fs", NULL, Uint, Hex, GPR_SIZE(fs), GPR_OFFSET(fs), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_fs, + NULL, NULL}, + {e_regSetGPR, gpr_gs, "gs", NULL, Uint, Hex, GPR_SIZE(gs), GPR_OFFSET(gs), + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_gs, + NULL, NULL}, + 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), + DEFINE_GPR_PSEUDO_8L(dil, edi), + DEFINE_GPR_PSEUDO_8L(sil, esi), + DEFINE_GPR_PSEUDO_8L(bpl, ebp), + DEFINE_GPR_PSEUDO_8L(spl, esp)}; + +const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_no_avx[] = { + {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw), + FPU_OFFSET(fcw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw), + FPU_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw), + FPU_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop), + FPU_OFFSET(fop), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip), + FPU_OFFSET(ip), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs), + FPU_OFFSET(cs), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp), + FPU_OFFSET(dp), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds), + FPU_OFFSET(ds), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr), + FPU_OFFSET(mxcsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex, + FPU_SIZE_UINT(mxcsrmask), FPU_OFFSET(mxcsrmask), INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + + {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, + INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL}, + {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, + INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL}, + {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, + INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL}, + {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, + INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL}, + {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, + INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL}, + {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, + INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL}, + {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, + INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL}, + {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, + INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL}, + + {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm0), FPU_OFFSET(xmm0), INVALID_NUB_REGNUM, dwarf_xmm0, + INVALID_NUB_REGNUM, debugserver_xmm0, NULL, NULL}, + {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm1), FPU_OFFSET(xmm1), INVALID_NUB_REGNUM, dwarf_xmm1, + INVALID_NUB_REGNUM, debugserver_xmm1, NULL, NULL}, + {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm2), FPU_OFFSET(xmm2), INVALID_NUB_REGNUM, dwarf_xmm2, + INVALID_NUB_REGNUM, debugserver_xmm2, NULL, NULL}, + {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm3), FPU_OFFSET(xmm3), INVALID_NUB_REGNUM, dwarf_xmm3, + INVALID_NUB_REGNUM, debugserver_xmm3, NULL, NULL}, + {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm4), FPU_OFFSET(xmm4), INVALID_NUB_REGNUM, dwarf_xmm4, + INVALID_NUB_REGNUM, debugserver_xmm4, NULL, NULL}, + {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm5), FPU_OFFSET(xmm5), INVALID_NUB_REGNUM, dwarf_xmm5, + INVALID_NUB_REGNUM, debugserver_xmm5, NULL, NULL}, + {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm6), FPU_OFFSET(xmm6), INVALID_NUB_REGNUM, dwarf_xmm6, + INVALID_NUB_REGNUM, debugserver_xmm6, NULL, NULL}, + {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm7), FPU_OFFSET(xmm7), INVALID_NUB_REGNUM, dwarf_xmm7, + INVALID_NUB_REGNUM, debugserver_xmm7, NULL, NULL}}; + +static const char *g_contained_ymm0[] = {"ymm0", NULL}; +static const char *g_contained_ymm1[] = {"ymm1", NULL}; +static const char *g_contained_ymm2[] = {"ymm2", NULL}; +static const char *g_contained_ymm3[] = {"ymm3", NULL}; +static const char *g_contained_ymm4[] = {"ymm4", NULL}; +static const char *g_contained_ymm5[] = {"ymm5", NULL}; +static const char *g_contained_ymm6[] = {"ymm6", NULL}; +static const char *g_contained_ymm7[] = {"ymm7", NULL}; + +const DNBRegisterInfo DNBArchImplI386::g_fpu_registers_avx[] = { + {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw), + AVX_OFFSET(fcw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw), + AVX_OFFSET(fsw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw), + AVX_OFFSET(ftw), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop), + AVX_OFFSET(fop), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip), + AVX_OFFSET(ip), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs), + AVX_OFFSET(cs), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp), + AVX_OFFSET(dp), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds), + AVX_OFFSET(ds), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr), + AVX_OFFSET(mxcsr), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex, + FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + + {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), INVALID_NUB_REGNUM, dwarf_stmm0, + INVALID_NUB_REGNUM, debugserver_stmm0, NULL, NULL}, + {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), INVALID_NUB_REGNUM, dwarf_stmm1, + INVALID_NUB_REGNUM, debugserver_stmm1, NULL, NULL}, + {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), INVALID_NUB_REGNUM, dwarf_stmm2, + INVALID_NUB_REGNUM, debugserver_stmm2, NULL, NULL}, + {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), INVALID_NUB_REGNUM, dwarf_stmm3, + INVALID_NUB_REGNUM, debugserver_stmm3, NULL, NULL}, + {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), INVALID_NUB_REGNUM, dwarf_stmm4, + INVALID_NUB_REGNUM, debugserver_stmm4, NULL, NULL}, + {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), INVALID_NUB_REGNUM, dwarf_stmm5, + INVALID_NUB_REGNUM, debugserver_stmm5, NULL, NULL}, + {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), INVALID_NUB_REGNUM, dwarf_stmm6, + INVALID_NUB_REGNUM, debugserver_stmm6, NULL, NULL}, + {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), INVALID_NUB_REGNUM, dwarf_stmm7, + INVALID_NUB_REGNUM, debugserver_stmm7, NULL, NULL}, + + {e_regSetFPU, fpu_ymm0, "ymm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm0), AVX_OFFSET_YMM(0), INVALID_NUB_REGNUM, dwarf_ymm0, + INVALID_NUB_REGNUM, debugserver_ymm0, NULL, NULL}, + {e_regSetFPU, fpu_ymm1, "ymm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm1), AVX_OFFSET_YMM(1), INVALID_NUB_REGNUM, dwarf_ymm1, + INVALID_NUB_REGNUM, debugserver_ymm1, NULL, NULL}, + {e_regSetFPU, fpu_ymm2, "ymm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm2), AVX_OFFSET_YMM(2), INVALID_NUB_REGNUM, dwarf_ymm2, + INVALID_NUB_REGNUM, debugserver_ymm2, NULL, NULL}, + {e_regSetFPU, fpu_ymm3, "ymm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm3), AVX_OFFSET_YMM(3), INVALID_NUB_REGNUM, dwarf_ymm3, + INVALID_NUB_REGNUM, debugserver_ymm3, NULL, NULL}, + {e_regSetFPU, fpu_ymm4, "ymm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm4), AVX_OFFSET_YMM(4), INVALID_NUB_REGNUM, dwarf_ymm4, + INVALID_NUB_REGNUM, debugserver_ymm4, NULL, NULL}, + {e_regSetFPU, fpu_ymm5, "ymm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm5), AVX_OFFSET_YMM(5), INVALID_NUB_REGNUM, dwarf_ymm5, + INVALID_NUB_REGNUM, debugserver_ymm5, NULL, NULL}, + {e_regSetFPU, fpu_ymm6, "ymm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm6), AVX_OFFSET_YMM(6), INVALID_NUB_REGNUM, dwarf_ymm6, + INVALID_NUB_REGNUM, debugserver_ymm6, NULL, NULL}, + {e_regSetFPU, fpu_ymm7, "ymm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm7), AVX_OFFSET_YMM(7), INVALID_NUB_REGNUM, dwarf_ymm7, + INVALID_NUB_REGNUM, debugserver_ymm7, NULL, NULL}, + + {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm0), 0, INVALID_NUB_REGNUM, dwarf_xmm0, INVALID_NUB_REGNUM, + debugserver_xmm0, g_contained_ymm0, NULL}, + {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm1), 0, INVALID_NUB_REGNUM, dwarf_xmm1, INVALID_NUB_REGNUM, + debugserver_xmm1, g_contained_ymm1, NULL}, + {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm2), 0, INVALID_NUB_REGNUM, dwarf_xmm2, INVALID_NUB_REGNUM, + debugserver_xmm2, g_contained_ymm2, NULL}, + {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm3), 0, INVALID_NUB_REGNUM, dwarf_xmm3, INVALID_NUB_REGNUM, + debugserver_xmm3, g_contained_ymm3, NULL}, + {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm4), 0, INVALID_NUB_REGNUM, dwarf_xmm4, INVALID_NUB_REGNUM, + debugserver_xmm4, g_contained_ymm4, NULL}, + {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm5), 0, INVALID_NUB_REGNUM, dwarf_xmm5, INVALID_NUB_REGNUM, + debugserver_xmm5, g_contained_ymm5, NULL}, + {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm6), 0, INVALID_NUB_REGNUM, dwarf_xmm6, INVALID_NUB_REGNUM, + debugserver_xmm6, g_contained_ymm6, NULL}, + {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm7), 0, INVALID_NUB_REGNUM, dwarf_xmm7, INVALID_NUB_REGNUM, + debugserver_xmm7, g_contained_ymm7, NULL}, }; -const DNBRegisterInfo -DNBArchImplI386::g_exc_registers[] = -{ -{ e_regSetEXC, exc_trapno, "trapno" , NULL, Uint, Hex, EXC_SIZE (trapno) , EXC_OFFSET (trapno) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetEXC, exc_err, "err" , NULL, Uint, Hex, EXC_SIZE (err) , EXC_OFFSET (err) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL }, -{ e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, EXC_SIZE (faultvaddr), EXC_OFFSET (faultvaddr) , INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL } -}; +const DNBRegisterInfo DNBArchImplI386::g_exc_registers[] = { + {e_regSetEXC, exc_trapno, "trapno", NULL, Uint, Hex, EXC_SIZE(trapno), + EXC_OFFSET(trapno), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetEXC, exc_err, "err", NULL, Uint, Hex, EXC_SIZE(err), + EXC_OFFSET(err), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}, + {e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, + EXC_SIZE(faultvaddr), EXC_OFFSET(faultvaddr), INVALID_NUB_REGNUM, + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, NULL, NULL}}; // Number of registers in each register set -const size_t DNBArchImplI386::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplI386::k_num_fpu_registers_no_avx = sizeof(g_fpu_registers_no_avx)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplI386::k_num_fpu_registers_avx = sizeof(g_fpu_registers_avx)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplI386::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplI386::k_num_all_registers_no_avx = k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; -const size_t DNBArchImplI386::k_num_all_registers_avx = k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; +const size_t DNBArchImplI386::k_num_gpr_registers = + sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplI386::k_num_fpu_registers_no_avx = + sizeof(g_fpu_registers_no_avx) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplI386::k_num_fpu_registers_avx = + sizeof(g_fpu_registers_avx) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplI386::k_num_exc_registers = + sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplI386::k_num_all_registers_no_avx = + k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; +const size_t DNBArchImplI386::k_num_all_registers_avx = + k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index // of zero is for all registers, followed by other registers sets. The // register information for the all register set need not be filled in. //---------------------------------------------------------------------- -const DNBRegisterSetInfo -DNBArchImplI386::g_reg_sets_no_avx[] = -{ - { "i386 Registers", NULL, k_num_all_registers_no_avx }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_fpu_registers_no_avx, k_num_fpu_registers_no_avx }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; - -const DNBRegisterSetInfo -DNBArchImplI386::g_reg_sets_avx[] = -{ - { "i386 Registers", NULL, k_num_all_registers_avx }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; +const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_no_avx[] = { + {"i386 Registers", NULL, k_num_all_registers_no_avx}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_fpu_registers_no_avx, + k_num_fpu_registers_no_avx}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; + +const DNBRegisterSetInfo DNBArchImplI386::g_reg_sets_avx[] = { + {"i386 Registers", NULL, k_num_all_registers_avx}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; // Total number of register sets for this architecture -const size_t DNBArchImplI386::k_num_register_sets = sizeof(g_reg_sets_no_avx)/sizeof(DNBRegisterSetInfo); +const size_t DNBArchImplI386::k_num_register_sets = + sizeof(g_reg_sets_no_avx) / sizeof(DNBRegisterSetInfo); -DNBArchProtocol * -DNBArchImplI386::Create (MachThread *thread) -{ - DNBArchImplI386 *obj = new DNBArchImplI386 (thread); - return obj; +DNBArchProtocol *DNBArchImplI386::Create(MachThread *thread) { + DNBArchImplI386 *obj = new DNBArchImplI386(thread); + return obj; } -const uint8_t * -DNBArchImplI386::SoftwareBreakpointOpcode (nub_size_t byte_size) -{ - static const uint8_t g_breakpoint_opcode[] = { 0xCC }; - if (byte_size == 1) - return g_breakpoint_opcode; - return NULL; +const uint8_t *DNBArchImplI386::SoftwareBreakpointOpcode(nub_size_t byte_size) { + static const uint8_t g_breakpoint_opcode[] = {0xCC}; + if (byte_size == 1) + return g_breakpoint_opcode; + return NULL; } const DNBRegisterSetInfo * -DNBArchImplI386::GetRegisterSetInfo(nub_size_t *num_reg_sets) -{ - *num_reg_sets = k_num_register_sets; - if (CPUHasAVX() || FORCE_AVX_REGS) - return g_reg_sets_avx; - else - return g_reg_sets_no_avx; +DNBArchImplI386::GetRegisterSetInfo(nub_size_t *num_reg_sets) { + *num_reg_sets = k_num_register_sets; + if (CPUHasAVX() || FORCE_AVX_REGS) + return g_reg_sets_avx; + else + return g_reg_sets_no_avx; } +void DNBArchImplI386::Initialize() { + DNBArchPluginInfo arch_plugin_info = { + CPU_TYPE_I386, DNBArchImplI386::Create, + DNBArchImplI386::GetRegisterSetInfo, + DNBArchImplI386::SoftwareBreakpointOpcode}; -void -DNBArchImplI386::Initialize() -{ - DNBArchPluginInfo arch_plugin_info = - { - CPU_TYPE_I386, - DNBArchImplI386::Create, - DNBArchImplI386::GetRegisterSetInfo, - DNBArchImplI386::SoftwareBreakpointOpcode - }; - - // Register this arch plug-in with the main protocol class - DNBArchProtocol::RegisterArchPlugin (arch_plugin_info); + // Register this arch plug-in with the main protocol class + DNBArchProtocol::RegisterArchPlugin(arch_plugin_info); } -bool -DNBArchImplI386::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_eip; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_esp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_ebp; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_eflags; - break; - - case GENERIC_REGNUM_RA: // Return Address - default: - return false; - } +bool DNBArchImplI386::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_eip; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_esp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_ebp; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_eflags; + break; + + case GENERIC_REGNUM_RA: // Return Address + default: + return false; } + } + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - value->info = *regInfo; - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - value->value.uint32 = ((uint32_t*)(&m_state.context.gpr))[reg]; - return true; - } - break; - - case e_regSetFPU: - if (CPUHasAVX() || FORCE_AVX_REGS) - { - switch (reg) - { - case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)); return true; - case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)); return true; - case fpu_ftw: value->value.uint8 = m_state.context.fpu.avx.__fpu_ftw; return true; - case fpu_fop: value->value.uint16 = m_state.context.fpu.avx.__fpu_fop; return true; - case fpu_ip: value->value.uint32 = m_state.context.fpu.avx.__fpu_ip; return true; - case fpu_cs: value->value.uint16 = m_state.context.fpu.avx.__fpu_cs; return true; - case fpu_dp: value->value.uint32 = m_state.context.fpu.avx.__fpu_dp; return true; - case fpu_ds: value->value.uint16 = m_state.context.fpu.avx.__fpu_ds; return true; - case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsr; return true; - case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsrmask; return true; - - case fpu_stmm0: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg, 10); return true; - case fpu_stmm1: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg, 10); return true; - case fpu_stmm2: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg, 10); return true; - case fpu_stmm3: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg, 10); return true; - case fpu_stmm4: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg, 10); return true; - case fpu_stmm5: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg, 10); return true; - case fpu_stmm6: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg, 10); return true; - case fpu_stmm7: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg, 10); return true; - - case fpu_xmm0: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg, 16); return true; - case fpu_xmm1: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg, 16); return true; - case fpu_xmm2: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg, 16); return true; - case fpu_xmm3: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg, 16); return true; - case fpu_xmm4: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg, 16); return true; - case fpu_xmm5: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg, 16); return true; - case fpu_xmm6: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg, 16); return true; - case fpu_xmm7: memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg, 16); return true; - -#define MEMCPY_YMM(n) \ - memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg, 16); \ - memcpy((&value->value.uint8) + 16, m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg, 16); - case fpu_ymm0: MEMCPY_YMM(0); return true; - case fpu_ymm1: MEMCPY_YMM(1); return true; - case fpu_ymm2: MEMCPY_YMM(2); return true; - case fpu_ymm3: MEMCPY_YMM(3); return true; - case fpu_ymm4: MEMCPY_YMM(4); return true; - case fpu_ymm5: MEMCPY_YMM(5); return true; - case fpu_ymm6: MEMCPY_YMM(6); return true; - case fpu_ymm7: MEMCPY_YMM(7); return true; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + value->info = *regInfo; + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + value->value.uint32 = ((uint32_t *)(&m_state.context.gpr))[reg]; + return true; + } + break; + + case e_regSetFPU: + if (CPUHasAVX() || FORCE_AVX_REGS) { + switch (reg) { + case fpu_fcw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)); + return true; + case fpu_fsw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)); + return true; + case fpu_ftw: + value->value.uint8 = m_state.context.fpu.avx.__fpu_ftw; + return true; + case fpu_fop: + value->value.uint16 = m_state.context.fpu.avx.__fpu_fop; + return true; + case fpu_ip: + value->value.uint32 = m_state.context.fpu.avx.__fpu_ip; + return true; + case fpu_cs: + value->value.uint16 = m_state.context.fpu.avx.__fpu_cs; + return true; + case fpu_dp: + value->value.uint32 = m_state.context.fpu.avx.__fpu_dp; + return true; + case fpu_ds: + value->value.uint16 = m_state.context.fpu.avx.__fpu_ds; + return true; + case fpu_mxcsr: + value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsr; + return true; + case fpu_mxcsrmask: + value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsrmask; + return true; + + case fpu_stmm0: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg, 10); + return true; + case fpu_stmm1: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg, 10); + return true; + case fpu_stmm2: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg, 10); + return true; + case fpu_stmm3: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg, 10); + return true; + case fpu_stmm4: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg, 10); + return true; + case fpu_stmm5: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg, 10); + return true; + case fpu_stmm6: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg, 10); + return true; + case fpu_stmm7: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg, 10); + return true; + + case fpu_xmm0: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg, 16); + return true; + case fpu_xmm1: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg, 16); + return true; + case fpu_xmm2: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg, 16); + return true; + case fpu_xmm3: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg, 16); + return true; + case fpu_xmm4: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg, 16); + return true; + case fpu_xmm5: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg, 16); + return true; + case fpu_xmm6: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg, 16); + return true; + case fpu_xmm7: + memcpy(&value->value.uint8, + m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg, 16); + return true; + +#define MEMCPY_YMM(n) \ + memcpy(&value->value.uint8, m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg, \ + 16); \ + memcpy((&value->value.uint8) + 16, \ + m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg, 16); + case fpu_ymm0: + MEMCPY_YMM(0); + return true; + case fpu_ymm1: + MEMCPY_YMM(1); + return true; + case fpu_ymm2: + MEMCPY_YMM(2); + return true; + case fpu_ymm3: + MEMCPY_YMM(3); + return true; + case fpu_ymm4: + MEMCPY_YMM(4); + return true; + case fpu_ymm5: + MEMCPY_YMM(5); + return true; + case fpu_ymm6: + MEMCPY_YMM(6); + return true; + case fpu_ymm7: + MEMCPY_YMM(7); + return true; #undef MEMCPY_YMM - } - } - else - { - switch (reg) - { - case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)); return true; - case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)); return true; - case fpu_ftw: value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw; return true; - case fpu_fop: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop; return true; - case fpu_ip: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_ip; return true; - case fpu_cs: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_cs; return true; - case fpu_dp: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_dp; return true; - case fpu_ds: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_ds; return true; - case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsr; return true; - case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsrmask; return true; - - case fpu_stmm0: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg, 10); return true; - case fpu_stmm1: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg, 10); return true; - case fpu_stmm2: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg, 10); return true; - case fpu_stmm3: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg, 10); return true; - case fpu_stmm4: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg, 10); return true; - case fpu_stmm5: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg, 10); return true; - case fpu_stmm6: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg, 10); return true; - case fpu_stmm7: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg, 10); return true; - - case fpu_xmm0: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg, 16); return true; - case fpu_xmm1: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg, 16); return true; - case fpu_xmm2: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg, 16); return true; - case fpu_xmm3: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg, 16); return true; - case fpu_xmm4: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg, 16); return true; - case fpu_xmm5: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg, 16); return true; - case fpu_xmm6: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg, 16); return true; - case fpu_xmm7: memcpy(&value->value.uint8, m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg, 16); return true; - } - } - break; - - case e_regSetEXC: - if (reg < k_num_exc_registers) - { - value->value.uint32 = (&m_state.context.exc.__trapno)[reg]; - return true; - } - break; } + } else { + switch (reg) { + case fpu_fcw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)); + return true; + case fpu_fsw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)); + return true; + case fpu_ftw: + value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw; + return true; + case fpu_fop: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop; + return true; + case fpu_ip: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_ip; + return true; + case fpu_cs: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_cs; + return true; + case fpu_dp: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_dp; + return true; + case fpu_ds: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_ds; + return true; + case fpu_mxcsr: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsr; + return true; + case fpu_mxcsrmask: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsrmask; + return true; + + case fpu_stmm0: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg, 10); + return true; + case fpu_stmm1: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg, 10); + return true; + case fpu_stmm2: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg, 10); + return true; + case fpu_stmm3: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg, 10); + return true; + case fpu_stmm4: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg, 10); + return true; + case fpu_stmm5: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg, 10); + return true; + case fpu_stmm6: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg, 10); + return true; + case fpu_stmm7: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg, 10); + return true; + + case fpu_xmm0: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg, 16); + return true; + case fpu_xmm1: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg, 16); + return true; + case fpu_xmm2: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg, 16); + return true; + case fpu_xmm3: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg, 16); + return true; + case fpu_xmm4: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg, 16); + return true; + case fpu_xmm5: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg, 16); + return true; + case fpu_xmm6: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg, 16); + return true; + case fpu_xmm7: + memcpy(&value->value.uint8, + m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg, 16); + return true; + } + } + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) { + value->value.uint32 = (&m_state.context.exc.__trapno)[reg]; + return true; + } + break; } - return false; + } + return false; } - -bool -DNBArchImplI386::SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_eip; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_esp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_ebp; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_eflags; - break; - - case GENERIC_REGNUM_RA: // Return Address - default: - return false; - } +bool DNBArchImplI386::SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_eip; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_esp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_ebp; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_eflags; + break; + + case GENERIC_REGNUM_RA: // Return Address + default: + return false; } + } + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - bool success = false; - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - ((uint32_t*)(&m_state.context.gpr))[reg] = value->value.uint32; - success = true; - } - break; - - case e_regSetFPU: - if (CPUHasAVX() || FORCE_AVX_REGS) - { - switch (reg) - { - case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)) = value->value.uint16; success = true; break; - case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)) = value->value.uint16; success = true; break; - case fpu_ftw: m_state.context.fpu.avx.__fpu_ftw = value->value.uint8; success = true; break; - case fpu_fop: m_state.context.fpu.avx.__fpu_fop = value->value.uint16; success = true; break; - case fpu_ip: m_state.context.fpu.avx.__fpu_ip = value->value.uint32; success = true; break; - case fpu_cs: m_state.context.fpu.avx.__fpu_cs = value->value.uint16; success = true; break; - case fpu_dp: m_state.context.fpu.avx.__fpu_dp = value->value.uint32; success = true; break; - case fpu_ds: m_state.context.fpu.avx.__fpu_ds = value->value.uint16; success = true; break; - case fpu_mxcsr: m_state.context.fpu.avx.__fpu_mxcsr = value->value.uint32; success = true; break; - case fpu_mxcsrmask: m_state.context.fpu.avx.__fpu_mxcsrmask = value->value.uint32; success = true; break; - - case fpu_stmm0: memcpy (m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm1: memcpy (m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm2: memcpy (m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm3: memcpy (m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm4: memcpy (m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm5: memcpy (m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm6: memcpy (m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm7: memcpy (m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg, &value->value.uint8, 10); success = true; break; - - case fpu_xmm0: memcpy(m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm1: memcpy(m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm2: memcpy(m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm3: memcpy(m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm4: memcpy(m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm5: memcpy(m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm6: memcpy(m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm7: memcpy(m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg, &value->value.uint8, 16); success = true; break; - -#define MEMCPY_YMM(n) \ - memcpy(m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg, &value->value.uint8, 16); \ - memcpy(m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg, (&value->value.uint8) + 16, 16); - case fpu_ymm0: MEMCPY_YMM(0); return true; - case fpu_ymm1: MEMCPY_YMM(1); return true; - case fpu_ymm2: MEMCPY_YMM(2); return true; - case fpu_ymm3: MEMCPY_YMM(3); return true; - case fpu_ymm4: MEMCPY_YMM(4); return true; - case fpu_ymm5: MEMCPY_YMM(5); return true; - case fpu_ymm6: MEMCPY_YMM(6); return true; - case fpu_ymm7: MEMCPY_YMM(7); return true; + bool success = false; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + ((uint32_t *)(&m_state.context.gpr))[reg] = value->value.uint32; + success = true; + } + break; + + case e_regSetFPU: + if (CPUHasAVX() || FORCE_AVX_REGS) { + switch (reg) { + case fpu_fcw: + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)) = + value->value.uint16; + success = true; + break; + case fpu_fsw: + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)) = + value->value.uint16; + success = true; + break; + case fpu_ftw: + m_state.context.fpu.avx.__fpu_ftw = value->value.uint8; + success = true; + break; + case fpu_fop: + m_state.context.fpu.avx.__fpu_fop = value->value.uint16; + success = true; + break; + case fpu_ip: + m_state.context.fpu.avx.__fpu_ip = value->value.uint32; + success = true; + break; + case fpu_cs: + m_state.context.fpu.avx.__fpu_cs = value->value.uint16; + success = true; + break; + case fpu_dp: + m_state.context.fpu.avx.__fpu_dp = value->value.uint32; + success = true; + break; + case fpu_ds: + m_state.context.fpu.avx.__fpu_ds = value->value.uint16; + success = true; + break; + case fpu_mxcsr: + m_state.context.fpu.avx.__fpu_mxcsr = value->value.uint32; + success = true; + break; + case fpu_mxcsrmask: + m_state.context.fpu.avx.__fpu_mxcsrmask = value->value.uint32; + success = true; + break; + + case fpu_stmm0: + memcpy(m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm1: + memcpy(m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm2: + memcpy(m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm3: + memcpy(m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm4: + memcpy(m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm5: + memcpy(m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm6: + memcpy(m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm7: + memcpy(m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + + case fpu_xmm0: + memcpy(m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm1: + memcpy(m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm2: + memcpy(m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm3: + memcpy(m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm4: + memcpy(m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm5: + memcpy(m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm6: + memcpy(m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm7: + memcpy(m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + +#define MEMCPY_YMM(n) \ + memcpy(m_state.context.fpu.avx.__fpu_xmm##n.__xmm_reg, &value->value.uint8, \ + 16); \ + memcpy(m_state.context.fpu.avx.__fpu_ymmh##n.__xmm_reg, \ + (&value->value.uint8) + 16, 16); + case fpu_ymm0: + MEMCPY_YMM(0); + return true; + case fpu_ymm1: + MEMCPY_YMM(1); + return true; + case fpu_ymm2: + MEMCPY_YMM(2); + return true; + case fpu_ymm3: + MEMCPY_YMM(3); + return true; + case fpu_ymm4: + MEMCPY_YMM(4); + return true; + case fpu_ymm5: + MEMCPY_YMM(5); + return true; + case fpu_ymm6: + MEMCPY_YMM(6); + return true; + case fpu_ymm7: + MEMCPY_YMM(7); + return true; #undef MEMCPY_YMM - } - } - else - { - switch (reg) - { - case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)) = value->value.uint16; success = true; break; - case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)) = value->value.uint16; success = true; break; - case fpu_ftw: m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8; success = true; break; - case fpu_fop: m_state.context.fpu.no_avx.__fpu_fop = value->value.uint16; success = true; break; - case fpu_ip: m_state.context.fpu.no_avx.__fpu_ip = value->value.uint32; success = true; break; - case fpu_cs: m_state.context.fpu.no_avx.__fpu_cs = value->value.uint16; success = true; break; - case fpu_dp: m_state.context.fpu.no_avx.__fpu_dp = value->value.uint32; success = true; break; - case fpu_ds: m_state.context.fpu.no_avx.__fpu_ds = value->value.uint16; success = true; break; - case fpu_mxcsr: m_state.context.fpu.no_avx.__fpu_mxcsr = value->value.uint32; success = true; break; - case fpu_mxcsrmask: m_state.context.fpu.no_avx.__fpu_mxcsrmask = value->value.uint32; success = true; break; - - case fpu_stmm0: memcpy (m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm1: memcpy (m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm2: memcpy (m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm3: memcpy (m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm4: memcpy (m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm5: memcpy (m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm6: memcpy (m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg, &value->value.uint8, 10); success = true; break; - case fpu_stmm7: memcpy (m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg, &value->value.uint8, 10); success = true; break; - - case fpu_xmm0: memcpy(m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm1: memcpy(m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm2: memcpy(m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm3: memcpy(m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm4: memcpy(m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm5: memcpy(m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm6: memcpy(m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg, &value->value.uint8, 16); success = true; break; - case fpu_xmm7: memcpy(m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg, &value->value.uint8, 16); success = true; break; - } - } - break; - - case e_regSetEXC: - if (reg < k_num_exc_registers) - { - (&m_state.context.exc.__trapno)[reg] = value->value.uint32; - success = true; - } - break; } + } else { + switch (reg) { + case fpu_fcw: + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)) = + value->value.uint16; + success = true; + break; + case fpu_fsw: + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)) = + value->value.uint16; + success = true; + break; + case fpu_ftw: + m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8; + success = true; + break; + case fpu_fop: + m_state.context.fpu.no_avx.__fpu_fop = value->value.uint16; + success = true; + break; + case fpu_ip: + m_state.context.fpu.no_avx.__fpu_ip = value->value.uint32; + success = true; + break; + case fpu_cs: + m_state.context.fpu.no_avx.__fpu_cs = value->value.uint16; + success = true; + break; + case fpu_dp: + m_state.context.fpu.no_avx.__fpu_dp = value->value.uint32; + success = true; + break; + case fpu_ds: + m_state.context.fpu.no_avx.__fpu_ds = value->value.uint16; + success = true; + break; + case fpu_mxcsr: + m_state.context.fpu.no_avx.__fpu_mxcsr = value->value.uint32; + success = true; + break; + case fpu_mxcsrmask: + m_state.context.fpu.no_avx.__fpu_mxcsrmask = value->value.uint32; + success = true; + break; + + case fpu_stmm0: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm1: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm2: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm3: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm4: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm5: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm6: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + case fpu_stmm7: + memcpy(m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg, + &value->value.uint8, 10); + success = true; + break; + + case fpu_xmm0: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm1: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm2: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm3: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm4: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm5: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm6: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + case fpu_xmm7: + memcpy(m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg, + &value->value.uint8, 16); + success = true; + break; + } + } + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) { + (&m_state.context.exc.__trapno)[reg] = value->value.uint32; + success = true; + } + break; } + } - if (success) - return SetRegisterState(set) == KERN_SUCCESS; - return false; + if (success) + return SetRegisterState(set) == KERN_SUCCESS; + return false; } - -uint32_t -DNBArchImplI386::GetRegisterContextSize() -{ - static uint32_t g_cached_size = 0; - if (g_cached_size == 0) - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - for (size_t i=0; i<k_num_fpu_registers_avx; ++i) - { - if (g_fpu_registers_avx[i].value_regs == NULL) - g_cached_size += g_fpu_registers_avx[i].size; - } - } - else - { - for (size_t i=0; i<k_num_fpu_registers_no_avx; ++i) - { - if (g_fpu_registers_no_avx[i].value_regs == NULL) - g_cached_size += g_fpu_registers_no_avx[i].size; - } - } - DNBLogThreaded ("DNBArchImplX86_64::GetRegisterContextSize() - GPR = %zu, FPU = %u, EXC = %zu", sizeof(GPR), g_cached_size, sizeof(EXC)); - g_cached_size += sizeof(GPR); - g_cached_size += sizeof(EXC); - DNBLogThreaded ("DNBArchImplX86_64::GetRegisterContextSize() - GPR + FPU + EXC = %u", g_cached_size); +uint32_t DNBArchImplI386::GetRegisterContextSize() { + static uint32_t g_cached_size = 0; + if (g_cached_size == 0) { + if (CPUHasAVX() || FORCE_AVX_REGS) { + for (size_t i = 0; i < k_num_fpu_registers_avx; ++i) { + if (g_fpu_registers_avx[i].value_regs == NULL) + g_cached_size += g_fpu_registers_avx[i].size; + } + } else { + for (size_t i = 0; i < k_num_fpu_registers_no_avx; ++i) { + if (g_fpu_registers_no_avx[i].value_regs == NULL) + g_cached_size += g_fpu_registers_no_avx[i].size; + } } - return g_cached_size; + DNBLogThreaded("DNBArchImplX86_64::GetRegisterContextSize() - GPR = %zu, " + "FPU = %u, EXC = %zu", + sizeof(GPR), g_cached_size, sizeof(EXC)); + g_cached_size += sizeof(GPR); + g_cached_size += sizeof(EXC); + DNBLogThreaded( + "DNBArchImplX86_64::GetRegisterContextSize() - GPR + FPU + EXC = %u", + g_cached_size); + } + return g_cached_size; } - -nub_size_t -DNBArchImplI386::GetRegisterContext (void *buf, nub_size_t buf_len) -{ - uint32_t size = GetRegisterContextSize(); - - if (buf && buf_len) - { - if (size > buf_len) - size = static_cast<uint32_t>(buf_len); - - bool force = false; - kern_return_t kret; - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) error: GPR regs failed to read: %u ", buf, (uint64_t)buf_len, kret); - size = 0; - } - else if ((kret = GetFPUState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) error: %s regs failed to read: %u", buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); - size = 0; - } - else if ((kret = GetEXCState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) error: EXC regs failed to read: %u", buf, (uint64_t)buf_len, kret); - size = 0; - } - else - { - uint8_t *p = (uint8_t *)buf; - // Copy the GPR registers - memcpy(p, &m_state.context.gpr, sizeof(GPR)); - p += sizeof(GPR); - - if (CPUHasAVX() || FORCE_AVX_REGS) - { - // Walk around the gaps in the FPU regs - memcpy(p, &m_state.context.fpu.avx.__fpu_fcw, 5); - p += 5; - memcpy(p, &m_state.context.fpu.avx.__fpu_fop, 8); - p += 8; - memcpy(p, &m_state.context.fpu.avx.__fpu_dp, 6); - p += 6; - memcpy(p, &m_state.context.fpu.avx.__fpu_mxcsr, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(p, &m_state.context.fpu.avx.__fpu_stmm0 + i, 10); - p += 10; - } - - // Interleave the XMM and YMMH registers to make the YMM registers - for (size_t i=0; i<8; ++i) - { - memcpy(p, &m_state.context.fpu.avx.__fpu_xmm0 + i, 16); - p += 16; - memcpy(p, &m_state.context.fpu.avx.__fpu_ymmh0 + i, 16); - p += 16; - } - } - else - { - // Walk around the gaps in the FPU regs - memcpy(p, &m_state.context.fpu.no_avx.__fpu_fcw, 5); - p += 5; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_fop, 8); - p += 8; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_dp, 6); - p += 6; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_mxcsr, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(p, &m_state.context.fpu.no_avx.__fpu_stmm0 + i, 10); - p += 10; - } - - // Copy the XMM registers in a single block - memcpy(p, &m_state.context.fpu.no_avx.__fpu_xmm0, 8 * 16); - p += 8 * 16; - } - - // Copy the exception registers - memcpy(p, &m_state.context.exc, sizeof(EXC)); - p += sizeof(EXC); - - // make sure we end up with exactly what we think we should have - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); +nub_size_t DNBArchImplI386::GetRegisterContext(void *buf, nub_size_t buf_len) { + uint32_t size = GetRegisterContextSize(); + + if (buf && buf_len) { + if (size > buf_len) + size = static_cast<uint32_t>(buf_len); + + bool force = false; + kern_return_t kret; + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = " + "%p, len = %llu) error: GPR regs failed to " + "read: %u ", + buf, (uint64_t)buf_len, kret); + size = 0; + } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf( + LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = " + "%llu) error: %s regs failed to read: %u", + buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); + size = 0; + } else if ((kret = GetEXCState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = " + "%p, len = %llu) error: EXC regs failed to " + "read: %u", + buf, (uint64_t)buf_len, kret); + size = 0; + } else { + uint8_t *p = (uint8_t *)buf; + // Copy the GPR registers + memcpy(p, &m_state.context.gpr, sizeof(GPR)); + p += sizeof(GPR); + + if (CPUHasAVX() || FORCE_AVX_REGS) { + // Walk around the gaps in the FPU regs + memcpy(p, &m_state.context.fpu.avx.__fpu_fcw, 5); + p += 5; + memcpy(p, &m_state.context.fpu.avx.__fpu_fop, 8); + p += 8; + memcpy(p, &m_state.context.fpu.avx.__fpu_dp, 6); + p += 6; + memcpy(p, &m_state.context.fpu.avx.__fpu_mxcsr, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(p, &m_state.context.fpu.avx.__fpu_stmm0 + i, 10); + p += 10; } - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) => %llu", buf, (uint64_t)buf_len, (uint64_t)size); - // Return the size of the register context even if NULL was passed in - return size; -} -nub_size_t -DNBArchImplI386::SetRegisterContext (const void *buf, nub_size_t buf_len) -{ - nub_size_t size = sizeof (m_state.context); - if (buf == NULL || buf_len == 0) - size = 0; - - if (size) - { - if (size > buf_len) - size = buf_len; - - uint8_t *p = (uint8_t *)buf; - // Copy the GPR registers - memcpy(&m_state.context.gpr, p, sizeof(GPR)); - p += sizeof(GPR); - - if (CPUHasAVX() || FORCE_AVX_REGS) - { - // Walk around the gaps in the FPU regs - memcpy(&m_state.context.fpu.avx.__fpu_fcw, p, 5); - p += 5; - memcpy(&m_state.context.fpu.avx.__fpu_fop, p, 8); - p += 8; - memcpy(&m_state.context.fpu.avx.__fpu_dp, p, 6); - p += 6; - memcpy(&m_state.context.fpu.avx.__fpu_mxcsr, p, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(&m_state.context.fpu.avx.__fpu_stmm0 + i, p, 10); - p += 10; - } - - // Interleave the XMM and YMMH registers to make the YMM registers - for (size_t i=0; i<8; ++i) - { - memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + i, p, 16); - p += 16; - memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + i, p, 16); - p += 16; - } + // Interleave the XMM and YMMH registers to make the YMM registers + for (size_t i = 0; i < 8; ++i) { + memcpy(p, &m_state.context.fpu.avx.__fpu_xmm0 + i, 16); + p += 16; + memcpy(p, &m_state.context.fpu.avx.__fpu_ymmh0 + i, 16); + p += 16; } - else - { - // Copy fcw through mxcsrmask as there is no padding - memcpy(&m_state.context.fpu.no_avx.__fpu_fcw, p, 5); - p += 5; - memcpy(&m_state.context.fpu.no_avx.__fpu_fop, p, 8); - p += 8; - memcpy(&m_state.context.fpu.no_avx.__fpu_dp, p, 6); - p += 6; - memcpy(&m_state.context.fpu.no_avx.__fpu_mxcsr, p, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + i, p, 10); - p += 10; - } - - // Copy the XMM registers in a single block - memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0, p, 8 * 16); - p += 8 * 16; + } else { + // Walk around the gaps in the FPU regs + memcpy(p, &m_state.context.fpu.no_avx.__fpu_fcw, 5); + p += 5; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_fop, 8); + p += 8; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_dp, 6); + p += 6; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_mxcsr, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(p, &m_state.context.fpu.no_avx.__fpu_stmm0 + i, 10); + p += 10; } - - // Copy the exception registers - memcpy(&m_state.context.exc, p, sizeof(EXC)); - p += sizeof(EXC); - - // make sure we end up with exactly what we think we should have - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - kern_return_t kret; - if ((kret = SetGPRState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) error: GPR regs failed to write: %u", buf, (uint64_t)buf_len, kret); - if ((kret = SetFPUState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) error: %s regs failed to write: %u", buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); - if ((kret = SetEXCState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) error: EXP regs failed to write: %u", buf, (uint64_t)buf_len, kret); - } - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) => %llu", buf, (uint64_t)buf_len, (uint64_t)size); - return size; -} + // Copy the XMM registers in a single block + memcpy(p, &m_state.context.fpu.no_avx.__fpu_xmm0, 8 * 16); + p += 8 * 16; + } -uint32_t -DNBArchImplI386::SaveRegisterState () -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + // Copy the exception registers + memcpy(p, &m_state.context.exc, sizeof(EXC)); + p += sizeof(EXC); - bool force = true; - - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: GPR regs failed to read: %u ", kret); - } - else if ((kret = GetFPUState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret); - } - else - { - const uint32_t save_id = GetNextRegisterStateSaveID (); - m_saved_register_states[save_id] = m_state.context; - return save_id; + // make sure we end up with exactly what we think we should have + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); } - return 0; + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchImplI386::GetRegisterContext (buf = %p, len = %llu) => %llu", buf, + (uint64_t)buf_len, (uint64_t)size); + // Return the size of the register context even if NULL was passed in + return size; } -bool -DNBArchImplI386::RestoreRegisterState (uint32_t save_id) -{ - SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); - if (pos != m_saved_register_states.end()) - { - m_state.context.gpr = pos->second.gpr; - m_state.context.fpu = pos->second.fpu; - m_state.context.exc = pos->second.exc; - m_state.SetError(e_regSetGPR, Read, 0); - m_state.SetError(e_regSetFPU, Read, 0); - m_state.SetError(e_regSetEXC, Read, 0); - kern_return_t kret; - bool success = true; - if ((kret = SetGPRState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); - success = false; - } - else if ((kret = SetFPUState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplI386::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret); - success = false; - } - m_saved_register_states.erase(pos); - return success; + +nub_size_t DNBArchImplI386::SetRegisterContext(const void *buf, + nub_size_t buf_len) { + nub_size_t size = sizeof(m_state.context); + if (buf == NULL || buf_len == 0) + size = 0; + + if (size) { + if (size > buf_len) + size = buf_len; + + uint8_t *p = (uint8_t *)buf; + // Copy the GPR registers + memcpy(&m_state.context.gpr, p, sizeof(GPR)); + p += sizeof(GPR); + + if (CPUHasAVX() || FORCE_AVX_REGS) { + // Walk around the gaps in the FPU regs + memcpy(&m_state.context.fpu.avx.__fpu_fcw, p, 5); + p += 5; + memcpy(&m_state.context.fpu.avx.__fpu_fop, p, 8); + p += 8; + memcpy(&m_state.context.fpu.avx.__fpu_dp, p, 6); + p += 6; + memcpy(&m_state.context.fpu.avx.__fpu_mxcsr, p, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(&m_state.context.fpu.avx.__fpu_stmm0 + i, p, 10); + p += 10; + } + + // Interleave the XMM and YMMH registers to make the YMM registers + for (size_t i = 0; i < 8; ++i) { + memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + i, p, 16); + p += 16; + memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + i, p, 16); + p += 16; + } + } else { + // Copy fcw through mxcsrmask as there is no padding + memcpy(&m_state.context.fpu.no_avx.__fpu_fcw, p, 5); + p += 5; + memcpy(&m_state.context.fpu.no_avx.__fpu_fop, p, 8); + p += 8; + memcpy(&m_state.context.fpu.no_avx.__fpu_dp, p, 6); + p += 6; + memcpy(&m_state.context.fpu.no_avx.__fpu_mxcsr, p, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + i, p, 10); + p += 10; + } + + // Copy the XMM registers in a single block + memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0, p, 8 * 16); + p += 8 * 16; } - return false; -} + // Copy the exception registers + memcpy(&m_state.context.exc, p, sizeof(EXC)); + p += sizeof(EXC); + + // make sure we end up with exactly what we think we should have + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + kern_return_t kret; + if ((kret = SetGPRState()) != KERN_SUCCESS) + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = " + "%p, len = %llu) error: GPR regs failed to " + "write: %u", + buf, (uint64_t)buf_len, kret); + if ((kret = SetFPUState()) != KERN_SUCCESS) + DNBLogThreadedIf( + LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = %p, len = " + "%llu) error: %s regs failed to write: %u", + buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); + if ((kret = SetEXCState()) != KERN_SUCCESS) + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SetRegisterContext (buf = " + "%p, len = %llu) error: EXP regs failed to " + "write: %u", + buf, (uint64_t)buf_len, kret); + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchImplI386::SetRegisterContext (buf = %p, len = %llu) => %llu", buf, + (uint64_t)buf_len, (uint64_t)size); + return size; +} -kern_return_t -DNBArchImplI386::GetRegisterState(int set, bool force) -{ - switch (set) - { - case e_regSetALL: return GetGPRState(force) | GetFPUState(force) | GetEXCState(force); - case e_regSetGPR: return GetGPRState(force); - case e_regSetFPU: return GetFPUState(force); - case e_regSetEXC: return GetEXCState(force); - default: break; +uint32_t DNBArchImplI386::SaveRegisterState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: " + "GPR regs failed to read: %u ", + kret); + } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::SaveRegisterState () error: " + "%s regs failed to read: %u", + CPUHasAVX() ? "AVX" : "FPU", kret); + } else { + const uint32_t save_id = GetNextRegisterStateSaveID(); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return 0; +} +bool DNBArchImplI386::RestoreRegisterState(uint32_t save_id) { + SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) { + m_state.context.gpr = pos->second.gpr; + m_state.context.fpu = pos->second.fpu; + m_state.context.exc = pos->second.exc; + m_state.SetError(e_regSetGPR, Read, 0); + m_state.SetError(e_regSetFPU, Read, 0); + m_state.SetError(e_regSetEXC, Read, 0); + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::RestoreRegisterState " + "(save_id = %u) error: GPR regs failed to " + "write: %u", + save_id, kret); + success = false; + } else if ((kret = SetFPUState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplI386::RestoreRegisterState " + "(save_id = %u) error: %s regs failed to " + "write: %u", + save_id, CPUHasAVX() ? "AVX" : "FPU", kret); + success = false; } - return KERN_INVALID_ARGUMENT; + m_saved_register_states.erase(pos); + return success; + } + return false; } -kern_return_t -DNBArchImplI386::SetRegisterState(int set) -{ - // Make sure we have a valid context to set. - if (RegisterSetStateIsValid(set)) - { - switch (set) - { - case e_regSetALL: return SetGPRState() | SetFPUState() | SetEXCState(); - case e_regSetGPR: return SetGPRState(); - case e_regSetFPU: return SetFPUState(); - case e_regSetEXC: return SetEXCState(); - default: break; - } +kern_return_t DNBArchImplI386::GetRegisterState(int set, bool force) { + switch (set) { + case e_regSetALL: + return GetGPRState(force) | GetFPUState(force) | GetEXCState(force); + case e_regSetGPR: + return GetGPRState(force); + case e_regSetFPU: + return GetFPUState(force); + case e_regSetEXC: + return GetEXCState(force); + default: + break; + } + return KERN_INVALID_ARGUMENT; +} + +kern_return_t DNBArchImplI386::SetRegisterState(int set) { + // Make sure we have a valid context to set. + if (RegisterSetStateIsValid(set)) { + switch (set) { + case e_regSetALL: + return SetGPRState() | SetFPUState() | SetEXCState(); + case e_regSetGPR: + return SetGPRState(); + case e_regSetFPU: + return SetFPUState(); + case e_regSetEXC: + return SetEXCState(); + default: + break; } - return KERN_INVALID_ARGUMENT; + } + return KERN_INVALID_ARGUMENT; } -bool -DNBArchImplI386::RegisterSetStateIsValid (int set) const -{ - return m_state.RegsAreValid(set); +bool DNBArchImplI386::RegisterSetStateIsValid(int set) const { + return m_state.RegsAreValid(set); } -#endif // #if defined (__i386__) +#endif // #if defined (__i386__) diff --git a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h index 6b4252151fe..5b042668818 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h +++ b/lldb/tools/debugserver/source/MacOSX/i386/DNBArchImplI386.h @@ -14,242 +14,219 @@ #ifndef __DNBArchImplI386_h__ #define __DNBArchImplI386_h__ -#if defined (__i386__) || defined (__x86_64__) +#if defined(__i386__) || defined(__x86_64__) -#include "DNBArch.h" #include "../HasAVX.h" +#include "DNBArch.h" #include "MachRegisterStatesI386.h" #include <map> class MachThread; -class DNBArchImplI386 : public DNBArchProtocol -{ +class DNBArchImplI386 : public DNBArchProtocol { public: - DNBArchImplI386(MachThread *thread) : - DNBArchProtocol(), - m_thread(thread), - m_state(), - m_2pc_dbg_checkpoint(), - m_2pc_trans_state(Trans_Done), - m_saved_register_states() - { - } - virtual ~DNBArchImplI386() - { - } - - static void Initialize(); - - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState (); - virtual bool RestoreRegisterState (uint32_t save_id); - - virtual kern_return_t GetRegisterState (int set, bool force); - virtual kern_return_t SetRegisterState (int set); - virtual bool RegisterSetStateIsValid (int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data& exc); - - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + DNBArchImplI386(MachThread *thread) + : DNBArchProtocol(), m_thread(thread), m_state(), m_2pc_dbg_checkpoint(), + m_2pc_trans_state(Trans_Done), m_saved_register_states() {} + virtual ~DNBArchImplI386() {} + + static void Initialize(); + + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value); + virtual bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value); + virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); + virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState(); + virtual bool RestoreRegisterState(uint32_t save_id); + + virtual kern_return_t GetRegisterState(int set, bool force); + virtual kern_return_t SetRegisterState(int set); + virtual bool RegisterSetStateIsValid(int set) const; + + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual void ThreadWillResume(); + virtual bool ThreadDidStop(); + virtual bool NotifyException(MachException::Data &exc); + + virtual uint32_t NumSupportedHardwareWatchpoints(); + virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task); + virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); protected: - kern_return_t EnableHardwareSingleStep (bool enable); - - typedef __i386_thread_state_t GPR; - typedef __i386_float_state_t FPU; - typedef __i386_exception_state_t EXC; - typedef __i386_avx_state_t AVX; - typedef __i386_debug_state_t DBG; - - static const DNBRegisterInfo g_gpr_registers[]; - static const DNBRegisterInfo g_fpu_registers_no_avx[]; - static const DNBRegisterInfo g_fpu_registers_avx[]; - static const DNBRegisterInfo g_exc_registers[]; - static const DNBRegisterSetInfo g_reg_sets_no_avx[]; - static const DNBRegisterSetInfo g_reg_sets_avx[]; - static const size_t k_num_gpr_registers; - static const size_t k_num_fpu_registers_no_avx; - static const size_t k_num_fpu_registers_avx; - static const size_t k_num_exc_registers; - static const size_t k_num_all_registers_no_avx; - static const size_t k_num_all_registers_avx; - static const size_t k_num_register_sets; - - typedef enum RegisterSetTag - { - e_regSetALL = REGISTER_SET_ALL, - e_regSetGPR, - e_regSetFPU, - e_regSetEXC, - e_regSetDBG, - kNumRegisterSets - } RegisterSet; - - typedef enum RegisterSetWordSizeTag - { - e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int), - e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int), - e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int), - e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int), - e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int) - } RegisterSetWordSize; - - enum - { - Read = 0, - Write = 1, - kNumErrors = 2 - }; - - struct Context - { - GPR gpr; - union { - FPU no_avx; - AVX avx; - } fpu; - EXC exc; - DBG dbg; - }; - - struct State - { - Context context; - kern_return_t gpr_errs[2]; // Read/Write errors - kern_return_t fpu_errs[2]; // Read/Write errors - kern_return_t exc_errs[2]; // Read/Write errors - kern_return_t dbg_errs[2]; // Read/Write errors - - State() - { - uint32_t i; - for (i=0; i<kNumErrors; i++) - { - gpr_errs[i] = -1; - fpu_errs[i] = -1; - exc_errs[i] = -1; - dbg_errs[i] = -1; - } - } - void InvalidateAllRegisterStates() - { - SetError (e_regSetALL, Read, -1); - } - kern_return_t GetError (int flavor, uint32_t err_idx) const - { - if (err_idx < kNumErrors) - { - switch (flavor) - { - // When getting all errors, just OR all values together to see if - // we got any kind of error. - case e_regSetALL: return gpr_errs[err_idx] | - fpu_errs[err_idx] | - exc_errs[err_idx]; - case e_regSetGPR: return gpr_errs[err_idx]; - case e_regSetFPU: return fpu_errs[err_idx]; - case e_regSetEXC: return exc_errs[err_idx]; - case e_regSetDBG: return dbg_errs[err_idx]; - default: break; - } - } - return -1; - } - bool SetError (int flavor, uint32_t err_idx, kern_return_t err) - { - if (err_idx < kNumErrors) - { - switch (flavor) - { - case e_regSetALL: - gpr_errs[err_idx] = - fpu_errs[err_idx] = - exc_errs[err_idx] = - dbg_errs[err_idx] = err; - return true; - - case e_regSetGPR: - gpr_errs[err_idx] = err; - return true; - - case e_regSetFPU: - fpu_errs[err_idx] = err; - return true; - - case e_regSetEXC: - exc_errs[err_idx] = err; - return true; - - case e_regSetDBG: - dbg_errs[err_idx] = err; - return true; - - default: break; - } - } - return false; + kern_return_t EnableHardwareSingleStep(bool enable); + + typedef __i386_thread_state_t GPR; + typedef __i386_float_state_t FPU; + typedef __i386_exception_state_t EXC; + typedef __i386_avx_state_t AVX; + typedef __i386_debug_state_t DBG; + + static const DNBRegisterInfo g_gpr_registers[]; + static const DNBRegisterInfo g_fpu_registers_no_avx[]; + static const DNBRegisterInfo g_fpu_registers_avx[]; + static const DNBRegisterInfo g_exc_registers[]; + static const DNBRegisterSetInfo g_reg_sets_no_avx[]; + static const DNBRegisterSetInfo g_reg_sets_avx[]; + static const size_t k_num_gpr_registers; + static const size_t k_num_fpu_registers_no_avx; + static const size_t k_num_fpu_registers_avx; + static const size_t k_num_exc_registers; + static const size_t k_num_all_registers_no_avx; + static const size_t k_num_all_registers_avx; + static const size_t k_num_register_sets; + + typedef enum RegisterSetTag { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, + e_regSetFPU, + e_regSetEXC, + e_regSetDBG, + kNumRegisterSets + } RegisterSet; + + typedef enum RegisterSetWordSizeTag { + e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int), + e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int), + e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int), + e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int), + e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int) + } RegisterSetWordSize; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + struct Context { + GPR gpr; + union { + FPU no_avx; + AVX avx; + } fpu; + EXC exc; + DBG dbg; + }; + + struct State { + Context context; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t fpu_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t dbg_errs[2]; // Read/Write errors + + State() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + fpu_errs[i] = -1; + exc_errs[i] = -1; + dbg_errs[i] = -1; + } + } + void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); } + kern_return_t GetError(int flavor, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (flavor) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case e_regSetALL: + return gpr_errs[err_idx] | fpu_errs[err_idx] | exc_errs[err_idx]; + case e_regSetGPR: + return gpr_errs[err_idx]; + case e_regSetFPU: + return fpu_errs[err_idx]; + case e_regSetEXC: + return exc_errs[err_idx]; + case e_regSetDBG: + return dbg_errs[err_idx]; + default: + break; } - bool RegsAreValid (int flavor) const - { - return GetError(flavor, Read) == KERN_SUCCESS; + } + return -1; + } + bool SetError(int flavor, uint32_t err_idx, kern_return_t err) { + if (err_idx < kNumErrors) { + switch (flavor) { + case e_regSetALL: + gpr_errs[err_idx] = fpu_errs[err_idx] = exc_errs[err_idx] = + dbg_errs[err_idx] = err; + return true; + + case e_regSetGPR: + gpr_errs[err_idx] = err; + return true; + + case e_regSetFPU: + fpu_errs[err_idx] = err; + return true; + + case e_regSetEXC: + exc_errs[err_idx] = err; + return true; + + case e_regSetDBG: + dbg_errs[err_idx] = err; + return true; + + default: + break; } - }; - - kern_return_t GetGPRState (bool force); - kern_return_t GetFPUState (bool force); - kern_return_t GetEXCState (bool force); - kern_return_t GetDBGState (bool force); - - kern_return_t SetGPRState (); - kern_return_t SetFPUState (); - kern_return_t SetEXCState (); - kern_return_t SetDBGState (bool also_set_on_task); - - static DNBArchProtocol * - Create (MachThread *thread); - - static const uint8_t * - SoftwareBreakpointOpcode (nub_size_t byte_size); - - static const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets); - - static uint32_t - GetRegisterContextSize(); - - // Helper functions for watchpoint manipulations. - static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write); - static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); - static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index); - static void ClearWatchpointHits(DBG &debug_state); - static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); - static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - - virtual bool StartTransForHWP(); - virtual bool RollbackTransForHWP(); - virtual bool FinishTransForHWP(); - DBG GetDBGCheckpoint(); - - MachThread *m_thread; - State m_state; - DBG m_2pc_dbg_checkpoint; - uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? - typedef std::map<uint32_t, Context> SaveRegisterStates; - SaveRegisterStates m_saved_register_states; + } + return false; + } + bool RegsAreValid(int flavor) const { + return GetError(flavor, Read) == KERN_SUCCESS; + } + }; + + kern_return_t GetGPRState(bool force); + kern_return_t GetFPUState(bool force); + kern_return_t GetEXCState(bool force); + kern_return_t GetDBGState(bool force); + + kern_return_t SetGPRState(); + kern_return_t SetFPUState(); + kern_return_t SetEXCState(); + kern_return_t SetDBGState(bool also_set_on_task); + + static DNBArchProtocol *Create(MachThread *thread); + + static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); + + static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); + + static uint32_t GetRegisterContextSize(); + + // Helper functions for watchpoint manipulations. + static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, + nub_addr_t addr, nub_size_t size, bool read, + bool write); + static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); + static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index); + static void ClearWatchpointHits(DBG &debug_state); + static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); + static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + + virtual bool StartTransForHWP(); + virtual bool RollbackTransForHWP(); + virtual bool FinishTransForHWP(); + DBG GetDBGCheckpoint(); + + MachThread *m_thread; + State m_state; + DBG m_2pc_dbg_checkpoint; + uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning + // (0), Done (1), or Rolled Back (2)? + typedef std::map<uint32_t, Context> SaveRegisterStates; + SaveRegisterStates m_saved_register_states; }; -#endif // #if defined (__i386__) || defined (__x86_64__) -#endif // #ifndef __DNBArchImplI386_h__ +#endif // #if defined (__i386__) || defined (__x86_64__) +#endif // #ifndef __DNBArchImplI386_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h b/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h index 59cfbe055a3..900aa15a75d 100644 --- a/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h +++ b/lldb/tools/debugserver/source/MacOSX/i386/MachRegisterStatesI386.h @@ -16,165 +16,163 @@ #include <inttypes.h> -#define __i386_THREAD_STATE 1 -#define __i386_FLOAT_STATE 2 -#define __i386_EXCEPTION_STATE 3 -#define __i386_DEBUG_STATE 10 -#define __i386_AVX_STATE 16 +#define __i386_THREAD_STATE 1 +#define __i386_FLOAT_STATE 2 +#define __i386_EXCEPTION_STATE 3 +#define __i386_DEBUG_STATE 10 +#define __i386_AVX_STATE 16 typedef struct { - uint32_t __eax; - uint32_t __ebx; - uint32_t __ecx; - uint32_t __edx; - uint32_t __edi; - uint32_t __esi; - uint32_t __ebp; - uint32_t __esp; - uint32_t __ss; - uint32_t __eflags; - uint32_t __eip; - uint32_t __cs; - uint32_t __ds; - uint32_t __es; - uint32_t __fs; - uint32_t __gs; + uint32_t __eax; + uint32_t __ebx; + uint32_t __ecx; + uint32_t __edx; + uint32_t __edi; + uint32_t __esi; + uint32_t __ebp; + uint32_t __esp; + uint32_t __ss; + uint32_t __eflags; + uint32_t __eip; + uint32_t __cs; + uint32_t __ds; + uint32_t __es; + uint32_t __fs; + uint32_t __gs; } __i386_thread_state_t; typedef struct { - uint16_t __invalid : 1; - uint16_t __denorm : 1; - uint16_t __zdiv : 1; - uint16_t __ovrfl : 1; - uint16_t __undfl : 1; - uint16_t __precis : 1; - uint16_t __PAD1 : 2; - uint16_t __pc : 2; - uint16_t __rc : 2; - uint16_t __PAD2 : 1; - uint16_t __PAD3 : 3; + uint16_t __invalid : 1; + uint16_t __denorm : 1; + uint16_t __zdiv : 1; + uint16_t __ovrfl : 1; + uint16_t __undfl : 1; + uint16_t __precis : 1; + uint16_t __PAD1 : 2; + uint16_t __pc : 2; + uint16_t __rc : 2; + uint16_t __PAD2 : 1; + uint16_t __PAD3 : 3; } __i386_fp_control_t; typedef struct { - uint16_t __invalid : 1; - uint16_t __denorm : 1; - uint16_t __zdiv : 1; - uint16_t __ovrfl : 1; - uint16_t __undfl : 1; - uint16_t __precis : 1; - uint16_t __stkflt : 1; - uint16_t __errsumm : 1; - uint16_t __c0 : 1; - uint16_t __c1 : 1; - uint16_t __c2 : 1; - uint16_t __tos : 3; - uint16_t __c3 : 1; - uint16_t __busy : 1; + uint16_t __invalid : 1; + uint16_t __denorm : 1; + uint16_t __zdiv : 1; + uint16_t __ovrfl : 1; + uint16_t __undfl : 1; + uint16_t __precis : 1; + uint16_t __stkflt : 1; + uint16_t __errsumm : 1; + uint16_t __c0 : 1; + uint16_t __c1 : 1; + uint16_t __c2 : 1; + uint16_t __tos : 3; + uint16_t __c3 : 1; + uint16_t __busy : 1; } __i386_fp_status_t; typedef struct { - uint8_t __mmst_reg[10]; - uint8_t __mmst_rsrv[6]; + uint8_t __mmst_reg[10]; + uint8_t __mmst_rsrv[6]; } __i386_mmst_reg; -typedef struct { - uint8_t __xmm_reg[16]; -} __i386_xmm_reg; +typedef struct { uint8_t __xmm_reg[16]; } __i386_xmm_reg; typedef struct { - uint32_t __fpu_reserved[2]; - __i386_fp_control_t __fpu_fcw; - __i386_fp_status_t __fpu_fsw; - uint8_t __fpu_ftw; - uint8_t __fpu_rsrv1; - uint16_t __fpu_fop; - uint32_t __fpu_ip; - uint16_t __fpu_cs; - uint16_t __fpu_rsrv2; - uint32_t __fpu_dp; - uint16_t __fpu_ds; - uint16_t __fpu_rsrv3; - uint32_t __fpu_mxcsr; - uint32_t __fpu_mxcsrmask; - __i386_mmst_reg __fpu_stmm0; - __i386_mmst_reg __fpu_stmm1; - __i386_mmst_reg __fpu_stmm2; - __i386_mmst_reg __fpu_stmm3; - __i386_mmst_reg __fpu_stmm4; - __i386_mmst_reg __fpu_stmm5; - __i386_mmst_reg __fpu_stmm6; - __i386_mmst_reg __fpu_stmm7; - __i386_xmm_reg __fpu_xmm0; - __i386_xmm_reg __fpu_xmm1; - __i386_xmm_reg __fpu_xmm2; - __i386_xmm_reg __fpu_xmm3; - __i386_xmm_reg __fpu_xmm4; - __i386_xmm_reg __fpu_xmm5; - __i386_xmm_reg __fpu_xmm6; - __i386_xmm_reg __fpu_xmm7; - uint8_t __fpu_rsrv4[14*16]; - uint32_t __fpu_reserved1; + uint32_t __fpu_reserved[2]; + __i386_fp_control_t __fpu_fcw; + __i386_fp_status_t __fpu_fsw; + uint8_t __fpu_ftw; + uint8_t __fpu_rsrv1; + uint16_t __fpu_fop; + uint32_t __fpu_ip; + uint16_t __fpu_cs; + uint16_t __fpu_rsrv2; + uint32_t __fpu_dp; + uint16_t __fpu_ds; + uint16_t __fpu_rsrv3; + uint32_t __fpu_mxcsr; + uint32_t __fpu_mxcsrmask; + __i386_mmst_reg __fpu_stmm0; + __i386_mmst_reg __fpu_stmm1; + __i386_mmst_reg __fpu_stmm2; + __i386_mmst_reg __fpu_stmm3; + __i386_mmst_reg __fpu_stmm4; + __i386_mmst_reg __fpu_stmm5; + __i386_mmst_reg __fpu_stmm6; + __i386_mmst_reg __fpu_stmm7; + __i386_xmm_reg __fpu_xmm0; + __i386_xmm_reg __fpu_xmm1; + __i386_xmm_reg __fpu_xmm2; + __i386_xmm_reg __fpu_xmm3; + __i386_xmm_reg __fpu_xmm4; + __i386_xmm_reg __fpu_xmm5; + __i386_xmm_reg __fpu_xmm6; + __i386_xmm_reg __fpu_xmm7; + uint8_t __fpu_rsrv4[14 * 16]; + uint32_t __fpu_reserved1; } __i386_float_state_t; typedef struct { - uint32_t __fpu_reserved[2]; - __i386_fp_control_t __fpu_fcw; - __i386_fp_status_t __fpu_fsw; - uint8_t __fpu_ftw; - uint8_t __fpu_rsrv1; - uint16_t __fpu_fop; - uint32_t __fpu_ip; - uint16_t __fpu_cs; - uint16_t __fpu_rsrv2; - uint32_t __fpu_dp; - uint16_t __fpu_ds; - uint16_t __fpu_rsrv3; - uint32_t __fpu_mxcsr; - uint32_t __fpu_mxcsrmask; - __i386_mmst_reg __fpu_stmm0; - __i386_mmst_reg __fpu_stmm1; - __i386_mmst_reg __fpu_stmm2; - __i386_mmst_reg __fpu_stmm3; - __i386_mmst_reg __fpu_stmm4; - __i386_mmst_reg __fpu_stmm5; - __i386_mmst_reg __fpu_stmm6; - __i386_mmst_reg __fpu_stmm7; - __i386_xmm_reg __fpu_xmm0; - __i386_xmm_reg __fpu_xmm1; - __i386_xmm_reg __fpu_xmm2; - __i386_xmm_reg __fpu_xmm3; - __i386_xmm_reg __fpu_xmm4; - __i386_xmm_reg __fpu_xmm5; - __i386_xmm_reg __fpu_xmm6; - __i386_xmm_reg __fpu_xmm7; - uint8_t __fpu_rsrv4[14*16]; - uint32_t __fpu_reserved1; - uint8_t __avx_reserved1[64]; - __i386_xmm_reg __fpu_ymmh0; - __i386_xmm_reg __fpu_ymmh1; - __i386_xmm_reg __fpu_ymmh2; - __i386_xmm_reg __fpu_ymmh3; - __i386_xmm_reg __fpu_ymmh4; - __i386_xmm_reg __fpu_ymmh5; - __i386_xmm_reg __fpu_ymmh6; - __i386_xmm_reg __fpu_ymmh7; + uint32_t __fpu_reserved[2]; + __i386_fp_control_t __fpu_fcw; + __i386_fp_status_t __fpu_fsw; + uint8_t __fpu_ftw; + uint8_t __fpu_rsrv1; + uint16_t __fpu_fop; + uint32_t __fpu_ip; + uint16_t __fpu_cs; + uint16_t __fpu_rsrv2; + uint32_t __fpu_dp; + uint16_t __fpu_ds; + uint16_t __fpu_rsrv3; + uint32_t __fpu_mxcsr; + uint32_t __fpu_mxcsrmask; + __i386_mmst_reg __fpu_stmm0; + __i386_mmst_reg __fpu_stmm1; + __i386_mmst_reg __fpu_stmm2; + __i386_mmst_reg __fpu_stmm3; + __i386_mmst_reg __fpu_stmm4; + __i386_mmst_reg __fpu_stmm5; + __i386_mmst_reg __fpu_stmm6; + __i386_mmst_reg __fpu_stmm7; + __i386_xmm_reg __fpu_xmm0; + __i386_xmm_reg __fpu_xmm1; + __i386_xmm_reg __fpu_xmm2; + __i386_xmm_reg __fpu_xmm3; + __i386_xmm_reg __fpu_xmm4; + __i386_xmm_reg __fpu_xmm5; + __i386_xmm_reg __fpu_xmm6; + __i386_xmm_reg __fpu_xmm7; + uint8_t __fpu_rsrv4[14 * 16]; + uint32_t __fpu_reserved1; + uint8_t __avx_reserved1[64]; + __i386_xmm_reg __fpu_ymmh0; + __i386_xmm_reg __fpu_ymmh1; + __i386_xmm_reg __fpu_ymmh2; + __i386_xmm_reg __fpu_ymmh3; + __i386_xmm_reg __fpu_ymmh4; + __i386_xmm_reg __fpu_ymmh5; + __i386_xmm_reg __fpu_ymmh6; + __i386_xmm_reg __fpu_ymmh7; } __i386_avx_state_t; typedef struct { - uint32_t __trapno; - uint32_t __err; - uint32_t __faultvaddr; + uint32_t __trapno; + uint32_t __err; + uint32_t __faultvaddr; } __i386_exception_state_t; typedef struct { - uint32_t __dr0; - uint32_t __dr1; - uint32_t __dr2; - uint32_t __dr3; - uint32_t __dr4; - uint32_t __dr5; - uint32_t __dr6; - uint32_t __dr7; + uint32_t __dr0; + uint32_t __dr1; + uint32_t __dr2; + uint32_t __dr3; + uint32_t __dr4; + uint32_t __dr5; + uint32_t __dr6; + uint32_t __dr7; } __i386_debug_state_t; #endif diff --git a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp index c6f1a718ac9..1653287430a 100644 --- a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp +++ b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) +#if defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) #if __DARWIN_UNIX03 #define PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(reg) __##reg @@ -20,550 +20,473 @@ #endif #include "MacOSX/ppc/DNBArchImpl.h" -#include "MacOSX/MachThread.h" #include "DNBBreakpoint.h" #include "DNBLog.h" #include "DNBRegisterInfo.h" +#include "MacOSX/MachThread.h" -static const uint8_t g_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 }; +static const uint8_t g_breakpoint_opcode[] = {0x7F, 0xC0, 0x00, 0x08}; -const uint8_t * -DNBArchMachPPC::SoftwareBreakpointOpcode (nub_size_t size) -{ - if (size == 4) - return g_breakpoint_opcode; - return NULL; +const uint8_t *DNBArchMachPPC::SoftwareBreakpointOpcode(nub_size_t size) { + if (size == 4) + return g_breakpoint_opcode; + return NULL; } -uint32_t -DNBArchMachPPC::GetCPUType() -{ - return CPU_TYPE_POWERPC; -} +uint32_t DNBArchMachPPC::GetCPUType() { return CPU_TYPE_POWERPC; } -uint64_t -DNBArchMachPPC::GetPC(uint64_t failValue) -{ - // Get program counter - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0); - return failValue; +uint64_t DNBArchMachPPC::GetPC(uint64_t failValue) { + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0); + return failValue; } -kern_return_t -DNBArchMachPPC::SetPC(uint64_t value) -{ - // Get program counter - kern_return_t err = GetGPRState(false); - if (err == KERN_SUCCESS) - { - m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0) = value; - err = SetGPRState(); - } - return err == KERN_SUCCESS; +kern_return_t DNBArchMachPPC::SetPC(uint64_t value) { + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) { + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0) = value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; } -uint64_t -DNBArchMachPPC::GetSP(uint64_t failValue) -{ - // Get stack pointer - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(r1); - return failValue; +uint64_t DNBArchMachPPC::GetSP(uint64_t failValue) { + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(r1); + return failValue; } -kern_return_t -DNBArchMachPPC::GetGPRState(bool force) -{ - if (force || m_state.GetError(e_regSetGPR, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeGPR; - m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetGPR, (thread_state_t)&m_state.gpr, &count)); - } - return m_state.GetError(e_regSetGPR, Read); +kern_return_t DNBArchMachPPC::GetGPRState(bool force) { + if (force || m_state.GetError(e_regSetGPR, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeGPR; + m_state.SetError(e_regSetGPR, Read, + ::thread_get_state(m_thread->MachPortNumber(), e_regSetGPR, + (thread_state_t)&m_state.gpr, &count)); + } + return m_state.GetError(e_regSetGPR, Read); } -kern_return_t -DNBArchMachPPC::GetFPRState(bool force) -{ - if (force || m_state.GetError(e_regSetFPR, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeFPR; - m_state.SetError(e_regSetFPR, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetFPR, (thread_state_t)&m_state.fpr, &count)); - } - return m_state.GetError(e_regSetFPR, Read); +kern_return_t DNBArchMachPPC::GetFPRState(bool force) { + if (force || m_state.GetError(e_regSetFPR, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeFPR; + m_state.SetError(e_regSetFPR, Read, + ::thread_get_state(m_thread->MachPortNumber(), e_regSetFPR, + (thread_state_t)&m_state.fpr, &count)); + } + return m_state.GetError(e_regSetFPR, Read); } -kern_return_t -DNBArchMachPPC::GetEXCState(bool force) -{ - if (force || m_state.GetError(e_regSetEXC, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeEXC; - m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetEXC, (thread_state_t)&m_state.exc, &count)); - } - return m_state.GetError(e_regSetEXC, Read); +kern_return_t DNBArchMachPPC::GetEXCState(bool force) { + if (force || m_state.GetError(e_regSetEXC, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeEXC; + m_state.SetError(e_regSetEXC, Read, + ::thread_get_state(m_thread->MachPortNumber(), e_regSetEXC, + (thread_state_t)&m_state.exc, &count)); + } + return m_state.GetError(e_regSetEXC, Read); } -kern_return_t -DNBArchMachPPC::GetVECState(bool force) -{ - if (force || m_state.GetError(e_regSetVEC, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeVEC; - m_state.SetError(e_regSetVEC, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetVEC, (thread_state_t)&m_state.vec, &count)); - } - return m_state.GetError(e_regSetVEC, Read); +kern_return_t DNBArchMachPPC::GetVECState(bool force) { + if (force || m_state.GetError(e_regSetVEC, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeVEC; + m_state.SetError(e_regSetVEC, Read, + ::thread_get_state(m_thread->MachPortNumber(), e_regSetVEC, + (thread_state_t)&m_state.vec, &count)); + } + return m_state.GetError(e_regSetVEC, Read); } -kern_return_t -DNBArchMachPPC::SetGPRState() -{ - m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetGPR, (thread_state_t)&m_state.gpr, e_regSetWordSizeGPR)); - return m_state.GetError(e_regSetGPR, Write); +kern_return_t DNBArchMachPPC::SetGPRState() { + m_state.SetError(e_regSetGPR, Write, + ::thread_set_state(m_thread->MachPortNumber(), e_regSetGPR, + (thread_state_t)&m_state.gpr, + e_regSetWordSizeGPR)); + return m_state.GetError(e_regSetGPR, Write); } -kern_return_t -DNBArchMachPPC::SetFPRState() -{ - m_state.SetError(e_regSetFPR, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetFPR, (thread_state_t)&m_state.fpr, e_regSetWordSizeFPR)); - return m_state.GetError(e_regSetFPR, Write); +kern_return_t DNBArchMachPPC::SetFPRState() { + m_state.SetError(e_regSetFPR, Write, + ::thread_set_state(m_thread->MachPortNumber(), e_regSetFPR, + (thread_state_t)&m_state.fpr, + e_regSetWordSizeFPR)); + return m_state.GetError(e_regSetFPR, Write); } -kern_return_t -DNBArchMachPPC::SetEXCState() -{ - m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetEXC, (thread_state_t)&m_state.exc, e_regSetWordSizeEXC)); - return m_state.GetError(e_regSetEXC, Write); +kern_return_t DNBArchMachPPC::SetEXCState() { + m_state.SetError(e_regSetEXC, Write, + ::thread_set_state(m_thread->MachPortNumber(), e_regSetEXC, + (thread_state_t)&m_state.exc, + e_regSetWordSizeEXC)); + return m_state.GetError(e_regSetEXC, Write); } -kern_return_t -DNBArchMachPPC::SetVECState() -{ - m_state.SetError(e_regSetVEC, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetVEC, (thread_state_t)&m_state.vec, e_regSetWordSizeVEC)); - return m_state.GetError(e_regSetVEC, Write); +kern_return_t DNBArchMachPPC::SetVECState() { + m_state.SetError(e_regSetVEC, Write, + ::thread_set_state(m_thread->MachPortNumber(), e_regSetVEC, + (thread_state_t)&m_state.vec, + e_regSetWordSizeVEC)); + return m_state.GetError(e_regSetVEC, Write); } -bool -DNBArchMachPPC::ThreadWillResume() -{ - bool success = true; +bool DNBArchMachPPC::ThreadWillResume() { + bool success = true; - // Do we need to step this thread? If so, let the mach thread tell us so. - if (m_thread->IsStepping()) - { - // This is the primary thread, let the arch do anything it needs - success = EnableHardwareSingleStep(true) == KERN_SUCCESS; - } - return success; + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) { + // This is the primary thread, let the arch do anything it needs + success = EnableHardwareSingleStep(true) == KERN_SUCCESS; + } + return success; } -bool -DNBArchMachPPC::ThreadDidStop() -{ - bool success = true; - - m_state.InvalidateAllRegisterStates(); - - // Are we stepping a single instruction? - if (GetGPRState(true) == KERN_SUCCESS) - { - // We are single stepping, was this the primary thread? - if (m_thread->IsStepping()) - { - // This was the primary thread, we need to clear the trace - // bit if so. - success = EnableHardwareSingleStep(false) == KERN_SUCCESS; - } - else - { - // The MachThread will automatically restore the suspend count - // in ThreadDidStop(), so we don't need to do anything here if - // we weren't the primary thread the last time - } +bool DNBArchMachPPC::ThreadDidStop() { + bool success = true; + + m_state.InvalidateAllRegisterStates(); + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } else { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time } - return success; + } + return success; } - // Set the single step bit in the processor status register. -kern_return_t -DNBArchMachPPC::EnableHardwareSingleStep (bool enable) -{ - DNBLogThreadedIf(LOG_STEP, "DNBArchMachPPC::EnableHardwareSingleStep( enable = %d )", enable); - if (GetGPRState(false) == KERN_SUCCESS) - { - const uint32_t trace_bit = 0x400; - if (enable) - m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) |= trace_bit; - else - m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) &= ~trace_bit; - return SetGPRState(); - } - return m_state.GetError(e_regSetGPR, Read); +kern_return_t DNBArchMachPPC::EnableHardwareSingleStep(bool enable) { + DNBLogThreadedIf(LOG_STEP, + "DNBArchMachPPC::EnableHardwareSingleStep( enable = %d )", + enable); + if (GetGPRState(false) == KERN_SUCCESS) { + const uint32_t trace_bit = 0x400; + if (enable) + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) |= trace_bit; + else + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) &= ~trace_bit; + return SetGPRState(); + } + return m_state.GetError(e_regSetGPR, Read); } //---------------------------------------------------------------------- // Register information definitions for 32 bit PowerPC. //---------------------------------------------------------------------- -enum gpr_regnums -{ - e_regNumGPR_srr0, - e_regNumGPR_srr1, - e_regNumGPR_r0, - e_regNumGPR_r1, - e_regNumGPR_r2, - e_regNumGPR_r3, - e_regNumGPR_r4, - e_regNumGPR_r5, - e_regNumGPR_r6, - e_regNumGPR_r7, - e_regNumGPR_r8, - e_regNumGPR_r9, - e_regNumGPR_r10, - e_regNumGPR_r11, - e_regNumGPR_r12, - e_regNumGPR_r13, - e_regNumGPR_r14, - e_regNumGPR_r15, - e_regNumGPR_r16, - e_regNumGPR_r17, - e_regNumGPR_r18, - e_regNumGPR_r19, - e_regNumGPR_r20, - e_regNumGPR_r21, - e_regNumGPR_r22, - e_regNumGPR_r23, - e_regNumGPR_r24, - e_regNumGPR_r25, - e_regNumGPR_r26, - e_regNumGPR_r27, - e_regNumGPR_r28, - e_regNumGPR_r29, - e_regNumGPR_r30, - e_regNumGPR_r31, - e_regNumGPR_cr, - e_regNumGPR_xer, - e_regNumGPR_lr, - e_regNumGPR_ctr, - e_regNumGPR_mq, - e_regNumGPR_vrsave +enum gpr_regnums { + e_regNumGPR_srr0, + e_regNumGPR_srr1, + e_regNumGPR_r0, + e_regNumGPR_r1, + e_regNumGPR_r2, + e_regNumGPR_r3, + e_regNumGPR_r4, + e_regNumGPR_r5, + e_regNumGPR_r6, + e_regNumGPR_r7, + e_regNumGPR_r8, + e_regNumGPR_r9, + e_regNumGPR_r10, + e_regNumGPR_r11, + e_regNumGPR_r12, + e_regNumGPR_r13, + e_regNumGPR_r14, + e_regNumGPR_r15, + e_regNumGPR_r16, + e_regNumGPR_r17, + e_regNumGPR_r18, + e_regNumGPR_r19, + e_regNumGPR_r20, + e_regNumGPR_r21, + e_regNumGPR_r22, + e_regNumGPR_r23, + e_regNumGPR_r24, + e_regNumGPR_r25, + e_regNumGPR_r26, + e_regNumGPR_r27, + e_regNumGPR_r28, + e_regNumGPR_r29, + e_regNumGPR_r30, + e_regNumGPR_r31, + e_regNumGPR_cr, + e_regNumGPR_xer, + e_regNumGPR_lr, + e_regNumGPR_ctr, + e_regNumGPR_mq, + e_regNumGPR_vrsave }; - - - // General purpose registers -static DNBRegisterInfo g_gpr_registers[] = -{ - { "srr0" , Uint, 4, Hex }, - { "srr1" , Uint, 4, Hex }, - { "r0" , Uint, 4, Hex }, - { "r1" , Uint, 4, Hex }, - { "r2" , Uint, 4, Hex }, - { "r3" , Uint, 4, Hex }, - { "r4" , Uint, 4, Hex }, - { "r5" , Uint, 4, Hex }, - { "r6" , Uint, 4, Hex }, - { "r7" , Uint, 4, Hex }, - { "r8" , Uint, 4, Hex }, - { "r9" , Uint, 4, Hex }, - { "r10" , Uint, 4, Hex }, - { "r11" , Uint, 4, Hex }, - { "r12" , Uint, 4, Hex }, - { "r13" , Uint, 4, Hex }, - { "r14" , Uint, 4, Hex }, - { "r15" , Uint, 4, Hex }, - { "r16" , Uint, 4, Hex }, - { "r17" , Uint, 4, Hex }, - { "r18" , Uint, 4, Hex }, - { "r19" , Uint, 4, Hex }, - { "r20" , Uint, 4, Hex }, - { "r21" , Uint, 4, Hex }, - { "r22" , Uint, 4, Hex }, - { "r23" , Uint, 4, Hex }, - { "r24" , Uint, 4, Hex }, - { "r25" , Uint, 4, Hex }, - { "r26" , Uint, 4, Hex }, - { "r27" , Uint, 4, Hex }, - { "r28" , Uint, 4, Hex }, - { "r29" , Uint, 4, Hex }, - { "r30" , Uint, 4, Hex }, - { "r31" , Uint, 4, Hex }, - { "cr" , Uint, 4, Hex }, - { "xer" , Uint, 4, Hex }, - { "lr" , Uint, 4, Hex }, - { "ctr" , Uint, 4, Hex }, - { "mq" , Uint, 4, Hex }, - { "vrsave", Uint, 4, Hex }, +static DNBRegisterInfo g_gpr_registers[] = { + {"srr0", Uint, 4, Hex}, {"srr1", Uint, 4, Hex}, {"r0", Uint, 4, Hex}, + {"r1", Uint, 4, Hex}, {"r2", Uint, 4, Hex}, {"r3", Uint, 4, Hex}, + {"r4", Uint, 4, Hex}, {"r5", Uint, 4, Hex}, {"r6", Uint, 4, Hex}, + {"r7", Uint, 4, Hex}, {"r8", Uint, 4, Hex}, {"r9", Uint, 4, Hex}, + {"r10", Uint, 4, Hex}, {"r11", Uint, 4, Hex}, {"r12", Uint, 4, Hex}, + {"r13", Uint, 4, Hex}, {"r14", Uint, 4, Hex}, {"r15", Uint, 4, Hex}, + {"r16", Uint, 4, Hex}, {"r17", Uint, 4, Hex}, {"r18", Uint, 4, Hex}, + {"r19", Uint, 4, Hex}, {"r20", Uint, 4, Hex}, {"r21", Uint, 4, Hex}, + {"r22", Uint, 4, Hex}, {"r23", Uint, 4, Hex}, {"r24", Uint, 4, Hex}, + {"r25", Uint, 4, Hex}, {"r26", Uint, 4, Hex}, {"r27", Uint, 4, Hex}, + {"r28", Uint, 4, Hex}, {"r29", Uint, 4, Hex}, {"r30", Uint, 4, Hex}, + {"r31", Uint, 4, Hex}, {"cr", Uint, 4, Hex}, {"xer", Uint, 4, Hex}, + {"lr", Uint, 4, Hex}, {"ctr", Uint, 4, Hex}, {"mq", Uint, 4, Hex}, + {"vrsave", Uint, 4, Hex}, }; // Floating point registers -static DNBRegisterInfo g_fpr_registers[] = -{ - { "fp0" , IEEE754, 8, Float }, - { "fp1" , IEEE754, 8, Float }, - { "fp2" , IEEE754, 8, Float }, - { "fp3" , IEEE754, 8, Float }, - { "fp4" , IEEE754, 8, Float }, - { "fp5" , IEEE754, 8, Float }, - { "fp6" , IEEE754, 8, Float }, - { "fp7" , IEEE754, 8, Float }, - { "fp8" , IEEE754, 8, Float }, - { "fp9" , IEEE754, 8, Float }, - { "fp10" , IEEE754, 8, Float }, - { "fp11" , IEEE754, 8, Float }, - { "fp12" , IEEE754, 8, Float }, - { "fp13" , IEEE754, 8, Float }, - { "fp14" , IEEE754, 8, Float }, - { "fp15" , IEEE754, 8, Float }, - { "fp16" , IEEE754, 8, Float }, - { "fp17" , IEEE754, 8, Float }, - { "fp18" , IEEE754, 8, Float }, - { "fp19" , IEEE754, 8, Float }, - { "fp20" , IEEE754, 8, Float }, - { "fp21" , IEEE754, 8, Float }, - { "fp22" , IEEE754, 8, Float }, - { "fp23" , IEEE754, 8, Float }, - { "fp24" , IEEE754, 8, Float }, - { "fp25" , IEEE754, 8, Float }, - { "fp26" , IEEE754, 8, Float }, - { "fp27" , IEEE754, 8, Float }, - { "fp28" , IEEE754, 8, Float }, - { "fp29" , IEEE754, 8, Float }, - { "fp30" , IEEE754, 8, Float }, - { "fp31" , IEEE754, 8, Float }, - { "fpscr" , Uint, 4, Hex } -}; +static DNBRegisterInfo g_fpr_registers[] = { + {"fp0", IEEE754, 8, Float}, {"fp1", IEEE754, 8, Float}, + {"fp2", IEEE754, 8, Float}, {"fp3", IEEE754, 8, Float}, + {"fp4", IEEE754, 8, Float}, {"fp5", IEEE754, 8, Float}, + {"fp6", IEEE754, 8, Float}, {"fp7", IEEE754, 8, Float}, + {"fp8", IEEE754, 8, Float}, {"fp9", IEEE754, 8, Float}, + {"fp10", IEEE754, 8, Float}, {"fp11", IEEE754, 8, Float}, + {"fp12", IEEE754, 8, Float}, {"fp13", IEEE754, 8, Float}, + {"fp14", IEEE754, 8, Float}, {"fp15", IEEE754, 8, Float}, + {"fp16", IEEE754, 8, Float}, {"fp17", IEEE754, 8, Float}, + {"fp18", IEEE754, 8, Float}, {"fp19", IEEE754, 8, Float}, + {"fp20", IEEE754, 8, Float}, {"fp21", IEEE754, 8, Float}, + {"fp22", IEEE754, 8, Float}, {"fp23", IEEE754, 8, Float}, + {"fp24", IEEE754, 8, Float}, {"fp25", IEEE754, 8, Float}, + {"fp26", IEEE754, 8, Float}, {"fp27", IEEE754, 8, Float}, + {"fp28", IEEE754, 8, Float}, {"fp29", IEEE754, 8, Float}, + {"fp30", IEEE754, 8, Float}, {"fp31", IEEE754, 8, Float}, + {"fpscr", Uint, 4, Hex}}; // Exception registers -static DNBRegisterInfo g_exc_registers[] = -{ - { "dar" , Uint, 4, Hex }, - { "dsisr" , Uint, 4, Hex }, - { "exception" , Uint, 4, Hex } -}; +static DNBRegisterInfo g_exc_registers[] = {{"dar", Uint, 4, Hex}, + {"dsisr", Uint, 4, Hex}, + {"exception", Uint, 4, Hex}}; // Altivec registers -static DNBRegisterInfo g_vec_registers[] = -{ - { "vr0" , Vector, 16, VectorOfFloat32 }, - { "vr1" , Vector, 16, VectorOfFloat32 }, - { "vr2" , Vector, 16, VectorOfFloat32 }, - { "vr3" , Vector, 16, VectorOfFloat32 }, - { "vr4" , Vector, 16, VectorOfFloat32 }, - { "vr5" , Vector, 16, VectorOfFloat32 }, - { "vr6" , Vector, 16, VectorOfFloat32 }, - { "vr7" , Vector, 16, VectorOfFloat32 }, - { "vr8" , Vector, 16, VectorOfFloat32 }, - { "vr9" , Vector, 16, VectorOfFloat32 }, - { "vr10" , Vector, 16, VectorOfFloat32 }, - { "vr11" , Vector, 16, VectorOfFloat32 }, - { "vr12" , Vector, 16, VectorOfFloat32 }, - { "vr13" , Vector, 16, VectorOfFloat32 }, - { "vr14" , Vector, 16, VectorOfFloat32 }, - { "vr15" , Vector, 16, VectorOfFloat32 }, - { "vr16" , Vector, 16, VectorOfFloat32 }, - { "vr17" , Vector, 16, VectorOfFloat32 }, - { "vr18" , Vector, 16, VectorOfFloat32 }, - { "vr19" , Vector, 16, VectorOfFloat32 }, - { "vr20" , Vector, 16, VectorOfFloat32 }, - { "vr21" , Vector, 16, VectorOfFloat32 }, - { "vr22" , Vector, 16, VectorOfFloat32 }, - { "vr23" , Vector, 16, VectorOfFloat32 }, - { "vr24" , Vector, 16, VectorOfFloat32 }, - { "vr25" , Vector, 16, VectorOfFloat32 }, - { "vr26" , Vector, 16, VectorOfFloat32 }, - { "vr27" , Vector, 16, VectorOfFloat32 }, - { "vr28" , Vector, 16, VectorOfFloat32 }, - { "vr29" , Vector, 16, VectorOfFloat32 }, - { "vr30" , Vector, 16, VectorOfFloat32 }, - { "vr31" , Vector, 16, VectorOfFloat32 }, - { "vscr" , Uint, 16, Hex }, - { "vrvalid" , Uint, 4, Hex } -}; +static DNBRegisterInfo g_vec_registers[] = { + {"vr0", Vector, 16, VectorOfFloat32}, + {"vr1", Vector, 16, VectorOfFloat32}, + {"vr2", Vector, 16, VectorOfFloat32}, + {"vr3", Vector, 16, VectorOfFloat32}, + {"vr4", Vector, 16, VectorOfFloat32}, + {"vr5", Vector, 16, VectorOfFloat32}, + {"vr6", Vector, 16, VectorOfFloat32}, + {"vr7", Vector, 16, VectorOfFloat32}, + {"vr8", Vector, 16, VectorOfFloat32}, + {"vr9", Vector, 16, VectorOfFloat32}, + {"vr10", Vector, 16, VectorOfFloat32}, + {"vr11", Vector, 16, VectorOfFloat32}, + {"vr12", Vector, 16, VectorOfFloat32}, + {"vr13", Vector, 16, VectorOfFloat32}, + {"vr14", Vector, 16, VectorOfFloat32}, + {"vr15", Vector, 16, VectorOfFloat32}, + {"vr16", Vector, 16, VectorOfFloat32}, + {"vr17", Vector, 16, VectorOfFloat32}, + {"vr18", Vector, 16, VectorOfFloat32}, + {"vr19", Vector, 16, VectorOfFloat32}, + {"vr20", Vector, 16, VectorOfFloat32}, + {"vr21", Vector, 16, VectorOfFloat32}, + {"vr22", Vector, 16, VectorOfFloat32}, + {"vr23", Vector, 16, VectorOfFloat32}, + {"vr24", Vector, 16, VectorOfFloat32}, + {"vr25", Vector, 16, VectorOfFloat32}, + {"vr26", Vector, 16, VectorOfFloat32}, + {"vr27", Vector, 16, VectorOfFloat32}, + {"vr28", Vector, 16, VectorOfFloat32}, + {"vr29", Vector, 16, VectorOfFloat32}, + {"vr30", Vector, 16, VectorOfFloat32}, + {"vr31", Vector, 16, VectorOfFloat32}, + {"vscr", Uint, 16, Hex}, + {"vrvalid", Uint, 4, Hex}}; // Number of registers in each register set -const size_t k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); -const size_t k_num_fpr_registers = sizeof(g_fpr_registers)/sizeof(DNBRegisterInfo); -const size_t k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); -const size_t k_num_vec_registers = sizeof(g_vec_registers)/sizeof(DNBRegisterInfo); +const size_t k_num_gpr_registers = + sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); +const size_t k_num_fpr_registers = + sizeof(g_fpr_registers) / sizeof(DNBRegisterInfo); +const size_t k_num_exc_registers = + sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); +const size_t k_num_vec_registers = + sizeof(g_vec_registers) / sizeof(DNBRegisterInfo); // Total number of registers for this architecture -const size_t k_num_ppc_registers = k_num_gpr_registers + k_num_fpr_registers + k_num_exc_registers + k_num_vec_registers; +const size_t k_num_ppc_registers = k_num_gpr_registers + k_num_fpr_registers + + k_num_exc_registers + k_num_vec_registers; //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index // of zero is for all registers, followed by other registers sets. The // register information for the all register set need not be filled in. //---------------------------------------------------------------------- -static const DNBRegisterSetInfo g_reg_sets[] = -{ - { "PowerPC Registers", NULL, k_num_ppc_registers }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_fpr_registers, k_num_fpr_registers }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers }, - { "Altivec Registers", g_vec_registers, k_num_vec_registers } -}; +static const DNBRegisterSetInfo g_reg_sets[] = { + {"PowerPC Registers", NULL, k_num_ppc_registers}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_fpr_registers, k_num_fpr_registers}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}, + {"Altivec Registers", g_vec_registers, k_num_vec_registers}}; // Total number of register sets for this architecture -const size_t k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo); - +const size_t k_num_register_sets = + sizeof(g_reg_sets) / sizeof(DNBRegisterSetInfo); const DNBRegisterSetInfo * -DNBArchMachPPC::GetRegisterSetInfo(nub_size_t *num_reg_sets) const -{ - *num_reg_sets = k_num_register_sets; - return g_reg_sets; +DNBArchMachPPC::GetRegisterSetInfo(nub_size_t *num_reg_sets) const { + *num_reg_sets = k_num_register_sets; + return g_reg_sets; } -bool -DNBArchMachPPC::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) const -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = e_regNumGPR_srr0; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = e_regNumGPR_r1; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - // Return false for now instead of returning r30 as gcc 3.x would - // use a variety of registers for the FP and it takes inspecting - // the stack to make sure there is a frame pointer before we can - // determine the FP. - return false; - - case GENERIC_REGNUM_RA: // Return Address - set = e_regSetGPR; - reg = e_regNumGPR_lr; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = e_regNumGPR_srr1; - break; - - default: - return false; - } +bool DNBArchMachPPC::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) const { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = e_regNumGPR_srr0; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = e_regNumGPR_r1; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + // Return false for now instead of returning r30 as gcc 3.x would + // use a variety of registers for the FP and it takes inspecting + // the stack to make sure there is a frame pointer before we can + // determine the FP. + return false; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = e_regNumGPR_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = e_regNumGPR_srr1; + break; + + default: + return false; } + } - if (!m_state.RegsAreValid(set)) - return false; + if (!m_state.RegsAreValid(set)) + return false; - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - value->info = *regInfo; - switch (set) + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + value->info = *regInfo; + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + value->value.uint32 = + (&m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0))[reg]; + return true; + } + break; + + case e_regSetFPR: + if (reg < 32) { + value->value.float64 = + m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpregs)[reg]; + return true; + } else if (reg == 32) { + value->value.uint32 = + m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpscr); + return true; + } + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) { + value->value.uint32 = + (&m_state.exc.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(dar))[reg]; + return true; + } + break; + + case e_regSetVEC: + if (reg < k_num_vec_registers) { + if (reg < 33) // FP0 - FP31 and VSCR + { + // Copy all 4 uint32 values for this vector register + value->value.v_uint32[0] = + m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg] + [0]; + value->value.v_uint32[1] = + m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg] + [1]; + value->value.v_uint32[2] = + m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg] + [2]; + value->value.v_uint32[3] = + m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg] + [3]; + return true; + } else if (reg == 34) // VRVALID { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - value->value.uint32 = (&m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0))[reg]; - return true; - } - break; - - case e_regSetFPR: - if (reg < 32) - { - value->value.float64 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpregs)[reg]; - return true; - } - else if (reg == 32) - { - value->value.uint32 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpscr); - return true; - } - break; - - case e_regSetEXC: - if (reg < k_num_exc_registers) - { - value->value.uint32 = (&m_state.exc.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(dar))[reg]; - return true; - } - break; - - case e_regSetVEC: - if (reg < k_num_vec_registers) - { - if (reg < 33) // FP0 - FP31 and VSCR - { - // Copy all 4 uint32 values for this vector register - value->value.v_uint32[0] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][0]; - value->value.v_uint32[1] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][1]; - value->value.v_uint32[2] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][2]; - value->value.v_uint32[3] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][3]; - return true; - } - else if (reg == 34) // VRVALID - { - value->value.uint32 = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vrvalid); - return true; - } - } - break; + value->value.uint32 = + m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vrvalid); + return true; } + } + break; } - return false; + } + return false; } - -kern_return_t -DNBArchMachPPC::GetRegisterState(int set, bool force) -{ - switch (set) - { - case e_regSetALL: - return GetGPRState(force) | - GetFPRState(force) | - GetEXCState(force) | - GetVECState(force); - case e_regSetGPR: return GetGPRState(force); - case e_regSetFPR: return GetFPRState(force); - case e_regSetEXC: return GetEXCState(force); - case e_regSetVEC: return GetVECState(force); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachPPC::GetRegisterState(int set, bool force) { + switch (set) { + case e_regSetALL: + return GetGPRState(force) | GetFPRState(force) | GetEXCState(force) | + GetVECState(force); + case e_regSetGPR: + return GetGPRState(force); + case e_regSetFPR: + return GetFPRState(force); + case e_regSetEXC: + return GetEXCState(force); + case e_regSetVEC: + return GetVECState(force); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -kern_return_t -DNBArchMachPPC::SetRegisterState(int set) -{ - // Make sure we have a valid context to set. - kern_return_t err = GetRegisterState(set, false); - if (err != KERN_SUCCESS) - return err; - - switch (set) - { - case e_regSetALL: return SetGPRState() | SetFPRState() | SetEXCState() | SetVECState(); - case e_regSetGPR: return SetGPRState(); - case e_regSetFPR: return SetFPRState(); - case e_regSetEXC: return SetEXCState(); - case e_regSetVEC: return SetVECState(); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchMachPPC::SetRegisterState(int set) { + // Make sure we have a valid context to set. + kern_return_t err = GetRegisterState(set, false); + if (err != KERN_SUCCESS) + return err; + + switch (set) { + case e_regSetALL: + return SetGPRState() | SetFPRState() | SetEXCState() | SetVECState(); + case e_regSetGPR: + return SetGPRState(); + case e_regSetFPR: + return SetFPRState(); + case e_regSetEXC: + return SetEXCState(); + case e_regSetVEC: + return SetVECState(); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -bool -DNBArchMachPPC::RegisterSetStateIsValid (int set) const -{ - return m_state.RegsAreValid(set); +bool DNBArchMachPPC::RegisterSetStateIsValid(int set) const { + return m_state.RegsAreValid(set); } - -#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) - +#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) diff --git a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h index 8ea81538dc4..8aed9fc0f80 100644 --- a/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h +++ b/lldb/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.h @@ -14,166 +14,147 @@ #ifndef __DebugNubArchMachPPC_h__ #define __DebugNubArchMachPPC_h__ -#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) +#if defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) #include "DNBArch.h" class MachThread; -class DNBArchMachPPC : public DNBArchProtocol -{ +class DNBArchMachPPC : public DNBArchProtocol { public: - DNBArchMachPPC(MachThread *thread) : - m_thread(thread), - m_state() - { - } + DNBArchMachPPC(MachThread *thread) : m_thread(thread), m_state() {} - virtual ~DNBArchMachPPC() - { - } + virtual ~DNBArchMachPPC() {} - virtual const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets) const; - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) const; - virtual kern_return_t GetRegisterState (int set, bool force); - virtual kern_return_t SetRegisterState (int set); - virtual bool RegisterSetStateIsValid (int set) const; + virtual const DNBRegisterSetInfo * + GetRegisterSetInfo(nub_size_t *num_reg_sets) const; + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) const; + virtual kern_return_t GetRegisterState(int set, bool force); + virtual kern_return_t SetRegisterState(int set); + virtual bool RegisterSetStateIsValid(int set) const; - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual bool ThreadWillResume(); - virtual bool ThreadDidStop(); + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual bool ThreadWillResume(); + virtual bool ThreadDidStop(); - static const uint8_t * SoftwareBreakpointOpcode (nub_size_t byte_size); - static uint32_t GetCPUType(); + static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); + static uint32_t GetCPUType(); protected: - - - kern_return_t EnableHardwareSingleStep (bool enable); - - typedef enum RegisterSetTag - { - e_regSetALL = REGISTER_SET_ALL, - e_regSetGPR, - e_regSetFPR, - e_regSetEXC, - e_regSetVEC, - kNumRegisterSets - } RegisterSet; - - typedef enum RegisterSetWordSizeTag - { - e_regSetWordSizeGPR = PPC_THREAD_STATE_COUNT, - e_regSetWordSizeFPR = PPC_FLOAT_STATE_COUNT, - e_regSetWordSizeEXC = PPC_EXCEPTION_STATE_COUNT, - e_regSetWordSizeVEC = PPC_VECTOR_STATE_COUNT - } RegisterSetWordSize; - - enum - { - Read = 0, - Write = 1, - kNumErrors = 2 - }; - - struct State - { - ppc_thread_state_t gpr; - ppc_float_state_t fpr; - ppc_exception_state_t exc; - ppc_vector_state_t vec; - kern_return_t gpr_errs[2]; // Read/Write errors - kern_return_t fpr_errs[2]; // Read/Write errors - kern_return_t exc_errs[2]; // Read/Write errors - kern_return_t vec_errs[2]; // Read/Write errors - - State() - { - uint32_t i; - for (i=0; i<kNumErrors; i++) - { - gpr_errs[i] = -1; - fpr_errs[i] = -1; - exc_errs[i] = -1; - vec_errs[i] = -1; - } - } - void InvalidateAllRegisterStates() - { - SetError (e_regSetALL, Read, -1); - } - kern_return_t GetError (int set, uint32_t err_idx) const - { - if (err_idx < kNumErrors) - { - switch (set) - { - // When getting all errors, just OR all values together to see if - // we got any kind of error. - case e_regSetALL: return gpr_errs[err_idx] | fpr_errs[err_idx] | exc_errs[err_idx] | vec_errs[err_idx]; - case e_regSetGPR: return gpr_errs[err_idx]; - case e_regSetFPR: return fpr_errs[err_idx]; - case e_regSetEXC: return exc_errs[err_idx]; - case e_regSetVEC: return vec_errs[err_idx]; - default: break; - } - } - return -1; - } - bool SetError (int set, uint32_t err_idx, kern_return_t err) - { - if (err_idx < kNumErrors) - { - switch (set) - { - case e_regSetALL: - gpr_errs[err_idx] = fpr_errs[err_idx] = exc_errs[err_idx] = vec_errs[err_idx] = err; - return true; - - case e_regSetGPR: - gpr_errs[err_idx] = err; - return true; - - case e_regSetFPR: - fpr_errs[err_idx] = err; - return true; - - case e_regSetEXC: - exc_errs[err_idx] = err; - return true; - - case e_regSetVEC: - vec_errs[err_idx] = err; - return true; - - default: break; - } - } - return false; + kern_return_t EnableHardwareSingleStep(bool enable); + + typedef enum RegisterSetTag { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, + e_regSetFPR, + e_regSetEXC, + e_regSetVEC, + kNumRegisterSets + } RegisterSet; + + typedef enum RegisterSetWordSizeTag { + e_regSetWordSizeGPR = PPC_THREAD_STATE_COUNT, + e_regSetWordSizeFPR = PPC_FLOAT_STATE_COUNT, + e_regSetWordSizeEXC = PPC_EXCEPTION_STATE_COUNT, + e_regSetWordSizeVEC = PPC_VECTOR_STATE_COUNT + } RegisterSetWordSize; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + struct State { + ppc_thread_state_t gpr; + ppc_float_state_t fpr; + ppc_exception_state_t exc; + ppc_vector_state_t vec; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t fpr_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t vec_errs[2]; // Read/Write errors + + State() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + fpr_errs[i] = -1; + exc_errs[i] = -1; + vec_errs[i] = -1; + } + } + void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); } + kern_return_t GetError(int set, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (set) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case e_regSetALL: + return gpr_errs[err_idx] | fpr_errs[err_idx] | exc_errs[err_idx] | + vec_errs[err_idx]; + case e_regSetGPR: + return gpr_errs[err_idx]; + case e_regSetFPR: + return fpr_errs[err_idx]; + case e_regSetEXC: + return exc_errs[err_idx]; + case e_regSetVEC: + return vec_errs[err_idx]; + default: + break; } - bool RegsAreValid (int set) const - { - return GetError(set, Read) == KERN_SUCCESS; + } + return -1; + } + bool SetError(int set, uint32_t err_idx, kern_return_t err) { + if (err_idx < kNumErrors) { + switch (set) { + case e_regSetALL: + gpr_errs[err_idx] = fpr_errs[err_idx] = exc_errs[err_idx] = + vec_errs[err_idx] = err; + return true; + + case e_regSetGPR: + gpr_errs[err_idx] = err; + return true; + + case e_regSetFPR: + fpr_errs[err_idx] = err; + return true; + + case e_regSetEXC: + exc_errs[err_idx] = err; + return true; + + case e_regSetVEC: + vec_errs[err_idx] = err; + return true; + + default: + break; } - }; + } + return false; + } + bool RegsAreValid(int set) const { + return GetError(set, Read) == KERN_SUCCESS; + } + }; - kern_return_t GetGPRState (bool force); - kern_return_t GetFPRState (bool force); - kern_return_t GetEXCState (bool force); - kern_return_t GetVECState (bool force); + kern_return_t GetGPRState(bool force); + kern_return_t GetFPRState(bool force); + kern_return_t GetEXCState(bool force); + kern_return_t GetVECState(bool force); - kern_return_t SetGPRState (); - kern_return_t SetFPRState (); - kern_return_t SetEXCState (); - kern_return_t SetVECState (); + kern_return_t SetGPRState(); + kern_return_t SetFPRState(); + kern_return_t SetEXCState(); + kern_return_t SetVECState(); protected: - MachThread * m_thread; - State m_state; + MachThread *m_thread; + State m_state; }; -#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) -#endif // #ifndef __DebugNubArchMachPPC_h__ +#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) +#endif // #ifndef __DebugNubArchMachPPC_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/stack_logging.h b/lldb/tools/debugserver/source/MacOSX/stack_logging.h index 5b0a3080349..5209e38a08e 100644 --- a/lldb/tools/debugserver/source/MacOSX/stack_logging.h +++ b/lldb/tools/debugserver/source/MacOSX/stack_logging.h @@ -2,14 +2,14 @@ * Copyright (c) 1999-2007 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -17,7 +17,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_LICENSE_HEADER_END@ */ @@ -26,96 +26,132 @@ #import <malloc/malloc.h> -#define stack_logging_type_free 0 -#define stack_logging_type_generic 1 /* anything that is not allocation/deallocation */ -#define stack_logging_type_alloc 2 /* malloc, realloc, etc... */ -#define stack_logging_type_dealloc 4 /* free, realloc, etc... */ +#define stack_logging_type_free 0 +#define stack_logging_type_generic \ + 1 /* anything that is not allocation/deallocation */ +#define stack_logging_type_alloc 2 /* malloc, realloc, etc... */ +#define stack_logging_type_dealloc 4 /* free, realloc, etc... */ // Following flags are absorbed by stack_logging_log_stack() -#define stack_logging_flag_zone 8 /* NSZoneMalloc, etc... */ -#define stack_logging_flag_calloc 16 /* multiply arguments to get the size */ -#define stack_logging_flag_object 32 /* NSAllocateObject(Class, extraBytes, zone) */ -#define stack_logging_flag_cleared 64 /* for NewEmptyHandle */ -#define stack_logging_flag_handle 128 /* for Handle (de-)allocation routines */ -#define stack_logging_flag_set_handle_size 256 /* (Handle, newSize) treated specially */ +#define stack_logging_flag_zone 8 /* NSZoneMalloc, etc... */ +#define stack_logging_flag_calloc 16 /* multiply arguments to get the size */ +#define stack_logging_flag_object \ + 32 /* NSAllocateObject(Class, extraBytes, zone) */ +#define stack_logging_flag_cleared 64 /* for NewEmptyHandle */ +#define stack_logging_flag_handle 128 /* for Handle (de-)allocation routines \ + */ +#define stack_logging_flag_set_handle_size \ + 256 /* (Handle, newSize) treated specially */ /* Macro used to disguise addresses so that leak finding can work */ -#define STACK_LOGGING_DISGUISE(address) ((address) ^ 0x00005555) /* nicely idempotent */ - -extern "C" int stack_logging_enable_logging; /* when clear, no logging takes place */ -extern "C" int stack_logging_dontcompact; /* default is to compact; when set does not compact alloc/free logs; useful for tracing history */ - - -extern "C" void stack_logging_log_stack(unsigned type, unsigned arg1, unsigned arg2, unsigned arg3, unsigned result, unsigned num_hot_to_skip); -/* This is the old log-to-memory logger, which is now deprecated. It remains for compatibility with performance tools that haven't been updated to disk_stack_logging_log_stack() yet. */ - -extern "C" void __disk_stack_logging_log_stack(uint32_t type_flags, uintptr_t zone_ptr, uintptr_t size, uintptr_t ptr_arg, uintptr_t return_val, uint32_t num_hot_to_skip); -/* Fits as the malloc_logger; logs malloc/free/realloc events and can log custom events if called directly */ - +#define STACK_LOGGING_DISGUISE(address) \ + ((address) ^ 0x00005555) /* nicely idempotent */ + +extern "C" int + stack_logging_enable_logging; /* when clear, no logging takes place */ +extern "C" int stack_logging_dontcompact; /* default is to compact; when set + does not compact alloc/free logs; + useful for tracing history */ + +extern "C" void stack_logging_log_stack(unsigned type, unsigned arg1, + unsigned arg2, unsigned arg3, + unsigned result, + unsigned num_hot_to_skip); +/* This is the old log-to-memory logger, which is now deprecated. It remains + * for compatibility with performance tools that haven't been updated to + * disk_stack_logging_log_stack() yet. */ + +extern "C" void +__disk_stack_logging_log_stack(uint32_t type_flags, uintptr_t zone_ptr, + uintptr_t size, uintptr_t ptr_arg, + uintptr_t return_val, uint32_t num_hot_to_skip); +/* Fits as the malloc_logger; logs malloc/free/realloc events and can log custom + * events if called directly */ /* 64-bit-aware stack log access. */ typedef struct { - uint32_t type_flags; - uint64_t stack_identifier; - uint64_t argument; - mach_vm_address_t address; + uint32_t type_flags; + uint64_t stack_identifier; + uint64_t argument; + mach_vm_address_t address; } mach_stack_logging_record_t; -extern "C" kern_return_t __mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count); +extern "C" kern_return_t +__mach_stack_logging_get_frames(task_t task, mach_vm_address_t address, + mach_vm_address_t *stack_frames_buffer, + uint32_t max_stack_frames, uint32_t *count); /* Gets the last allocation record (malloc, realloc, or free) about address */ -extern "C" kern_return_t __mach_stack_logging_enumerate_records(task_t task, mach_vm_address_t address, void enumerator(mach_stack_logging_record_t, void *), void *context); -/* Applies enumerator to all records involving address sending context as enumerator's second parameter; if !address, applies enumerator to all records */ +extern "C" kern_return_t __mach_stack_logging_enumerate_records( + task_t task, mach_vm_address_t address, + void enumerator(mach_stack_logging_record_t, void *), void *context); +/* Applies enumerator to all records involving address sending context as + * enumerator's second parameter; if !address, applies enumerator to all records + */ -extern "C" kern_return_t __mach_stack_logging_frames_for_uniqued_stack(task_t task, uint64_t stack_identifier, mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, uint32_t *count); +extern "C" kern_return_t __mach_stack_logging_frames_for_uniqued_stack( + task_t task, uint64_t stack_identifier, + mach_vm_address_t *stack_frames_buffer, uint32_t max_stack_frames, + uint32_t *count); /* Given a uniqued_stack fills stack_frames_buffer */ - #pragma mark - #pragma mark Legacy -/* The following is the old 32-bit-only, in-process-memory stack logging. This is deprecated and clients should move to the above 64-bit-aware disk stack logging SPI. */ +/* The following is the old 32-bit-only, in-process-memory stack logging. This + * is deprecated and clients should move to the above 64-bit-aware disk stack + * logging SPI. */ typedef struct { - unsigned type; - unsigned uniqued_stack; - unsigned argument; - unsigned address; /* disguised, to avoid confusing leaks */ + unsigned type; + unsigned uniqued_stack; + unsigned argument; + unsigned address; /* disguised, to avoid confusing leaks */ } stack_logging_record_t; typedef struct { - unsigned overall_num_bytes; - unsigned num_records; - unsigned lock; /* 0 means OK to lock; used for inter-process locking */ - unsigned *uniquing_table; /* allocated using vm_allocate() */ - /* hashtable organized as (PC, uniqued parent) - Only the second half of the table is active - To enable us to grow dynamically */ - unsigned uniquing_table_num_pages; /* number of pages of the table */ - unsigned extra_retain_count; /* not used by stack_logging_log_stack */ - unsigned filler[2]; /* align to cache lines for better performance */ - stack_logging_record_t records[0]; /* records follow here */ + unsigned overall_num_bytes; + unsigned num_records; + unsigned lock; /* 0 means OK to lock; used for inter-process locking */ + unsigned *uniquing_table; /* allocated using vm_allocate() */ + /* hashtable organized as (PC, uniqued parent) + Only the second half of the table is active + To enable us to grow dynamically */ + unsigned uniquing_table_num_pages; /* number of pages of the table */ + unsigned extra_retain_count; /* not used by stack_logging_log_stack */ + unsigned filler[2]; /* align to cache lines for better performance */ + stack_logging_record_t records[0]; /* records follow here */ } stack_logging_record_list_t; extern "C" stack_logging_record_list_t *stack_logging_the_record_list; /* This is the global variable containing all logs */ -extern "C" kern_return_t stack_logging_get_frames(task_t task, memory_reader_t reader, vm_address_t address, vm_address_t *stack_frames_buffer, unsigned max_stack_frames, unsigned *num_frames); +extern "C" kern_return_t +stack_logging_get_frames(task_t task, memory_reader_t reader, + vm_address_t address, + vm_address_t *stack_frames_buffer, + unsigned max_stack_frames, unsigned *num_frames); /* Gets the last record in stack_logging_the_record_list about address */ -#define STACK_LOGGING_ENUMERATION_PROVIDED 1 // temporary to avoid dependencies between projects +#define STACK_LOGGING_ENUMERATION_PROVIDED \ + 1 // temporary to avoid dependencies between projects -extern "C" kern_return_t stack_logging_enumerate_records(task_t task, memory_reader_t reader, vm_address_t address, void enumerator(stack_logging_record_t, void *), void *context); +extern "C" kern_return_t stack_logging_enumerate_records( + task_t task, memory_reader_t reader, vm_address_t address, + void enumerator(stack_logging_record_t, void *), void *context); /* Gets all the records about address; If !address, gets all records */ -extern "C" kern_return_t stack_logging_frames_for_uniqued_stack(task_t task, memory_reader_t reader, unsigned uniqued_stack, vm_address_t *stack_frames_buffer, unsigned max_stack_frames, unsigned *num_frames); +extern "C" kern_return_t stack_logging_frames_for_uniqued_stack( + task_t task, memory_reader_t reader, unsigned uniqued_stack, + vm_address_t *stack_frames_buffer, unsigned max_stack_frames, + unsigned *num_frames); /* Given a uniqued_stack fills stack_frames_buffer */ - - -extern "C" void thread_stack_pcs(vm_address_t *buffer, unsigned max, unsigned *num); -/* Convenience to fill buffer with the PCs of the frames, starting with the hot frames; +extern "C" void thread_stack_pcs(vm_address_t *buffer, unsigned max, + unsigned *num); +/* Convenience to fill buffer with the PCs of the frames, starting with the hot + frames; num: returned number of frames */ diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp index 3d2805cddb9..b8d35fe2f7c 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.cpp @@ -11,54 +11,46 @@ // //===----------------------------------------------------------------------===// -#if defined (__i386__) || defined (__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include <sys/cdefs.h> -#include <sys/types.h> #include <sys/sysctl.h> +#include <sys/types.h> -#include "MacOSX/x86_64/DNBArchImplX86_64.h" #include "../HasAVX.h" #include "DNBLog.h" -#include "MachThread.h" +#include "MacOSX/x86_64/DNBArchImplX86_64.h" #include "MachProcess.h" +#include "MachThread.h" #include <mach/mach.h> #include <stdlib.h> -#if defined (LLDB_DEBUGSERVER_RELEASE) || defined (LLDB_DEBUGSERVER_DEBUG) -enum debugState { - debugStateUnknown, - debugStateOff, - debugStateOn -}; +#if defined(LLDB_DEBUGSERVER_RELEASE) || defined(LLDB_DEBUGSERVER_DEBUG) +enum debugState { debugStateUnknown, debugStateOff, debugStateOn }; static debugState sFPUDebugState = debugStateUnknown; static debugState sAVXForceState = debugStateUnknown; -static bool DebugFPURegs () -{ - if (sFPUDebugState == debugStateUnknown) - { - if (getenv("DNB_DEBUG_FPU_REGS")) - sFPUDebugState = debugStateOn; - else - sFPUDebugState = debugStateOff; - } - - return (sFPUDebugState == debugStateOn); +static bool DebugFPURegs() { + if (sFPUDebugState == debugStateUnknown) { + if (getenv("DNB_DEBUG_FPU_REGS")) + sFPUDebugState = debugStateOn; + else + sFPUDebugState = debugStateOff; + } + + return (sFPUDebugState == debugStateOn); } -static bool ForceAVXRegs () -{ - if (sFPUDebugState == debugStateUnknown) - { - if (getenv("DNB_DEBUG_X86_FORCE_AVX_REGS")) - sAVXForceState = debugStateOn; - else - sAVXForceState = debugStateOff; - } - - return (sAVXForceState == debugStateOn); +static bool ForceAVXRegs() { + if (sFPUDebugState == debugStateUnknown) { + if (getenv("DNB_DEBUG_X86_FORCE_AVX_REGS")) + sAVXForceState = debugStateOn; + else + sAVXForceState = debugStateOff; + } + + return (sAVXForceState == debugStateOn); } #define DEBUG_FPU_REGS (DebugFPURegs()) @@ -68,2222 +60,2501 @@ static bool ForceAVXRegs () #define FORCE_AVX_REGS (0) #endif - -extern "C" bool -CPUHasAVX() -{ - enum AVXPresence - { - eAVXUnknown = -1, - eAVXNotPresent = 0, - eAVXPresent = 1 - }; - - static AVXPresence g_has_avx = eAVXUnknown; - if (g_has_avx == eAVXUnknown) - { - g_has_avx = eAVXNotPresent; - - // Only xnu-2020 or later has AVX support, any versions before - // this have a busted thread_get_state RPC where it would truncate - // the thread state buffer (<rdar://problem/10122874>). So we need to - // verify the kernel version number manually or disable AVX support. - int mib[2]; - char buffer[1024]; - size_t length = sizeof(buffer); - uint64_t xnu_version = 0; - mib[0] = CTL_KERN; - mib[1] = KERN_VERSION; - int err = ::sysctl(mib, 2, &buffer, &length, NULL, 0); - if (err == 0) - { - const char *xnu = strstr (buffer, "xnu-"); - if (xnu) - { - const char *xnu_version_cstr = xnu + 4; - xnu_version = strtoull (xnu_version_cstr, NULL, 0); - if (xnu_version >= 2020 && xnu_version != ULLONG_MAX) - { - if (::HasAVX()) - { - g_has_avx = eAVXPresent; - } - } - } +extern "C" bool CPUHasAVX() { + enum AVXPresence { eAVXUnknown = -1, eAVXNotPresent = 0, eAVXPresent = 1 }; + + static AVXPresence g_has_avx = eAVXUnknown; + if (g_has_avx == eAVXUnknown) { + g_has_avx = eAVXNotPresent; + + // Only xnu-2020 or later has AVX support, any versions before + // this have a busted thread_get_state RPC where it would truncate + // the thread state buffer (<rdar://problem/10122874>). So we need to + // verify the kernel version number manually or disable AVX support. + int mib[2]; + char buffer[1024]; + size_t length = sizeof(buffer); + uint64_t xnu_version = 0; + mib[0] = CTL_KERN; + mib[1] = KERN_VERSION; + int err = ::sysctl(mib, 2, &buffer, &length, NULL, 0); + if (err == 0) { + const char *xnu = strstr(buffer, "xnu-"); + if (xnu) { + const char *xnu_version_cstr = xnu + 4; + xnu_version = strtoull(xnu_version_cstr, NULL, 0); + if (xnu_version >= 2020 && xnu_version != ULLONG_MAX) { + if (::HasAVX()) { + g_has_avx = eAVXPresent; + } } - DNBLogThreadedIf (LOG_THREAD, "CPUHasAVX(): g_has_avx = %i (err = %i, errno = %i, xnu_version = %llu)", g_has_avx, err, errno, xnu_version); + } } - - return (g_has_avx == eAVXPresent); + DNBLogThreadedIf(LOG_THREAD, "CPUHasAVX(): g_has_avx = %i (err = %i, errno " + "= %i, xnu_version = %llu)", + g_has_avx, err, errno, xnu_version); + } + + return (g_has_avx == eAVXPresent); } -uint64_t -DNBArchImplX86_64::GetPC(uint64_t failValue) -{ - // Get program counter - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__rip; - return failValue; +uint64_t DNBArchImplX86_64::GetPC(uint64_t failValue) { + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__rip; + return failValue; } -kern_return_t -DNBArchImplX86_64::SetPC(uint64_t value) -{ - // Get program counter - kern_return_t err = GetGPRState(false); - if (err == KERN_SUCCESS) - { - m_state.context.gpr.__rip = value; - err = SetGPRState(); - } - return err == KERN_SUCCESS; +kern_return_t DNBArchImplX86_64::SetPC(uint64_t value) { + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) { + m_state.context.gpr.__rip = value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; } -uint64_t -DNBArchImplX86_64::GetSP(uint64_t failValue) -{ - // Get stack pointer - if (GetGPRState(false) == KERN_SUCCESS) - return m_state.context.gpr.__rsp; - return failValue; +uint64_t DNBArchImplX86_64::GetSP(uint64_t failValue) { + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.context.gpr.__rsp; + return failValue; } // Uncomment the value below to verify the values in the debugger. //#define DEBUG_GPR_VALUES 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED -kern_return_t -DNBArchImplX86_64::GetGPRState(bool force) -{ - if (force || m_state.GetError(e_regSetGPR, Read)) - { +kern_return_t DNBArchImplX86_64::GetGPRState(bool force) { + if (force || m_state.GetError(e_regSetGPR, Read)) { #if DEBUG_GPR_VALUES - m_state.context.gpr.__rax = ('a' << 8) + 'x'; - m_state.context.gpr.__rbx = ('b' << 8) + 'x'; - m_state.context.gpr.__rcx = ('c' << 8) + 'x'; - m_state.context.gpr.__rdx = ('d' << 8) + 'x'; - m_state.context.gpr.__rdi = ('d' << 8) + 'i'; - m_state.context.gpr.__rsi = ('s' << 8) + 'i'; - m_state.context.gpr.__rbp = ('b' << 8) + 'p'; - m_state.context.gpr.__rsp = ('s' << 8) + 'p'; - m_state.context.gpr.__r8 = ('r' << 8) + '8'; - m_state.context.gpr.__r9 = ('r' << 8) + '9'; - m_state.context.gpr.__r10 = ('r' << 8) + 'a'; - m_state.context.gpr.__r11 = ('r' << 8) + 'b'; - m_state.context.gpr.__r12 = ('r' << 8) + 'c'; - m_state.context.gpr.__r13 = ('r' << 8) + 'd'; - m_state.context.gpr.__r14 = ('r' << 8) + 'e'; - m_state.context.gpr.__r15 = ('r' << 8) + 'f'; - m_state.context.gpr.__rip = ('i' << 8) + 'p'; - m_state.context.gpr.__rflags = ('f' << 8) + 'l'; - m_state.context.gpr.__cs = ('c' << 8) + 's'; - m_state.context.gpr.__fs = ('f' << 8) + 's'; - m_state.context.gpr.__gs = ('g' << 8) + 's'; - m_state.SetError(e_regSetGPR, Read, 0); + m_state.context.gpr.__rax = ('a' << 8) + 'x'; + m_state.context.gpr.__rbx = ('b' << 8) + 'x'; + m_state.context.gpr.__rcx = ('c' << 8) + 'x'; + m_state.context.gpr.__rdx = ('d' << 8) + 'x'; + m_state.context.gpr.__rdi = ('d' << 8) + 'i'; + m_state.context.gpr.__rsi = ('s' << 8) + 'i'; + m_state.context.gpr.__rbp = ('b' << 8) + 'p'; + m_state.context.gpr.__rsp = ('s' << 8) + 'p'; + m_state.context.gpr.__r8 = ('r' << 8) + '8'; + m_state.context.gpr.__r9 = ('r' << 8) + '9'; + m_state.context.gpr.__r10 = ('r' << 8) + 'a'; + m_state.context.gpr.__r11 = ('r' << 8) + 'b'; + m_state.context.gpr.__r12 = ('r' << 8) + 'c'; + m_state.context.gpr.__r13 = ('r' << 8) + 'd'; + m_state.context.gpr.__r14 = ('r' << 8) + 'e'; + m_state.context.gpr.__r15 = ('r' << 8) + 'f'; + m_state.context.gpr.__rip = ('i' << 8) + 'p'; + m_state.context.gpr.__rflags = ('f' << 8) + 'l'; + m_state.context.gpr.__cs = ('c' << 8) + 's'; + m_state.context.gpr.__fs = ('f' << 8) + 's'; + m_state.context.gpr.__gs = ('g' << 8) + 's'; + m_state.SetError(e_regSetGPR, Read, 0); #else - mach_msg_type_number_t count = e_regSetWordSizeGPR; - m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE, (thread_state_t)&m_state.context.gpr, &count)); - DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x" - "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx" - "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx" - "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx" - "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx" - "\n\trip = %16.16llx" - "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx", - m_thread->MachPortNumber(), x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT, - m_state.GetError(e_regSetGPR, Read), - m_state.context.gpr.__rax,m_state.context.gpr.__rbx,m_state.context.gpr.__rcx, - m_state.context.gpr.__rdx,m_state.context.gpr.__rdi,m_state.context.gpr.__rsi, - m_state.context.gpr.__rbp,m_state.context.gpr.__rsp,m_state.context.gpr.__r8, - m_state.context.gpr.__r9, m_state.context.gpr.__r10,m_state.context.gpr.__r11, - m_state.context.gpr.__r12,m_state.context.gpr.__r13,m_state.context.gpr.__r14, - m_state.context.gpr.__r15,m_state.context.gpr.__rip,m_state.context.gpr.__rflags, - m_state.context.gpr.__cs,m_state.context.gpr.__fs, m_state.context.gpr.__gs); - - // DNBLogThreadedIf (LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) => 0x%8.8x" - // "\n\trax = %16.16llx" - // "\n\trbx = %16.16llx" - // "\n\trcx = %16.16llx" - // "\n\trdx = %16.16llx" - // "\n\trdi = %16.16llx" - // "\n\trsi = %16.16llx" - // "\n\trbp = %16.16llx" - // "\n\trsp = %16.16llx" - // "\n\t r8 = %16.16llx" - // "\n\t r9 = %16.16llx" - // "\n\tr10 = %16.16llx" - // "\n\tr11 = %16.16llx" - // "\n\tr12 = %16.16llx" - // "\n\tr13 = %16.16llx" - // "\n\tr14 = %16.16llx" - // "\n\tr15 = %16.16llx" - // "\n\trip = %16.16llx" - // "\n\tflg = %16.16llx" - // "\n\t cs = %16.16llx" - // "\n\t fs = %16.16llx" - // "\n\t gs = %16.16llx", - // m_thread->MachPortNumber(), - // x86_THREAD_STATE64, - // x86_THREAD_STATE64_COUNT, - // m_state.GetError(e_regSetGPR, Read), - // m_state.context.gpr.__rax, - // m_state.context.gpr.__rbx, - // m_state.context.gpr.__rcx, - // m_state.context.gpr.__rdx, - // m_state.context.gpr.__rdi, - // m_state.context.gpr.__rsi, - // m_state.context.gpr.__rbp, - // m_state.context.gpr.__rsp, - // m_state.context.gpr.__r8, - // m_state.context.gpr.__r9, - // m_state.context.gpr.__r10, - // m_state.context.gpr.__r11, - // m_state.context.gpr.__r12, - // m_state.context.gpr.__r13, - // m_state.context.gpr.__r14, - // m_state.context.gpr.__r15, - // m_state.context.gpr.__rip, - // m_state.context.gpr.__rflags, - // m_state.context.gpr.__cs, - // m_state.context.gpr.__fs, - // m_state.context.gpr.__gs); + mach_msg_type_number_t count = e_regSetWordSizeGPR; + m_state.SetError( + e_regSetGPR, Read, + ::thread_get_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, &count)); + DNBLogThreadedIf( + LOG_THREAD, + "::thread_get_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x" + "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx" + "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx" + "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx" + "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx" + "\n\trip = %16.16llx" + "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx", + m_thread->MachPortNumber(), x86_THREAD_STATE64, + x86_THREAD_STATE64_COUNT, m_state.GetError(e_regSetGPR, Read), + m_state.context.gpr.__rax, m_state.context.gpr.__rbx, + m_state.context.gpr.__rcx, m_state.context.gpr.__rdx, + m_state.context.gpr.__rdi, m_state.context.gpr.__rsi, + m_state.context.gpr.__rbp, m_state.context.gpr.__rsp, + m_state.context.gpr.__r8, m_state.context.gpr.__r9, + m_state.context.gpr.__r10, m_state.context.gpr.__r11, + m_state.context.gpr.__r12, m_state.context.gpr.__r13, + m_state.context.gpr.__r14, m_state.context.gpr.__r15, + m_state.context.gpr.__rip, m_state.context.gpr.__rflags, + m_state.context.gpr.__cs, m_state.context.gpr.__fs, + m_state.context.gpr.__gs); + +// DNBLogThreadedIf (LOG_THREAD, "thread_get_state(0x%4.4x, %u, &gpr, %u) +// => 0x%8.8x" +// "\n\trax = %16.16llx" +// "\n\trbx = %16.16llx" +// "\n\trcx = %16.16llx" +// "\n\trdx = %16.16llx" +// "\n\trdi = %16.16llx" +// "\n\trsi = %16.16llx" +// "\n\trbp = %16.16llx" +// "\n\trsp = %16.16llx" +// "\n\t r8 = %16.16llx" +// "\n\t r9 = %16.16llx" +// "\n\tr10 = %16.16llx" +// "\n\tr11 = %16.16llx" +// "\n\tr12 = %16.16llx" +// "\n\tr13 = %16.16llx" +// "\n\tr14 = %16.16llx" +// "\n\tr15 = %16.16llx" +// "\n\trip = %16.16llx" +// "\n\tflg = %16.16llx" +// "\n\t cs = %16.16llx" +// "\n\t fs = %16.16llx" +// "\n\t gs = %16.16llx", +// m_thread->MachPortNumber(), +// x86_THREAD_STATE64, +// x86_THREAD_STATE64_COUNT, +// m_state.GetError(e_regSetGPR, Read), +// m_state.context.gpr.__rax, +// m_state.context.gpr.__rbx, +// m_state.context.gpr.__rcx, +// m_state.context.gpr.__rdx, +// m_state.context.gpr.__rdi, +// m_state.context.gpr.__rsi, +// m_state.context.gpr.__rbp, +// m_state.context.gpr.__rsp, +// m_state.context.gpr.__r8, +// m_state.context.gpr.__r9, +// m_state.context.gpr.__r10, +// m_state.context.gpr.__r11, +// m_state.context.gpr.__r12, +// m_state.context.gpr.__r13, +// m_state.context.gpr.__r14, +// m_state.context.gpr.__r15, +// m_state.context.gpr.__rip, +// m_state.context.gpr.__rflags, +// m_state.context.gpr.__cs, +// m_state.context.gpr.__fs, +// m_state.context.gpr.__gs); #endif - } - return m_state.GetError(e_regSetGPR, Read); + } + return m_state.GetError(e_regSetGPR, Read); } // Uncomment the value below to verify the values in the debugger. //#define DEBUG_FPU_REGS 1 // DO NOT CHECK IN WITH THIS DEFINE ENABLED -kern_return_t -DNBArchImplX86_64::GetFPUState(bool force) -{ - if (force || m_state.GetError(e_regSetFPU, Read)) - { - if (DEBUG_FPU_REGS) { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - m_state.context.fpu.avx.__fpu_reserved[0] = -1; - m_state.context.fpu.avx.__fpu_reserved[1] = -1; - *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fcw) = 0x1234; - *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fsw) = 0x5678; - m_state.context.fpu.avx.__fpu_ftw = 1; - m_state.context.fpu.avx.__fpu_rsrv1 = UINT8_MAX; - m_state.context.fpu.avx.__fpu_fop = 2; - m_state.context.fpu.avx.__fpu_ip = 3; - m_state.context.fpu.avx.__fpu_cs = 4; - m_state.context.fpu.avx.__fpu_rsrv2 = UINT8_MAX; - m_state.context.fpu.avx.__fpu_dp = 5; - m_state.context.fpu.avx.__fpu_ds = 6; - m_state.context.fpu.avx.__fpu_rsrv3 = UINT16_MAX; - m_state.context.fpu.avx.__fpu_mxcsr = 8; - m_state.context.fpu.avx.__fpu_mxcsrmask = 9; - int i; - for (i=0; i<16; ++i) - { - if (i<10) - { - m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = 'a'; - m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = 'b'; - m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = 'c'; - m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = 'd'; - m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = 'e'; - m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = 'f'; - m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = 'g'; - m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = 'h'; - } - else - { - m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; - } - - m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg[i] = '0' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg[i] = '1' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg[i] = '2' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg[i] = '3' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg[i] = '4' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg[i] = '5' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg[i] = '6' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg[i] = '7' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm8.__xmm_reg[i] = '8' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm9.__xmm_reg[i] = '9' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm10.__xmm_reg[i] = 'A' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm11.__xmm_reg[i] = 'B' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm12.__xmm_reg[i] = 'C' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm13.__xmm_reg[i] = 'D' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm14.__xmm_reg[i] = 'E' + 2 * i; - m_state.context.fpu.avx.__fpu_xmm15.__xmm_reg[i] = 'F' + 2 * i; - - m_state.context.fpu.avx.__fpu_ymmh0.__xmm_reg[i] = '0' + i; - m_state.context.fpu.avx.__fpu_ymmh1.__xmm_reg[i] = '1' + i; - m_state.context.fpu.avx.__fpu_ymmh2.__xmm_reg[i] = '2' + i; - m_state.context.fpu.avx.__fpu_ymmh3.__xmm_reg[i] = '3' + i; - m_state.context.fpu.avx.__fpu_ymmh4.__xmm_reg[i] = '4' + i; - m_state.context.fpu.avx.__fpu_ymmh5.__xmm_reg[i] = '5' + i; - m_state.context.fpu.avx.__fpu_ymmh6.__xmm_reg[i] = '6' + i; - m_state.context.fpu.avx.__fpu_ymmh7.__xmm_reg[i] = '7' + i; - m_state.context.fpu.avx.__fpu_ymmh8.__xmm_reg[i] = '8' + i; - m_state.context.fpu.avx.__fpu_ymmh9.__xmm_reg[i] = '9' + i; - m_state.context.fpu.avx.__fpu_ymmh10.__xmm_reg[i] = 'A' + i; - m_state.context.fpu.avx.__fpu_ymmh11.__xmm_reg[i] = 'B' + i; - m_state.context.fpu.avx.__fpu_ymmh12.__xmm_reg[i] = 'C' + i; - m_state.context.fpu.avx.__fpu_ymmh13.__xmm_reg[i] = 'D' + i; - m_state.context.fpu.avx.__fpu_ymmh14.__xmm_reg[i] = 'E' + i; - m_state.context.fpu.avx.__fpu_ymmh15.__xmm_reg[i] = 'F' + i; - } - for (i=0; i<sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) - m_state.context.fpu.avx.__fpu_rsrv4[i] = INT8_MIN; - m_state.context.fpu.avx.__fpu_reserved1 = -1; - for (i=0; i<sizeof(m_state.context.fpu.avx.__avx_reserved1); ++i) - m_state.context.fpu.avx.__avx_reserved1[i] = INT8_MIN; - m_state.SetError(e_regSetFPU, Read, 0); - } - else - { - m_state.context.fpu.no_avx.__fpu_reserved[0] = -1; - m_state.context.fpu.no_avx.__fpu_reserved[1] = -1; - *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fcw) = 0x1234; - *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fsw) = 0x5678; - m_state.context.fpu.no_avx.__fpu_ftw = 1; - m_state.context.fpu.no_avx.__fpu_rsrv1 = UINT8_MAX; - m_state.context.fpu.no_avx.__fpu_fop = 2; - m_state.context.fpu.no_avx.__fpu_ip = 3; - m_state.context.fpu.no_avx.__fpu_cs = 4; - m_state.context.fpu.no_avx.__fpu_rsrv2 = 5; - m_state.context.fpu.no_avx.__fpu_dp = 6; - m_state.context.fpu.no_avx.__fpu_ds = 7; - m_state.context.fpu.no_avx.__fpu_rsrv3 = UINT16_MAX; - m_state.context.fpu.no_avx.__fpu_mxcsr = 8; - m_state.context.fpu.no_avx.__fpu_mxcsrmask = 9; - int i; - for (i=0; i<16; ++i) - { - if (i<10) - { - m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = 'a'; - m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = 'b'; - m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = 'c'; - m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = 'd'; - m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = 'e'; - m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = 'f'; - m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = 'g'; - m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = 'h'; - } - else - { - m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; - } - - m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg[i] = '0'; - m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg[i] = '1'; - m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg[i] = '2'; - m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg[i] = '3'; - m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg[i] = '4'; - m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg[i] = '5'; - m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg[i] = '6'; - m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg[i] = '7'; - m_state.context.fpu.no_avx.__fpu_xmm8.__xmm_reg[i] = '8'; - m_state.context.fpu.no_avx.__fpu_xmm9.__xmm_reg[i] = '9'; - m_state.context.fpu.no_avx.__fpu_xmm10.__xmm_reg[i] = 'A'; - m_state.context.fpu.no_avx.__fpu_xmm11.__xmm_reg[i] = 'B'; - m_state.context.fpu.no_avx.__fpu_xmm12.__xmm_reg[i] = 'C'; - m_state.context.fpu.no_avx.__fpu_xmm13.__xmm_reg[i] = 'D'; - m_state.context.fpu.no_avx.__fpu_xmm14.__xmm_reg[i] = 'E'; - m_state.context.fpu.no_avx.__fpu_xmm15.__xmm_reg[i] = 'F'; - } - for (i=0; i<sizeof(m_state.context.fpu.no_avx.__fpu_rsrv4); ++i) - m_state.context.fpu.no_avx.__fpu_rsrv4[i] = INT8_MIN; - m_state.context.fpu.no_avx.__fpu_reserved1 = -1; - m_state.SetError(e_regSetFPU, Read, 0); - } +kern_return_t DNBArchImplX86_64::GetFPUState(bool force) { + if (force || m_state.GetError(e_regSetFPU, Read)) { + if (DEBUG_FPU_REGS) { + if (CPUHasAVX() || FORCE_AVX_REGS) { + m_state.context.fpu.avx.__fpu_reserved[0] = -1; + m_state.context.fpu.avx.__fpu_reserved[1] = -1; + *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fcw) = 0x1234; + *(uint16_t *)&(m_state.context.fpu.avx.__fpu_fsw) = 0x5678; + m_state.context.fpu.avx.__fpu_ftw = 1; + m_state.context.fpu.avx.__fpu_rsrv1 = UINT8_MAX; + m_state.context.fpu.avx.__fpu_fop = 2; + m_state.context.fpu.avx.__fpu_ip = 3; + m_state.context.fpu.avx.__fpu_cs = 4; + m_state.context.fpu.avx.__fpu_rsrv2 = UINT8_MAX; + m_state.context.fpu.avx.__fpu_dp = 5; + m_state.context.fpu.avx.__fpu_ds = 6; + m_state.context.fpu.avx.__fpu_rsrv3 = UINT16_MAX; + m_state.context.fpu.avx.__fpu_mxcsr = 8; + m_state.context.fpu.avx.__fpu_mxcsrmask = 9; + int i; + for (i = 0; i < 16; ++i) { + if (i < 10) { + m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = 'a'; + m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = 'b'; + m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = 'c'; + m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = 'd'; + m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = 'e'; + m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = 'f'; + m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = 'g'; + m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = 'h'; + } else { + m_state.context.fpu.avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; + } + + m_state.context.fpu.avx.__fpu_xmm0.__xmm_reg[i] = '0' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm1.__xmm_reg[i] = '1' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm2.__xmm_reg[i] = '2' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm3.__xmm_reg[i] = '3' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm4.__xmm_reg[i] = '4' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm5.__xmm_reg[i] = '5' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm6.__xmm_reg[i] = '6' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm7.__xmm_reg[i] = '7' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm8.__xmm_reg[i] = '8' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm9.__xmm_reg[i] = '9' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm10.__xmm_reg[i] = 'A' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm11.__xmm_reg[i] = 'B' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm12.__xmm_reg[i] = 'C' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm13.__xmm_reg[i] = 'D' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm14.__xmm_reg[i] = 'E' + 2 * i; + m_state.context.fpu.avx.__fpu_xmm15.__xmm_reg[i] = 'F' + 2 * i; + + m_state.context.fpu.avx.__fpu_ymmh0.__xmm_reg[i] = '0' + i; + m_state.context.fpu.avx.__fpu_ymmh1.__xmm_reg[i] = '1' + i; + m_state.context.fpu.avx.__fpu_ymmh2.__xmm_reg[i] = '2' + i; + m_state.context.fpu.avx.__fpu_ymmh3.__xmm_reg[i] = '3' + i; + m_state.context.fpu.avx.__fpu_ymmh4.__xmm_reg[i] = '4' + i; + m_state.context.fpu.avx.__fpu_ymmh5.__xmm_reg[i] = '5' + i; + m_state.context.fpu.avx.__fpu_ymmh6.__xmm_reg[i] = '6' + i; + m_state.context.fpu.avx.__fpu_ymmh7.__xmm_reg[i] = '7' + i; + m_state.context.fpu.avx.__fpu_ymmh8.__xmm_reg[i] = '8' + i; + m_state.context.fpu.avx.__fpu_ymmh9.__xmm_reg[i] = '9' + i; + m_state.context.fpu.avx.__fpu_ymmh10.__xmm_reg[i] = 'A' + i; + m_state.context.fpu.avx.__fpu_ymmh11.__xmm_reg[i] = 'B' + i; + m_state.context.fpu.avx.__fpu_ymmh12.__xmm_reg[i] = 'C' + i; + m_state.context.fpu.avx.__fpu_ymmh13.__xmm_reg[i] = 'D' + i; + m_state.context.fpu.avx.__fpu_ymmh14.__xmm_reg[i] = 'E' + i; + m_state.context.fpu.avx.__fpu_ymmh15.__xmm_reg[i] = 'F' + i; + } + for (i = 0; i < sizeof(m_state.context.fpu.avx.__fpu_rsrv4); ++i) + m_state.context.fpu.avx.__fpu_rsrv4[i] = INT8_MIN; + m_state.context.fpu.avx.__fpu_reserved1 = -1; + for (i = 0; i < sizeof(m_state.context.fpu.avx.__avx_reserved1); ++i) + m_state.context.fpu.avx.__avx_reserved1[i] = INT8_MIN; + m_state.SetError(e_regSetFPU, Read, 0); + } else { + m_state.context.fpu.no_avx.__fpu_reserved[0] = -1; + m_state.context.fpu.no_avx.__fpu_reserved[1] = -1; + *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fcw) = 0x1234; + *(uint16_t *)&(m_state.context.fpu.no_avx.__fpu_fsw) = 0x5678; + m_state.context.fpu.no_avx.__fpu_ftw = 1; + m_state.context.fpu.no_avx.__fpu_rsrv1 = UINT8_MAX; + m_state.context.fpu.no_avx.__fpu_fop = 2; + m_state.context.fpu.no_avx.__fpu_ip = 3; + m_state.context.fpu.no_avx.__fpu_cs = 4; + m_state.context.fpu.no_avx.__fpu_rsrv2 = 5; + m_state.context.fpu.no_avx.__fpu_dp = 6; + m_state.context.fpu.no_avx.__fpu_ds = 7; + m_state.context.fpu.no_avx.__fpu_rsrv3 = UINT16_MAX; + m_state.context.fpu.no_avx.__fpu_mxcsr = 8; + m_state.context.fpu.no_avx.__fpu_mxcsrmask = 9; + int i; + for (i = 0; i < 16; ++i) { + if (i < 10) { + m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = 'a'; + m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = 'b'; + m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = 'c'; + m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = 'd'; + m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = 'e'; + m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = 'f'; + m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = 'g'; + m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = 'h'; + } else { + m_state.context.fpu.no_avx.__fpu_stmm0.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm1.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm2.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm3.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm4.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm5.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm6.__mmst_reg[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_stmm7.__mmst_reg[i] = INT8_MIN; + } + + m_state.context.fpu.no_avx.__fpu_xmm0.__xmm_reg[i] = '0'; + m_state.context.fpu.no_avx.__fpu_xmm1.__xmm_reg[i] = '1'; + m_state.context.fpu.no_avx.__fpu_xmm2.__xmm_reg[i] = '2'; + m_state.context.fpu.no_avx.__fpu_xmm3.__xmm_reg[i] = '3'; + m_state.context.fpu.no_avx.__fpu_xmm4.__xmm_reg[i] = '4'; + m_state.context.fpu.no_avx.__fpu_xmm5.__xmm_reg[i] = '5'; + m_state.context.fpu.no_avx.__fpu_xmm6.__xmm_reg[i] = '6'; + m_state.context.fpu.no_avx.__fpu_xmm7.__xmm_reg[i] = '7'; + m_state.context.fpu.no_avx.__fpu_xmm8.__xmm_reg[i] = '8'; + m_state.context.fpu.no_avx.__fpu_xmm9.__xmm_reg[i] = '9'; + m_state.context.fpu.no_avx.__fpu_xmm10.__xmm_reg[i] = 'A'; + m_state.context.fpu.no_avx.__fpu_xmm11.__xmm_reg[i] = 'B'; + m_state.context.fpu.no_avx.__fpu_xmm12.__xmm_reg[i] = 'C'; + m_state.context.fpu.no_avx.__fpu_xmm13.__xmm_reg[i] = 'D'; + m_state.context.fpu.no_avx.__fpu_xmm14.__xmm_reg[i] = 'E'; + m_state.context.fpu.no_avx.__fpu_xmm15.__xmm_reg[i] = 'F'; } - else - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - mach_msg_type_number_t count = e_regSetWordSizeAVX; - m_state.SetError(e_regSetFPU, Read, ::thread_get_state(m_thread->MachPortNumber(), __x86_64_AVX_STATE, (thread_state_t)&m_state.context.fpu.avx, &count)); - DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &avx, %u (%u passed in) carp) => 0x%8.8x", - m_thread->MachPortNumber(), __x86_64_AVX_STATE, (uint32_t)count, - e_regSetWordSizeAVX, m_state.GetError(e_regSetFPU, Read)); - } - else - { - mach_msg_type_number_t count = e_regSetWordSizeFPU; - m_state.SetError(e_regSetFPU, Read, ::thread_get_state(m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, (thread_state_t)&m_state.context.fpu.no_avx, &count)); - DNBLogThreadedIf (LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &fpu, %u (%u passed in) => 0x%8.8x", - m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, (uint32_t)count, - e_regSetWordSizeFPU, m_state.GetError(e_regSetFPU, Read)); - } - } + for (i = 0; i < sizeof(m_state.context.fpu.no_avx.__fpu_rsrv4); ++i) + m_state.context.fpu.no_avx.__fpu_rsrv4[i] = INT8_MIN; + m_state.context.fpu.no_avx.__fpu_reserved1 = -1; + m_state.SetError(e_regSetFPU, Read, 0); + } + } else { + if (CPUHasAVX() || FORCE_AVX_REGS) { + mach_msg_type_number_t count = e_regSetWordSizeAVX; + m_state.SetError(e_regSetFPU, Read, + ::thread_get_state( + m_thread->MachPortNumber(), __x86_64_AVX_STATE, + (thread_state_t)&m_state.context.fpu.avx, &count)); + DNBLogThreadedIf(LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &avx, " + "%u (%u passed in) carp) => 0x%8.8x", + m_thread->MachPortNumber(), __x86_64_AVX_STATE, + (uint32_t)count, e_regSetWordSizeAVX, + m_state.GetError(e_regSetFPU, Read)); + } else { + mach_msg_type_number_t count = e_regSetWordSizeFPU; + m_state.SetError( + e_regSetFPU, Read, + ::thread_get_state(m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, + (thread_state_t)&m_state.context.fpu.no_avx, + &count)); + DNBLogThreadedIf(LOG_THREAD, "::thread_get_state (0x%4.4x, %u, &fpu, " + "%u (%u passed in) => 0x%8.8x", + m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, + (uint32_t)count, e_regSetWordSizeFPU, + m_state.GetError(e_regSetFPU, Read)); + } } - return m_state.GetError(e_regSetFPU, Read); + } + return m_state.GetError(e_regSetFPU, Read); } -kern_return_t -DNBArchImplX86_64::GetEXCState(bool force) -{ - if (force || m_state.GetError(e_regSetEXC, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeEXC; - m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->MachPortNumber(), __x86_64_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, &count)); - } - return m_state.GetError(e_regSetEXC, Read); +kern_return_t DNBArchImplX86_64::GetEXCState(bool force) { + if (force || m_state.GetError(e_regSetEXC, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeEXC; + m_state.SetError( + e_regSetEXC, Read, + ::thread_get_state(m_thread->MachPortNumber(), __x86_64_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, &count)); + } + return m_state.GetError(e_regSetEXC, Read); } -kern_return_t -DNBArchImplX86_64::SetGPRState() -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); - - m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_THREAD_STATE, (thread_state_t)&m_state.context.gpr, e_regSetWordSizeGPR)); - DNBLogThreadedIf (LOG_THREAD, "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x" - "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx" - "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx" - "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx" - "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx" - "\n\trip = %16.16llx" - "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx", - m_thread->MachPortNumber(), __x86_64_THREAD_STATE, e_regSetWordSizeGPR, - m_state.GetError(e_regSetGPR, Write), - m_state.context.gpr.__rax,m_state.context.gpr.__rbx,m_state.context.gpr.__rcx, - m_state.context.gpr.__rdx,m_state.context.gpr.__rdi,m_state.context.gpr.__rsi, - m_state.context.gpr.__rbp,m_state.context.gpr.__rsp,m_state.context.gpr.__r8, - m_state.context.gpr.__r9, m_state.context.gpr.__r10,m_state.context.gpr.__r11, - m_state.context.gpr.__r12,m_state.context.gpr.__r13,m_state.context.gpr.__r14, - m_state.context.gpr.__r15,m_state.context.gpr.__rip,m_state.context.gpr.__rflags, - m_state.context.gpr.__cs, m_state.context.gpr.__fs, m_state.context.gpr.__gs); - return m_state.GetError(e_regSetGPR, Write); +kern_return_t DNBArchImplX86_64::SetGPRState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + m_state.SetError(e_regSetGPR, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __x86_64_THREAD_STATE, + (thread_state_t)&m_state.context.gpr, + e_regSetWordSizeGPR)); + DNBLogThreadedIf( + LOG_THREAD, + "::thread_set_state (0x%4.4x, %u, &gpr, %u) => 0x%8.8x" + "\n\trax = %16.16llx rbx = %16.16llx rcx = %16.16llx rdx = %16.16llx" + "\n\trdi = %16.16llx rsi = %16.16llx rbp = %16.16llx rsp = %16.16llx" + "\n\t r8 = %16.16llx r9 = %16.16llx r10 = %16.16llx r11 = %16.16llx" + "\n\tr12 = %16.16llx r13 = %16.16llx r14 = %16.16llx r15 = %16.16llx" + "\n\trip = %16.16llx" + "\n\tflg = %16.16llx cs = %16.16llx fs = %16.16llx gs = %16.16llx", + m_thread->MachPortNumber(), __x86_64_THREAD_STATE, e_regSetWordSizeGPR, + m_state.GetError(e_regSetGPR, Write), m_state.context.gpr.__rax, + m_state.context.gpr.__rbx, m_state.context.gpr.__rcx, + m_state.context.gpr.__rdx, m_state.context.gpr.__rdi, + m_state.context.gpr.__rsi, m_state.context.gpr.__rbp, + m_state.context.gpr.__rsp, m_state.context.gpr.__r8, + m_state.context.gpr.__r9, m_state.context.gpr.__r10, + m_state.context.gpr.__r11, m_state.context.gpr.__r12, + m_state.context.gpr.__r13, m_state.context.gpr.__r14, + m_state.context.gpr.__r15, m_state.context.gpr.__rip, + m_state.context.gpr.__rflags, m_state.context.gpr.__cs, + m_state.context.gpr.__fs, m_state.context.gpr.__gs); + return m_state.GetError(e_regSetGPR, Write); } -kern_return_t -DNBArchImplX86_64::SetFPUState() -{ - if (DEBUG_FPU_REGS) - { - m_state.SetError(e_regSetFPU, Write, 0); - return m_state.GetError(e_regSetFPU, Write); - } - else - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_AVX_STATE, (thread_state_t)&m_state.context.fpu.avx, e_regSetWordSizeAVX)); - return m_state.GetError(e_regSetFPU, Write); - } - else - { - m_state.SetError(e_regSetFPU, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, (thread_state_t)&m_state.context.fpu.no_avx, e_regSetWordSizeFPU)); - return m_state.GetError(e_regSetFPU, Write); - } +kern_return_t DNBArchImplX86_64::SetFPUState() { + if (DEBUG_FPU_REGS) { + m_state.SetError(e_regSetFPU, Write, 0); + return m_state.GetError(e_regSetFPU, Write); + } else { + if (CPUHasAVX() || FORCE_AVX_REGS) { + m_state.SetError( + e_regSetFPU, Write, + ::thread_set_state(m_thread->MachPortNumber(), __x86_64_AVX_STATE, + (thread_state_t)&m_state.context.fpu.avx, + e_regSetWordSizeAVX)); + return m_state.GetError(e_regSetFPU, Write); + } else { + m_state.SetError( + e_regSetFPU, Write, + ::thread_set_state(m_thread->MachPortNumber(), __x86_64_FLOAT_STATE, + (thread_state_t)&m_state.context.fpu.no_avx, + e_regSetWordSizeFPU)); + return m_state.GetError(e_regSetFPU, Write); } + } } -kern_return_t -DNBArchImplX86_64::SetEXCState() -{ - m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_EXCEPTION_STATE, (thread_state_t)&m_state.context.exc, e_regSetWordSizeEXC)); - return m_state.GetError(e_regSetEXC, Write); +kern_return_t DNBArchImplX86_64::SetEXCState() { + m_state.SetError(e_regSetEXC, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __x86_64_EXCEPTION_STATE, + (thread_state_t)&m_state.context.exc, + e_regSetWordSizeEXC)); + return m_state.GetError(e_regSetEXC, Write); } -kern_return_t -DNBArchImplX86_64::GetDBGState(bool force) -{ - if (force || m_state.GetError(e_regSetDBG, Read)) - { - mach_msg_type_number_t count = e_regSetWordSizeDBG; - m_state.SetError(e_regSetDBG, Read, ::thread_get_state(m_thread->MachPortNumber(), __x86_64_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, &count)); - } - return m_state.GetError(e_regSetDBG, Read); +kern_return_t DNBArchImplX86_64::GetDBGState(bool force) { + if (force || m_state.GetError(e_regSetDBG, Read)) { + mach_msg_type_number_t count = e_regSetWordSizeDBG; + m_state.SetError( + e_regSetDBG, Read, + ::thread_get_state(m_thread->MachPortNumber(), __x86_64_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, &count)); + } + return m_state.GetError(e_regSetDBG, Read); } -kern_return_t -DNBArchImplX86_64::SetDBGState(bool also_set_on_task) -{ - m_state.SetError(e_regSetDBG, Write, ::thread_set_state(m_thread->MachPortNumber(), __x86_64_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG)); - if (also_set_on_task) - { - kern_return_t kret = ::task_set_state(m_thread->Process()->Task().TaskPort(), __x86_64_DEBUG_STATE, (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG); - if (kret != KERN_SUCCESS) - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::SetDBGState failed to set debug control register state: 0x%8.8x.", kret); - } - return m_state.GetError(e_regSetDBG, Write); +kern_return_t DNBArchImplX86_64::SetDBGState(bool also_set_on_task) { + m_state.SetError(e_regSetDBG, Write, + ::thread_set_state(m_thread->MachPortNumber(), + __x86_64_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, + e_regSetWordSizeDBG)); + if (also_set_on_task) { + kern_return_t kret = ::task_set_state( + m_thread->Process()->Task().TaskPort(), __x86_64_DEBUG_STATE, + (thread_state_t)&m_state.context.dbg, e_regSetWordSizeDBG); + if (kret != KERN_SUCCESS) + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::SetDBGState failed " + "to set debug control register state: " + "0x%8.8x.", + kret); + } + return m_state.GetError(e_regSetDBG, Write); } -void -DNBArchImplX86_64::ThreadWillResume() -{ - // Do we need to step this thread? If so, let the mach thread tell us so. - if (m_thread->IsStepping()) - { - // This is the primary thread, let the arch do anything it needs - EnableHardwareSingleStep(true); - } - - // Reset the debug status register, if necessary, before we resume. - kern_return_t kret = GetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret); - if (kret != KERN_SUCCESS) - return; +void DNBArchImplX86_64::ThreadWillResume() { + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) { + // This is the primary thread, let the arch do anything it needs + EnableHardwareSingleStep(true); + } + + // Reset the debug status register, if necessary, before we resume. + kern_return_t kret = GetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplX86_64::ThreadWillResume() GetDBGState() => 0x%8.8x.", kret); + if (kret != KERN_SUCCESS) + return; - DBG &debug_state = m_state.context.dbg; - bool need_reset = false; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - if (IsWatchpointHit(debug_state, i)) - need_reset = true; - - if (need_reset) - { - ClearWatchpointHits(debug_state); - kret = SetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::ThreadWillResume() SetDBGState() => 0x%8.8x.", kret); - } + DBG &debug_state = m_state.context.dbg; + bool need_reset = false; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) + if (IsWatchpointHit(debug_state, i)) + need_reset = true; + + if (need_reset) { + ClearWatchpointHits(debug_state); + kret = SetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplX86_64::ThreadWillResume() SetDBGState() => 0x%8.8x.", + kret); + } } -bool -DNBArchImplX86_64::ThreadDidStop() -{ - bool success = true; - - m_state.InvalidateAllRegisterStates(); - - // Are we stepping a single instruction? - if (GetGPRState(true) == KERN_SUCCESS) - { - // We are single stepping, was this the primary thread? - if (m_thread->IsStepping()) - { - // This was the primary thread, we need to clear the trace - // bit if so. - success = EnableHardwareSingleStep(false) == KERN_SUCCESS; - } - else - { - // The MachThread will automatically restore the suspend count - // in ThreadDidStop(), so we don't need to do anything here if - // we weren't the primary thread the last time - } +bool DNBArchImplX86_64::ThreadDidStop() { + bool success = true; + + m_state.InvalidateAllRegisterStates(); + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } else { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time } - return success; + } + return success; } -bool -DNBArchImplX86_64::NotifyException(MachException::Data& exc) -{ - switch (exc.exc_type) - { - case EXC_BAD_ACCESS: - break; - case EXC_BAD_INSTRUCTION: - break; - case EXC_ARITHMETIC: - break; - case EXC_EMULATION: - break; - case EXC_SOFTWARE: - break; - case EXC_BREAKPOINT: - if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2) - { - // exc_code = EXC_I386_BPT - // - nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); - if (pc != INVALID_NUB_ADDRESS && pc > 0) - { - pc -= 1; - // Check for a breakpoint at one byte prior to the current PC value - // since the PC will be just past the trap. - - DNBBreakpoint *bp = m_thread->Process()->Breakpoints().FindByAddress(pc); - if (bp) - { - // Backup the PC for i386 since the trap was taken and the PC - // is at the address following the single byte trap instruction. - if (m_state.context.gpr.__rip > 0) - { - m_state.context.gpr.__rip = pc; - // Write the new PC back out - SetGPRState (); - } - } - return true; - } - } - else if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1) - { - // exc_code = EXC_I386_SGL - // - // Check whether this corresponds to a watchpoint hit event. - // If yes, set the exc_sub_code to the data break address. - nub_addr_t addr = 0; - uint32_t hw_index = GetHardwareWatchpointHit(addr); - if (hw_index != INVALID_NUB_HW_INDEX) - { - exc.exc_data[1] = addr; - // Piggyback the hw_index in the exc.data. - exc.exc_data.push_back(hw_index); - } - - return true; - } - break; - case EXC_SYSCALL: - break; - case EXC_MACH_SYSCALL: - break; - case EXC_RPC_ALERT: - break; +bool DNBArchImplX86_64::NotifyException(MachException::Data &exc) { + switch (exc.exc_type) { + case EXC_BAD_ACCESS: + break; + case EXC_BAD_INSTRUCTION: + break; + case EXC_ARITHMETIC: + break; + case EXC_EMULATION: + break; + case EXC_SOFTWARE: + break; + case EXC_BREAKPOINT: + if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 2) { + // exc_code = EXC_I386_BPT + // + nub_addr_t pc = GetPC(INVALID_NUB_ADDRESS); + if (pc != INVALID_NUB_ADDRESS && pc > 0) { + pc -= 1; + // Check for a breakpoint at one byte prior to the current PC value + // since the PC will be just past the trap. + + DNBBreakpoint *bp = + m_thread->Process()->Breakpoints().FindByAddress(pc); + if (bp) { + // Backup the PC for i386 since the trap was taken and the PC + // is at the address following the single byte trap instruction. + if (m_state.context.gpr.__rip > 0) { + m_state.context.gpr.__rip = pc; + // Write the new PC back out + SetGPRState(); + } + } + return true; + } + } else if (exc.exc_data.size() >= 2 && exc.exc_data[0] == 1) { + // exc_code = EXC_I386_SGL + // + // Check whether this corresponds to a watchpoint hit event. + // If yes, set the exc_sub_code to the data break address. + nub_addr_t addr = 0; + uint32_t hw_index = GetHardwareWatchpointHit(addr); + if (hw_index != INVALID_NUB_HW_INDEX) { + exc.exc_data[1] = addr; + // Piggyback the hw_index in the exc.data. + exc.exc_data.push_back(hw_index); + } + + return true; } - return false; + break; + case EXC_SYSCALL: + break; + case EXC_MACH_SYSCALL: + break; + case EXC_RPC_ALERT: + break; + } + return false; } -uint32_t -DNBArchImplX86_64::NumSupportedHardwareWatchpoints() -{ - // Available debug address registers: dr0, dr1, dr2, dr3. - return 4; +uint32_t DNBArchImplX86_64::NumSupportedHardwareWatchpoints() { + // Available debug address registers: dr0, dr1, dr2, dr3. + return 4; } -static uint32_t -size_and_rw_bits(nub_size_t size, bool read, bool write) -{ - uint32_t rw; - if (read) { - rw = 0x3; // READ or READ/WRITE - } else if (write) { - rw = 0x1; // WRITE - } else { - assert(0 && "read and write cannot both be false"); - } - - switch (size) { - case 1: - return rw; - case 2: - return (0x1 << 2) | rw; - case 4: - return (0x3 << 2) | rw; - case 8: - return (0x2 << 2) | rw; - } - assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); - return 0; +static uint32_t size_and_rw_bits(nub_size_t size, bool read, bool write) { + uint32_t rw; + if (read) { + rw = 0x3; // READ or READ/WRITE + } else if (write) { + rw = 0x1; // WRITE + } else { + assert(0 && "read and write cannot both be false"); + } + + switch (size) { + case 1: + return rw; + case 2: + return (0x1 << 2) | rw; + case 4: + return (0x3 << 2) | rw; + case 8: + return (0x2 << 2) | rw; + } + assert(0 && "invalid size, must be one of 1, 2, 4, or 8"); + return 0; } -void -DNBArchImplX86_64::SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write) -{ - // Set both dr7 (debug control register) and dri (debug address register). - - // dr7{7-0} encodes the local/gloabl enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - // - // dr7{31-16} encodes the rw/len bits: - // b_x+3, b_x+2, b_x+1, b_x - // where bits{x+1, x} => rw - // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io read-or-write (unused) - // and bits{x+3, x+2} => len - // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte - // - // dr0 -> bits{19-16} - // dr1 -> bits{23-20} - // dr2 -> bits{27-24} - // dr3 -> bits{31-28} - debug_state.__dr7 |= (1 << (2*hw_index) | - size_and_rw_bits(size, read, write) << (16+4*hw_index)); - switch (hw_index) { - case 0: - debug_state.__dr0 = addr; break; - case 1: - debug_state.__dr1 = addr; break; - case 2: - debug_state.__dr2 = addr; break; - case 3: - debug_state.__dr3 = addr; break; - default: - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - } - return; +void DNBArchImplX86_64::SetWatchpoint(DBG &debug_state, uint32_t hw_index, + nub_addr_t addr, nub_size_t size, + bool read, bool write) { + // Set both dr7 (debug control register) and dri (debug address register). + + // dr7{7-0} encodes the local/gloabl enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + // + // dr7{31-16} encodes the rw/len bits: + // b_x+3, b_x+2, b_x+1, b_x + // where bits{x+1, x} => rw + // 0b00: execute, 0b01: write, 0b11: read-or-write, 0b10: io + // read-or-write (unused) + // and bits{x+3, x+2} => len + // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte + // + // dr0 -> bits{19-16} + // dr1 -> bits{23-20} + // dr2 -> bits{27-24} + // dr3 -> bits{31-28} + debug_state.__dr7 |= + (1 << (2 * hw_index) | + size_and_rw_bits(size, read, write) << (16 + 4 * hw_index)); + switch (hw_index) { + case 0: + debug_state.__dr0 = addr; + break; + case 1: + debug_state.__dr1 = addr; + break; + case 2: + debug_state.__dr2 = addr; + break; + case 3: + debug_state.__dr3 = addr; + break; + default: + assert(0 && + "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; } -void -DNBArchImplX86_64::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) -{ - debug_state.__dr7 &= ~(3 << (2*hw_index)); - switch (hw_index) { - case 0: - debug_state.__dr0 = 0; break; - case 1: - debug_state.__dr1 = 0; break; - case 2: - debug_state.__dr2 = 0; break; - case 3: - debug_state.__dr3 = 0; break; - default: - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - } - return; +void DNBArchImplX86_64::ClearWatchpoint(DBG &debug_state, uint32_t hw_index) { + debug_state.__dr7 &= ~(3 << (2 * hw_index)); + switch (hw_index) { + case 0: + debug_state.__dr0 = 0; + break; + case 1: + debug_state.__dr1 = 0; + break; + case 2: + debug_state.__dr2 = 0; + break; + case 3: + debug_state.__dr3 = 0; + break; + default: + assert(0 && + "invalid hardware register index, must be one of 0, 1, 2, or 3"); + } + return; } -bool -DNBArchImplX86_64::IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index) -{ - // Check dr7 (debug control register) for local/global enable bits: - // global enable --. .-- local enable - // | | - // v v - // dr0 -> bits{1-0} - // dr1 -> bits{3-2} - // dr2 -> bits{5-4} - // dr3 -> bits{7-6} - return (debug_state.__dr7 & (3 << (2*hw_index))) == 0; +bool DNBArchImplX86_64::IsWatchpointVacant(const DBG &debug_state, + uint32_t hw_index) { + // Check dr7 (debug control register) for local/global enable bits: + // global enable --. .-- local enable + // | | + // v v + // dr0 -> bits{1-0} + // dr1 -> bits{3-2} + // dr2 -> bits{5-4} + // dr3 -> bits{7-6} + return (debug_state.__dr7 & (3 << (2 * hw_index))) == 0; } -// Resets local copy of debug status register to wait for the next debug exception. -void -DNBArchImplX86_64::ClearWatchpointHits(DBG &debug_state) -{ - // See also IsWatchpointHit(). - debug_state.__dr6 = 0; - return; +// Resets local copy of debug status register to wait for the next debug +// exception. +void DNBArchImplX86_64::ClearWatchpointHits(DBG &debug_state) { + // See also IsWatchpointHit(). + debug_state.__dr6 = 0; + return; } -bool -DNBArchImplX86_64::IsWatchpointHit(const DBG &debug_state, uint32_t hw_index) -{ - // Check dr6 (debug status register) whether a watchpoint hits: - // is watchpoint hit? - // | - // v - // dr0 -> bits{0} - // dr1 -> bits{1} - // dr2 -> bits{2} - // dr3 -> bits{3} - return (debug_state.__dr6 & (1 << hw_index)); +bool DNBArchImplX86_64::IsWatchpointHit(const DBG &debug_state, + uint32_t hw_index) { + // Check dr6 (debug status register) whether a watchpoint hits: + // is watchpoint hit? + // | + // v + // dr0 -> bits{0} + // dr1 -> bits{1} + // dr2 -> bits{2} + // dr3 -> bits{3} + return (debug_state.__dr6 & (1 << hw_index)); } -nub_addr_t -DNBArchImplX86_64::GetWatchAddress(const DBG &debug_state, uint32_t hw_index) -{ - switch (hw_index) { - case 0: - return debug_state.__dr0; - case 1: - return debug_state.__dr1; - case 2: - return debug_state.__dr2; - case 3: - return debug_state.__dr3; - } - assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); - return 0; +nub_addr_t DNBArchImplX86_64::GetWatchAddress(const DBG &debug_state, + uint32_t hw_index) { + switch (hw_index) { + case 0: + return debug_state.__dr0; + case 1: + return debug_state.__dr1; + case 2: + return debug_state.__dr2; + case 3: + return debug_state.__dr3; + } + assert(0 && "invalid hardware register index, must be one of 0, 1, 2, or 3"); + return 0; } -bool -DNBArchImplX86_64::StartTransForHWP() -{ - if (m_2pc_trans_state != Trans_Done && m_2pc_trans_state != Trans_Rolled_Back) - DNBLogError ("%s inconsistent state detected, expected %d or %d, got: %d", __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); - m_2pc_dbg_checkpoint = m_state.context.dbg; - m_2pc_trans_state = Trans_Pending; - return true; +bool DNBArchImplX86_64::StartTransForHWP() { + if (m_2pc_trans_state != Trans_Done && m_2pc_trans_state != Trans_Rolled_Back) + DNBLogError("%s inconsistent state detected, expected %d or %d, got: %d", + __FUNCTION__, Trans_Done, Trans_Rolled_Back, m_2pc_trans_state); + m_2pc_dbg_checkpoint = m_state.context.dbg; + m_2pc_trans_state = Trans_Pending; + return true; } -bool -DNBArchImplX86_64::RollbackTransForHWP() -{ - m_state.context.dbg = m_2pc_dbg_checkpoint; - if (m_2pc_trans_state != Trans_Pending) - DNBLogError ("%s inconsistent state detected, expected %d, got: %d", __FUNCTION__, Trans_Pending, m_2pc_trans_state); - m_2pc_trans_state = Trans_Rolled_Back; - kern_return_t kret = SetDBGState(false); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", kret); - - if (kret == KERN_SUCCESS) - return true; - else - return false; -} -bool -DNBArchImplX86_64::FinishTransForHWP() -{ - m_2pc_trans_state = Trans_Done; +bool DNBArchImplX86_64::RollbackTransForHWP() { + m_state.context.dbg = m_2pc_dbg_checkpoint; + if (m_2pc_trans_state != Trans_Pending) + DNBLogError("%s inconsistent state detected, expected %d, got: %d", + __FUNCTION__, Trans_Pending, m_2pc_trans_state); + m_2pc_trans_state = Trans_Rolled_Back; + kern_return_t kret = SetDBGState(false); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplX86_64::RollbackTransForHWP() SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) return true; + else + return false; +} +bool DNBArchImplX86_64::FinishTransForHWP() { + m_2pc_trans_state = Trans_Done; + return true; } -DNBArchImplX86_64::DBG -DNBArchImplX86_64::GetDBGCheckpoint() -{ - return m_2pc_dbg_checkpoint; +DNBArchImplX86_64::DBG DNBArchImplX86_64::GetDBGCheckpoint() { + return m_2pc_dbg_checkpoint; } -uint32_t -DNBArchImplX86_64::EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task) -{ - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::EnableHardwareWatchpoint(addr = 0x%llx, size = %llu, read = %u, write = %u)", (uint64_t)addr, (uint64_t)size, read, write); +uint32_t DNBArchImplX86_64::EnableHardwareWatchpoint(nub_addr_t addr, + nub_size_t size, bool read, + bool write, + bool also_set_on_task) { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "EnableHardwareWatchpoint(addr = 0x%llx, " + "size = %llu, read = %u, write = %u)", + (uint64_t)addr, (uint64_t)size, read, write); - const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); - // Can only watch 1, 2, 4, or 8 bytes. - if (!(size == 1 || size == 2 || size == 4 || size == 8)) - return INVALID_NUB_HW_INDEX; + // Can only watch 1, 2, 4, or 8 bytes. + if (!(size == 1 || size == 2 || size == 4 || size == 8)) + return INVALID_NUB_HW_INDEX; - // We must watch for either read or write - if (read == false && write == false) - return INVALID_NUB_HW_INDEX; + // We must watch for either read or write + if (read == false && write == false) + return INVALID_NUB_HW_INDEX; - // Read the debug state - kern_return_t kret = GetDBGState(false); + // Read the debug state + kern_return_t kret = GetDBGState(false); - if (kret == KERN_SUCCESS) - { - // Check to make sure we have the needed hardware support - uint32_t i = 0; + if (kret == KERN_SUCCESS) { + // Check to make sure we have the needed hardware support + uint32_t i = 0; - DBG &debug_state = m_state.context.dbg; - for (i = 0; i < num_hw_watchpoints; ++i) - { - if (IsWatchpointVacant(debug_state, i)) - break; - } + DBG &debug_state = m_state.context.dbg; + for (i = 0; i < num_hw_watchpoints; ++i) { + if (IsWatchpointVacant(debug_state, i)) + break; + } - // See if we found an available hw breakpoint slot above - if (i < num_hw_watchpoints) - { - StartTransForHWP(); - - // Modify our local copy of the debug state, first. - SetWatchpoint(debug_state, i, addr, size, read, write); - // Now set the watch point in the inferior. - kret = SetDBGState(also_set_on_task); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::EnableHardwareWatchpoint() SetDBGState() => 0x%8.8x.", kret); - - if (kret == KERN_SUCCESS) - return i; - else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. - m_state.context.dbg = GetDBGCheckpoint(); - } - else - { - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints); - } + // See if we found an available hw breakpoint slot above + if (i < num_hw_watchpoints) { + StartTransForHWP(); + + // Modify our local copy of the debug state, first. + SetWatchpoint(debug_state, i, addr, size, read, write); + // Now set the watch point in the inferior. + kret = SetDBGState(also_set_on_task); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "EnableHardwareWatchpoint() " + "SetDBGState() => 0x%8.8x.", + kret); + + if (kret == KERN_SUCCESS) + return i; + else // Revert to the previous debug state voluntarily. The transaction + // coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); + } else { + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "EnableHardwareWatchpoint(): All " + "hardware resources (%u) are in use.", + num_hw_watchpoints); } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } -bool -DNBArchImplX86_64::DisableHardwareWatchpoint (uint32_t hw_index, bool also_set_on_task) -{ - kern_return_t kret = GetDBGState(false); - - const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.context.dbg; - if (hw_index < num_hw_points && !IsWatchpointVacant(debug_state, hw_index)) - { - StartTransForHWP(); - - // Modify our local copy of the debug state, first. - ClearWatchpoint(debug_state, hw_index); - // Now disable the watch point in the inferior. - kret = SetDBGState(also_set_on_task); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::DisableHardwareWatchpoint( %u )", - hw_index); - - if (kret == KERN_SUCCESS) - return true; - else // Revert to the previous debug state voluntarily. The transaction coordinator knows that we have failed. - m_state.context.dbg = GetDBGCheckpoint(); - } +bool DNBArchImplX86_64::DisableHardwareWatchpoint(uint32_t hw_index, + bool also_set_on_task) { + kern_return_t kret = GetDBGState(false); + + const uint32_t num_hw_points = NumSupportedHardwareWatchpoints(); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.context.dbg; + if (hw_index < num_hw_points && + !IsWatchpointVacant(debug_state, hw_index)) { + StartTransForHWP(); + + // Modify our local copy of the debug state, first. + ClearWatchpoint(debug_state, hw_index); + // Now disable the watch point in the inferior. + kret = SetDBGState(also_set_on_task); + DNBLogThreadedIf(LOG_WATCHPOINTS, + "DNBArchImplX86_64::DisableHardwareWatchpoint( %u )", + hw_index); + + if (kret == KERN_SUCCESS) + return true; + else // Revert to the previous debug state voluntarily. The transaction + // coordinator knows that we have failed. + m_state.context.dbg = GetDBGCheckpoint(); } - return false; + } + return false; } // Iterate through the debug status register; return the index of the first hit. -uint32_t -DNBArchImplX86_64::GetHardwareWatchpointHit(nub_addr_t &addr) -{ - // Read the debug state - kern_return_t kret = GetDBGState(true); - DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", kret); - if (kret == KERN_SUCCESS) - { - DBG &debug_state = m_state.context.dbg; - uint32_t i, num = NumSupportedHardwareWatchpoints(); - for (i = 0; i < num; ++i) - { - if (IsWatchpointHit(debug_state, i)) - { - addr = GetWatchAddress(debug_state, i); - DNBLogThreadedIf(LOG_WATCHPOINTS, - "DNBArchImplX86_64::GetHardwareWatchpointHit() found => %u (addr = 0x%llx).", - i, - (uint64_t)addr); - return i; - } - } +uint32_t DNBArchImplX86_64::GetHardwareWatchpointHit(nub_addr_t &addr) { + // Read the debug state + kern_return_t kret = GetDBGState(true); + DNBLogThreadedIf( + LOG_WATCHPOINTS, + "DNBArchImplX86_64::GetHardwareWatchpointHit() GetDBGState() => 0x%8.8x.", + kret); + if (kret == KERN_SUCCESS) { + DBG &debug_state = m_state.context.dbg; + uint32_t i, num = NumSupportedHardwareWatchpoints(); + for (i = 0; i < num; ++i) { + if (IsWatchpointHit(debug_state, i)) { + addr = GetWatchAddress(debug_state, i); + DNBLogThreadedIf(LOG_WATCHPOINTS, "DNBArchImplX86_64::" + "GetHardwareWatchpointHit() found => " + "%u (addr = 0x%llx).", + i, (uint64_t)addr); + return i; + } } - return INVALID_NUB_HW_INDEX; + } + return INVALID_NUB_HW_INDEX; } // Set the single step bit in the processor status register. -kern_return_t -DNBArchImplX86_64::EnableHardwareSingleStep (bool enable) -{ - if (GetGPRState(false) == KERN_SUCCESS) - { - const uint32_t trace_bit = 0x100u; - if (enable) - m_state.context.gpr.__rflags |= trace_bit; - else - m_state.context.gpr.__rflags &= ~trace_bit; - return SetGPRState(); - } - return m_state.GetError(e_regSetGPR, Read); +kern_return_t DNBArchImplX86_64::EnableHardwareSingleStep(bool enable) { + if (GetGPRState(false) == KERN_SUCCESS) { + const uint32_t trace_bit = 0x100u; + if (enable) + m_state.context.gpr.__rflags |= trace_bit; + else + m_state.context.gpr.__rflags &= ~trace_bit; + return SetGPRState(); + } + return m_state.GetError(e_regSetGPR, Read); } - //---------------------------------------------------------------------- // Register information definitions //---------------------------------------------------------------------- -enum -{ - gpr_rax = 0, - gpr_rbx, - gpr_rcx, - gpr_rdx, - gpr_rdi, - gpr_rsi, - gpr_rbp, - gpr_rsp, - gpr_r8, - gpr_r9, - gpr_r10, - gpr_r11, - gpr_r12, - gpr_r13, - gpr_r14, - gpr_r15, - gpr_rip, - gpr_rflags, - gpr_cs, - gpr_fs, - gpr_gs, - gpr_eax, - gpr_ebx, - gpr_ecx, - gpr_edx, - gpr_edi, - gpr_esi, - gpr_ebp, - gpr_esp, - gpr_r8d, // Low 32 bits or r8 - gpr_r9d, // Low 32 bits or r9 - gpr_r10d, // Low 32 bits or r10 - gpr_r11d, // Low 32 bits or r11 - gpr_r12d, // Low 32 bits or r12 - gpr_r13d, // Low 32 bits or r13 - gpr_r14d, // Low 32 bits or r14 - gpr_r15d, // Low 32 bits or r15 - gpr_ax , - gpr_bx , - gpr_cx , - gpr_dx , - gpr_di , - gpr_si , - gpr_bp , - gpr_sp , - gpr_r8w, // Low 16 bits or r8 - gpr_r9w, // Low 16 bits or r9 - gpr_r10w, // Low 16 bits or r10 - gpr_r11w, // Low 16 bits or r11 - gpr_r12w, // Low 16 bits or r12 - gpr_r13w, // Low 16 bits or r13 - gpr_r14w, // Low 16 bits or r14 - gpr_r15w, // Low 16 bits or r15 - gpr_ah , - gpr_bh , - gpr_ch , - gpr_dh , - gpr_al , - gpr_bl , - gpr_cl , - gpr_dl , - gpr_dil, - gpr_sil, - gpr_bpl, - gpr_spl, - gpr_r8l, // Low 8 bits or r8 - gpr_r9l, // Low 8 bits or r9 - gpr_r10l, // Low 8 bits or r10 - gpr_r11l, // Low 8 bits or r11 - gpr_r12l, // Low 8 bits or r12 - gpr_r13l, // Low 8 bits or r13 - gpr_r14l, // Low 8 bits or r14 - gpr_r15l, // Low 8 bits or r15 - k_num_gpr_regs +enum { + gpr_rax = 0, + gpr_rbx, + gpr_rcx, + gpr_rdx, + gpr_rdi, + gpr_rsi, + gpr_rbp, + gpr_rsp, + gpr_r8, + gpr_r9, + gpr_r10, + gpr_r11, + gpr_r12, + gpr_r13, + gpr_r14, + gpr_r15, + gpr_rip, + gpr_rflags, + gpr_cs, + gpr_fs, + gpr_gs, + gpr_eax, + gpr_ebx, + gpr_ecx, + gpr_edx, + gpr_edi, + gpr_esi, + gpr_ebp, + gpr_esp, + gpr_r8d, // Low 32 bits or r8 + gpr_r9d, // Low 32 bits or r9 + gpr_r10d, // Low 32 bits or r10 + gpr_r11d, // Low 32 bits or r11 + gpr_r12d, // Low 32 bits or r12 + gpr_r13d, // Low 32 bits or r13 + gpr_r14d, // Low 32 bits or r14 + gpr_r15d, // Low 32 bits or r15 + gpr_ax, + gpr_bx, + gpr_cx, + gpr_dx, + gpr_di, + gpr_si, + gpr_bp, + gpr_sp, + gpr_r8w, // Low 16 bits or r8 + gpr_r9w, // Low 16 bits or r9 + gpr_r10w, // Low 16 bits or r10 + gpr_r11w, // Low 16 bits or r11 + gpr_r12w, // Low 16 bits or r12 + gpr_r13w, // Low 16 bits or r13 + gpr_r14w, // Low 16 bits or r14 + gpr_r15w, // Low 16 bits or r15 + gpr_ah, + gpr_bh, + gpr_ch, + gpr_dh, + gpr_al, + gpr_bl, + gpr_cl, + gpr_dl, + gpr_dil, + gpr_sil, + gpr_bpl, + gpr_spl, + gpr_r8l, // Low 8 bits or r8 + gpr_r9l, // Low 8 bits or r9 + gpr_r10l, // Low 8 bits or r10 + gpr_r11l, // Low 8 bits or r11 + gpr_r12l, // Low 8 bits or r12 + gpr_r13l, // Low 8 bits or r13 + gpr_r14l, // Low 8 bits or r14 + gpr_r15l, // Low 8 bits or r15 + k_num_gpr_regs }; enum { - fpu_fcw, - fpu_fsw, - fpu_ftw, - fpu_fop, - fpu_ip, - fpu_cs, - fpu_dp, - fpu_ds, - fpu_mxcsr, - fpu_mxcsrmask, - fpu_stmm0, - fpu_stmm1, - fpu_stmm2, - fpu_stmm3, - fpu_stmm4, - fpu_stmm5, - fpu_stmm6, - fpu_stmm7, - fpu_xmm0, - fpu_xmm1, - fpu_xmm2, - fpu_xmm3, - fpu_xmm4, - fpu_xmm5, - fpu_xmm6, - fpu_xmm7, - fpu_xmm8, - fpu_xmm9, - fpu_xmm10, - fpu_xmm11, - fpu_xmm12, - fpu_xmm13, - fpu_xmm14, - fpu_xmm15, - fpu_ymm0, - fpu_ymm1, - fpu_ymm2, - fpu_ymm3, - fpu_ymm4, - fpu_ymm5, - fpu_ymm6, - fpu_ymm7, - fpu_ymm8, - fpu_ymm9, - fpu_ymm10, - fpu_ymm11, - fpu_ymm12, - fpu_ymm13, - fpu_ymm14, - fpu_ymm15, - k_num_fpu_regs, - - // Aliases - fpu_fctrl = fpu_fcw, - fpu_fstat = fpu_fsw, - fpu_ftag = fpu_ftw, - fpu_fiseg = fpu_cs, - fpu_fioff = fpu_ip, - fpu_foseg = fpu_ds, - fpu_fooff = fpu_dp + fpu_fcw, + fpu_fsw, + fpu_ftw, + fpu_fop, + fpu_ip, + fpu_cs, + fpu_dp, + fpu_ds, + fpu_mxcsr, + fpu_mxcsrmask, + fpu_stmm0, + fpu_stmm1, + fpu_stmm2, + fpu_stmm3, + fpu_stmm4, + fpu_stmm5, + fpu_stmm6, + fpu_stmm7, + fpu_xmm0, + fpu_xmm1, + fpu_xmm2, + fpu_xmm3, + fpu_xmm4, + fpu_xmm5, + fpu_xmm6, + fpu_xmm7, + fpu_xmm8, + fpu_xmm9, + fpu_xmm10, + fpu_xmm11, + fpu_xmm12, + fpu_xmm13, + fpu_xmm14, + fpu_xmm15, + fpu_ymm0, + fpu_ymm1, + fpu_ymm2, + fpu_ymm3, + fpu_ymm4, + fpu_ymm5, + fpu_ymm6, + fpu_ymm7, + fpu_ymm8, + fpu_ymm9, + fpu_ymm10, + fpu_ymm11, + fpu_ymm12, + fpu_ymm13, + fpu_ymm14, + fpu_ymm15, + k_num_fpu_regs, + + // Aliases + fpu_fctrl = fpu_fcw, + fpu_fstat = fpu_fsw, + fpu_ftag = fpu_ftw, + fpu_fiseg = fpu_cs, + fpu_fioff = fpu_ip, + fpu_foseg = fpu_ds, + fpu_fooff = fpu_dp }; enum { - exc_trapno, - exc_err, - exc_faultvaddr, - k_num_exc_regs, + exc_trapno, + exc_err, + exc_faultvaddr, + k_num_exc_regs, }; - -enum ehframe_dwarf_regnums -{ - ehframe_dwarf_rax = 0, - ehframe_dwarf_rdx = 1, - ehframe_dwarf_rcx = 2, - ehframe_dwarf_rbx = 3, - ehframe_dwarf_rsi = 4, - ehframe_dwarf_rdi = 5, - ehframe_dwarf_rbp = 6, - ehframe_dwarf_rsp = 7, - ehframe_dwarf_r8, - ehframe_dwarf_r9, - ehframe_dwarf_r10, - ehframe_dwarf_r11, - ehframe_dwarf_r12, - ehframe_dwarf_r13, - ehframe_dwarf_r14, - ehframe_dwarf_r15, - ehframe_dwarf_rip, - ehframe_dwarf_xmm0, - ehframe_dwarf_xmm1, - ehframe_dwarf_xmm2, - ehframe_dwarf_xmm3, - ehframe_dwarf_xmm4, - ehframe_dwarf_xmm5, - ehframe_dwarf_xmm6, - ehframe_dwarf_xmm7, - ehframe_dwarf_xmm8, - ehframe_dwarf_xmm9, - ehframe_dwarf_xmm10, - ehframe_dwarf_xmm11, - ehframe_dwarf_xmm12, - ehframe_dwarf_xmm13, - ehframe_dwarf_xmm14, - ehframe_dwarf_xmm15, - ehframe_dwarf_stmm0, - ehframe_dwarf_stmm1, - ehframe_dwarf_stmm2, - ehframe_dwarf_stmm3, - ehframe_dwarf_stmm4, - ehframe_dwarf_stmm5, - ehframe_dwarf_stmm6, - ehframe_dwarf_stmm7, - ehframe_dwarf_ymm0 = ehframe_dwarf_xmm0, - ehframe_dwarf_ymm1 = ehframe_dwarf_xmm1, - ehframe_dwarf_ymm2 = ehframe_dwarf_xmm2, - ehframe_dwarf_ymm3 = ehframe_dwarf_xmm3, - ehframe_dwarf_ymm4 = ehframe_dwarf_xmm4, - ehframe_dwarf_ymm5 = ehframe_dwarf_xmm5, - ehframe_dwarf_ymm6 = ehframe_dwarf_xmm6, - ehframe_dwarf_ymm7 = ehframe_dwarf_xmm7, - ehframe_dwarf_ymm8 = ehframe_dwarf_xmm8, - ehframe_dwarf_ymm9 = ehframe_dwarf_xmm9, - ehframe_dwarf_ymm10 = ehframe_dwarf_xmm10, - ehframe_dwarf_ymm11 = ehframe_dwarf_xmm11, - ehframe_dwarf_ymm12 = ehframe_dwarf_xmm12, - ehframe_dwarf_ymm13 = ehframe_dwarf_xmm13, - ehframe_dwarf_ymm14 = ehframe_dwarf_xmm14, - ehframe_dwarf_ymm15 = ehframe_dwarf_xmm15 +enum ehframe_dwarf_regnums { + ehframe_dwarf_rax = 0, + ehframe_dwarf_rdx = 1, + ehframe_dwarf_rcx = 2, + ehframe_dwarf_rbx = 3, + ehframe_dwarf_rsi = 4, + ehframe_dwarf_rdi = 5, + ehframe_dwarf_rbp = 6, + ehframe_dwarf_rsp = 7, + ehframe_dwarf_r8, + ehframe_dwarf_r9, + ehframe_dwarf_r10, + ehframe_dwarf_r11, + ehframe_dwarf_r12, + ehframe_dwarf_r13, + ehframe_dwarf_r14, + ehframe_dwarf_r15, + ehframe_dwarf_rip, + ehframe_dwarf_xmm0, + ehframe_dwarf_xmm1, + ehframe_dwarf_xmm2, + ehframe_dwarf_xmm3, + ehframe_dwarf_xmm4, + ehframe_dwarf_xmm5, + ehframe_dwarf_xmm6, + ehframe_dwarf_xmm7, + ehframe_dwarf_xmm8, + ehframe_dwarf_xmm9, + ehframe_dwarf_xmm10, + ehframe_dwarf_xmm11, + ehframe_dwarf_xmm12, + ehframe_dwarf_xmm13, + ehframe_dwarf_xmm14, + ehframe_dwarf_xmm15, + ehframe_dwarf_stmm0, + ehframe_dwarf_stmm1, + ehframe_dwarf_stmm2, + ehframe_dwarf_stmm3, + ehframe_dwarf_stmm4, + ehframe_dwarf_stmm5, + ehframe_dwarf_stmm6, + ehframe_dwarf_stmm7, + ehframe_dwarf_ymm0 = ehframe_dwarf_xmm0, + ehframe_dwarf_ymm1 = ehframe_dwarf_xmm1, + ehframe_dwarf_ymm2 = ehframe_dwarf_xmm2, + ehframe_dwarf_ymm3 = ehframe_dwarf_xmm3, + ehframe_dwarf_ymm4 = ehframe_dwarf_xmm4, + ehframe_dwarf_ymm5 = ehframe_dwarf_xmm5, + ehframe_dwarf_ymm6 = ehframe_dwarf_xmm6, + ehframe_dwarf_ymm7 = ehframe_dwarf_xmm7, + ehframe_dwarf_ymm8 = ehframe_dwarf_xmm8, + ehframe_dwarf_ymm9 = ehframe_dwarf_xmm9, + ehframe_dwarf_ymm10 = ehframe_dwarf_xmm10, + ehframe_dwarf_ymm11 = ehframe_dwarf_xmm11, + ehframe_dwarf_ymm12 = ehframe_dwarf_xmm12, + ehframe_dwarf_ymm13 = ehframe_dwarf_xmm13, + ehframe_dwarf_ymm14 = ehframe_dwarf_xmm14, + ehframe_dwarf_ymm15 = ehframe_dwarf_xmm15 }; -enum debugserver_regnums -{ - debugserver_rax = 0, - debugserver_rbx = 1, - debugserver_rcx = 2, - debugserver_rdx = 3, - debugserver_rsi = 4, - debugserver_rdi = 5, - debugserver_rbp = 6, - debugserver_rsp = 7, - debugserver_r8 = 8, - debugserver_r9 = 9, - debugserver_r10 = 10, - debugserver_r11 = 11, - debugserver_r12 = 12, - debugserver_r13 = 13, - debugserver_r14 = 14, - debugserver_r15 = 15, - debugserver_rip = 16, - debugserver_rflags = 17, - debugserver_cs = 18, - debugserver_ss = 19, - debugserver_ds = 20, - debugserver_es = 21, - debugserver_fs = 22, - debugserver_gs = 23, - debugserver_stmm0 = 24, - debugserver_stmm1 = 25, - debugserver_stmm2 = 26, - debugserver_stmm3 = 27, - debugserver_stmm4 = 28, - debugserver_stmm5 = 29, - debugserver_stmm6 = 30, - debugserver_stmm7 = 31, - debugserver_fctrl = 32, debugserver_fcw = debugserver_fctrl, - debugserver_fstat = 33, debugserver_fsw = debugserver_fstat, - debugserver_ftag = 34, debugserver_ftw = debugserver_ftag, - debugserver_fiseg = 35, debugserver_fpu_cs = debugserver_fiseg, - debugserver_fioff = 36, debugserver_ip = debugserver_fioff, - debugserver_foseg = 37, debugserver_fpu_ds = debugserver_foseg, - debugserver_fooff = 38, debugserver_dp = debugserver_fooff, - debugserver_fop = 39, - debugserver_xmm0 = 40, - debugserver_xmm1 = 41, - debugserver_xmm2 = 42, - debugserver_xmm3 = 43, - debugserver_xmm4 = 44, - debugserver_xmm5 = 45, - debugserver_xmm6 = 46, - debugserver_xmm7 = 47, - debugserver_xmm8 = 48, - debugserver_xmm9 = 49, - debugserver_xmm10 = 50, - debugserver_xmm11 = 51, - debugserver_xmm12 = 52, - debugserver_xmm13 = 53, - debugserver_xmm14 = 54, - debugserver_xmm15 = 55, - debugserver_mxcsr = 56, - debugserver_ymm0 = debugserver_xmm0, - debugserver_ymm1 = debugserver_xmm1, - debugserver_ymm2 = debugserver_xmm2, - debugserver_ymm3 = debugserver_xmm3, - debugserver_ymm4 = debugserver_xmm4, - debugserver_ymm5 = debugserver_xmm5, - debugserver_ymm6 = debugserver_xmm6, - debugserver_ymm7 = debugserver_xmm7, - debugserver_ymm8 = debugserver_xmm8, - debugserver_ymm9 = debugserver_xmm9, - debugserver_ymm10 = debugserver_xmm10, - debugserver_ymm11 = debugserver_xmm11, - debugserver_ymm12 = debugserver_xmm12, - debugserver_ymm13 = debugserver_xmm13, - debugserver_ymm14 = debugserver_xmm14, - debugserver_ymm15 = debugserver_xmm15 +enum debugserver_regnums { + debugserver_rax = 0, + debugserver_rbx = 1, + debugserver_rcx = 2, + debugserver_rdx = 3, + debugserver_rsi = 4, + debugserver_rdi = 5, + debugserver_rbp = 6, + debugserver_rsp = 7, + debugserver_r8 = 8, + debugserver_r9 = 9, + debugserver_r10 = 10, + debugserver_r11 = 11, + debugserver_r12 = 12, + debugserver_r13 = 13, + debugserver_r14 = 14, + debugserver_r15 = 15, + debugserver_rip = 16, + debugserver_rflags = 17, + debugserver_cs = 18, + debugserver_ss = 19, + debugserver_ds = 20, + debugserver_es = 21, + debugserver_fs = 22, + debugserver_gs = 23, + debugserver_stmm0 = 24, + debugserver_stmm1 = 25, + debugserver_stmm2 = 26, + debugserver_stmm3 = 27, + debugserver_stmm4 = 28, + debugserver_stmm5 = 29, + debugserver_stmm6 = 30, + debugserver_stmm7 = 31, + debugserver_fctrl = 32, + debugserver_fcw = debugserver_fctrl, + debugserver_fstat = 33, + debugserver_fsw = debugserver_fstat, + debugserver_ftag = 34, + debugserver_ftw = debugserver_ftag, + debugserver_fiseg = 35, + debugserver_fpu_cs = debugserver_fiseg, + debugserver_fioff = 36, + debugserver_ip = debugserver_fioff, + debugserver_foseg = 37, + debugserver_fpu_ds = debugserver_foseg, + debugserver_fooff = 38, + debugserver_dp = debugserver_fooff, + debugserver_fop = 39, + debugserver_xmm0 = 40, + debugserver_xmm1 = 41, + debugserver_xmm2 = 42, + debugserver_xmm3 = 43, + debugserver_xmm4 = 44, + debugserver_xmm5 = 45, + debugserver_xmm6 = 46, + debugserver_xmm7 = 47, + debugserver_xmm8 = 48, + debugserver_xmm9 = 49, + debugserver_xmm10 = 50, + debugserver_xmm11 = 51, + debugserver_xmm12 = 52, + debugserver_xmm13 = 53, + debugserver_xmm14 = 54, + debugserver_xmm15 = 55, + debugserver_mxcsr = 56, + debugserver_ymm0 = debugserver_xmm0, + debugserver_ymm1 = debugserver_xmm1, + debugserver_ymm2 = debugserver_xmm2, + debugserver_ymm3 = debugserver_xmm3, + debugserver_ymm4 = debugserver_xmm4, + debugserver_ymm5 = debugserver_xmm5, + debugserver_ymm6 = debugserver_xmm6, + debugserver_ymm7 = debugserver_xmm7, + debugserver_ymm8 = debugserver_xmm8, + debugserver_ymm9 = debugserver_xmm9, + debugserver_ymm10 = debugserver_xmm10, + debugserver_ymm11 = debugserver_xmm11, + debugserver_ymm12 = debugserver_xmm12, + debugserver_ymm13 = debugserver_xmm13, + debugserver_ymm14 = debugserver_xmm14, + debugserver_ymm15 = debugserver_xmm15 }; -#define GPR_OFFSET(reg) (offsetof (DNBArchImplX86_64::GPR, __##reg)) -#define FPU_OFFSET(reg) (offsetof (DNBArchImplX86_64::FPU, __fpu_##reg) + offsetof (DNBArchImplX86_64::Context, fpu.no_avx)) -#define AVX_OFFSET(reg) (offsetof (DNBArchImplX86_64::AVX, __fpu_##reg) + offsetof (DNBArchImplX86_64::Context, fpu.avx)) -#define EXC_OFFSET(reg) (offsetof (DNBArchImplX86_64::EXC, __##reg) + offsetof (DNBArchImplX86_64::Context, exc)) -#define AVX_OFFSET_YMM(n) (AVX_OFFSET(ymmh0) + (32 * n)) - -#define GPR_SIZE(reg) (sizeof(((DNBArchImplX86_64::GPR *)NULL)->__##reg)) -#define FPU_SIZE_UINT(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg)) -#define FPU_SIZE_MMST(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__mmst_reg)) -#define FPU_SIZE_XMM(reg) (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__xmm_reg)) -#define FPU_SIZE_YMM(reg) (32) -#define EXC_SIZE(reg) (sizeof(((DNBArchImplX86_64::EXC *)NULL)->__##reg)) +#define GPR_OFFSET(reg) (offsetof(DNBArchImplX86_64::GPR, __##reg)) +#define FPU_OFFSET(reg) \ + (offsetof(DNBArchImplX86_64::FPU, __fpu_##reg) + \ + offsetof(DNBArchImplX86_64::Context, fpu.no_avx)) +#define AVX_OFFSET(reg) \ + (offsetof(DNBArchImplX86_64::AVX, __fpu_##reg) + \ + offsetof(DNBArchImplX86_64::Context, fpu.avx)) +#define EXC_OFFSET(reg) \ + (offsetof(DNBArchImplX86_64::EXC, __##reg) + \ + offsetof(DNBArchImplX86_64::Context, exc)) +#define AVX_OFFSET_YMM(n) (AVX_OFFSET(ymmh0) + (32 * n)) + +#define GPR_SIZE(reg) (sizeof(((DNBArchImplX86_64::GPR *)NULL)->__##reg)) +#define FPU_SIZE_UINT(reg) \ + (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg)) +#define FPU_SIZE_MMST(reg) \ + (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__mmst_reg)) +#define FPU_SIZE_XMM(reg) \ + (sizeof(((DNBArchImplX86_64::FPU *)NULL)->__fpu_##reg.__xmm_reg)) +#define FPU_SIZE_YMM(reg) (32) +#define EXC_SIZE(reg) (sizeof(((DNBArchImplX86_64::EXC *)NULL)->__##reg)) // These macros will auto define the register name, alt name, register size, // register offset, encoding, format and native register. This ensures that // the register state structures are defined correctly and have the correct // sizes and offsets. -#define DEFINE_GPR(reg) { e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, INVALID_NUB_REGNUM, debugserver_##reg, NULL, g_invalidate_##reg } -#define DEFINE_GPR_ALT(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, gen, debugserver_##reg, NULL, g_invalidate_##reg } -#define DEFINE_GPR_ALT2(reg, alt) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, debugserver_##reg, NULL, NULL } -#define DEFINE_GPR_ALT3(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, gen, debugserver_##reg, NULL, NULL } -#define DEFINE_GPR_ALT4(reg, alt, gen) { e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, gen, debugserver_##reg, NULL, NULL } - -#define DEFINE_GPR_PSEUDO_32(reg32,reg64) { e_regSetGPR, gpr_##reg32, #reg32, NULL, Uint, Hex, 4, 0,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 } -#define DEFINE_GPR_PSEUDO_16(reg16,reg64) { e_regSetGPR, gpr_##reg16, #reg16, NULL, Uint, Hex, 2, 0,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 } -#define DEFINE_GPR_PSEUDO_8H(reg8,reg64) { e_regSetGPR, gpr_##reg8 , #reg8 , NULL, Uint, Hex, 1, 1,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 } -#define DEFINE_GPR_PSEUDO_8L(reg8,reg64) { e_regSetGPR, gpr_##reg8 , #reg8 , NULL, Uint, Hex, 1, 0,INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 } +#define DEFINE_GPR(reg) \ + { \ + e_regSetGPR, gpr_##reg, #reg, NULL, Uint, Hex, GPR_SIZE(reg), \ + GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, \ + INVALID_NUB_REGNUM, debugserver_##reg, NULL, g_invalidate_##reg \ + } +#define DEFINE_GPR_ALT(reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), \ + GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, gen, \ + debugserver_##reg, NULL, g_invalidate_##reg \ + } +#define DEFINE_GPR_ALT2(reg, alt) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), \ + GPR_OFFSET(reg), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, debugserver_##reg, NULL, NULL \ + } +#define DEFINE_GPR_ALT3(reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), \ + GPR_OFFSET(reg), INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, gen, \ + debugserver_##reg, NULL, NULL \ + } +#define DEFINE_GPR_ALT4(reg, alt, gen) \ + { \ + e_regSetGPR, gpr_##reg, #reg, alt, Uint, Hex, GPR_SIZE(reg), \ + GPR_OFFSET(reg), ehframe_dwarf_##reg, ehframe_dwarf_##reg, gen, \ + debugserver_##reg, NULL, NULL \ + } + +#define DEFINE_GPR_PSEUDO_32(reg32, reg64) \ + { \ + e_regSetGPR, gpr_##reg32, #reg32, NULL, Uint, Hex, 4, 0, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 \ + } +#define DEFINE_GPR_PSEUDO_16(reg16, reg64) \ + { \ + e_regSetGPR, gpr_##reg16, #reg16, NULL, Uint, Hex, 2, 0, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, g_contained_##reg64, g_invalidate_##reg64 \ + } +#define DEFINE_GPR_PSEUDO_8H(reg8, reg64) \ + { \ + e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 1, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + g_contained_##reg64, g_invalidate_##reg64 \ + } +#define DEFINE_GPR_PSEUDO_8L(reg8, reg64) \ + { \ + e_regSetGPR, gpr_##reg8, #reg8, NULL, Uint, Hex, 1, 0, INVALID_NUB_REGNUM, \ + INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, INVALID_NUB_REGNUM, \ + g_contained_##reg64, g_invalidate_##reg64 \ + } // General purpose registers for 64 bit -const char *g_contained_rax[] = { "rax", NULL }; -const char *g_contained_rbx[] = { "rbx", NULL }; -const char *g_contained_rcx[] = { "rcx", NULL }; -const char *g_contained_rdx[] = { "rdx", NULL }; -const char *g_contained_rdi[] = { "rdi", NULL }; -const char *g_contained_rsi[] = { "rsi", NULL }; -const char *g_contained_rbp[] = { "rbp", NULL }; -const char *g_contained_rsp[] = { "rsp", NULL }; -const char *g_contained_r8[] = { "r8", NULL }; -const char *g_contained_r9[] = { "r9", NULL }; -const char *g_contained_r10[] = { "r10", NULL }; -const char *g_contained_r11[] = { "r11", NULL }; -const char *g_contained_r12[] = { "r12", NULL }; -const char *g_contained_r13[] = { "r13", NULL }; -const char *g_contained_r14[] = { "r14", NULL }; -const char *g_contained_r15[] = { "r15", NULL }; - -const char *g_invalidate_rax[] = { "rax", "eax", "ax", "ah", "al", NULL }; -const char *g_invalidate_rbx[] = { "rbx", "ebx", "bx", "bh", "bl", NULL }; -const char *g_invalidate_rcx[] = { "rcx", "ecx", "cx", "ch", "cl", NULL }; -const char *g_invalidate_rdx[] = { "rdx", "edx", "dx", "dh", "dl", NULL }; -const char *g_invalidate_rdi[] = { "rdi", "edi", "di", "dil", NULL }; -const char *g_invalidate_rsi[] = { "rsi", "esi", "si", "sil", NULL }; -const char *g_invalidate_rbp[] = { "rbp", "ebp", "bp", "bpl", NULL }; -const char *g_invalidate_rsp[] = { "rsp", "esp", "sp", "spl", NULL }; -const char *g_invalidate_r8 [] = { "r8", "r8d", "r8w", "r8l", NULL }; -const char *g_invalidate_r9 [] = { "r9", "r9d", "r9w", "r9l", NULL }; -const char *g_invalidate_r10[] = { "r10", "r10d", "r10w", "r10l", NULL }; -const char *g_invalidate_r11[] = { "r11", "r11d", "r11w", "r11l", NULL }; -const char *g_invalidate_r12[] = { "r12", "r12d", "r12w", "r12l", NULL }; -const char *g_invalidate_r13[] = { "r13", "r13d", "r13w", "r13l", NULL }; -const char *g_invalidate_r14[] = { "r14", "r14d", "r14w", "r14l", NULL }; -const char *g_invalidate_r15[] = { "r15", "r15d", "r15w", "r15l", NULL }; - -const DNBRegisterInfo -DNBArchImplX86_64::g_gpr_registers[] = -{ - DEFINE_GPR (rax), - DEFINE_GPR (rbx), - DEFINE_GPR_ALT (rcx , "arg4", GENERIC_REGNUM_ARG4), - DEFINE_GPR_ALT (rdx , "arg3", GENERIC_REGNUM_ARG3), - DEFINE_GPR_ALT (rdi , "arg1", GENERIC_REGNUM_ARG1), - DEFINE_GPR_ALT (rsi , "arg2", GENERIC_REGNUM_ARG2), - DEFINE_GPR_ALT (rbp , "fp" , GENERIC_REGNUM_FP), - DEFINE_GPR_ALT (rsp , "sp" , GENERIC_REGNUM_SP), - DEFINE_GPR_ALT (r8 , "arg5", GENERIC_REGNUM_ARG5), - DEFINE_GPR_ALT (r9 , "arg6", GENERIC_REGNUM_ARG6), - DEFINE_GPR (r10), - DEFINE_GPR (r11), - DEFINE_GPR (r12), - DEFINE_GPR (r13), - DEFINE_GPR (r14), - DEFINE_GPR (r15), - DEFINE_GPR_ALT4 (rip , "pc", GENERIC_REGNUM_PC), - DEFINE_GPR_ALT3 (rflags, "flags", GENERIC_REGNUM_FLAGS), - DEFINE_GPR_ALT2 (cs, NULL), - DEFINE_GPR_ALT2 (fs, NULL), - DEFINE_GPR_ALT2 (gs, NULL), - 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) -}; +const char *g_contained_rax[] = {"rax", NULL}; +const char *g_contained_rbx[] = {"rbx", NULL}; +const char *g_contained_rcx[] = {"rcx", NULL}; +const char *g_contained_rdx[] = {"rdx", NULL}; +const char *g_contained_rdi[] = {"rdi", NULL}; +const char *g_contained_rsi[] = {"rsi", NULL}; +const char *g_contained_rbp[] = {"rbp", NULL}; +const char *g_contained_rsp[] = {"rsp", NULL}; +const char *g_contained_r8[] = {"r8", NULL}; +const char *g_contained_r9[] = {"r9", NULL}; +const char *g_contained_r10[] = {"r10", NULL}; +const char *g_contained_r11[] = {"r11", NULL}; +const char *g_contained_r12[] = {"r12", NULL}; +const char *g_contained_r13[] = {"r13", NULL}; +const char *g_contained_r14[] = {"r14", NULL}; +const char *g_contained_r15[] = {"r15", NULL}; + +const char *g_invalidate_rax[] = {"rax", "eax", "ax", "ah", "al", NULL}; +const char *g_invalidate_rbx[] = {"rbx", "ebx", "bx", "bh", "bl", NULL}; +const char *g_invalidate_rcx[] = {"rcx", "ecx", "cx", "ch", "cl", NULL}; +const char *g_invalidate_rdx[] = {"rdx", "edx", "dx", "dh", "dl", NULL}; +const char *g_invalidate_rdi[] = {"rdi", "edi", "di", "dil", NULL}; +const char *g_invalidate_rsi[] = {"rsi", "esi", "si", "sil", NULL}; +const char *g_invalidate_rbp[] = {"rbp", "ebp", "bp", "bpl", NULL}; +const char *g_invalidate_rsp[] = {"rsp", "esp", "sp", "spl", NULL}; +const char *g_invalidate_r8[] = {"r8", "r8d", "r8w", "r8l", NULL}; +const char *g_invalidate_r9[] = {"r9", "r9d", "r9w", "r9l", NULL}; +const char *g_invalidate_r10[] = {"r10", "r10d", "r10w", "r10l", NULL}; +const char *g_invalidate_r11[] = {"r11", "r11d", "r11w", "r11l", NULL}; +const char *g_invalidate_r12[] = {"r12", "r12d", "r12w", "r12l", NULL}; +const char *g_invalidate_r13[] = {"r13", "r13d", "r13w", "r13l", NULL}; +const char *g_invalidate_r14[] = {"r14", "r14d", "r14w", "r14l", NULL}; +const char *g_invalidate_r15[] = {"r15", "r15d", "r15w", "r15l", NULL}; + +const DNBRegisterInfo DNBArchImplX86_64::g_gpr_registers[] = { + DEFINE_GPR(rax), + DEFINE_GPR(rbx), + DEFINE_GPR_ALT(rcx, "arg4", GENERIC_REGNUM_ARG4), + DEFINE_GPR_ALT(rdx, "arg3", GENERIC_REGNUM_ARG3), + DEFINE_GPR_ALT(rdi, "arg1", GENERIC_REGNUM_ARG1), + DEFINE_GPR_ALT(rsi, "arg2", GENERIC_REGNUM_ARG2), + DEFINE_GPR_ALT(rbp, "fp", GENERIC_REGNUM_FP), + DEFINE_GPR_ALT(rsp, "sp", GENERIC_REGNUM_SP), + DEFINE_GPR_ALT(r8, "arg5", GENERIC_REGNUM_ARG5), + DEFINE_GPR_ALT(r9, "arg6", GENERIC_REGNUM_ARG6), + DEFINE_GPR(r10), + DEFINE_GPR(r11), + DEFINE_GPR(r12), + DEFINE_GPR(r13), + DEFINE_GPR(r14), + DEFINE_GPR(r15), + DEFINE_GPR_ALT4(rip, "pc", GENERIC_REGNUM_PC), + DEFINE_GPR_ALT3(rflags, "flags", GENERIC_REGNUM_FLAGS), + DEFINE_GPR_ALT2(cs, NULL), + DEFINE_GPR_ALT2(fs, NULL), + DEFINE_GPR_ALT2(gs, NULL), + 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)}; // Floating point registers 64 bit -const DNBRegisterInfo -DNBArchImplX86_64::g_fpu_registers_no_avx[] = -{ - { e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , FPU_OFFSET(fcw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , FPU_OFFSET(fsw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , FPU_OFFSET(ftw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , FPU_OFFSET(fop) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , FPU_OFFSET(ip) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , FPU_OFFSET(cs) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , FPU_OFFSET(dp) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , FPU_OFFSET(ds) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , FPU_OFFSET(mxcsr) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , FPU_OFFSET(mxcsrmask) , -1U, -1U, -1U, -1U, NULL, NULL }, - - { e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), ehframe_dwarf_stmm0, ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL }, - { e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), ehframe_dwarf_stmm1, ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL }, - { e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), ehframe_dwarf_stmm2, ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL }, - { e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), ehframe_dwarf_stmm3, ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL }, - { e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), ehframe_dwarf_stmm4, ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL }, - { e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), ehframe_dwarf_stmm5, ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL }, - { e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), ehframe_dwarf_stmm6, ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL }, - { e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), ehframe_dwarf_stmm7, ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL }, - - { e_regSetFPU, fpu_xmm0 , "xmm0" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0) , FPU_OFFSET(xmm0) , ehframe_dwarf_xmm0 , ehframe_dwarf_xmm0 , -1U, debugserver_xmm0 , NULL, NULL }, - { e_regSetFPU, fpu_xmm1 , "xmm1" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1) , FPU_OFFSET(xmm1) , ehframe_dwarf_xmm1 , ehframe_dwarf_xmm1 , -1U, debugserver_xmm1 , NULL, NULL }, - { e_regSetFPU, fpu_xmm2 , "xmm2" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2) , FPU_OFFSET(xmm2) , ehframe_dwarf_xmm2 , ehframe_dwarf_xmm2 , -1U, debugserver_xmm2 , NULL, NULL }, - { e_regSetFPU, fpu_xmm3 , "xmm3" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3) , FPU_OFFSET(xmm3) , ehframe_dwarf_xmm3 , ehframe_dwarf_xmm3 , -1U, debugserver_xmm3 , NULL, NULL }, - { e_regSetFPU, fpu_xmm4 , "xmm4" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4) , FPU_OFFSET(xmm4) , ehframe_dwarf_xmm4 , ehframe_dwarf_xmm4 , -1U, debugserver_xmm4 , NULL, NULL }, - { e_regSetFPU, fpu_xmm5 , "xmm5" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5) , FPU_OFFSET(xmm5) , ehframe_dwarf_xmm5 , ehframe_dwarf_xmm5 , -1U, debugserver_xmm5 , NULL, NULL }, - { e_regSetFPU, fpu_xmm6 , "xmm6" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6) , FPU_OFFSET(xmm6) , ehframe_dwarf_xmm6 , ehframe_dwarf_xmm6 , -1U, debugserver_xmm6 , NULL, NULL }, - { e_regSetFPU, fpu_xmm7 , "xmm7" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7) , FPU_OFFSET(xmm7) , ehframe_dwarf_xmm7 , ehframe_dwarf_xmm7 , -1U, debugserver_xmm7 , NULL, NULL }, - { e_regSetFPU, fpu_xmm8 , "xmm8" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm8) , FPU_OFFSET(xmm8) , ehframe_dwarf_xmm8 , ehframe_dwarf_xmm8 , -1U, debugserver_xmm8 , NULL, NULL }, - { e_regSetFPU, fpu_xmm9 , "xmm9" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm9) , FPU_OFFSET(xmm9) , ehframe_dwarf_xmm9 , ehframe_dwarf_xmm9 , -1U, debugserver_xmm9 , NULL, NULL }, - { e_regSetFPU, fpu_xmm10, "xmm10" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm10) , FPU_OFFSET(xmm10), ehframe_dwarf_xmm10, ehframe_dwarf_xmm10, -1U, debugserver_xmm10, NULL, NULL }, - { e_regSetFPU, fpu_xmm11, "xmm11" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm11) , FPU_OFFSET(xmm11), ehframe_dwarf_xmm11, ehframe_dwarf_xmm11, -1U, debugserver_xmm11, NULL, NULL }, - { e_regSetFPU, fpu_xmm12, "xmm12" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm12) , FPU_OFFSET(xmm12), ehframe_dwarf_xmm12, ehframe_dwarf_xmm12, -1U, debugserver_xmm12, NULL, NULL }, - { e_regSetFPU, fpu_xmm13, "xmm13" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm13) , FPU_OFFSET(xmm13), ehframe_dwarf_xmm13, ehframe_dwarf_xmm13, -1U, debugserver_xmm13, NULL, NULL }, - { e_regSetFPU, fpu_xmm14, "xmm14" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm14) , FPU_OFFSET(xmm14), ehframe_dwarf_xmm14, ehframe_dwarf_xmm14, -1U, debugserver_xmm14, NULL, NULL }, - { e_regSetFPU, fpu_xmm15, "xmm15" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm15) , FPU_OFFSET(xmm15), ehframe_dwarf_xmm15, ehframe_dwarf_xmm15, -1U, debugserver_xmm15, NULL, NULL }, +const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_no_avx[] = { + {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw), + FPU_OFFSET(fcw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw), + FPU_OFFSET(fsw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw), + FPU_OFFSET(ftw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop), + FPU_OFFSET(fop), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip), + FPU_OFFSET(ip), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs), + FPU_OFFSET(cs), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp), + FPU_OFFSET(dp), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds), + FPU_OFFSET(ds), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr), + FPU_OFFSET(mxcsr), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex, + FPU_SIZE_UINT(mxcsrmask), FPU_OFFSET(mxcsrmask), -1U, -1U, -1U, -1U, NULL, + NULL}, + + {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm0), FPU_OFFSET(stmm0), ehframe_dwarf_stmm0, + ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL}, + {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm1), FPU_OFFSET(stmm1), ehframe_dwarf_stmm1, + ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL}, + {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm2), FPU_OFFSET(stmm2), ehframe_dwarf_stmm2, + ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL}, + {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm3), FPU_OFFSET(stmm3), ehframe_dwarf_stmm3, + ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL}, + {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm4), FPU_OFFSET(stmm4), ehframe_dwarf_stmm4, + ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL}, + {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm5), FPU_OFFSET(stmm5), ehframe_dwarf_stmm5, + ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL}, + {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm6), FPU_OFFSET(stmm6), ehframe_dwarf_stmm6, + ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL}, + {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm7), FPU_OFFSET(stmm7), ehframe_dwarf_stmm7, + ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL}, + + {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm0), FPU_OFFSET(xmm0), ehframe_dwarf_xmm0, + ehframe_dwarf_xmm0, -1U, debugserver_xmm0, NULL, NULL}, + {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm1), FPU_OFFSET(xmm1), ehframe_dwarf_xmm1, + ehframe_dwarf_xmm1, -1U, debugserver_xmm1, NULL, NULL}, + {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm2), FPU_OFFSET(xmm2), ehframe_dwarf_xmm2, + ehframe_dwarf_xmm2, -1U, debugserver_xmm2, NULL, NULL}, + {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm3), FPU_OFFSET(xmm3), ehframe_dwarf_xmm3, + ehframe_dwarf_xmm3, -1U, debugserver_xmm3, NULL, NULL}, + {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm4), FPU_OFFSET(xmm4), ehframe_dwarf_xmm4, + ehframe_dwarf_xmm4, -1U, debugserver_xmm4, NULL, NULL}, + {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm5), FPU_OFFSET(xmm5), ehframe_dwarf_xmm5, + ehframe_dwarf_xmm5, -1U, debugserver_xmm5, NULL, NULL}, + {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm6), FPU_OFFSET(xmm6), ehframe_dwarf_xmm6, + ehframe_dwarf_xmm6, -1U, debugserver_xmm6, NULL, NULL}, + {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm7), FPU_OFFSET(xmm7), ehframe_dwarf_xmm7, + ehframe_dwarf_xmm7, -1U, debugserver_xmm7, NULL, NULL}, + {e_regSetFPU, fpu_xmm8, "xmm8", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm8), FPU_OFFSET(xmm8), ehframe_dwarf_xmm8, + ehframe_dwarf_xmm8, -1U, debugserver_xmm8, NULL, NULL}, + {e_regSetFPU, fpu_xmm9, "xmm9", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm9), FPU_OFFSET(xmm9), ehframe_dwarf_xmm9, + ehframe_dwarf_xmm9, -1U, debugserver_xmm9, NULL, NULL}, + {e_regSetFPU, fpu_xmm10, "xmm10", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm10), FPU_OFFSET(xmm10), ehframe_dwarf_xmm10, + ehframe_dwarf_xmm10, -1U, debugserver_xmm10, NULL, NULL}, + {e_regSetFPU, fpu_xmm11, "xmm11", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm11), FPU_OFFSET(xmm11), ehframe_dwarf_xmm11, + ehframe_dwarf_xmm11, -1U, debugserver_xmm11, NULL, NULL}, + {e_regSetFPU, fpu_xmm12, "xmm12", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm12), FPU_OFFSET(xmm12), ehframe_dwarf_xmm12, + ehframe_dwarf_xmm12, -1U, debugserver_xmm12, NULL, NULL}, + {e_regSetFPU, fpu_xmm13, "xmm13", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm13), FPU_OFFSET(xmm13), ehframe_dwarf_xmm13, + ehframe_dwarf_xmm13, -1U, debugserver_xmm13, NULL, NULL}, + {e_regSetFPU, fpu_xmm14, "xmm14", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm14), FPU_OFFSET(xmm14), ehframe_dwarf_xmm14, + ehframe_dwarf_xmm14, -1U, debugserver_xmm14, NULL, NULL}, + {e_regSetFPU, fpu_xmm15, "xmm15", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm15), FPU_OFFSET(xmm15), ehframe_dwarf_xmm15, + ehframe_dwarf_xmm15, -1U, debugserver_xmm15, NULL, NULL}, }; -static const char *g_contained_ymm0 [] = { "ymm0", NULL }; -static const char *g_contained_ymm1 [] = { "ymm1", NULL }; -static const char *g_contained_ymm2 [] = { "ymm2", NULL }; -static const char *g_contained_ymm3 [] = { "ymm3", NULL }; -static const char *g_contained_ymm4 [] = { "ymm4", NULL }; -static const char *g_contained_ymm5 [] = { "ymm5", NULL }; -static const char *g_contained_ymm6 [] = { "ymm6", NULL }; -static const char *g_contained_ymm7 [] = { "ymm7", NULL }; -static const char *g_contained_ymm8 [] = { "ymm8", NULL }; -static const char *g_contained_ymm9 [] = { "ymm9", NULL }; -static const char *g_contained_ymm10[] = { "ymm10", NULL }; -static const char *g_contained_ymm11[] = { "ymm11", NULL }; -static const char *g_contained_ymm12[] = { "ymm12", NULL }; -static const char *g_contained_ymm13[] = { "ymm13", NULL }; -static const char *g_contained_ymm14[] = { "ymm14", NULL }; -static const char *g_contained_ymm15[] = { "ymm15", NULL }; - -const DNBRegisterInfo -DNBArchImplX86_64::g_fpu_registers_avx[] = -{ - { e_regSetFPU, fpu_fcw , "fctrl" , NULL, Uint, Hex, FPU_SIZE_UINT(fcw) , AVX_OFFSET(fcw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_fsw , "fstat" , NULL, Uint, Hex, FPU_SIZE_UINT(fsw) , AVX_OFFSET(fsw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ftw , "ftag" , NULL, Uint, Hex, FPU_SIZE_UINT(ftw) , AVX_OFFSET(ftw) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_fop , "fop" , NULL, Uint, Hex, FPU_SIZE_UINT(fop) , AVX_OFFSET(fop) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ip , "fioff" , NULL, Uint, Hex, FPU_SIZE_UINT(ip) , AVX_OFFSET(ip) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_cs , "fiseg" , NULL, Uint, Hex, FPU_SIZE_UINT(cs) , AVX_OFFSET(cs) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_dp , "fooff" , NULL, Uint, Hex, FPU_SIZE_UINT(dp) , AVX_OFFSET(dp) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_ds , "foseg" , NULL, Uint, Hex, FPU_SIZE_UINT(ds) , AVX_OFFSET(ds) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_mxcsr , "mxcsr" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr) , AVX_OFFSET(mxcsr) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetFPU, fpu_mxcsrmask, "mxcsrmask" , NULL, Uint, Hex, FPU_SIZE_UINT(mxcsrmask) , AVX_OFFSET(mxcsrmask) , -1U, -1U, -1U, -1U, NULL, NULL }, - - { e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), ehframe_dwarf_stmm0, ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL }, - { e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), ehframe_dwarf_stmm1, ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL }, - { e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), ehframe_dwarf_stmm2, ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL }, - { e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), ehframe_dwarf_stmm3, ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL }, - { e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), ehframe_dwarf_stmm4, ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL }, - { e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), ehframe_dwarf_stmm5, ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL }, - { e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), ehframe_dwarf_stmm6, ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL }, - { e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), ehframe_dwarf_stmm7, ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL }, - - { e_regSetFPU, fpu_ymm0 , "ymm0" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm0) , AVX_OFFSET_YMM(0) , ehframe_dwarf_ymm0 , ehframe_dwarf_ymm0 , -1U, debugserver_ymm0, NULL, NULL }, - { e_regSetFPU, fpu_ymm1 , "ymm1" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm1) , AVX_OFFSET_YMM(1) , ehframe_dwarf_ymm1 , ehframe_dwarf_ymm1 , -1U, debugserver_ymm1, NULL, NULL }, - { e_regSetFPU, fpu_ymm2 , "ymm2" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm2) , AVX_OFFSET_YMM(2) , ehframe_dwarf_ymm2 , ehframe_dwarf_ymm2 , -1U, debugserver_ymm2, NULL, NULL }, - { e_regSetFPU, fpu_ymm3 , "ymm3" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm3) , AVX_OFFSET_YMM(3) , ehframe_dwarf_ymm3 , ehframe_dwarf_ymm3 , -1U, debugserver_ymm3, NULL, NULL }, - { e_regSetFPU, fpu_ymm4 , "ymm4" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm4) , AVX_OFFSET_YMM(4) , ehframe_dwarf_ymm4 , ehframe_dwarf_ymm4 , -1U, debugserver_ymm4, NULL, NULL }, - { e_regSetFPU, fpu_ymm5 , "ymm5" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm5) , AVX_OFFSET_YMM(5) , ehframe_dwarf_ymm5 , ehframe_dwarf_ymm5 , -1U, debugserver_ymm5, NULL, NULL }, - { e_regSetFPU, fpu_ymm6 , "ymm6" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm6) , AVX_OFFSET_YMM(6) , ehframe_dwarf_ymm6 , ehframe_dwarf_ymm6 , -1U, debugserver_ymm6, NULL, NULL }, - { e_regSetFPU, fpu_ymm7 , "ymm7" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm7) , AVX_OFFSET_YMM(7) , ehframe_dwarf_ymm7 , ehframe_dwarf_ymm7 , -1U, debugserver_ymm7, NULL, NULL }, - { e_regSetFPU, fpu_ymm8 , "ymm8" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm8) , AVX_OFFSET_YMM(8) , ehframe_dwarf_ymm8 , ehframe_dwarf_ymm8 , -1U, debugserver_ymm8 , NULL, NULL }, - { e_regSetFPU, fpu_ymm9 , "ymm9" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm9) , AVX_OFFSET_YMM(9) , ehframe_dwarf_ymm9 , ehframe_dwarf_ymm9 , -1U, debugserver_ymm9 , NULL, NULL }, - { e_regSetFPU, fpu_ymm10, "ymm10" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm10) , AVX_OFFSET_YMM(10), ehframe_dwarf_ymm10, ehframe_dwarf_ymm10, -1U, debugserver_ymm10, NULL, NULL }, - { e_regSetFPU, fpu_ymm11, "ymm11" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm11) , AVX_OFFSET_YMM(11), ehframe_dwarf_ymm11, ehframe_dwarf_ymm11, -1U, debugserver_ymm11, NULL, NULL }, - { e_regSetFPU, fpu_ymm12, "ymm12" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm12) , AVX_OFFSET_YMM(12), ehframe_dwarf_ymm12, ehframe_dwarf_ymm12, -1U, debugserver_ymm12, NULL, NULL }, - { e_regSetFPU, fpu_ymm13, "ymm13" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm13) , AVX_OFFSET_YMM(13), ehframe_dwarf_ymm13, ehframe_dwarf_ymm13, -1U, debugserver_ymm13, NULL, NULL }, - { e_regSetFPU, fpu_ymm14, "ymm14" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm14) , AVX_OFFSET_YMM(14), ehframe_dwarf_ymm14, ehframe_dwarf_ymm14, -1U, debugserver_ymm14, NULL, NULL }, - { e_regSetFPU, fpu_ymm15, "ymm15" , NULL, Vector, VectorOfUInt8, FPU_SIZE_YMM(ymm15) , AVX_OFFSET_YMM(15), ehframe_dwarf_ymm15, ehframe_dwarf_ymm15, -1U, debugserver_ymm15, NULL, NULL }, - - { e_regSetFPU, fpu_xmm0 , "xmm0" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm0) , 0, ehframe_dwarf_xmm0 , ehframe_dwarf_xmm0 , -1U, debugserver_xmm0 , g_contained_ymm0 , NULL }, - { e_regSetFPU, fpu_xmm1 , "xmm1" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm1) , 0, ehframe_dwarf_xmm1 , ehframe_dwarf_xmm1 , -1U, debugserver_xmm1 , g_contained_ymm1 , NULL }, - { e_regSetFPU, fpu_xmm2 , "xmm2" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm2) , 0, ehframe_dwarf_xmm2 , ehframe_dwarf_xmm2 , -1U, debugserver_xmm2 , g_contained_ymm2 , NULL }, - { e_regSetFPU, fpu_xmm3 , "xmm3" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm3) , 0, ehframe_dwarf_xmm3 , ehframe_dwarf_xmm3 , -1U, debugserver_xmm3 , g_contained_ymm3 , NULL }, - { e_regSetFPU, fpu_xmm4 , "xmm4" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm4) , 0, ehframe_dwarf_xmm4 , ehframe_dwarf_xmm4 , -1U, debugserver_xmm4 , g_contained_ymm4 , NULL }, - { e_regSetFPU, fpu_xmm5 , "xmm5" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm5) , 0, ehframe_dwarf_xmm5 , ehframe_dwarf_xmm5 , -1U, debugserver_xmm5 , g_contained_ymm5 , NULL }, - { e_regSetFPU, fpu_xmm6 , "xmm6" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm6) , 0, ehframe_dwarf_xmm6 , ehframe_dwarf_xmm6 , -1U, debugserver_xmm6 , g_contained_ymm6 , NULL }, - { e_regSetFPU, fpu_xmm7 , "xmm7" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm7) , 0, ehframe_dwarf_xmm7 , ehframe_dwarf_xmm7 , -1U, debugserver_xmm7 , g_contained_ymm7 , NULL }, - { e_regSetFPU, fpu_xmm8 , "xmm8" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm8) , 0, ehframe_dwarf_xmm8 , ehframe_dwarf_xmm8 , -1U, debugserver_xmm8 , g_contained_ymm8 , NULL }, - { e_regSetFPU, fpu_xmm9 , "xmm9" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm9) , 0, ehframe_dwarf_xmm9 , ehframe_dwarf_xmm9 , -1U, debugserver_xmm9 , g_contained_ymm9 , NULL }, - { e_regSetFPU, fpu_xmm10, "xmm10" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm10) , 0, ehframe_dwarf_xmm10, ehframe_dwarf_xmm10, -1U, debugserver_xmm10, g_contained_ymm10, NULL }, - { e_regSetFPU, fpu_xmm11, "xmm11" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm11) , 0, ehframe_dwarf_xmm11, ehframe_dwarf_xmm11, -1U, debugserver_xmm11, g_contained_ymm11, NULL }, - { e_regSetFPU, fpu_xmm12, "xmm12" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm12) , 0, ehframe_dwarf_xmm12, ehframe_dwarf_xmm12, -1U, debugserver_xmm12, g_contained_ymm12, NULL }, - { e_regSetFPU, fpu_xmm13, "xmm13" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm13) , 0, ehframe_dwarf_xmm13, ehframe_dwarf_xmm13, -1U, debugserver_xmm13, g_contained_ymm13, NULL }, - { e_regSetFPU, fpu_xmm14, "xmm14" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm14) , 0, ehframe_dwarf_xmm14, ehframe_dwarf_xmm14, -1U, debugserver_xmm14, g_contained_ymm14, NULL }, - { e_regSetFPU, fpu_xmm15, "xmm15" , NULL, Vector, VectorOfUInt8, FPU_SIZE_XMM(xmm15) , 0, ehframe_dwarf_xmm15, ehframe_dwarf_xmm15, -1U, debugserver_xmm15, g_contained_ymm15, NULL } - +static const char *g_contained_ymm0[] = {"ymm0", NULL}; +static const char *g_contained_ymm1[] = {"ymm1", NULL}; +static const char *g_contained_ymm2[] = {"ymm2", NULL}; +static const char *g_contained_ymm3[] = {"ymm3", NULL}; +static const char *g_contained_ymm4[] = {"ymm4", NULL}; +static const char *g_contained_ymm5[] = {"ymm5", NULL}; +static const char *g_contained_ymm6[] = {"ymm6", NULL}; +static const char *g_contained_ymm7[] = {"ymm7", NULL}; +static const char *g_contained_ymm8[] = {"ymm8", NULL}; +static const char *g_contained_ymm9[] = {"ymm9", NULL}; +static const char *g_contained_ymm10[] = {"ymm10", NULL}; +static const char *g_contained_ymm11[] = {"ymm11", NULL}; +static const char *g_contained_ymm12[] = {"ymm12", NULL}; +static const char *g_contained_ymm13[] = {"ymm13", NULL}; +static const char *g_contained_ymm14[] = {"ymm14", NULL}; +static const char *g_contained_ymm15[] = {"ymm15", NULL}; + +const DNBRegisterInfo DNBArchImplX86_64::g_fpu_registers_avx[] = { + {e_regSetFPU, fpu_fcw, "fctrl", NULL, Uint, Hex, FPU_SIZE_UINT(fcw), + AVX_OFFSET(fcw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_fsw, "fstat", NULL, Uint, Hex, FPU_SIZE_UINT(fsw), + AVX_OFFSET(fsw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ftw, "ftag", NULL, Uint, Hex, FPU_SIZE_UINT(ftw), + AVX_OFFSET(ftw), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_fop, "fop", NULL, Uint, Hex, FPU_SIZE_UINT(fop), + AVX_OFFSET(fop), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ip, "fioff", NULL, Uint, Hex, FPU_SIZE_UINT(ip), + AVX_OFFSET(ip), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_cs, "fiseg", NULL, Uint, Hex, FPU_SIZE_UINT(cs), + AVX_OFFSET(cs), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_dp, "fooff", NULL, Uint, Hex, FPU_SIZE_UINT(dp), + AVX_OFFSET(dp), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_ds, "foseg", NULL, Uint, Hex, FPU_SIZE_UINT(ds), + AVX_OFFSET(ds), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_mxcsr, "mxcsr", NULL, Uint, Hex, FPU_SIZE_UINT(mxcsr), + AVX_OFFSET(mxcsr), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetFPU, fpu_mxcsrmask, "mxcsrmask", NULL, Uint, Hex, + FPU_SIZE_UINT(mxcsrmask), AVX_OFFSET(mxcsrmask), -1U, -1U, -1U, -1U, NULL, + NULL}, + + {e_regSetFPU, fpu_stmm0, "stmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm0), AVX_OFFSET(stmm0), ehframe_dwarf_stmm0, + ehframe_dwarf_stmm0, -1U, debugserver_stmm0, NULL, NULL}, + {e_regSetFPU, fpu_stmm1, "stmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm1), AVX_OFFSET(stmm1), ehframe_dwarf_stmm1, + ehframe_dwarf_stmm1, -1U, debugserver_stmm1, NULL, NULL}, + {e_regSetFPU, fpu_stmm2, "stmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm2), AVX_OFFSET(stmm2), ehframe_dwarf_stmm2, + ehframe_dwarf_stmm2, -1U, debugserver_stmm2, NULL, NULL}, + {e_regSetFPU, fpu_stmm3, "stmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm3), AVX_OFFSET(stmm3), ehframe_dwarf_stmm3, + ehframe_dwarf_stmm3, -1U, debugserver_stmm3, NULL, NULL}, + {e_regSetFPU, fpu_stmm4, "stmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm4), AVX_OFFSET(stmm4), ehframe_dwarf_stmm4, + ehframe_dwarf_stmm4, -1U, debugserver_stmm4, NULL, NULL}, + {e_regSetFPU, fpu_stmm5, "stmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm5), AVX_OFFSET(stmm5), ehframe_dwarf_stmm5, + ehframe_dwarf_stmm5, -1U, debugserver_stmm5, NULL, NULL}, + {e_regSetFPU, fpu_stmm6, "stmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm6), AVX_OFFSET(stmm6), ehframe_dwarf_stmm6, + ehframe_dwarf_stmm6, -1U, debugserver_stmm6, NULL, NULL}, + {e_regSetFPU, fpu_stmm7, "stmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_MMST(stmm7), AVX_OFFSET(stmm7), ehframe_dwarf_stmm7, + ehframe_dwarf_stmm7, -1U, debugserver_stmm7, NULL, NULL}, + + {e_regSetFPU, fpu_ymm0, "ymm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm0), AVX_OFFSET_YMM(0), ehframe_dwarf_ymm0, + ehframe_dwarf_ymm0, -1U, debugserver_ymm0, NULL, NULL}, + {e_regSetFPU, fpu_ymm1, "ymm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm1), AVX_OFFSET_YMM(1), ehframe_dwarf_ymm1, + ehframe_dwarf_ymm1, -1U, debugserver_ymm1, NULL, NULL}, + {e_regSetFPU, fpu_ymm2, "ymm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm2), AVX_OFFSET_YMM(2), ehframe_dwarf_ymm2, + ehframe_dwarf_ymm2, -1U, debugserver_ymm2, NULL, NULL}, + {e_regSetFPU, fpu_ymm3, "ymm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm3), AVX_OFFSET_YMM(3), ehframe_dwarf_ymm3, + ehframe_dwarf_ymm3, -1U, debugserver_ymm3, NULL, NULL}, + {e_regSetFPU, fpu_ymm4, "ymm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm4), AVX_OFFSET_YMM(4), ehframe_dwarf_ymm4, + ehframe_dwarf_ymm4, -1U, debugserver_ymm4, NULL, NULL}, + {e_regSetFPU, fpu_ymm5, "ymm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm5), AVX_OFFSET_YMM(5), ehframe_dwarf_ymm5, + ehframe_dwarf_ymm5, -1U, debugserver_ymm5, NULL, NULL}, + {e_regSetFPU, fpu_ymm6, "ymm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm6), AVX_OFFSET_YMM(6), ehframe_dwarf_ymm6, + ehframe_dwarf_ymm6, -1U, debugserver_ymm6, NULL, NULL}, + {e_regSetFPU, fpu_ymm7, "ymm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm7), AVX_OFFSET_YMM(7), ehframe_dwarf_ymm7, + ehframe_dwarf_ymm7, -1U, debugserver_ymm7, NULL, NULL}, + {e_regSetFPU, fpu_ymm8, "ymm8", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm8), AVX_OFFSET_YMM(8), ehframe_dwarf_ymm8, + ehframe_dwarf_ymm8, -1U, debugserver_ymm8, NULL, NULL}, + {e_regSetFPU, fpu_ymm9, "ymm9", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm9), AVX_OFFSET_YMM(9), ehframe_dwarf_ymm9, + ehframe_dwarf_ymm9, -1U, debugserver_ymm9, NULL, NULL}, + {e_regSetFPU, fpu_ymm10, "ymm10", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm10), AVX_OFFSET_YMM(10), ehframe_dwarf_ymm10, + ehframe_dwarf_ymm10, -1U, debugserver_ymm10, NULL, NULL}, + {e_regSetFPU, fpu_ymm11, "ymm11", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm11), AVX_OFFSET_YMM(11), ehframe_dwarf_ymm11, + ehframe_dwarf_ymm11, -1U, debugserver_ymm11, NULL, NULL}, + {e_regSetFPU, fpu_ymm12, "ymm12", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm12), AVX_OFFSET_YMM(12), ehframe_dwarf_ymm12, + ehframe_dwarf_ymm12, -1U, debugserver_ymm12, NULL, NULL}, + {e_regSetFPU, fpu_ymm13, "ymm13", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm13), AVX_OFFSET_YMM(13), ehframe_dwarf_ymm13, + ehframe_dwarf_ymm13, -1U, debugserver_ymm13, NULL, NULL}, + {e_regSetFPU, fpu_ymm14, "ymm14", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm14), AVX_OFFSET_YMM(14), ehframe_dwarf_ymm14, + ehframe_dwarf_ymm14, -1U, debugserver_ymm14, NULL, NULL}, + {e_regSetFPU, fpu_ymm15, "ymm15", NULL, Vector, VectorOfUInt8, + FPU_SIZE_YMM(ymm15), AVX_OFFSET_YMM(15), ehframe_dwarf_ymm15, + ehframe_dwarf_ymm15, -1U, debugserver_ymm15, NULL, NULL}, + + {e_regSetFPU, fpu_xmm0, "xmm0", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm0), 0, ehframe_dwarf_xmm0, ehframe_dwarf_xmm0, -1U, + debugserver_xmm0, g_contained_ymm0, NULL}, + {e_regSetFPU, fpu_xmm1, "xmm1", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm1), 0, ehframe_dwarf_xmm1, ehframe_dwarf_xmm1, -1U, + debugserver_xmm1, g_contained_ymm1, NULL}, + {e_regSetFPU, fpu_xmm2, "xmm2", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm2), 0, ehframe_dwarf_xmm2, ehframe_dwarf_xmm2, -1U, + debugserver_xmm2, g_contained_ymm2, NULL}, + {e_regSetFPU, fpu_xmm3, "xmm3", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm3), 0, ehframe_dwarf_xmm3, ehframe_dwarf_xmm3, -1U, + debugserver_xmm3, g_contained_ymm3, NULL}, + {e_regSetFPU, fpu_xmm4, "xmm4", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm4), 0, ehframe_dwarf_xmm4, ehframe_dwarf_xmm4, -1U, + debugserver_xmm4, g_contained_ymm4, NULL}, + {e_regSetFPU, fpu_xmm5, "xmm5", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm5), 0, ehframe_dwarf_xmm5, ehframe_dwarf_xmm5, -1U, + debugserver_xmm5, g_contained_ymm5, NULL}, + {e_regSetFPU, fpu_xmm6, "xmm6", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm6), 0, ehframe_dwarf_xmm6, ehframe_dwarf_xmm6, -1U, + debugserver_xmm6, g_contained_ymm6, NULL}, + {e_regSetFPU, fpu_xmm7, "xmm7", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm7), 0, ehframe_dwarf_xmm7, ehframe_dwarf_xmm7, -1U, + debugserver_xmm7, g_contained_ymm7, NULL}, + {e_regSetFPU, fpu_xmm8, "xmm8", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm8), 0, ehframe_dwarf_xmm8, ehframe_dwarf_xmm8, -1U, + debugserver_xmm8, g_contained_ymm8, NULL}, + {e_regSetFPU, fpu_xmm9, "xmm9", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm9), 0, ehframe_dwarf_xmm9, ehframe_dwarf_xmm9, -1U, + debugserver_xmm9, g_contained_ymm9, NULL}, + {e_regSetFPU, fpu_xmm10, "xmm10", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm10), 0, ehframe_dwarf_xmm10, ehframe_dwarf_xmm10, -1U, + debugserver_xmm10, g_contained_ymm10, NULL}, + {e_regSetFPU, fpu_xmm11, "xmm11", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm11), 0, ehframe_dwarf_xmm11, ehframe_dwarf_xmm11, -1U, + debugserver_xmm11, g_contained_ymm11, NULL}, + {e_regSetFPU, fpu_xmm12, "xmm12", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm12), 0, ehframe_dwarf_xmm12, ehframe_dwarf_xmm12, -1U, + debugserver_xmm12, g_contained_ymm12, NULL}, + {e_regSetFPU, fpu_xmm13, "xmm13", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm13), 0, ehframe_dwarf_xmm13, ehframe_dwarf_xmm13, -1U, + debugserver_xmm13, g_contained_ymm13, NULL}, + {e_regSetFPU, fpu_xmm14, "xmm14", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm14), 0, ehframe_dwarf_xmm14, ehframe_dwarf_xmm14, -1U, + debugserver_xmm14, g_contained_ymm14, NULL}, + {e_regSetFPU, fpu_xmm15, "xmm15", NULL, Vector, VectorOfUInt8, + FPU_SIZE_XMM(xmm15), 0, ehframe_dwarf_xmm15, ehframe_dwarf_xmm15, -1U, + debugserver_xmm15, g_contained_ymm15, NULL} }; // Exception registers -const DNBRegisterInfo -DNBArchImplX86_64::g_exc_registers[] = -{ - { e_regSetEXC, exc_trapno, "trapno" , NULL, Uint, Hex, EXC_SIZE (trapno) , EXC_OFFSET (trapno) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetEXC, exc_err, "err" , NULL, Uint, Hex, EXC_SIZE (err) , EXC_OFFSET (err) , -1U, -1U, -1U, -1U, NULL, NULL }, - { e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, EXC_SIZE (faultvaddr), EXC_OFFSET (faultvaddr) , -1U, -1U, -1U, -1U, NULL, NULL } -}; +const DNBRegisterInfo DNBArchImplX86_64::g_exc_registers[] = { + {e_regSetEXC, exc_trapno, "trapno", NULL, Uint, Hex, EXC_SIZE(trapno), + EXC_OFFSET(trapno), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetEXC, exc_err, "err", NULL, Uint, Hex, EXC_SIZE(err), + EXC_OFFSET(err), -1U, -1U, -1U, -1U, NULL, NULL}, + {e_regSetEXC, exc_faultvaddr, "faultvaddr", NULL, Uint, Hex, + EXC_SIZE(faultvaddr), EXC_OFFSET(faultvaddr), -1U, -1U, -1U, -1U, NULL, + NULL}}; // Number of registers in each register set -const size_t DNBArchImplX86_64::k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplX86_64::k_num_fpu_registers_no_avx = sizeof(g_fpu_registers_no_avx)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplX86_64::k_num_fpu_registers_avx = sizeof(g_fpu_registers_avx)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplX86_64::k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); -const size_t DNBArchImplX86_64::k_num_all_registers_no_avx = k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; -const size_t DNBArchImplX86_64::k_num_all_registers_avx = k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; +const size_t DNBArchImplX86_64::k_num_gpr_registers = + sizeof(g_gpr_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplX86_64::k_num_fpu_registers_no_avx = + sizeof(g_fpu_registers_no_avx) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplX86_64::k_num_fpu_registers_avx = + sizeof(g_fpu_registers_avx) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplX86_64::k_num_exc_registers = + sizeof(g_exc_registers) / sizeof(DNBRegisterInfo); +const size_t DNBArchImplX86_64::k_num_all_registers_no_avx = + k_num_gpr_registers + k_num_fpu_registers_no_avx + k_num_exc_registers; +const size_t DNBArchImplX86_64::k_num_all_registers_avx = + k_num_gpr_registers + k_num_fpu_registers_avx + k_num_exc_registers; //---------------------------------------------------------------------- // Register set definitions. The first definitions at register set index // of zero is for all registers, followed by other registers sets. The // register information for the all register set need not be filled in. //---------------------------------------------------------------------- -const DNBRegisterSetInfo -DNBArchImplX86_64::g_reg_sets_no_avx[] = -{ - { "x86_64 Registers", NULL, k_num_all_registers_no_avx }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_fpu_registers_no_avx, k_num_fpu_registers_no_avx }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; - -const DNBRegisterSetInfo -DNBArchImplX86_64::g_reg_sets_avx[] = -{ - { "x86_64 Registers", NULL, k_num_all_registers_avx }, - { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, - { "Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx }, - { "Exception State Registers", g_exc_registers, k_num_exc_registers } -}; +const DNBRegisterSetInfo DNBArchImplX86_64::g_reg_sets_no_avx[] = { + {"x86_64 Registers", NULL, k_num_all_registers_no_avx}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_fpu_registers_no_avx, + k_num_fpu_registers_no_avx}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; + +const DNBRegisterSetInfo DNBArchImplX86_64::g_reg_sets_avx[] = { + {"x86_64 Registers", NULL, k_num_all_registers_avx}, + {"General Purpose Registers", g_gpr_registers, k_num_gpr_registers}, + {"Floating Point Registers", g_fpu_registers_avx, k_num_fpu_registers_avx}, + {"Exception State Registers", g_exc_registers, k_num_exc_registers}}; // Total number of register sets for this architecture -const size_t DNBArchImplX86_64::k_num_register_sets = sizeof(g_reg_sets_avx)/sizeof(DNBRegisterSetInfo); - +const size_t DNBArchImplX86_64::k_num_register_sets = + sizeof(g_reg_sets_avx) / sizeof(DNBRegisterSetInfo); -DNBArchProtocol * -DNBArchImplX86_64::Create (MachThread *thread) -{ - DNBArchImplX86_64 *obj = new DNBArchImplX86_64 (thread); - return obj; +DNBArchProtocol *DNBArchImplX86_64::Create(MachThread *thread) { + DNBArchImplX86_64 *obj = new DNBArchImplX86_64(thread); + return obj; } const uint8_t * -DNBArchImplX86_64::SoftwareBreakpointOpcode (nub_size_t byte_size) -{ - static const uint8_t g_breakpoint_opcode[] = { 0xCC }; - if (byte_size == 1) - return g_breakpoint_opcode; - return NULL; +DNBArchImplX86_64::SoftwareBreakpointOpcode(nub_size_t byte_size) { + static const uint8_t g_breakpoint_opcode[] = {0xCC}; + if (byte_size == 1) + return g_breakpoint_opcode; + return NULL; } const DNBRegisterSetInfo * -DNBArchImplX86_64::GetRegisterSetInfo(nub_size_t *num_reg_sets) -{ - *num_reg_sets = k_num_register_sets; - - if (CPUHasAVX() || FORCE_AVX_REGS) - return g_reg_sets_avx; - else - return g_reg_sets_no_avx; +DNBArchImplX86_64::GetRegisterSetInfo(nub_size_t *num_reg_sets) { + *num_reg_sets = k_num_register_sets; + + if (CPUHasAVX() || FORCE_AVX_REGS) + return g_reg_sets_avx; + else + return g_reg_sets_no_avx; } -void -DNBArchImplX86_64::Initialize() -{ - DNBArchPluginInfo arch_plugin_info = - { - CPU_TYPE_X86_64, - DNBArchImplX86_64::Create, - DNBArchImplX86_64::GetRegisterSetInfo, - DNBArchImplX86_64::SoftwareBreakpointOpcode - }; - - // Register this arch plug-in with the main protocol class - DNBArchProtocol::RegisterArchPlugin (arch_plugin_info); +void DNBArchImplX86_64::Initialize() { + DNBArchPluginInfo arch_plugin_info = { + CPU_TYPE_X86_64, DNBArchImplX86_64::Create, + DNBArchImplX86_64::GetRegisterSetInfo, + DNBArchImplX86_64::SoftwareBreakpointOpcode}; + + // Register this arch plug-in with the main protocol class + DNBArchProtocol::RegisterArchPlugin(arch_plugin_info); } -bool -DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_rip; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_rsp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_rbp; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_rflags; - break; - - case GENERIC_REGNUM_RA: // Return Address - default: - return false; - } +bool DNBArchImplX86_64::GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_rip; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_rsp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_rbp; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_rflags; + break; + + case GENERIC_REGNUM_RA: // Return Address + default: + return false; } - - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - value->info = *regInfo; - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - value->value.uint64 = ((uint64_t*)(&m_state.context.gpr))[reg]; - return true; - } - break; - - case e_regSetFPU: - if (CPUHasAVX() || FORCE_AVX_REGS) - { - switch (reg) - { - case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)); return true; - case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)); return true; - case fpu_ftw: value->value.uint8 = m_state.context.fpu.avx.__fpu_ftw; return true; - case fpu_fop: value->value.uint16 = m_state.context.fpu.avx.__fpu_fop; return true; - case fpu_ip: value->value.uint32 = m_state.context.fpu.avx.__fpu_ip; return true; - case fpu_cs: value->value.uint16 = m_state.context.fpu.avx.__fpu_cs; return true; - case fpu_dp: value->value.uint32 = m_state.context.fpu.avx.__fpu_dp; return true; - case fpu_ds: value->value.uint16 = m_state.context.fpu.avx.__fpu_ds; return true; - case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsr; return true; - case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsrmask; return true; - - case fpu_stmm0: - case fpu_stmm1: - case fpu_stmm2: - case fpu_stmm3: - case fpu_stmm4: - case fpu_stmm5: - case fpu_stmm6: - case fpu_stmm7: - memcpy(&value->value.uint8, &m_state.context.fpu.avx.__fpu_stmm0 + (reg - fpu_stmm0), 10); - return true; - - case fpu_xmm0: - case fpu_xmm1: - case fpu_xmm2: - case fpu_xmm3: - case fpu_xmm4: - case fpu_xmm5: - case fpu_xmm6: - case fpu_xmm7: - case fpu_xmm8: - case fpu_xmm9: - case fpu_xmm10: - case fpu_xmm11: - case fpu_xmm12: - case fpu_xmm13: - case fpu_xmm14: - case fpu_xmm15: - memcpy(&value->value.uint8, &m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_xmm0), 16); - return true; - - case fpu_ymm0: - case fpu_ymm1: - case fpu_ymm2: - case fpu_ymm3: - case fpu_ymm4: - case fpu_ymm5: - case fpu_ymm6: - case fpu_ymm7: - case fpu_ymm8: - case fpu_ymm9: - case fpu_ymm10: - case fpu_ymm11: - case fpu_ymm12: - case fpu_ymm13: - case fpu_ymm14: - case fpu_ymm15: - memcpy(&value->value.uint8, &m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_ymm0), 16); - memcpy((&value->value.uint8) + 16, &m_state.context.fpu.avx.__fpu_ymmh0 + (reg - fpu_ymm0), 16); - return true; - } - } - else - { - switch (reg) - { - case fpu_fcw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)); return true; - case fpu_fsw: value->value.uint16 = *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)); return true; - case fpu_ftw: value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw; return true; - case fpu_fop: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop; return true; - case fpu_ip: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_ip; return true; - case fpu_cs: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_cs; return true; - case fpu_dp: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_dp; return true; - case fpu_ds: value->value.uint16 = m_state.context.fpu.no_avx.__fpu_ds; return true; - case fpu_mxcsr: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsr; return true; - case fpu_mxcsrmask: value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsrmask; return true; - - case fpu_stmm0: - case fpu_stmm1: - case fpu_stmm2: - case fpu_stmm3: - case fpu_stmm4: - case fpu_stmm5: - case fpu_stmm6: - case fpu_stmm7: - memcpy(&value->value.uint8, &m_state.context.fpu.no_avx.__fpu_stmm0 + (reg - fpu_stmm0), 10); - return true; - - case fpu_xmm0: - case fpu_xmm1: - case fpu_xmm2: - case fpu_xmm3: - case fpu_xmm4: - case fpu_xmm5: - case fpu_xmm6: - case fpu_xmm7: - case fpu_xmm8: - case fpu_xmm9: - case fpu_xmm10: - case fpu_xmm11: - case fpu_xmm12: - case fpu_xmm13: - case fpu_xmm14: - case fpu_xmm15: - memcpy(&value->value.uint8, &m_state.context.fpu.no_avx.__fpu_xmm0 + (reg - fpu_xmm0), 16); - return true; - } - } - break; - - case e_regSetEXC: - switch (reg) - { - case exc_trapno: value->value.uint32 = m_state.context.exc.__trapno; return true; - case exc_err: value->value.uint32 = m_state.context.exc.__err; return true; - case exc_faultvaddr:value->value.uint64 = m_state.context.exc.__faultvaddr; return true; - } - break; + } + + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + value->info = *regInfo; + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + value->value.uint64 = ((uint64_t *)(&m_state.context.gpr))[reg]; + return true; + } + break; + + case e_regSetFPU: + if (CPUHasAVX() || FORCE_AVX_REGS) { + switch (reg) { + case fpu_fcw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)); + return true; + case fpu_fsw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)); + return true; + case fpu_ftw: + value->value.uint8 = m_state.context.fpu.avx.__fpu_ftw; + return true; + case fpu_fop: + value->value.uint16 = m_state.context.fpu.avx.__fpu_fop; + return true; + case fpu_ip: + value->value.uint32 = m_state.context.fpu.avx.__fpu_ip; + return true; + case fpu_cs: + value->value.uint16 = m_state.context.fpu.avx.__fpu_cs; + return true; + case fpu_dp: + value->value.uint32 = m_state.context.fpu.avx.__fpu_dp; + return true; + case fpu_ds: + value->value.uint16 = m_state.context.fpu.avx.__fpu_ds; + return true; + case fpu_mxcsr: + value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsr; + return true; + case fpu_mxcsrmask: + value->value.uint32 = m_state.context.fpu.avx.__fpu_mxcsrmask; + return true; + + case fpu_stmm0: + case fpu_stmm1: + case fpu_stmm2: + case fpu_stmm3: + case fpu_stmm4: + case fpu_stmm5: + case fpu_stmm6: + case fpu_stmm7: + memcpy(&value->value.uint8, + &m_state.context.fpu.avx.__fpu_stmm0 + (reg - fpu_stmm0), 10); + return true; + + case fpu_xmm0: + case fpu_xmm1: + case fpu_xmm2: + case fpu_xmm3: + case fpu_xmm4: + case fpu_xmm5: + case fpu_xmm6: + case fpu_xmm7: + case fpu_xmm8: + case fpu_xmm9: + case fpu_xmm10: + case fpu_xmm11: + case fpu_xmm12: + case fpu_xmm13: + case fpu_xmm14: + case fpu_xmm15: + memcpy(&value->value.uint8, + &m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_xmm0), 16); + return true; + + case fpu_ymm0: + case fpu_ymm1: + case fpu_ymm2: + case fpu_ymm3: + case fpu_ymm4: + case fpu_ymm5: + case fpu_ymm6: + case fpu_ymm7: + case fpu_ymm8: + case fpu_ymm9: + case fpu_ymm10: + case fpu_ymm11: + case fpu_ymm12: + case fpu_ymm13: + case fpu_ymm14: + case fpu_ymm15: + memcpy(&value->value.uint8, + &m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_ymm0), 16); + memcpy((&value->value.uint8) + 16, + &m_state.context.fpu.avx.__fpu_ymmh0 + (reg - fpu_ymm0), 16); + return true; } + } else { + switch (reg) { + case fpu_fcw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)); + return true; + case fpu_fsw: + value->value.uint16 = + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)); + return true; + case fpu_ftw: + value->value.uint8 = m_state.context.fpu.no_avx.__fpu_ftw; + return true; + case fpu_fop: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_fop; + return true; + case fpu_ip: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_ip; + return true; + case fpu_cs: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_cs; + return true; + case fpu_dp: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_dp; + return true; + case fpu_ds: + value->value.uint16 = m_state.context.fpu.no_avx.__fpu_ds; + return true; + case fpu_mxcsr: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsr; + return true; + case fpu_mxcsrmask: + value->value.uint32 = m_state.context.fpu.no_avx.__fpu_mxcsrmask; + return true; + + case fpu_stmm0: + case fpu_stmm1: + case fpu_stmm2: + case fpu_stmm3: + case fpu_stmm4: + case fpu_stmm5: + case fpu_stmm6: + case fpu_stmm7: + memcpy(&value->value.uint8, + &m_state.context.fpu.no_avx.__fpu_stmm0 + (reg - fpu_stmm0), + 10); + return true; + + case fpu_xmm0: + case fpu_xmm1: + case fpu_xmm2: + case fpu_xmm3: + case fpu_xmm4: + case fpu_xmm5: + case fpu_xmm6: + case fpu_xmm7: + case fpu_xmm8: + case fpu_xmm9: + case fpu_xmm10: + case fpu_xmm11: + case fpu_xmm12: + case fpu_xmm13: + case fpu_xmm14: + case fpu_xmm15: + memcpy(&value->value.uint8, + &m_state.context.fpu.no_avx.__fpu_xmm0 + (reg - fpu_xmm0), 16); + return true; + } + } + break; + + case e_regSetEXC: + switch (reg) { + case exc_trapno: + value->value.uint32 = m_state.context.exc.__trapno; + return true; + case exc_err: + value->value.uint32 = m_state.context.exc.__err; + return true; + case exc_faultvaddr: + value->value.uint64 = m_state.context.exc.__faultvaddr; + return true; + } + break; } - return false; + } + return false; } +bool DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value) { + if (set == REGISTER_SET_GENERIC) { + switch (reg) { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = gpr_rip; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = gpr_rsp; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + set = e_regSetGPR; + reg = gpr_rbp; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = gpr_rflags; + break; + + case GENERIC_REGNUM_RA: // Return Address + default: + return false; + } + } -bool -DNBArchImplX86_64::SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value) -{ - if (set == REGISTER_SET_GENERIC) - { - switch (reg) - { - case GENERIC_REGNUM_PC: // Program Counter - set = e_regSetGPR; - reg = gpr_rip; - break; - - case GENERIC_REGNUM_SP: // Stack Pointer - set = e_regSetGPR; - reg = gpr_rsp; - break; - - case GENERIC_REGNUM_FP: // Frame Pointer - set = e_regSetGPR; - reg = gpr_rbp; - break; - - case GENERIC_REGNUM_FLAGS: // Processor flags register - set = e_regSetGPR; - reg = gpr_rflags; - break; - - case GENERIC_REGNUM_RA: // Return Address - default: - return false; + if (GetRegisterState(set, false) != KERN_SUCCESS) + return false; + + bool success = false; + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) { + switch (set) { + case e_regSetGPR: + if (reg < k_num_gpr_registers) { + ((uint64_t *)(&m_state.context.gpr))[reg] = value->value.uint64; + success = true; + } + break; + + case e_regSetFPU: + if (CPUHasAVX() || FORCE_AVX_REGS) { + switch (reg) { + case fpu_fcw: + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)) = + value->value.uint16; + success = true; + break; + case fpu_fsw: + *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)) = + value->value.uint16; + success = true; + break; + case fpu_ftw: + m_state.context.fpu.avx.__fpu_ftw = value->value.uint8; + success = true; + break; + case fpu_fop: + m_state.context.fpu.avx.__fpu_fop = value->value.uint16; + success = true; + break; + case fpu_ip: + m_state.context.fpu.avx.__fpu_ip = value->value.uint32; + success = true; + break; + case fpu_cs: + m_state.context.fpu.avx.__fpu_cs = value->value.uint16; + success = true; + break; + case fpu_dp: + m_state.context.fpu.avx.__fpu_dp = value->value.uint32; + success = true; + break; + case fpu_ds: + m_state.context.fpu.avx.__fpu_ds = value->value.uint16; + success = true; + break; + case fpu_mxcsr: + m_state.context.fpu.avx.__fpu_mxcsr = value->value.uint32; + success = true; + break; + case fpu_mxcsrmask: + m_state.context.fpu.avx.__fpu_mxcsrmask = value->value.uint32; + success = true; + break; + + case fpu_stmm0: + case fpu_stmm1: + case fpu_stmm2: + case fpu_stmm3: + case fpu_stmm4: + case fpu_stmm5: + case fpu_stmm6: + case fpu_stmm7: + memcpy(&m_state.context.fpu.avx.__fpu_stmm0 + (reg - fpu_stmm0), + &value->value.uint8, 10); + success = true; + break; + + case fpu_xmm0: + case fpu_xmm1: + case fpu_xmm2: + case fpu_xmm3: + case fpu_xmm4: + case fpu_xmm5: + case fpu_xmm6: + case fpu_xmm7: + case fpu_xmm8: + case fpu_xmm9: + case fpu_xmm10: + case fpu_xmm11: + case fpu_xmm12: + case fpu_xmm13: + case fpu_xmm14: + case fpu_xmm15: + memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_xmm0), + &value->value.uint8, 16); + success = true; + break; + + case fpu_ymm0: + case fpu_ymm1: + case fpu_ymm2: + case fpu_ymm3: + case fpu_ymm4: + case fpu_ymm5: + case fpu_ymm6: + case fpu_ymm7: + case fpu_ymm8: + case fpu_ymm9: + case fpu_ymm10: + case fpu_ymm11: + case fpu_ymm12: + case fpu_ymm13: + case fpu_ymm14: + case fpu_ymm15: + memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_ymm0), + &value->value.uint8, 16); + memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + (reg - fpu_ymm0), + (&value->value.uint8) + 16, 16); + return true; } - } - - if (GetRegisterState(set, false) != KERN_SUCCESS) - return false; - - bool success = false; - const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); - if (regInfo) - { - switch (set) - { - case e_regSetGPR: - if (reg < k_num_gpr_registers) - { - ((uint64_t*)(&m_state.context.gpr))[reg] = value->value.uint64; - success = true; - } - break; - - case e_regSetFPU: - if (CPUHasAVX() || FORCE_AVX_REGS) - { - switch (reg) - { - case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fcw)) = value->value.uint16; success = true; break; - case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.avx.__fpu_fsw)) = value->value.uint16; success = true; break; - case fpu_ftw: m_state.context.fpu.avx.__fpu_ftw = value->value.uint8; success = true; break; - case fpu_fop: m_state.context.fpu.avx.__fpu_fop = value->value.uint16; success = true; break; - case fpu_ip: m_state.context.fpu.avx.__fpu_ip = value->value.uint32; success = true; break; - case fpu_cs: m_state.context.fpu.avx.__fpu_cs = value->value.uint16; success = true; break; - case fpu_dp: m_state.context.fpu.avx.__fpu_dp = value->value.uint32; success = true; break; - case fpu_ds: m_state.context.fpu.avx.__fpu_ds = value->value.uint16; success = true; break; - case fpu_mxcsr: m_state.context.fpu.avx.__fpu_mxcsr = value->value.uint32; success = true; break; - case fpu_mxcsrmask: m_state.context.fpu.avx.__fpu_mxcsrmask = value->value.uint32; success = true; break; - - case fpu_stmm0: - case fpu_stmm1: - case fpu_stmm2: - case fpu_stmm3: - case fpu_stmm4: - case fpu_stmm5: - case fpu_stmm6: - case fpu_stmm7: - memcpy (&m_state.context.fpu.avx.__fpu_stmm0 + (reg - fpu_stmm0), &value->value.uint8, 10); - success = true; - break; - - case fpu_xmm0: - case fpu_xmm1: - case fpu_xmm2: - case fpu_xmm3: - case fpu_xmm4: - case fpu_xmm5: - case fpu_xmm6: - case fpu_xmm7: - case fpu_xmm8: - case fpu_xmm9: - case fpu_xmm10: - case fpu_xmm11: - case fpu_xmm12: - case fpu_xmm13: - case fpu_xmm14: - case fpu_xmm15: - memcpy (&m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_xmm0), &value->value.uint8, 16); - success = true; - break; - - case fpu_ymm0: - case fpu_ymm1: - case fpu_ymm2: - case fpu_ymm3: - case fpu_ymm4: - case fpu_ymm5: - case fpu_ymm6: - case fpu_ymm7: - case fpu_ymm8: - case fpu_ymm9: - case fpu_ymm10: - case fpu_ymm11: - case fpu_ymm12: - case fpu_ymm13: - case fpu_ymm14: - case fpu_ymm15: - memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + (reg - fpu_ymm0), &value->value.uint8, 16); - memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + (reg - fpu_ymm0), (&value->value.uint8) + 16, 16); - return true; - } - } - else - { - switch (reg) - { - case fpu_fcw: *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)) = value->value.uint16; success = true; break; - case fpu_fsw: *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)) = value->value.uint16; success = true; break; - case fpu_ftw: m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8; success = true; break; - case fpu_fop: m_state.context.fpu.no_avx.__fpu_fop = value->value.uint16; success = true; break; - case fpu_ip: m_state.context.fpu.no_avx.__fpu_ip = value->value.uint32; success = true; break; - case fpu_cs: m_state.context.fpu.no_avx.__fpu_cs = value->value.uint16; success = true; break; - case fpu_dp: m_state.context.fpu.no_avx.__fpu_dp = value->value.uint32; success = true; break; - case fpu_ds: m_state.context.fpu.no_avx.__fpu_ds = value->value.uint16; success = true; break; - case fpu_mxcsr: m_state.context.fpu.no_avx.__fpu_mxcsr = value->value.uint32; success = true; break; - case fpu_mxcsrmask: m_state.context.fpu.no_avx.__fpu_mxcsrmask = value->value.uint32; success = true; break; - - case fpu_stmm0: - case fpu_stmm1: - case fpu_stmm2: - case fpu_stmm3: - case fpu_stmm4: - case fpu_stmm5: - case fpu_stmm6: - case fpu_stmm7: - memcpy (&m_state.context.fpu.no_avx.__fpu_stmm0 + (reg - fpu_stmm0), &value->value.uint8, 10); - success = true; - break; - - case fpu_xmm0: - case fpu_xmm1: - case fpu_xmm2: - case fpu_xmm3: - case fpu_xmm4: - case fpu_xmm5: - case fpu_xmm6: - case fpu_xmm7: - case fpu_xmm8: - case fpu_xmm9: - case fpu_xmm10: - case fpu_xmm11: - case fpu_xmm12: - case fpu_xmm13: - case fpu_xmm14: - case fpu_xmm15: - memcpy (&m_state.context.fpu.no_avx.__fpu_xmm0 + (reg - fpu_xmm0), &value->value.uint8, 16); - success = true; - break; - } - } - break; - - case e_regSetEXC: - switch (reg) - { - case exc_trapno: m_state.context.exc.__trapno = value->value.uint32; success = true; break; - case exc_err: m_state.context.exc.__err = value->value.uint32; success = true; break; - case exc_faultvaddr:m_state.context.exc.__faultvaddr = value->value.uint64; success = true; break; - } - break; + } else { + switch (reg) { + case fpu_fcw: + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fcw)) = + value->value.uint16; + success = true; + break; + case fpu_fsw: + *((uint16_t *)(&m_state.context.fpu.no_avx.__fpu_fsw)) = + value->value.uint16; + success = true; + break; + case fpu_ftw: + m_state.context.fpu.no_avx.__fpu_ftw = value->value.uint8; + success = true; + break; + case fpu_fop: + m_state.context.fpu.no_avx.__fpu_fop = value->value.uint16; + success = true; + break; + case fpu_ip: + m_state.context.fpu.no_avx.__fpu_ip = value->value.uint32; + success = true; + break; + case fpu_cs: + m_state.context.fpu.no_avx.__fpu_cs = value->value.uint16; + success = true; + break; + case fpu_dp: + m_state.context.fpu.no_avx.__fpu_dp = value->value.uint32; + success = true; + break; + case fpu_ds: + m_state.context.fpu.no_avx.__fpu_ds = value->value.uint16; + success = true; + break; + case fpu_mxcsr: + m_state.context.fpu.no_avx.__fpu_mxcsr = value->value.uint32; + success = true; + break; + case fpu_mxcsrmask: + m_state.context.fpu.no_avx.__fpu_mxcsrmask = value->value.uint32; + success = true; + break; + + case fpu_stmm0: + case fpu_stmm1: + case fpu_stmm2: + case fpu_stmm3: + case fpu_stmm4: + case fpu_stmm5: + case fpu_stmm6: + case fpu_stmm7: + memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + (reg - fpu_stmm0), + &value->value.uint8, 10); + success = true; + break; + + case fpu_xmm0: + case fpu_xmm1: + case fpu_xmm2: + case fpu_xmm3: + case fpu_xmm4: + case fpu_xmm5: + case fpu_xmm6: + case fpu_xmm7: + case fpu_xmm8: + case fpu_xmm9: + case fpu_xmm10: + case fpu_xmm11: + case fpu_xmm12: + case fpu_xmm13: + case fpu_xmm14: + case fpu_xmm15: + memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0 + (reg - fpu_xmm0), + &value->value.uint8, 16); + success = true; + break; } + } + break; + + case e_regSetEXC: + switch (reg) { + case exc_trapno: + m_state.context.exc.__trapno = value->value.uint32; + success = true; + break; + case exc_err: + m_state.context.exc.__err = value->value.uint32; + success = true; + break; + case exc_faultvaddr: + m_state.context.exc.__faultvaddr = value->value.uint64; + success = true; + break; + } + break; } - - if (success) - return SetRegisterState(set) == KERN_SUCCESS; - return false; + } + + if (success) + return SetRegisterState(set) == KERN_SUCCESS; + return false; } -uint32_t -DNBArchImplX86_64::GetRegisterContextSize() -{ - static uint32_t g_cached_size = 0; - if (g_cached_size == 0) - { - if (CPUHasAVX() || FORCE_AVX_REGS) - { - for (size_t i=0; i<k_num_fpu_registers_avx; ++i) - { - if (g_fpu_registers_avx[i].value_regs == NULL) - g_cached_size += g_fpu_registers_avx[i].size; - } - } - else - { - for (size_t i=0; i<k_num_fpu_registers_no_avx; ++i) - { - if (g_fpu_registers_no_avx[i].value_regs == NULL) - g_cached_size += g_fpu_registers_no_avx[i].size; - } - } - DNBLogThreaded ("DNBArchImplX86_64::GetRegisterContextSize() - GPR = %zu, FPU = %u, EXC = %zu", sizeof(GPR), g_cached_size, sizeof(EXC)); - g_cached_size += sizeof(GPR); - g_cached_size += sizeof(EXC); - DNBLogThreaded ("DNBArchImplX86_64::GetRegisterContextSize() - GPR + FPU + EXC = %u", g_cached_size); +uint32_t DNBArchImplX86_64::GetRegisterContextSize() { + static uint32_t g_cached_size = 0; + if (g_cached_size == 0) { + if (CPUHasAVX() || FORCE_AVX_REGS) { + for (size_t i = 0; i < k_num_fpu_registers_avx; ++i) { + if (g_fpu_registers_avx[i].value_regs == NULL) + g_cached_size += g_fpu_registers_avx[i].size; + } + } else { + for (size_t i = 0; i < k_num_fpu_registers_no_avx; ++i) { + if (g_fpu_registers_no_avx[i].value_regs == NULL) + g_cached_size += g_fpu_registers_no_avx[i].size; + } } - return g_cached_size; + DNBLogThreaded("DNBArchImplX86_64::GetRegisterContextSize() - GPR = %zu, " + "FPU = %u, EXC = %zu", + sizeof(GPR), g_cached_size, sizeof(EXC)); + g_cached_size += sizeof(GPR); + g_cached_size += sizeof(EXC); + DNBLogThreaded( + "DNBArchImplX86_64::GetRegisterContextSize() - GPR + FPU + EXC = %u", + g_cached_size); + } + return g_cached_size; } -nub_size_t -DNBArchImplX86_64::GetRegisterContext (void *buf, nub_size_t buf_len) -{ - uint32_t size = GetRegisterContextSize(); - - if (buf && buf_len) - { - bool force = false; - kern_return_t kret; - - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %llu) error: GPR regs failed to read: %u ", buf, (uint64_t)buf_len, kret); - size = 0; - } - else - if ((kret = GetFPUState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %llu) error: %s regs failed to read: %u", buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); - size = 0; +nub_size_t DNBArchImplX86_64::GetRegisterContext(void *buf, + nub_size_t buf_len) { + uint32_t size = GetRegisterContextSize(); + + if (buf && buf_len) { + bool force = false; + kern_return_t kret; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf " + "= %p, len = %llu) error: GPR regs failed " + "to read: %u ", + buf, (uint64_t)buf_len, kret); + size = 0; + } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf( + LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = " + "%llu) error: %s regs failed to read: %u", + buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); + size = 0; + } else if ((kret = GetEXCState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf " + "= %p, len = %llu) error: EXC regs failed " + "to read: %u", + buf, (uint64_t)buf_len, kret); + size = 0; + } else { + uint8_t *p = (uint8_t *)buf; + // Copy the GPR registers + memcpy(p, &m_state.context.gpr, sizeof(GPR)); + p += sizeof(GPR); + + if (CPUHasAVX() || FORCE_AVX_REGS) { + // Walk around the gaps in the FPU regs + memcpy(p, &m_state.context.fpu.avx.__fpu_fcw, 5); + p += 5; + memcpy(p, &m_state.context.fpu.avx.__fpu_fop, 8); + p += 8; + memcpy(p, &m_state.context.fpu.avx.__fpu_dp, 6); + p += 6; + memcpy(p, &m_state.context.fpu.avx.__fpu_mxcsr, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(p, &m_state.context.fpu.avx.__fpu_stmm0 + i, 10); + p += 10; } - else - if ((kret = GetEXCState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %llu) error: EXC regs failed to read: %u", buf, (uint64_t)buf_len, kret); - size = 0; + + // Interleave the XMM and YMMH registers to make the YMM registers + for (size_t i = 0; i < 16; ++i) { + memcpy(p, &m_state.context.fpu.avx.__fpu_xmm0 + i, 16); + p += 16; + memcpy(p, &m_state.context.fpu.avx.__fpu_ymmh0 + i, 16); + p += 16; } - else - { - uint8_t *p = (uint8_t *)buf; - // Copy the GPR registers - memcpy(p, &m_state.context.gpr, sizeof(GPR)); - p += sizeof(GPR); - - if (CPUHasAVX() || FORCE_AVX_REGS) - { - // Walk around the gaps in the FPU regs - memcpy(p, &m_state.context.fpu.avx.__fpu_fcw, 5); - p += 5; - memcpy(p, &m_state.context.fpu.avx.__fpu_fop, 8); - p += 8; - memcpy(p, &m_state.context.fpu.avx.__fpu_dp, 6); - p += 6; - memcpy(p, &m_state.context.fpu.avx.__fpu_mxcsr, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(p, &m_state.context.fpu.avx.__fpu_stmm0 + i, 10); - p += 10; - } - - // Interleave the XMM and YMMH registers to make the YMM registers - for (size_t i=0; i<16; ++i) - { - memcpy(p, &m_state.context.fpu.avx.__fpu_xmm0 + i, 16); - p += 16; - memcpy(p, &m_state.context.fpu.avx.__fpu_ymmh0 + i, 16); - p += 16; - } - } - else - { - // Walk around the gaps in the FPU regs - memcpy(p, &m_state.context.fpu.no_avx.__fpu_fcw, 5); - p += 5; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_fop, 8); - p += 8; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_dp, 6); - p += 6; - memcpy(p, &m_state.context.fpu.no_avx.__fpu_mxcsr, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(p, &m_state.context.fpu.no_avx.__fpu_stmm0 + i, 10); - p += 10; - } - - // Copy the XMM registers in a single block - memcpy(p, &m_state.context.fpu.no_avx.__fpu_xmm0, 16 * 16); - p += 16 * 16; - } - - // Copy the exception registers - memcpy(p, &m_state.context.exc, sizeof(EXC)); - p += sizeof(EXC); - - // make sure we end up with exactly what we think we should have - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); + } else { + // Walk around the gaps in the FPU regs + memcpy(p, &m_state.context.fpu.no_avx.__fpu_fcw, 5); + p += 5; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_fop, 8); + p += 8; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_dp, 6); + p += 6; + memcpy(p, &m_state.context.fpu.no_avx.__fpu_mxcsr, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(p, &m_state.context.fpu.no_avx.__fpu_stmm0 + i, 10); + p += 10; } - } + // Copy the XMM registers in a single block + memcpy(p, &m_state.context.fpu.no_avx.__fpu_xmm0, 16 * 16); + p += 16 * 16; + } - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %llu) => %u", buf, (uint64_t)buf_len, size); - // Return the size of the register context even if NULL was passed in - return size; -} + // Copy the exception registers + memcpy(p, &m_state.context.exc, sizeof(EXC)); + p += sizeof(EXC); -nub_size_t -DNBArchImplX86_64::SetRegisterContext (const void *buf, nub_size_t buf_len) -{ - uint32_t size = GetRegisterContextSize(); - if (buf == NULL || buf_len == 0) - size = 0; - - if (size) - { - if (size > buf_len) - size = static_cast<uint32_t>(buf_len); - - uint8_t *p = (uint8_t *)buf; - // Copy the GPR registers - memcpy(&m_state.context.gpr, p, sizeof(GPR)); - p += sizeof(GPR); - - if (CPUHasAVX() || FORCE_AVX_REGS) - { - // Walk around the gaps in the FPU regs - memcpy(&m_state.context.fpu.avx.__fpu_fcw, p, 5); - p += 5; - memcpy(&m_state.context.fpu.avx.__fpu_fop, p, 8); - p += 8; - memcpy(&m_state.context.fpu.avx.__fpu_dp, p, 6); - p += 6; - memcpy(&m_state.context.fpu.avx.__fpu_mxcsr, p, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(&m_state.context.fpu.avx.__fpu_stmm0 + i, p, 10); - p += 10; - } - - // Interleave the XMM and YMMH registers to make the YMM registers - for (size_t i=0; i<16; ++i) - { - memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + i, p, 16); - p += 16; - memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + i, p, 16); - p += 16; - } - } - else - { - // Copy fcw through mxcsrmask as there is no padding - memcpy(&m_state.context.fpu.no_avx.__fpu_fcw, p, 5); - p += 5; - memcpy(&m_state.context.fpu.no_avx.__fpu_fop, p, 8); - p += 8; - memcpy(&m_state.context.fpu.no_avx.__fpu_dp, p, 6); - p += 6; - memcpy(&m_state.context.fpu.no_avx.__fpu_mxcsr, p, 8); - p += 8; - - // Work around the padding between the stmm registers as they are 16 - // byte structs with 10 bytes of the value in each - for (size_t i=0; i<8; ++i) - { - memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + i, p, 10); - p += 10; - } - - // Copy the XMM registers in a single block - memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0, p, 16 * 16); - p += 16 * 16; - } - - // Copy the exception registers - memcpy(&m_state.context.exc, p, sizeof(EXC)); - p += sizeof(EXC); - - // make sure we end up with exactly what we think we should have - size_t bytes_written = p - (uint8_t *)buf; - UNUSED_IF_ASSERT_DISABLED(bytes_written); - assert (bytes_written == size); - - kern_return_t kret; - if ((kret = SetGPRState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %llu) error: GPR regs failed to write: %u", buf, (uint64_t)buf_len, kret); - if ((kret = SetFPUState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %llu) error: %s regs failed to write: %u", buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); - if ((kret = SetEXCState()) != KERN_SUCCESS) - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %llu) error: EXP regs failed to write: %u", buf, (uint64_t)buf_len, kret); + // make sure we end up with exactly what we think we should have + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); } - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %llu) => %llu", buf, (uint64_t)buf_len, (uint64_t)size); - return size; + } + + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchImplX86_64::GetRegisterContext (buf = %p, len = %llu) => %u", buf, + (uint64_t)buf_len, size); + // Return the size of the register context even if NULL was passed in + return size; } -uint32_t -DNBArchImplX86_64::SaveRegisterState () -{ - kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); - DNBLogThreadedIf (LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u (SetGPRState() for stop_count = %u)", m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); - - // Always re-read the registers because above we call thread_abort_safely(); - bool force = true; - - if ((kret = GetGPRState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: GPR regs failed to read: %u ", kret); - } - else if ((kret = GetFPUState(force)) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () error: %s regs failed to read: %u", CPUHasAVX() ? "AVX" : "FPU", kret); - } - else - { - const uint32_t save_id = GetNextRegisterStateSaveID (); - m_saved_register_states[save_id] = m_state.context; - return save_id; +nub_size_t DNBArchImplX86_64::SetRegisterContext(const void *buf, + nub_size_t buf_len) { + uint32_t size = GetRegisterContextSize(); + if (buf == NULL || buf_len == 0) + size = 0; + + if (size) { + if (size > buf_len) + size = static_cast<uint32_t>(buf_len); + + uint8_t *p = (uint8_t *)buf; + // Copy the GPR registers + memcpy(&m_state.context.gpr, p, sizeof(GPR)); + p += sizeof(GPR); + + if (CPUHasAVX() || FORCE_AVX_REGS) { + // Walk around the gaps in the FPU regs + memcpy(&m_state.context.fpu.avx.__fpu_fcw, p, 5); + p += 5; + memcpy(&m_state.context.fpu.avx.__fpu_fop, p, 8); + p += 8; + memcpy(&m_state.context.fpu.avx.__fpu_dp, p, 6); + p += 6; + memcpy(&m_state.context.fpu.avx.__fpu_mxcsr, p, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(&m_state.context.fpu.avx.__fpu_stmm0 + i, p, 10); + p += 10; + } + + // Interleave the XMM and YMMH registers to make the YMM registers + for (size_t i = 0; i < 16; ++i) { + memcpy(&m_state.context.fpu.avx.__fpu_xmm0 + i, p, 16); + p += 16; + memcpy(&m_state.context.fpu.avx.__fpu_ymmh0 + i, p, 16); + p += 16; + } + } else { + // Copy fcw through mxcsrmask as there is no padding + memcpy(&m_state.context.fpu.no_avx.__fpu_fcw, p, 5); + p += 5; + memcpy(&m_state.context.fpu.no_avx.__fpu_fop, p, 8); + p += 8; + memcpy(&m_state.context.fpu.no_avx.__fpu_dp, p, 6); + p += 6; + memcpy(&m_state.context.fpu.no_avx.__fpu_mxcsr, p, 8); + p += 8; + + // Work around the padding between the stmm registers as they are 16 + // byte structs with 10 bytes of the value in each + for (size_t i = 0; i < 8; ++i) { + memcpy(&m_state.context.fpu.no_avx.__fpu_stmm0 + i, p, 10); + p += 10; + } + + // Copy the XMM registers in a single block + memcpy(&m_state.context.fpu.no_avx.__fpu_xmm0, p, 16 * 16); + p += 16 * 16; } - return 0; + + // Copy the exception registers + memcpy(&m_state.context.exc, p, sizeof(EXC)); + p += sizeof(EXC); + + // make sure we end up with exactly what we think we should have + size_t bytes_written = p - (uint8_t *)buf; + UNUSED_IF_ASSERT_DISABLED(bytes_written); + assert(bytes_written == size); + + kern_return_t kret; + if ((kret = SetGPRState()) != KERN_SUCCESS) + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf " + "= %p, len = %llu) error: GPR regs failed " + "to write: %u", + buf, (uint64_t)buf_len, kret); + if ((kret = SetFPUState()) != KERN_SUCCESS) + DNBLogThreadedIf( + LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = " + "%llu) error: %s regs failed to write: %u", + buf, (uint64_t)buf_len, CPUHasAVX() ? "AVX" : "FPU", kret); + if ((kret = SetEXCState()) != KERN_SUCCESS) + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::SetRegisterContext (buf " + "= %p, len = %llu) error: EXP regs failed " + "to write: %u", + buf, (uint64_t)buf_len, kret); + } + DNBLogThreadedIf( + LOG_THREAD, + "DNBArchImplX86_64::SetRegisterContext (buf = %p, len = %llu) => %llu", + buf, (uint64_t)buf_len, (uint64_t)size); + return size; } -bool -DNBArchImplX86_64::RestoreRegisterState (uint32_t save_id) -{ - SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); - if (pos != m_saved_register_states.end()) - { - m_state.context.gpr = pos->second.gpr; - m_state.context.fpu = pos->second.fpu; - m_state.SetError(e_regSetGPR, Read, 0); - m_state.SetError(e_regSetFPU, Read, 0); - kern_return_t kret; - bool success = true; - if ((kret = SetGPRState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: GPR regs failed to write: %u", save_id, kret); - success = false; - } - else if ((kret = SetFPUState()) != KERN_SUCCESS) - { - DNBLogThreadedIf (LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState (save_id = %u) error: %s regs failed to write: %u", save_id, CPUHasAVX() ? "AVX" : "FPU", kret); - success = false; - } - m_saved_register_states.erase(pos); - return success; + +uint32_t DNBArchImplX86_64::SaveRegisterState() { + kern_return_t kret = ::thread_abort_safely(m_thread->MachPortNumber()); + DNBLogThreadedIf( + LOG_THREAD, "thread = 0x%4.4x calling thread_abort_safely (tid) => %u " + "(SetGPRState() for stop_count = %u)", + m_thread->MachPortNumber(), kret, m_thread->Process()->StopCount()); + + // Always re-read the registers because above we call thread_abort_safely(); + bool force = true; + + if ((kret = GetGPRState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () " + "error: GPR regs failed to read: %u ", + kret); + } else if ((kret = GetFPUState(force)) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::SaveRegisterState () " + "error: %s regs failed to read: %u", + CPUHasAVX() ? "AVX" : "FPU", kret); + } else { + const uint32_t save_id = GetNextRegisterStateSaveID(); + m_saved_register_states[save_id] = m_state.context; + return save_id; + } + return 0; +} +bool DNBArchImplX86_64::RestoreRegisterState(uint32_t save_id) { + SaveRegisterStates::iterator pos = m_saved_register_states.find(save_id); + if (pos != m_saved_register_states.end()) { + m_state.context.gpr = pos->second.gpr; + m_state.context.fpu = pos->second.fpu; + m_state.SetError(e_regSetGPR, Read, 0); + m_state.SetError(e_regSetFPU, Read, 0); + kern_return_t kret; + bool success = true; + if ((kret = SetGPRState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState " + "(save_id = %u) error: GPR regs failed to " + "write: %u", + save_id, kret); + success = false; + } else if ((kret = SetFPUState()) != KERN_SUCCESS) { + DNBLogThreadedIf(LOG_THREAD, "DNBArchImplX86_64::RestoreRegisterState " + "(save_id = %u) error: %s regs failed to " + "write: %u", + save_id, CPUHasAVX() ? "AVX" : "FPU", kret); + success = false; } - return false; + m_saved_register_states.erase(pos); + return success; + } + return false; } - -kern_return_t -DNBArchImplX86_64::GetRegisterState(int set, bool force) -{ - switch (set) - { - case e_regSetALL: return GetGPRState(force) | GetFPUState(force) | GetEXCState(force); - case e_regSetGPR: return GetGPRState(force); - case e_regSetFPU: return GetFPUState(force); - case e_regSetEXC: return GetEXCState(force); - default: break; - } - return KERN_INVALID_ARGUMENT; +kern_return_t DNBArchImplX86_64::GetRegisterState(int set, bool force) { + switch (set) { + case e_regSetALL: + return GetGPRState(force) | GetFPUState(force) | GetEXCState(force); + case e_regSetGPR: + return GetGPRState(force); + case e_regSetFPU: + return GetFPUState(force); + case e_regSetEXC: + return GetEXCState(force); + default: + break; + } + return KERN_INVALID_ARGUMENT; } -kern_return_t -DNBArchImplX86_64::SetRegisterState(int set) -{ - // Make sure we have a valid context to set. - if (RegisterSetStateIsValid(set)) - { - switch (set) - { - case e_regSetALL: return SetGPRState() | SetFPUState() | SetEXCState(); - case e_regSetGPR: return SetGPRState(); - case e_regSetFPU: return SetFPUState(); - case e_regSetEXC: return SetEXCState(); - default: break; - } +kern_return_t DNBArchImplX86_64::SetRegisterState(int set) { + // Make sure we have a valid context to set. + if (RegisterSetStateIsValid(set)) { + switch (set) { + case e_regSetALL: + return SetGPRState() | SetFPUState() | SetEXCState(); + case e_regSetGPR: + return SetGPRState(); + case e_regSetFPU: + return SetFPUState(); + case e_regSetEXC: + return SetEXCState(); + default: + break; } - return KERN_INVALID_ARGUMENT; + } + return KERN_INVALID_ARGUMENT; } -bool -DNBArchImplX86_64::RegisterSetStateIsValid (int set) const -{ - return m_state.RegsAreValid(set); +bool DNBArchImplX86_64::RegisterSetStateIsValid(int set) const { + return m_state.RegsAreValid(set); } - - -#endif // #if defined (__i386__) || defined (__x86_64__) +#endif // #if defined (__i386__) || defined (__x86_64__) diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h index 20844951261..1b8a3c7da4b 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/DNBArchImplX86_64.h @@ -14,7 +14,7 @@ #ifndef __DNBArchImplX86_64_h__ #define __DNBArchImplX86_64_h__ -#if defined (__i386__) || defined (__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #include "DNBArch.h" #include "MachRegisterStatesX86_64.h" @@ -22,239 +22,213 @@ class MachThread; -class DNBArchImplX86_64 : public DNBArchProtocol -{ +class DNBArchImplX86_64 : public DNBArchProtocol { public: - DNBArchImplX86_64(MachThread *thread) : - DNBArchProtocol(), - m_thread(thread), - m_state(), - m_2pc_dbg_checkpoint(), - m_2pc_trans_state(Trans_Done), - m_saved_register_states() - { + DNBArchImplX86_64(MachThread *thread) + : DNBArchProtocol(), m_thread(thread), m_state(), m_2pc_dbg_checkpoint(), + m_2pc_trans_state(Trans_Done), m_saved_register_states() {} + virtual ~DNBArchImplX86_64() {} + + static void Initialize(); + + virtual bool GetRegisterValue(uint32_t set, uint32_t reg, + DNBRegisterValue *value); + virtual bool SetRegisterValue(uint32_t set, uint32_t reg, + const DNBRegisterValue *value); + virtual nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); + virtual nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); + virtual uint32_t SaveRegisterState(); + virtual bool RestoreRegisterState(uint32_t save_id); + + virtual kern_return_t GetRegisterState(int set, bool force); + virtual kern_return_t SetRegisterState(int set); + virtual bool RegisterSetStateIsValid(int set) const; + + virtual uint64_t GetPC(uint64_t failValue); // Get program counter + virtual kern_return_t SetPC(uint64_t value); + virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer + virtual void ThreadWillResume(); + virtual bool ThreadDidStop(); + virtual bool NotifyException(MachException::Data &exc); + + virtual uint32_t NumSupportedHardwareWatchpoints(); + virtual uint32_t EnableHardwareWatchpoint(nub_addr_t addr, nub_size_t size, + bool read, bool write, + bool also_set_on_task); + virtual bool DisableHardwareWatchpoint(uint32_t hw_break_index, + bool also_set_on_task); + virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + +protected: + kern_return_t EnableHardwareSingleStep(bool enable); + + typedef __x86_64_thread_state_t GPR; + typedef __x86_64_float_state_t FPU; + typedef __x86_64_exception_state_t EXC; + typedef __x86_64_avx_state_t AVX; + typedef __x86_64_debug_state_t DBG; + + static const DNBRegisterInfo g_gpr_registers[]; + static const DNBRegisterInfo g_fpu_registers_no_avx[]; + static const DNBRegisterInfo g_fpu_registers_avx[]; + static const DNBRegisterInfo g_exc_registers[]; + static const DNBRegisterSetInfo g_reg_sets_no_avx[]; + static const DNBRegisterSetInfo g_reg_sets_avx[]; + static const size_t k_num_gpr_registers; + static const size_t k_num_fpu_registers_no_avx; + static const size_t k_num_fpu_registers_avx; + static const size_t k_num_exc_registers; + static const size_t k_num_all_registers_no_avx; + static const size_t k_num_all_registers_avx; + static const size_t k_num_register_sets; + + typedef enum RegisterSetTag { + e_regSetALL = REGISTER_SET_ALL, + e_regSetGPR, + e_regSetFPU, + e_regSetEXC, + e_regSetDBG, + kNumRegisterSets + } RegisterSet; + + typedef enum RegisterSetWordSizeTag { + e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int), + e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int), + e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int), + e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int), + e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int) + } RegisterSetWordSize; + + enum { Read = 0, Write = 1, kNumErrors = 2 }; + + struct Context { + GPR gpr; + union { + FPU no_avx; + AVX avx; + } fpu; + EXC exc; + DBG dbg; + }; + + struct State { + Context context; + kern_return_t gpr_errs[2]; // Read/Write errors + kern_return_t fpu_errs[2]; // Read/Write errors + kern_return_t exc_errs[2]; // Read/Write errors + kern_return_t dbg_errs[2]; // Read/Write errors + + State() { + uint32_t i; + for (i = 0; i < kNumErrors; i++) { + gpr_errs[i] = -1; + fpu_errs[i] = -1; + exc_errs[i] = -1; + dbg_errs[i] = -1; + } } - virtual ~DNBArchImplX86_64() - { + + void InvalidateAllRegisterStates() { SetError(e_regSetALL, Read, -1); } + + kern_return_t GetError(int flavor, uint32_t err_idx) const { + if (err_idx < kNumErrors) { + switch (flavor) { + // When getting all errors, just OR all values together to see if + // we got any kind of error. + case e_regSetALL: + return gpr_errs[err_idx] | fpu_errs[err_idx] | exc_errs[err_idx]; + case e_regSetGPR: + return gpr_errs[err_idx]; + case e_regSetFPU: + return fpu_errs[err_idx]; + case e_regSetEXC: + return exc_errs[err_idx]; + case e_regSetDBG: + return dbg_errs[err_idx]; + default: + break; + } + } + return -1; } - static void Initialize(); - - virtual bool GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value); - virtual bool SetRegisterValue(uint32_t set, uint32_t reg, const DNBRegisterValue *value); - virtual nub_size_t GetRegisterContext (void *buf, nub_size_t buf_len); - virtual nub_size_t SetRegisterContext (const void *buf, nub_size_t buf_len); - virtual uint32_t SaveRegisterState (); - virtual bool RestoreRegisterState (uint32_t save_id); - - virtual kern_return_t GetRegisterState (int set, bool force); - virtual kern_return_t SetRegisterState (int set); - virtual bool RegisterSetStateIsValid (int set) const; - - virtual uint64_t GetPC(uint64_t failValue); // Get program counter - virtual kern_return_t SetPC(uint64_t value); - virtual uint64_t GetSP(uint64_t failValue); // Get stack pointer - virtual void ThreadWillResume(); - virtual bool ThreadDidStop(); - virtual bool NotifyException(MachException::Data& exc); - - virtual uint32_t NumSupportedHardwareWatchpoints(); - virtual uint32_t EnableHardwareWatchpoint (nub_addr_t addr, nub_size_t size, bool read, bool write, bool also_set_on_task); - virtual bool DisableHardwareWatchpoint (uint32_t hw_break_index, bool also_set_on_task); - virtual uint32_t GetHardwareWatchpointHit(nub_addr_t &addr); + bool SetError(int flavor, uint32_t err_idx, kern_return_t err) { + if (err_idx < kNumErrors) { + switch (flavor) { + case e_regSetALL: + gpr_errs[err_idx] = fpu_errs[err_idx] = exc_errs[err_idx] = + dbg_errs[err_idx] = err; + return true; -protected: - kern_return_t EnableHardwareSingleStep (bool enable); - - typedef __x86_64_thread_state_t GPR; - typedef __x86_64_float_state_t FPU; - typedef __x86_64_exception_state_t EXC; - typedef __x86_64_avx_state_t AVX; - typedef __x86_64_debug_state_t DBG; - - static const DNBRegisterInfo g_gpr_registers[]; - static const DNBRegisterInfo g_fpu_registers_no_avx[]; - static const DNBRegisterInfo g_fpu_registers_avx[]; - static const DNBRegisterInfo g_exc_registers[]; - static const DNBRegisterSetInfo g_reg_sets_no_avx[]; - static const DNBRegisterSetInfo g_reg_sets_avx[]; - static const size_t k_num_gpr_registers; - static const size_t k_num_fpu_registers_no_avx; - static const size_t k_num_fpu_registers_avx; - static const size_t k_num_exc_registers; - static const size_t k_num_all_registers_no_avx; - static const size_t k_num_all_registers_avx; - static const size_t k_num_register_sets; - - typedef enum RegisterSetTag - { - e_regSetALL = REGISTER_SET_ALL, - e_regSetGPR, - e_regSetFPU, - e_regSetEXC, - e_regSetDBG, - kNumRegisterSets - } RegisterSet; - - typedef enum RegisterSetWordSizeTag - { - e_regSetWordSizeGPR = sizeof(GPR) / sizeof(int), - e_regSetWordSizeFPU = sizeof(FPU) / sizeof(int), - e_regSetWordSizeEXC = sizeof(EXC) / sizeof(int), - e_regSetWordSizeAVX = sizeof(AVX) / sizeof(int), - e_regSetWordSizeDBG = sizeof(DBG) / sizeof(int) - } RegisterSetWordSize; - - enum - { - Read = 0, - Write = 1, - kNumErrors = 2 - }; - - struct Context - { - GPR gpr; - union { - FPU no_avx; - AVX avx; - } fpu; - EXC exc; - DBG dbg; - }; - - struct State - { - Context context; - kern_return_t gpr_errs[2]; // Read/Write errors - kern_return_t fpu_errs[2]; // Read/Write errors - kern_return_t exc_errs[2]; // Read/Write errors - kern_return_t dbg_errs[2]; // Read/Write errors - - State() - { - uint32_t i; - for (i=0; i<kNumErrors; i++) - { - gpr_errs[i] = -1; - fpu_errs[i] = -1; - exc_errs[i] = -1; - dbg_errs[i] = -1; - } - } - - void - InvalidateAllRegisterStates() - { - SetError (e_regSetALL, Read, -1); - } + case e_regSetGPR: + gpr_errs[err_idx] = err; + return true; - kern_return_t - GetError (int flavor, uint32_t err_idx) const - { - if (err_idx < kNumErrors) - { - switch (flavor) - { - // When getting all errors, just OR all values together to see if - // we got any kind of error. - case e_regSetALL: return gpr_errs[err_idx] | - fpu_errs[err_idx] | - exc_errs[err_idx]; - case e_regSetGPR: return gpr_errs[err_idx]; - case e_regSetFPU: return fpu_errs[err_idx]; - case e_regSetEXC: return exc_errs[err_idx]; - case e_regSetDBG: return dbg_errs[err_idx]; - default: break; - } - } - return -1; - } + case e_regSetFPU: + fpu_errs[err_idx] = err; + return true; - bool - SetError (int flavor, uint32_t err_idx, kern_return_t err) - { - if (err_idx < kNumErrors) - { - switch (flavor) - { - case e_regSetALL: - gpr_errs[err_idx] = - fpu_errs[err_idx] = - exc_errs[err_idx] = - dbg_errs[err_idx] = err; - return true; - - case e_regSetGPR: - gpr_errs[err_idx] = err; - return true; - - case e_regSetFPU: - fpu_errs[err_idx] = err; - return true; - - case e_regSetEXC: - exc_errs[err_idx] = err; - return true; - - case e_regSetDBG: - dbg_errs[err_idx] = err; - return true; - - default: break; - } - } - return false; - } + case e_regSetEXC: + exc_errs[err_idx] = err; + return true; + + case e_regSetDBG: + dbg_errs[err_idx] = err; + return true; - bool - RegsAreValid (int flavor) const - { - return GetError(flavor, Read) == KERN_SUCCESS; + default: + break; } - }; - - kern_return_t GetGPRState (bool force); - kern_return_t GetFPUState (bool force); - kern_return_t GetEXCState (bool force); - kern_return_t GetDBGState (bool force); - - kern_return_t SetGPRState (); - kern_return_t SetFPUState (); - kern_return_t SetEXCState (); - kern_return_t SetDBGState (bool also_set_on_task); - - static DNBArchProtocol * - Create (MachThread *thread); - - static const uint8_t * - SoftwareBreakpointOpcode (nub_size_t byte_size); - - static const DNBRegisterSetInfo * - GetRegisterSetInfo(nub_size_t *num_reg_sets); - - static uint32_t GetRegisterContextSize(); - - // Helper functions for watchpoint manipulations. - static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, nub_addr_t addr, nub_size_t size, bool read, bool write); - static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); - static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index); - static void ClearWatchpointHits(DBG &debug_state); - static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); - static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); - - virtual bool StartTransForHWP(); - virtual bool RollbackTransForHWP(); - virtual bool FinishTransForHWP(); - DBG GetDBGCheckpoint(); - - MachThread *m_thread; - State m_state; - DBG m_2pc_dbg_checkpoint; - uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning (0), Done (1), or Rolled Back (2)? - typedef std::map<uint32_t, Context> SaveRegisterStates; - SaveRegisterStates m_saved_register_states; + } + return false; + } + + bool RegsAreValid(int flavor) const { + return GetError(flavor, Read) == KERN_SUCCESS; + } + }; + + kern_return_t GetGPRState(bool force); + kern_return_t GetFPUState(bool force); + kern_return_t GetEXCState(bool force); + kern_return_t GetDBGState(bool force); + + kern_return_t SetGPRState(); + kern_return_t SetFPUState(); + kern_return_t SetEXCState(); + kern_return_t SetDBGState(bool also_set_on_task); + + static DNBArchProtocol *Create(MachThread *thread); + + static const uint8_t *SoftwareBreakpointOpcode(nub_size_t byte_size); + + static const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets); + + static uint32_t GetRegisterContextSize(); + + // Helper functions for watchpoint manipulations. + static void SetWatchpoint(DBG &debug_state, uint32_t hw_index, + nub_addr_t addr, nub_size_t size, bool read, + bool write); + static void ClearWatchpoint(DBG &debug_state, uint32_t hw_index); + static bool IsWatchpointVacant(const DBG &debug_state, uint32_t hw_index); + static void ClearWatchpointHits(DBG &debug_state); + static bool IsWatchpointHit(const DBG &debug_state, uint32_t hw_index); + static nub_addr_t GetWatchAddress(const DBG &debug_state, uint32_t hw_index); + + virtual bool StartTransForHWP(); + virtual bool RollbackTransForHWP(); + virtual bool FinishTransForHWP(); + DBG GetDBGCheckpoint(); + + MachThread *m_thread; + State m_state; + DBG m_2pc_dbg_checkpoint; + uint32_t m_2pc_trans_state; // Is transaction of DBG state change: Pedning + // (0), Done (1), or Rolled Back (2)? + typedef std::map<uint32_t, Context> SaveRegisterStates; + SaveRegisterStates m_saved_register_states; }; -#endif // #if defined (__i386__) || defined (__x86_64__) -#endif // #ifndef __DNBArchImplX86_64_h__ +#endif // #if defined (__i386__) || defined (__x86_64__) +#endif // #ifndef __DNBArchImplX86_64_h__ diff --git a/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h b/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h index 4e48e9645dd..5ed67611e6e 100644 --- a/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h +++ b/lldb/tools/debugserver/source/MacOSX/x86_64/MachRegisterStatesX86_64.h @@ -1,4 +1,5 @@ -//===-- MachRegisterStatesX86_64.h --------------------------------*- C++ -*-===// +//===-- MachRegisterStatesX86_64.h --------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -16,195 +17,192 @@ #include <inttypes.h> -#define __x86_64_THREAD_STATE 4 -#define __x86_64_FLOAT_STATE 5 -#define __x86_64_EXCEPTION_STATE 6 -#define __x86_64_DEBUG_STATE 11 -#define __x86_64_AVX_STATE 17 +#define __x86_64_THREAD_STATE 4 +#define __x86_64_FLOAT_STATE 5 +#define __x86_64_EXCEPTION_STATE 6 +#define __x86_64_DEBUG_STATE 11 +#define __x86_64_AVX_STATE 17 typedef struct { - uint64_t __rax; - uint64_t __rbx; - uint64_t __rcx; - uint64_t __rdx; - uint64_t __rdi; - uint64_t __rsi; - uint64_t __rbp; - uint64_t __rsp; - uint64_t __r8; - uint64_t __r9; - uint64_t __r10; - uint64_t __r11; - uint64_t __r12; - uint64_t __r13; - uint64_t __r14; - uint64_t __r15; - uint64_t __rip; - uint64_t __rflags; - uint64_t __cs; - uint64_t __fs; - uint64_t __gs; + uint64_t __rax; + uint64_t __rbx; + uint64_t __rcx; + uint64_t __rdx; + uint64_t __rdi; + uint64_t __rsi; + uint64_t __rbp; + uint64_t __rsp; + uint64_t __r8; + uint64_t __r9; + uint64_t __r10; + uint64_t __r11; + uint64_t __r12; + uint64_t __r13; + uint64_t __r14; + uint64_t __r15; + uint64_t __rip; + uint64_t __rflags; + uint64_t __cs; + uint64_t __fs; + uint64_t __gs; } __x86_64_thread_state_t; typedef struct { - uint16_t __invalid : 1; - uint16_t __denorm : 1; - uint16_t __zdiv : 1; - uint16_t __ovrfl : 1; - uint16_t __undfl : 1; - uint16_t __precis : 1; - uint16_t __PAD1 : 2; - uint16_t __pc : 2; - uint16_t __rc : 2; - uint16_t __PAD2 : 1; - uint16_t __PAD3 : 3; + uint16_t __invalid : 1; + uint16_t __denorm : 1; + uint16_t __zdiv : 1; + uint16_t __ovrfl : 1; + uint16_t __undfl : 1; + uint16_t __precis : 1; + uint16_t __PAD1 : 2; + uint16_t __pc : 2; + uint16_t __rc : 2; + uint16_t __PAD2 : 1; + uint16_t __PAD3 : 3; } __x86_64_fp_control_t; typedef struct { - uint16_t __invalid : 1; - uint16_t __denorm : 1; - uint16_t __zdiv : 1; - uint16_t __ovrfl : 1; - uint16_t __undfl : 1; - uint16_t __precis : 1; - uint16_t __stkflt : 1; - uint16_t __errsumm : 1; - uint16_t __c0 : 1; - uint16_t __c1 : 1; - uint16_t __c2 : 1; - uint16_t __tos : 3; - uint16_t __c3 : 1; - uint16_t __busy : 1; + uint16_t __invalid : 1; + uint16_t __denorm : 1; + uint16_t __zdiv : 1; + uint16_t __ovrfl : 1; + uint16_t __undfl : 1; + uint16_t __precis : 1; + uint16_t __stkflt : 1; + uint16_t __errsumm : 1; + uint16_t __c0 : 1; + uint16_t __c1 : 1; + uint16_t __c2 : 1; + uint16_t __tos : 3; + uint16_t __c3 : 1; + uint16_t __busy : 1; } __x86_64_fp_status_t; typedef struct { - uint8_t __mmst_reg[10]; - uint8_t __mmst_rsrv[6]; + uint8_t __mmst_reg[10]; + uint8_t __mmst_rsrv[6]; } __x86_64_mmst_reg; -typedef struct { - uint8_t __xmm_reg[16]; -} __x86_64_xmm_reg; +typedef struct { uint8_t __xmm_reg[16]; } __x86_64_xmm_reg; typedef struct { - int32_t __fpu_reserved[2]; - __x86_64_fp_control_t __fpu_fcw; - __x86_64_fp_status_t __fpu_fsw; - uint8_t __fpu_ftw; - uint8_t __fpu_rsrv1; - uint16_t __fpu_fop; - uint32_t __fpu_ip; - uint16_t __fpu_cs; - uint16_t __fpu_rsrv2; - uint32_t __fpu_dp; - uint16_t __fpu_ds; - uint16_t __fpu_rsrv3; - uint32_t __fpu_mxcsr; - uint32_t __fpu_mxcsrmask; - __x86_64_mmst_reg __fpu_stmm0; - __x86_64_mmst_reg __fpu_stmm1; - __x86_64_mmst_reg __fpu_stmm2; - __x86_64_mmst_reg __fpu_stmm3; - __x86_64_mmst_reg __fpu_stmm4; - __x86_64_mmst_reg __fpu_stmm5; - __x86_64_mmst_reg __fpu_stmm6; - __x86_64_mmst_reg __fpu_stmm7; - __x86_64_xmm_reg __fpu_xmm0; - __x86_64_xmm_reg __fpu_xmm1; - __x86_64_xmm_reg __fpu_xmm2; - __x86_64_xmm_reg __fpu_xmm3; - __x86_64_xmm_reg __fpu_xmm4; - __x86_64_xmm_reg __fpu_xmm5; - __x86_64_xmm_reg __fpu_xmm6; - __x86_64_xmm_reg __fpu_xmm7; - __x86_64_xmm_reg __fpu_xmm8; - __x86_64_xmm_reg __fpu_xmm9; - __x86_64_xmm_reg __fpu_xmm10; - __x86_64_xmm_reg __fpu_xmm11; - __x86_64_xmm_reg __fpu_xmm12; - __x86_64_xmm_reg __fpu_xmm13; - __x86_64_xmm_reg __fpu_xmm14; - __x86_64_xmm_reg __fpu_xmm15; - uint8_t __fpu_rsrv4[6*16]; - int32_t __fpu_reserved1; + int32_t __fpu_reserved[2]; + __x86_64_fp_control_t __fpu_fcw; + __x86_64_fp_status_t __fpu_fsw; + uint8_t __fpu_ftw; + uint8_t __fpu_rsrv1; + uint16_t __fpu_fop; + uint32_t __fpu_ip; + uint16_t __fpu_cs; + uint16_t __fpu_rsrv2; + uint32_t __fpu_dp; + uint16_t __fpu_ds; + uint16_t __fpu_rsrv3; + uint32_t __fpu_mxcsr; + uint32_t __fpu_mxcsrmask; + __x86_64_mmst_reg __fpu_stmm0; + __x86_64_mmst_reg __fpu_stmm1; + __x86_64_mmst_reg __fpu_stmm2; + __x86_64_mmst_reg __fpu_stmm3; + __x86_64_mmst_reg __fpu_stmm4; + __x86_64_mmst_reg __fpu_stmm5; + __x86_64_mmst_reg __fpu_stmm6; + __x86_64_mmst_reg __fpu_stmm7; + __x86_64_xmm_reg __fpu_xmm0; + __x86_64_xmm_reg __fpu_xmm1; + __x86_64_xmm_reg __fpu_xmm2; + __x86_64_xmm_reg __fpu_xmm3; + __x86_64_xmm_reg __fpu_xmm4; + __x86_64_xmm_reg __fpu_xmm5; + __x86_64_xmm_reg __fpu_xmm6; + __x86_64_xmm_reg __fpu_xmm7; + __x86_64_xmm_reg __fpu_xmm8; + __x86_64_xmm_reg __fpu_xmm9; + __x86_64_xmm_reg __fpu_xmm10; + __x86_64_xmm_reg __fpu_xmm11; + __x86_64_xmm_reg __fpu_xmm12; + __x86_64_xmm_reg __fpu_xmm13; + __x86_64_xmm_reg __fpu_xmm14; + __x86_64_xmm_reg __fpu_xmm15; + uint8_t __fpu_rsrv4[6 * 16]; + int32_t __fpu_reserved1; } __x86_64_float_state_t; typedef struct { - uint32_t __fpu_reserved[2]; - __x86_64_fp_control_t __fpu_fcw; - __x86_64_fp_status_t __fpu_fsw; - uint8_t __fpu_ftw; - uint8_t __fpu_rsrv1; - uint16_t __fpu_fop; - uint32_t __fpu_ip; - uint16_t __fpu_cs; - uint16_t __fpu_rsrv2; - uint32_t __fpu_dp; - uint16_t __fpu_ds; - uint16_t __fpu_rsrv3; - uint32_t __fpu_mxcsr; - uint32_t __fpu_mxcsrmask; - __x86_64_mmst_reg __fpu_stmm0; - __x86_64_mmst_reg __fpu_stmm1; - __x86_64_mmst_reg __fpu_stmm2; - __x86_64_mmst_reg __fpu_stmm3; - __x86_64_mmst_reg __fpu_stmm4; - __x86_64_mmst_reg __fpu_stmm5; - __x86_64_mmst_reg __fpu_stmm6; - __x86_64_mmst_reg __fpu_stmm7; - __x86_64_xmm_reg __fpu_xmm0; - __x86_64_xmm_reg __fpu_xmm1; - __x86_64_xmm_reg __fpu_xmm2; - __x86_64_xmm_reg __fpu_xmm3; - __x86_64_xmm_reg __fpu_xmm4; - __x86_64_xmm_reg __fpu_xmm5; - __x86_64_xmm_reg __fpu_xmm6; - __x86_64_xmm_reg __fpu_xmm7; - __x86_64_xmm_reg __fpu_xmm8; - __x86_64_xmm_reg __fpu_xmm9; - __x86_64_xmm_reg __fpu_xmm10; - __x86_64_xmm_reg __fpu_xmm11; - __x86_64_xmm_reg __fpu_xmm12; - __x86_64_xmm_reg __fpu_xmm13; - __x86_64_xmm_reg __fpu_xmm14; - __x86_64_xmm_reg __fpu_xmm15; - uint8_t __fpu_rsrv4[6*16]; - uint32_t __fpu_reserved1; - uint8_t __avx_reserved1[64]; - __x86_64_xmm_reg __fpu_ymmh0; - __x86_64_xmm_reg __fpu_ymmh1; - __x86_64_xmm_reg __fpu_ymmh2; - __x86_64_xmm_reg __fpu_ymmh3; - __x86_64_xmm_reg __fpu_ymmh4; - __x86_64_xmm_reg __fpu_ymmh5; - __x86_64_xmm_reg __fpu_ymmh6; - __x86_64_xmm_reg __fpu_ymmh7; - __x86_64_xmm_reg __fpu_ymmh8; - __x86_64_xmm_reg __fpu_ymmh9; - __x86_64_xmm_reg __fpu_ymmh10; - __x86_64_xmm_reg __fpu_ymmh11; - __x86_64_xmm_reg __fpu_ymmh12; - __x86_64_xmm_reg __fpu_ymmh13; - __x86_64_xmm_reg __fpu_ymmh14; - __x86_64_xmm_reg __fpu_ymmh15; + uint32_t __fpu_reserved[2]; + __x86_64_fp_control_t __fpu_fcw; + __x86_64_fp_status_t __fpu_fsw; + uint8_t __fpu_ftw; + uint8_t __fpu_rsrv1; + uint16_t __fpu_fop; + uint32_t __fpu_ip; + uint16_t __fpu_cs; + uint16_t __fpu_rsrv2; + uint32_t __fpu_dp; + uint16_t __fpu_ds; + uint16_t __fpu_rsrv3; + uint32_t __fpu_mxcsr; + uint32_t __fpu_mxcsrmask; + __x86_64_mmst_reg __fpu_stmm0; + __x86_64_mmst_reg __fpu_stmm1; + __x86_64_mmst_reg __fpu_stmm2; + __x86_64_mmst_reg __fpu_stmm3; + __x86_64_mmst_reg __fpu_stmm4; + __x86_64_mmst_reg __fpu_stmm5; + __x86_64_mmst_reg __fpu_stmm6; + __x86_64_mmst_reg __fpu_stmm7; + __x86_64_xmm_reg __fpu_xmm0; + __x86_64_xmm_reg __fpu_xmm1; + __x86_64_xmm_reg __fpu_xmm2; + __x86_64_xmm_reg __fpu_xmm3; + __x86_64_xmm_reg __fpu_xmm4; + __x86_64_xmm_reg __fpu_xmm5; + __x86_64_xmm_reg __fpu_xmm6; + __x86_64_xmm_reg __fpu_xmm7; + __x86_64_xmm_reg __fpu_xmm8; + __x86_64_xmm_reg __fpu_xmm9; + __x86_64_xmm_reg __fpu_xmm10; + __x86_64_xmm_reg __fpu_xmm11; + __x86_64_xmm_reg __fpu_xmm12; + __x86_64_xmm_reg __fpu_xmm13; + __x86_64_xmm_reg __fpu_xmm14; + __x86_64_xmm_reg __fpu_xmm15; + uint8_t __fpu_rsrv4[6 * 16]; + uint32_t __fpu_reserved1; + uint8_t __avx_reserved1[64]; + __x86_64_xmm_reg __fpu_ymmh0; + __x86_64_xmm_reg __fpu_ymmh1; + __x86_64_xmm_reg __fpu_ymmh2; + __x86_64_xmm_reg __fpu_ymmh3; + __x86_64_xmm_reg __fpu_ymmh4; + __x86_64_xmm_reg __fpu_ymmh5; + __x86_64_xmm_reg __fpu_ymmh6; + __x86_64_xmm_reg __fpu_ymmh7; + __x86_64_xmm_reg __fpu_ymmh8; + __x86_64_xmm_reg __fpu_ymmh9; + __x86_64_xmm_reg __fpu_ymmh10; + __x86_64_xmm_reg __fpu_ymmh11; + __x86_64_xmm_reg __fpu_ymmh12; + __x86_64_xmm_reg __fpu_ymmh13; + __x86_64_xmm_reg __fpu_ymmh14; + __x86_64_xmm_reg __fpu_ymmh15; } __x86_64_avx_state_t; typedef struct { - uint32_t __trapno; - uint32_t __err; - uint64_t __faultvaddr; + uint32_t __trapno; + uint32_t __err; + uint64_t __faultvaddr; } __x86_64_exception_state_t; - typedef struct { - uint64_t __dr0; - uint64_t __dr1; - uint64_t __dr2; - uint64_t __dr3; - uint64_t __dr4; - uint64_t __dr5; - uint64_t __dr6; - uint64_t __dr7; + uint64_t __dr0; + uint64_t __dr1; + uint64_t __dr2; + uint64_t __dr3; + uint64_t __dr4; + uint64_t __dr5; + uint64_t __dr6; + uint64_t __dr7; } __x86_64_debug_state_t; #endif diff --git a/lldb/tools/debugserver/source/PThreadCondition.h b/lldb/tools/debugserver/source/PThreadCondition.h index 787cc7941d5..9cd64bf2472 100644 --- a/lldb/tools/debugserver/source/PThreadCondition.h +++ b/lldb/tools/debugserver/source/PThreadCondition.h @@ -16,38 +16,20 @@ #include <pthread.h> -class PThreadCondition -{ +class PThreadCondition { public: + PThreadCondition() { ::pthread_cond_init(&m_condition, NULL); } - PThreadCondition() - { - ::pthread_cond_init (&m_condition, NULL); - } + ~PThreadCondition() { ::pthread_cond_destroy(&m_condition); } - ~PThreadCondition() - { - ::pthread_cond_destroy (&m_condition); - } + pthread_cond_t *Condition() { return &m_condition; } - pthread_cond_t *Condition() - { - return &m_condition; - } + int Broadcast() { return ::pthread_cond_broadcast(&m_condition); } - int Broadcast() - { - return ::pthread_cond_broadcast (&m_condition); - } - - int Signal() - { - return ::pthread_cond_signal (&m_condition); - } + int Signal() { return ::pthread_cond_signal(&m_condition); } protected: - pthread_cond_t m_condition; + pthread_cond_t m_condition; }; #endif - diff --git a/lldb/tools/debugserver/source/PThreadEvent.cpp b/lldb/tools/debugserver/source/PThreadEvent.cpp index 47e72756a96..1b0900ca710 100644 --- a/lldb/tools/debugserver/source/PThreadEvent.cpp +++ b/lldb/tools/debugserver/source/PThreadEvent.cpp @@ -12,117 +12,98 @@ //===----------------------------------------------------------------------===// #include "PThreadEvent.h" -#include "errno.h" #include "DNBLog.h" +#include "errno.h" -PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) : - m_mutex(), - m_set_condition(), - m_reset_condition(), - m_bits(bits), - m_validBits(validBits), - m_reset_ack_mask(0) -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", this, __FUNCTION__, bits, validBits); +PThreadEvent::PThreadEvent(uint32_t bits, uint32_t validBits) + : m_mutex(), m_set_condition(), m_reset_condition(), m_bits(bits), + m_validBits(validBits), m_reset_ack_mask(0) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, 0x%8.8x)", + // this, __FUNCTION__, bits, validBits); } -PThreadEvent::~PThreadEvent() -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); +PThreadEvent::~PThreadEvent() { + // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); } - -uint32_t -PThreadEvent::NewEventBit() -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - uint32_t mask = 1; - while (mask & m_validBits) - mask <<= 1; - m_validBits |= mask; - return mask; +uint32_t PThreadEvent::NewEventBit() { + // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + uint32_t mask = 1; + while (mask & m_validBits) + mask <<= 1; + m_validBits |= mask; + return mask; } -void -PThreadEvent::FreeEventBits(const uint32_t mask) -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); - if (mask) - { - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - m_bits &= ~mask; - m_validBits &= ~mask; - } +void PThreadEvent::FreeEventBits(const uint32_t mask) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, + // __FUNCTION__, mask); + if (mask) { + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + m_bits &= ~mask; + m_validBits &= ~mask; + } } - -uint32_t -PThreadEvent::GetEventBits() const -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - uint32_t bits = m_bits; - return bits; +uint32_t PThreadEvent::GetEventBits() const { + // DNBLogThreadedIf(LOG_EVENTS, "%p %s", this, LLVM_PRETTY_FUNCTION); + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + uint32_t bits = m_bits; + return bits; } // Replace the event bits with a new bitmask value -void -PThreadEvent::ReplaceEventBits(const uint32_t bits) -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, bits); - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - // Make sure we have some bits and that they aren't already set... - if (m_bits != bits) - { - // Figure out which bits are changing - uint32_t changed_bits = m_bits ^ bits; - // Set the new bit values - m_bits = bits; - // If any new bits are set, then broadcast - if (changed_bits & m_bits) - m_set_condition.Broadcast(); - } +void PThreadEvent::ReplaceEventBits(const uint32_t bits) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, + // __FUNCTION__, bits); + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + // Make sure we have some bits and that they aren't already set... + if (m_bits != bits) { + // Figure out which bits are changing + uint32_t changed_bits = m_bits ^ bits; + // Set the new bit values + m_bits = bits; + // If any new bits are set, then broadcast + if (changed_bits & m_bits) + m_set_condition.Broadcast(); + } } // Set one or more event bits and broadcast if any new event bits get set // that weren't already set. -void -PThreadEvent::SetEvents(const uint32_t mask) -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); - // Make sure we have some bits to set - if (mask) - { - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - // Save the old event bit state so we can tell if things change - uint32_t old = m_bits; - // Set the all event bits that are set in 'mask' - m_bits |= mask; - // Broadcast only if any extra bits got set. - if (old != m_bits) - m_set_condition.Broadcast(); - } +void PThreadEvent::SetEvents(const uint32_t mask) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, + // __FUNCTION__, mask); + // Make sure we have some bits to set + if (mask) { + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + // Save the old event bit state so we can tell if things change + uint32_t old = m_bits; + // Set the all event bits that are set in 'mask' + m_bits |= mask; + // Broadcast only if any extra bits got set. + if (old != m_bits) + m_set_condition.Broadcast(); + } } // Reset one or more event bits -void -PThreadEvent::ResetEvents(const uint32_t mask) -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, __FUNCTION__, mask); - if (mask) - { - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - - // Save the old event bit state so we can tell if things change - uint32_t old = m_bits; - // Clear the all event bits that are set in 'mask' - m_bits &= ~mask; - // Broadcast only if any extra bits got reset. - if (old != m_bits) - m_reset_condition.Broadcast(); - } +void PThreadEvent::ResetEvents(const uint32_t mask) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x)", this, + // __FUNCTION__, mask); + if (mask) { + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + + // Save the old event bit state so we can tell if things change + uint32_t old = m_bits; + // Clear the all event bits that are set in 'mask' + m_bits &= ~mask; + // Broadcast only if any extra bits got reset. + if (old != m_bits) + m_reset_condition.Broadcast(); + } } //---------------------------------------------------------------------- @@ -130,98 +111,90 @@ PThreadEvent::ResetEvents(const uint32_t mask) // 'mask'. If 'timeout_abstime' is NULL, then wait forever. //---------------------------------------------------------------------- uint32_t -PThreadEvent::WaitForSetEvents(const uint32_t mask, const struct timespec *timeout_abstime) const -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); - int err = 0; - // pthread_cond_timedwait() or pthread_cond_wait() will atomically - // unlock the mutex and wait for the condition to be set. When either - // function returns, they will re-lock the mutex. We use an auto lock/unlock - // class (PThreadMutex::Locker) to allow us to return at any point in this - // function and not have to worry about unlocking the mutex. - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - do - { - // Check our predicate (event bits) in case any are already set - if (mask & m_bits) - { - uint32_t bits_set = mask & m_bits; - // Our PThreadMutex::Locker will automatically unlock our mutex - return bits_set; - } - if (timeout_abstime) - { - // Wait for condition to get broadcast, or for a timeout. If we get - // a timeout we will drop out of the do loop and return false which - // is what we want. - err = ::pthread_cond_timedwait (m_set_condition.Condition(), m_mutex.Mutex(), timeout_abstime); - // Retest our predicate in case of a race condition right at the end - // of the timeout. - if (err == ETIMEDOUT) - { - uint32_t bits_set = mask & m_bits; - return bits_set; - } - } - else - { - // Wait for condition to get broadcast. The only error this function - // should return is if - err = ::pthread_cond_wait (m_set_condition.Condition(), m_mutex.Mutex()); - } - } while (err == 0); - return 0; +PThreadEvent::WaitForSetEvents(const uint32_t mask, + const struct timespec *timeout_abstime) const { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, + // __FUNCTION__, mask, timeout_abstime); + int err = 0; + // pthread_cond_timedwait() or pthread_cond_wait() will atomically + // unlock the mutex and wait for the condition to be set. When either + // function returns, they will re-lock the mutex. We use an auto lock/unlock + // class (PThreadMutex::Locker) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + do { + // Check our predicate (event bits) in case any are already set + if (mask & m_bits) { + uint32_t bits_set = mask & m_bits; + // Our PThreadMutex::Locker will automatically unlock our mutex + return bits_set; + } + if (timeout_abstime) { + // Wait for condition to get broadcast, or for a timeout. If we get + // a timeout we will drop out of the do loop and return false which + // is what we want. + err = ::pthread_cond_timedwait(m_set_condition.Condition(), + m_mutex.Mutex(), timeout_abstime); + // Retest our predicate in case of a race condition right at the end + // of the timeout. + if (err == ETIMEDOUT) { + uint32_t bits_set = mask & m_bits; + return bits_set; + } + } else { + // Wait for condition to get broadcast. The only error this function + // should return is if + err = ::pthread_cond_wait(m_set_condition.Condition(), m_mutex.Mutex()); + } + } while (err == 0); + return 0; } //---------------------------------------------------------------------- // Wait until 'timeout_abstime' for any events in 'mask' to reset. // If 'timeout_abstime' is NULL, then wait forever. //---------------------------------------------------------------------- -uint32_t -PThreadEvent::WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime) const -{ - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); - int err = 0; - // pthread_cond_timedwait() or pthread_cond_wait() will atomically - // unlock the mutex and wait for the condition to be set. When either - // function returns, they will re-lock the mutex. We use an auto lock/unlock - // class (PThreadMutex::Locker) to allow us to return at any point in this - // function and not have to worry about unlocking the mutex. - PTHREAD_MUTEX_LOCKER (locker, m_mutex); - do - { - // Check our predicate (event bits) each time through this do loop - if ((mask & m_bits) == 0) - { - // All the bits requested have been reset, return zero indicating - // which bits from the mask were still set (none of them) - return 0; - } - if (timeout_abstime) - { - // Wait for condition to get broadcast, or for a timeout. If we get - // a timeout we will drop out of the do loop and return false which - // is what we want. - err = ::pthread_cond_timedwait (m_reset_condition.Condition(), m_mutex.Mutex(), timeout_abstime); - } - else - { - // Wait for condition to get broadcast. The only error this function - // should return is if - err = ::pthread_cond_wait (m_reset_condition.Condition(), m_mutex.Mutex()); - } - } while (err == 0); - // Return a mask indicating which bits (if any) were still set - return mask & m_bits; +uint32_t PThreadEvent::WaitForEventsToReset( + const uint32_t mask, const struct timespec *timeout_abstime) const { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, + // __FUNCTION__, mask, timeout_abstime); + int err = 0; + // pthread_cond_timedwait() or pthread_cond_wait() will atomically + // unlock the mutex and wait for the condition to be set. When either + // function returns, they will re-lock the mutex. We use an auto lock/unlock + // class (PThreadMutex::Locker) to allow us to return at any point in this + // function and not have to worry about unlocking the mutex. + PTHREAD_MUTEX_LOCKER(locker, m_mutex); + do { + // Check our predicate (event bits) each time through this do loop + if ((mask & m_bits) == 0) { + // All the bits requested have been reset, return zero indicating + // which bits from the mask were still set (none of them) + return 0; + } + if (timeout_abstime) { + // Wait for condition to get broadcast, or for a timeout. If we get + // a timeout we will drop out of the do loop and return false which + // is what we want. + err = ::pthread_cond_timedwait(m_reset_condition.Condition(), + m_mutex.Mutex(), timeout_abstime); + } else { + // Wait for condition to get broadcast. The only error this function + // should return is if + err = ::pthread_cond_wait(m_reset_condition.Condition(), m_mutex.Mutex()); + } + } while (err == 0); + // Return a mask indicating which bits (if any) were still set + return mask & m_bits; } uint32_t -PThreadEvent::WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime) const -{ - if (mask & m_reset_ack_mask) - { - // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, __FUNCTION__, mask, timeout_abstime); - return WaitForEventsToReset (mask & m_reset_ack_mask, timeout_abstime); - } - return 0; +PThreadEvent::WaitForResetAck(const uint32_t mask, + const struct timespec *timeout_abstime) const { + if (mask & m_reset_ack_mask) { + // DNBLogThreadedIf(LOG_EVENTS, "%p PThreadEvent::%s (0x%8.8x, %p)", this, + // __FUNCTION__, mask, timeout_abstime); + return WaitForEventsToReset(mask & m_reset_ack_mask, timeout_abstime); + } + return 0; } diff --git a/lldb/tools/debugserver/source/PThreadEvent.h b/lldb/tools/debugserver/source/PThreadEvent.h index 46c7cc09b12..fbcd4593352 100644 --- a/lldb/tools/debugserver/source/PThreadEvent.h +++ b/lldb/tools/debugserver/source/PThreadEvent.h @@ -13,47 +13,52 @@ #ifndef __PThreadEvent_h__ #define __PThreadEvent_h__ -#include "PThreadMutex.h" #include "PThreadCondition.h" +#include "PThreadMutex.h" #include <stdint.h> #include <time.h> -class PThreadEvent -{ +class PThreadEvent { public: - PThreadEvent (uint32_t bits = 0, uint32_t validBits = 0); - ~PThreadEvent (); - - uint32_t NewEventBit (); - void FreeEventBits (const uint32_t mask); - - void ReplaceEventBits (const uint32_t bits); - uint32_t GetEventBits () const; - void SetEvents (const uint32_t mask); - void ResetEvents (const uint32_t mask); - // Wait for events to be set or reset. These functions take an optional - // timeout value. If timeout is NULL an infinite timeout will be used. - uint32_t WaitForSetEvents (const uint32_t mask, const struct timespec *timeout_abstime = NULL) const; - uint32_t WaitForEventsToReset(const uint32_t mask, const struct timespec *timeout_abstime = NULL) const; - - uint32_t GetResetAckMask () const { return m_reset_ack_mask; } - uint32_t SetResetAckMask (uint32_t mask) { return m_reset_ack_mask = mask; } - uint32_t WaitForResetAck (const uint32_t mask, const struct timespec *timeout_abstime = NULL) const; + PThreadEvent(uint32_t bits = 0, uint32_t validBits = 0); + ~PThreadEvent(); + + uint32_t NewEventBit(); + void FreeEventBits(const uint32_t mask); + + void ReplaceEventBits(const uint32_t bits); + uint32_t GetEventBits() const; + void SetEvents(const uint32_t mask); + void ResetEvents(const uint32_t mask); + // Wait for events to be set or reset. These functions take an optional + // timeout value. If timeout is NULL an infinite timeout will be used. + uint32_t + WaitForSetEvents(const uint32_t mask, + const struct timespec *timeout_abstime = NULL) const; + uint32_t + WaitForEventsToReset(const uint32_t mask, + const struct timespec *timeout_abstime = NULL) const; + + uint32_t GetResetAckMask() const { return m_reset_ack_mask; } + uint32_t SetResetAckMask(uint32_t mask) { return m_reset_ack_mask = mask; } + uint32_t WaitForResetAck(const uint32_t mask, + const struct timespec *timeout_abstime = NULL) const; + protected: - //---------------------------------------------------------------------- - // pthread condition and mutex variable to control access and allow - // blocking between the main thread and the spotlight index thread. - //---------------------------------------------------------------------- - mutable PThreadMutex m_mutex; - mutable PThreadCondition m_set_condition; - mutable PThreadCondition m_reset_condition; - uint32_t m_bits; - uint32_t m_validBits; - uint32_t m_reset_ack_mask; -private: - PThreadEvent(const PThreadEvent&); // Outlaw copy constructor - PThreadEvent& operator=(const PThreadEvent& rhs); + //---------------------------------------------------------------------- + // pthread condition and mutex variable to control access and allow + // blocking between the main thread and the spotlight index thread. + //---------------------------------------------------------------------- + mutable PThreadMutex m_mutex; + mutable PThreadCondition m_set_condition; + mutable PThreadCondition m_reset_condition; + uint32_t m_bits; + uint32_t m_validBits; + uint32_t m_reset_ack_mask; +private: + PThreadEvent(const PThreadEvent &); // Outlaw copy constructor + PThreadEvent &operator=(const PThreadEvent &rhs); }; #endif // #ifndef __PThreadEvent_h__ diff --git a/lldb/tools/debugserver/source/PThreadMutex.cpp b/lldb/tools/debugserver/source/PThreadMutex.cpp index bd91ed0154b..32db862f6b4 100644 --- a/lldb/tools/debugserver/source/PThreadMutex.cpp +++ b/lldb/tools/debugserver/source/PThreadMutex.cpp @@ -19,66 +19,53 @@ // Project includes #include "DNBTimer.h" -#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS) +#if defined(DEBUG_PTHREAD_MUTEX_DEADLOCKS) -PThreadMutex::Locker::Locker(PThreadMutex& m, const char *function, const char *file, const int line) : - m_pMutex(m.Mutex()), - m_function(function), - m_file(file), - m_line(line), - m_lock_time(0) -{ - Lock(); +PThreadMutex::Locker::Locker(PThreadMutex &m, const char *function, + const char *file, const int line) + : m_pMutex(m.Mutex()), m_function(function), m_file(file), m_line(line), + m_lock_time(0) { + Lock(); } -PThreadMutex::Locker::Locker(PThreadMutex* m, const char *function, const char *file, const int line) : - m_pMutex(m ? m->Mutex() : NULL), - m_function(function), - m_file(file), - m_line(line), - m_lock_time(0) -{ - Lock(); +PThreadMutex::Locker::Locker(PThreadMutex *m, const char *function, + const char *file, const int line) + : m_pMutex(m ? m->Mutex() : NULL), m_function(function), m_file(file), + m_line(line), m_lock_time(0) { + Lock(); } -PThreadMutex::Locker::Locker(pthread_mutex_t *mutex, const char *function, const char *file, const int line) : - m_pMutex(mutex), - m_function(function), - m_file(file), - m_line(line), - m_lock_time(0) -{ - Lock(); +PThreadMutex::Locker::Locker(pthread_mutex_t *mutex, const char *function, + const char *file, const int line) + : m_pMutex(mutex), m_function(function), m_file(file), m_line(line), + m_lock_time(0) { + Lock(); } +PThreadMutex::Locker::~Locker() { Unlock(); } -PThreadMutex::Locker::~Locker() -{ - Unlock(); -} - - -void -PThreadMutex::Locker::Lock() -{ - if (m_pMutex) - { - m_lock_time = DNBTimer::GetTimeOfDay(); - if (::pthread_mutex_trylock (m_pMutex) != 0) - { - fprintf(stdout, "::pthread_mutex_trylock (%8.8p) mutex is locked (function %s in %s:%i), waiting...\n", m_pMutex, m_function, m_file, m_line); - ::pthread_mutex_lock (m_pMutex); - fprintf(stdout, "::pthread_mutex_lock (%8.8p) succeeded after %6llu usecs (function %s in %s:%i)\n", m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, m_file, m_line); - } +void PThreadMutex::Locker::Lock() { + if (m_pMutex) { + m_lock_time = DNBTimer::GetTimeOfDay(); + if (::pthread_mutex_trylock(m_pMutex) != 0) { + fprintf(stdout, "::pthread_mutex_trylock (%8.8p) mutex is locked " + "(function %s in %s:%i), waiting...\n", + m_pMutex, m_function, m_file, m_line); + ::pthread_mutex_lock(m_pMutex); + fprintf(stdout, "::pthread_mutex_lock (%8.8p) succeeded after %6llu " + "usecs (function %s in %s:%i)\n", + m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, + m_file, m_line); } + } } - -void -PThreadMutex::Locker::Unlock() -{ - fprintf(stdout, "::pthread_mutex_unlock (%8.8p) had lock for %6llu usecs in %s in %s:%i\n", m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, m_file, m_line); - ::pthread_mutex_unlock (m_pMutex); +void PThreadMutex::Locker::Unlock() { + fprintf(stdout, "::pthread_mutex_unlock (%8.8p) had lock for %6llu usecs in " + "%s in %s:%i\n", + m_pMutex, DNBTimer::GetTimeOfDay() - m_lock_time, m_function, m_file, + m_line); + ::pthread_mutex_unlock(m_pMutex); } #endif diff --git a/lldb/tools/debugserver/source/PThreadMutex.h b/lldb/tools/debugserver/source/PThreadMutex.h index 9a12f6e8e03..c6ec293c5e5 100644 --- a/lldb/tools/debugserver/source/PThreadMutex.h +++ b/lldb/tools/debugserver/source/PThreadMutex.h @@ -14,135 +14,107 @@ #ifndef __PThreadMutex_h__ #define __PThreadMutex_h__ -#include <pthread.h> #include <assert.h> +#include <pthread.h> #include <stdint.h> //#define DEBUG_PTHREAD_MUTEX_DEADLOCKS 1 -#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS) -#define PTHREAD_MUTEX_LOCKER(var, mutex) PThreadMutex::Locker var(mutex, __FUNCTION__, __FILE__, __LINE__) +#if defined(DEBUG_PTHREAD_MUTEX_DEADLOCKS) +#define PTHREAD_MUTEX_LOCKER(var, mutex) \ + PThreadMutex::Locker var(mutex, __FUNCTION__, __FILE__, __LINE__) #else #define PTHREAD_MUTEX_LOCKER(var, mutex) PThreadMutex::Locker var(mutex) #endif -class PThreadMutex -{ +class PThreadMutex { public: - - class Locker - { - public: -#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS) - - Locker(PThreadMutex& m, const char *function, const char *file, int line); - Locker(PThreadMutex* m, const char *function, const char *file, int line); - Locker(pthread_mutex_t *mutex, const char *function, const char *file, int line); - ~Locker(); - void Lock(); - void Unlock(); + class Locker { + public: +#if defined(DEBUG_PTHREAD_MUTEX_DEADLOCKS) + + Locker(PThreadMutex &m, const char *function, const char *file, int line); + Locker(PThreadMutex *m, const char *function, const char *file, int line); + Locker(pthread_mutex_t *mutex, const char *function, const char *file, + int line); + ~Locker(); + void Lock(); + void Unlock(); #else - Locker(PThreadMutex& m) : - m_pMutex(m.Mutex()) - { - Lock(); - } - - Locker(PThreadMutex* m) : - m_pMutex(m ? m->Mutex() : NULL) - { - Lock(); - } - - Locker(pthread_mutex_t *mutex) : - m_pMutex(mutex) - { - Lock(); - } - - void Lock() - { - if (m_pMutex) - ::pthread_mutex_lock (m_pMutex); - } - - void Unlock() - { - if (m_pMutex) - ::pthread_mutex_unlock (m_pMutex); - } - - ~Locker() - { - Unlock(); - } + Locker(PThreadMutex &m) : m_pMutex(m.Mutex()) { Lock(); } -#endif - - // unlock any the current mutex and lock the new one if it is valid - void Reset(pthread_mutex_t *pMutex = NULL) - { - Unlock(); - m_pMutex = pMutex; - Lock(); - } - pthread_mutex_t *m_pMutex; -#if defined (DEBUG_PTHREAD_MUTEX_DEADLOCKS) - const char *m_function; - const char *m_file; - int m_line; - uint64_t m_lock_time; -#endif - }; + Locker(PThreadMutex *m) : m_pMutex(m ? m->Mutex() : NULL) { Lock(); } + Locker(pthread_mutex_t *mutex) : m_pMutex(mutex) { Lock(); } - PThreadMutex() - { - int err; - err = ::pthread_mutex_init (&m_mutex, NULL); assert(err == 0); + void Lock() { + if (m_pMutex) + ::pthread_mutex_lock(m_pMutex); } - PThreadMutex(int type) - { - int err; - ::pthread_mutexattr_t attr; - err = ::pthread_mutexattr_init (&attr); assert(err == 0); - err = ::pthread_mutexattr_settype (&attr, type); assert(err == 0); - err = ::pthread_mutex_init (&m_mutex, &attr); assert(err == 0); - err = ::pthread_mutexattr_destroy (&attr); assert(err == 0); + void Unlock() { + if (m_pMutex) + ::pthread_mutex_unlock(m_pMutex); } - ~PThreadMutex() - { - int err; - err = ::pthread_mutex_destroy (&m_mutex); - if (err != 0) - { - err = Unlock(); - if (err == 0) - ::pthread_mutex_destroy (&m_mutex); - } - } + ~Locker() { Unlock(); } - pthread_mutex_t *Mutex() - { - return &m_mutex; - } +#endif - int Lock() - { - return ::pthread_mutex_lock (&m_mutex); + // unlock any the current mutex and lock the new one if it is valid + void Reset(pthread_mutex_t *pMutex = NULL) { + Unlock(); + m_pMutex = pMutex; + Lock(); } - - int Unlock() - { - return ::pthread_mutex_unlock (&m_mutex); + pthread_mutex_t *m_pMutex; +#if defined(DEBUG_PTHREAD_MUTEX_DEADLOCKS) + const char *m_function; + const char *m_file; + int m_line; + uint64_t m_lock_time; +#endif + }; + + PThreadMutex() { + int err; + err = ::pthread_mutex_init(&m_mutex, NULL); + assert(err == 0); + } + + PThreadMutex(int type) { + int err; + ::pthread_mutexattr_t attr; + err = ::pthread_mutexattr_init(&attr); + assert(err == 0); + err = ::pthread_mutexattr_settype(&attr, type); + assert(err == 0); + err = ::pthread_mutex_init(&m_mutex, &attr); + assert(err == 0); + err = ::pthread_mutexattr_destroy(&attr); + assert(err == 0); + } + + ~PThreadMutex() { + int err; + err = ::pthread_mutex_destroy(&m_mutex); + if (err != 0) { + err = Unlock(); + if (err == 0) + ::pthread_mutex_destroy(&m_mutex); } + } + + pthread_mutex_t *Mutex() { return &m_mutex; } + + int Lock() { return ::pthread_mutex_lock(&m_mutex); } + + int Unlock() { return ::pthread_mutex_unlock(&m_mutex); } protected: - pthread_mutex_t m_mutex; + pthread_mutex_t m_mutex; }; #endif diff --git a/lldb/tools/debugserver/source/PseudoTerminal.cpp b/lldb/tools/debugserver/source/PseudoTerminal.cpp index f1b505cabd4..616aec989c8 100644 --- a/lldb/tools/debugserver/source/PseudoTerminal.cpp +++ b/lldb/tools/debugserver/source/PseudoTerminal.cpp @@ -19,11 +19,8 @@ //---------------------------------------------------------------------- // PseudoTerminal constructor //---------------------------------------------------------------------- -PseudoTerminal::PseudoTerminal() : - m_master_fd(invalid_fd), - m_slave_fd(invalid_fd) -{ -} +PseudoTerminal::PseudoTerminal() + : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} //---------------------------------------------------------------------- // Destructor @@ -32,36 +29,29 @@ PseudoTerminal::PseudoTerminal() : // to release any file descriptors that are needed beyond the lifespan // of this object. //---------------------------------------------------------------------- -PseudoTerminal::~PseudoTerminal() -{ - CloseMaster(); - CloseSlave(); +PseudoTerminal::~PseudoTerminal() { + CloseMaster(); + CloseSlave(); } //---------------------------------------------------------------------- // Close the master file descriptor if it is valid. //---------------------------------------------------------------------- -void -PseudoTerminal::CloseMaster() -{ - if (m_master_fd > 0) - { - ::close (m_master_fd); - m_master_fd = invalid_fd; - } +void PseudoTerminal::CloseMaster() { + if (m_master_fd > 0) { + ::close(m_master_fd); + m_master_fd = invalid_fd; + } } //---------------------------------------------------------------------- // Close the slave file descriptor if it is valid. //---------------------------------------------------------------------- -void -PseudoTerminal::CloseSlave() -{ - if (m_slave_fd > 0) - { - ::close (m_slave_fd); - m_slave_fd = invalid_fd; - } +void PseudoTerminal::CloseSlave() { + if (m_slave_fd > 0) { + ::close(m_slave_fd); + m_slave_fd = invalid_fd; + } } //---------------------------------------------------------------------- @@ -75,31 +65,26 @@ PseudoTerminal::CloseSlave() // RETURNS: // Zero when successful, non-zero indicating an error occurred. //---------------------------------------------------------------------- -PseudoTerminal::Error -PseudoTerminal::OpenFirstAvailableMaster(int oflag) -{ - // Open the master side of a pseudo terminal - m_master_fd = ::posix_openpt (oflag); - if (m_master_fd < 0) - { - return err_posix_openpt_failed; - } +PseudoTerminal::Error PseudoTerminal::OpenFirstAvailableMaster(int oflag) { + // Open the master side of a pseudo terminal + m_master_fd = ::posix_openpt(oflag); + if (m_master_fd < 0) { + return err_posix_openpt_failed; + } - // Grant access to the slave pseudo terminal - if (::grantpt (m_master_fd) < 0) - { - CloseMaster(); - return err_grantpt_failed; - } + // Grant access to the slave pseudo terminal + if (::grantpt(m_master_fd) < 0) { + CloseMaster(); + return err_grantpt_failed; + } - // Clear the lock flag on the slave pseudo terminal - if (::unlockpt (m_master_fd) < 0) - { - CloseMaster(); - return err_unlockpt_failed; - } + // Clear the lock flag on the slave pseudo terminal + if (::unlockpt(m_master_fd) < 0) { + CloseMaster(); + return err_unlockpt_failed; + } - return success; + return success; } //---------------------------------------------------------------------- @@ -112,27 +97,23 @@ PseudoTerminal::OpenFirstAvailableMaster(int oflag) // RETURNS: // Zero when successful, non-zero indicating an error occurred. //---------------------------------------------------------------------- -PseudoTerminal::Error -PseudoTerminal::OpenSlave(int oflag) -{ - CloseSlave(); +PseudoTerminal::Error PseudoTerminal::OpenSlave(int oflag) { + CloseSlave(); - // Open the master side of a pseudo terminal - const char *slave_name = SlaveName(); + // Open the master side of a pseudo terminal + const char *slave_name = SlaveName(); - if (slave_name == NULL) - return err_ptsname_failed; + if (slave_name == NULL) + return err_ptsname_failed; - m_slave_fd = ::open (slave_name, oflag); + m_slave_fd = ::open(slave_name, oflag); - if (m_slave_fd < 0) - return err_open_slave_failed; + if (m_slave_fd < 0) + return err_open_slave_failed; - return success; + return success; } - - //---------------------------------------------------------------------- // Get the name of the slave pseudo terminal. A master pseudo terminal // should already be valid prior to calling this function (see @@ -144,15 +125,12 @@ PseudoTerminal::OpenSlave(int oflag) // that comes from static memory, so a copy of the string should be // made as subsequent calls can change this value. //---------------------------------------------------------------------- -const char* -PseudoTerminal::SlaveName() const -{ - if (m_master_fd < 0) - return NULL; - return ::ptsname (m_master_fd); +const char *PseudoTerminal::SlaveName() const { + if (m_master_fd < 0) + return NULL; + return ::ptsname(m_master_fd); } - //---------------------------------------------------------------------- // Fork a child process that and have its stdio routed to a pseudo // terminal. @@ -175,53 +153,44 @@ PseudoTerminal::SlaveName() const // in the child process: zero //---------------------------------------------------------------------- -pid_t -PseudoTerminal::Fork(PseudoTerminal::Error& error) -{ - pid_t pid = invalid_pid; - error = OpenFirstAvailableMaster (O_RDWR|O_NOCTTY); - - if (error == 0) - { - // Successfully opened our master pseudo terminal - - pid = ::fork (); - if (pid < 0) - { - // Fork failed - error = err_fork_failed; - } - else if (pid == 0) - { - // Child Process - ::setsid(); - - error = OpenSlave (O_RDWR); - if (error == 0) - { - // Successfully opened slave - // We are done with the master in the child process so lets close it - CloseMaster (); - -#if defined (TIOCSCTTY) - // Acquire the controlling terminal - if (::ioctl (m_slave_fd, TIOCSCTTY, (char *)0) < 0) - error = err_failed_to_acquire_controlling_terminal; +pid_t PseudoTerminal::Fork(PseudoTerminal::Error &error) { + pid_t pid = invalid_pid; + error = OpenFirstAvailableMaster(O_RDWR | O_NOCTTY); + + if (error == 0) { + // Successfully opened our master pseudo terminal + + pid = ::fork(); + if (pid < 0) { + // Fork failed + error = err_fork_failed; + } else if (pid == 0) { + // Child Process + ::setsid(); + + error = OpenSlave(O_RDWR); + if (error == 0) { + // Successfully opened slave + // We are done with the master in the child process so lets close it + CloseMaster(); + +#if defined(TIOCSCTTY) + // Acquire the controlling terminal + if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) + error = err_failed_to_acquire_controlling_terminal; #endif - // Duplicate all stdio file descriptors to the slave pseudo terminal - if (::dup2 (m_slave_fd, STDIN_FILENO) != STDIN_FILENO) - error = error ? error : err_dup2_failed_on_stdin; - if (::dup2 (m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) - error = error ? error : err_dup2_failed_on_stdout; - if (::dup2 (m_slave_fd, STDERR_FILENO) != STDERR_FILENO) - error = error ? error : err_dup2_failed_on_stderr; - } - } - else - { - // Parent Process - // Do nothing and let the pid get returned! - } + // Duplicate all stdio file descriptors to the slave pseudo terminal + if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) + error = error ? error : err_dup2_failed_on_stdin; + if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) + error = error ? error : err_dup2_failed_on_stdout; + if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) + error = error ? error : err_dup2_failed_on_stderr; + } + } else { + // Parent Process + // Do nothing and let the pid get returned! } - return pid; + } + return pid; } diff --git a/lldb/tools/debugserver/source/PseudoTerminal.h b/lldb/tools/debugserver/source/PseudoTerminal.h index da6b79307b9..409c78ff5e3 100644 --- a/lldb/tools/debugserver/source/PseudoTerminal.h +++ b/lldb/tools/debugserver/source/PseudoTerminal.h @@ -15,80 +15,73 @@ #define __PseudoTerminal_h__ #include <fcntl.h> -#include <termios.h> #include <string> +#include <termios.h> -class PseudoTerminal -{ +class PseudoTerminal { public: - enum { - invalid_fd = -1, - invalid_pid = -1 - }; + enum { invalid_fd = -1, invalid_pid = -1 }; - enum Error - { - success = 0, - err_posix_openpt_failed = -2, - err_grantpt_failed = -3, - err_unlockpt_failed = -4, - err_ptsname_failed = -5, - err_open_slave_failed = -6, - err_fork_failed = -7, - err_setsid_failed = -8, - err_failed_to_acquire_controlling_terminal = -9, - err_dup2_failed_on_stdin = -10, - err_dup2_failed_on_stdout = -11, - err_dup2_failed_on_stderr = -12 - }; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - PseudoTerminal (); - ~PseudoTerminal (); + enum Error { + success = 0, + err_posix_openpt_failed = -2, + err_grantpt_failed = -3, + err_unlockpt_failed = -4, + err_ptsname_failed = -5, + err_open_slave_failed = -6, + err_fork_failed = -7, + err_setsid_failed = -8, + err_failed_to_acquire_controlling_terminal = -9, + err_dup2_failed_on_stdin = -10, + err_dup2_failed_on_stdout = -11, + err_dup2_failed_on_stderr = -12 + }; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + PseudoTerminal(); + ~PseudoTerminal(); - void CloseMaster (); - void CloseSlave (); - Error OpenFirstAvailableMaster (int oflag); - Error OpenSlave (int oflag); - int MasterFD () const { return m_master_fd; } - int SlaveFD () const { return m_slave_fd; } - int ReleaseMasterFD () - { - // Release ownership of the master pseudo terminal file - // descriptor without closing it. (the destructor for this - // class will close it otherwise!) - int fd = m_master_fd; - m_master_fd = invalid_fd; - return fd; - } - int ReleaseSlaveFD () - { - // Release ownership of the slave pseudo terminal file - // descriptor without closing it (the destructor for this - // class will close it otherwise!) - int fd = m_slave_fd; - m_slave_fd = invalid_fd; - return fd; - } + void CloseMaster(); + void CloseSlave(); + Error OpenFirstAvailableMaster(int oflag); + Error OpenSlave(int oflag); + int MasterFD() const { return m_master_fd; } + int SlaveFD() const { return m_slave_fd; } + int ReleaseMasterFD() { + // Release ownership of the master pseudo terminal file + // descriptor without closing it. (the destructor for this + // class will close it otherwise!) + int fd = m_master_fd; + m_master_fd = invalid_fd; + return fd; + } + int ReleaseSlaveFD() { + // Release ownership of the slave pseudo terminal file + // descriptor without closing it (the destructor for this + // class will close it otherwise!) + int fd = m_slave_fd; + m_slave_fd = invalid_fd; + return fd; + } - const char* SlaveName () const; + const char *SlaveName() const; + + pid_t Fork(Error &error); - pid_t Fork(Error& error); protected: - //------------------------------------------------------------------ - // Classes that inherit from PseudoTerminal can see and modify these - //------------------------------------------------------------------ - int m_master_fd; - int m_slave_fd; + //------------------------------------------------------------------ + // Classes that inherit from PseudoTerminal can see and modify these + //------------------------------------------------------------------ + int m_master_fd; + int m_slave_fd; private: - //------------------------------------------------------------------ - // Outlaw copy and assignment constructors - //------------------------------------------------------------------ - PseudoTerminal(const PseudoTerminal& rhs); - PseudoTerminal& operator=(const PseudoTerminal& rhs); - + //------------------------------------------------------------------ + // Outlaw copy and assignment constructors + //------------------------------------------------------------------ + PseudoTerminal(const PseudoTerminal &rhs); + PseudoTerminal &operator=(const PseudoTerminal &rhs); }; #endif // #ifndef __PseudoTerminal_h__ diff --git a/lldb/tools/debugserver/source/RNBContext.cpp b/lldb/tools/debugserver/source/RNBContext.cpp index 0b44fdbd581..483cdf9a486 100644 --- a/lldb/tools/debugserver/source/RNBContext.cpp +++ b/lldb/tools/debugserver/source/RNBContext.cpp @@ -13,269 +13,266 @@ #include "RNBContext.h" -#include <sys/stat.h> #include <sstream> +#include <sys/stat.h> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <pthread.h> #include <sched.h> #endif -#include "RNBRemote.h" +#include "CFString.h" #include "DNB.h" #include "DNBLog.h" -#include "CFString.h" - +#include "RNBRemote.h" //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -RNBContext::~RNBContext() -{ - SetProcessID (INVALID_NUB_PROCESS); -} +RNBContext::~RNBContext() { SetProcessID(INVALID_NUB_PROCESS); } //---------------------------------------------------------------------- // RNBContext constructor //---------------------------------------------------------------------- -const char * -RNBContext::EnvironmentAtIndex (size_t index) -{ - if (index < m_env_vec.size()) - return m_env_vec[index].c_str(); - else - return NULL; +const char *RNBContext::EnvironmentAtIndex(size_t index) { + if (index < m_env_vec.size()) + return m_env_vec[index].c_str(); + else + return NULL; } - -const char * -RNBContext::ArgumentAtIndex (size_t index) -{ - if (index < m_arg_vec.size()) - return m_arg_vec[index].c_str(); - else - return NULL; +const char *RNBContext::ArgumentAtIndex(size_t index) { + if (index < m_arg_vec.size()) + return m_arg_vec[index].c_str(); + else + return NULL; } -bool -RNBContext::SetWorkingDirectory (const char *path) -{ - struct stat working_directory_stat; - if (::stat (path, &working_directory_stat) != 0) - { - m_working_directory.clear(); - return false; - } - m_working_directory.assign(path); - return true; +bool RNBContext::SetWorkingDirectory(const char *path) { + struct stat working_directory_stat; + if (::stat(path, &working_directory_stat) != 0) { + m_working_directory.clear(); + return false; + } + m_working_directory.assign(path); + return true; } - -void -RNBContext::SetProcessID (nub_process_t pid) -{ - // Delete and events we created - if (m_pid != INVALID_NUB_PROCESS) - { - StopProcessStatusThread (); - // Unregister this context as a client of the process's events. - } - // Assign our new process ID - m_pid = pid; - - if (pid != INVALID_NUB_PROCESS) - { - StartProcessStatusThread (); - } +void RNBContext::SetProcessID(nub_process_t pid) { + // Delete and events we created + if (m_pid != INVALID_NUB_PROCESS) { + StopProcessStatusThread(); + // Unregister this context as a client of the process's events. + } + // Assign our new process ID + m_pid = pid; + + if (pid != INVALID_NUB_PROCESS) { + StartProcessStatusThread(); + } } -void -RNBContext::StartProcessStatusThread() -{ - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); - if ((m_events.GetEventBits() & event_proc_thread_running) == 0) - { - int err = ::pthread_create (&m_pid_pthread, NULL, ThreadFunctionProcessStatus, this); - if (err == 0) - { - // Our thread was successfully kicked off, wait for it to - // set the started event so we can safely continue - m_events.WaitForSetEvents (event_proc_thread_running); - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", __FUNCTION__); - } - else - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread failed to start: err = %i", __FUNCTION__, err); - m_events.ResetEvents (event_proc_thread_running); - m_events.SetEvents (event_proc_thread_exiting); - } +void RNBContext::StartProcessStatusThread() { + DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); + if ((m_events.GetEventBits() & event_proc_thread_running) == 0) { + int err = ::pthread_create(&m_pid_pthread, NULL, + ThreadFunctionProcessStatus, this); + if (err == 0) { + // Our thread was successfully kicked off, wait for it to + // set the started event so we can safely continue + m_events.WaitForSetEvents(event_proc_thread_running); + DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread got started!", + __FUNCTION__); + } else { + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s thread failed to start: err = %i", + __FUNCTION__, err); + m_events.ResetEvents(event_proc_thread_running); + m_events.SetEvents(event_proc_thread_exiting); } + } } -void -RNBContext::StopProcessStatusThread() -{ - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); - if ((m_events.GetEventBits() & event_proc_thread_running) == event_proc_thread_running) - { - struct timespec timeout_abstime; - DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); - // Wait for 2 seconds for the rx thread to exit - if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, &timeout_abstime) == RNBContext::event_proc_thread_exiting) - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread stopped as requeseted", __FUNCTION__); - } - else - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s thread did not stop in 2 seconds...", __FUNCTION__); - // Kill the RX thread??? - } +void RNBContext::StopProcessStatusThread() { + DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s called", __FUNCTION__); + if ((m_events.GetEventBits() & event_proc_thread_running) == + event_proc_thread_running) { + struct timespec timeout_abstime; + DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); + // Wait for 2 seconds for the rx thread to exit + if (m_events.WaitForSetEvents(RNBContext::event_proc_thread_exiting, + &timeout_abstime) == + RNBContext::event_proc_thread_exiting) { + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s thread stopped as requeseted", + __FUNCTION__); + } else { + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s thread did not stop in 2 seconds...", + __FUNCTION__); + // Kill the RX thread??? } + } } //---------------------------------------------------------------------- // This thread's sole purpose is to watch for any status changes in the // child process. //---------------------------------------------------------------------- -void* -RNBContext::ThreadFunctionProcessStatus(void *arg) -{ - RNBRemoteSP remoteSP(g_remoteSP); - RNBRemote* remote = remoteSP.get(); - if (remote == NULL) - return NULL; - RNBContext& ctx = remote->Context(); - - nub_process_t pid = ctx.ProcessID(); - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", __FUNCTION__, arg, pid); - ctx.Events().SetEvents (RNBContext::event_proc_thread_running); - -#if defined (__APPLE__) - pthread_setname_np ("child process status watcher thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } +void *RNBContext::ThreadFunctionProcessStatus(void *arg) { + RNBRemoteSP remoteSP(g_remoteSP); + RNBRemote *remote = remoteSP.get(); + if (remote == NULL) + return NULL; + RNBContext &ctx = remote->Context(); + + nub_process_t pid = ctx.ProcessID(); + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s (arg=%p, pid=%4.4x): thread starting...", + __FUNCTION__, arg, pid); + ctx.Events().SetEvents(RNBContext::event_proc_thread_running); + +#if defined(__APPLE__) + pthread_setname_np("child process status watcher thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } #endif #endif - bool done = false; - while (!done) - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true)...", __FUNCTION__); - nub_event_t pid_status_event = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true, NULL); - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s calling DNBProcessWaitForEvent(pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | eEventStdioAvailable | eEventProfileDataAvailable, true) => 0x%8.8x", __FUNCTION__, pid_status_event); - - if (pid_status_event == 0) - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back from DNBProcessWaitForEvent....", __FUNCTION__, pid); - // done = true; + bool done = false; + while (!done) { + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s calling DNBProcessWaitForEvent(pid, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged | eEventStdioAvailable " + "| eEventProfileDataAvailable, true)...", + __FUNCTION__); + nub_event_t pid_status_event = DNBProcessWaitForEvents( + pid, + eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged | + eEventStdioAvailable | eEventProfileDataAvailable, + true, NULL); + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s calling DNBProcessWaitForEvent(pid, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged | eEventStdioAvailable " + "| eEventProfileDataAvailable, true) => 0x%8.8x", + __FUNCTION__, pid_status_event); + + if (pid_status_event == 0) { + DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got ZERO back " + "from DNBProcessWaitForEvent....", + __FUNCTION__, pid); + // done = true; + } else { + if (pid_status_event & eEventStdioAvailable) { + DNBLogThreadedIf( + LOG_RNB_PROC, + "RNBContext::%s (pid=%4.4x) got stdio available event....", + __FUNCTION__, pid); + ctx.Events().SetEvents(RNBContext::event_proc_stdio_available); + // Wait for the main thread to consume this notification if it requested + // we wait for it + ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available); + } + + if (pid_status_event & eEventProfileDataAvailable) { + DNBLogThreadedIf( + LOG_RNB_PROC, + "RNBContext::%s (pid=%4.4x) got profile data event....", + __FUNCTION__, pid); + ctx.Events().SetEvents(RNBContext::event_proc_profile_data); + // Wait for the main thread to consume this notification if it requested + // we wait for it + ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data); + } + + if (pid_status_event & (eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged)) { + nub_state_t pid_state = DNBProcessGetState(pid); + DNBLogThreadedIf( + LOG_RNB_PROC, + "RNBContext::%s (pid=%4.4x) got process state change: %s", + __FUNCTION__, pid, DNBStateAsString(pid_state)); + + // Let the main thread know there is a process state change to see + ctx.Events().SetEvents(RNBContext::event_proc_state_changed); + // Wait for the main thread to consume this notification if it requested + // we wait for it + ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed); + + switch (pid_state) { + case eStateStopped: + break; + + case eStateInvalid: + case eStateExited: + case eStateDetached: + done = true; + break; + default: + break; } - else - { - if (pid_status_event & eEventStdioAvailable) - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got stdio available event....", __FUNCTION__, pid); - ctx.Events().SetEvents (RNBContext::event_proc_stdio_available); - // Wait for the main thread to consume this notification if it requested we wait for it - ctx.Events().WaitForResetAck(RNBContext::event_proc_stdio_available); - } - - if (pid_status_event & eEventProfileDataAvailable) - { - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got profile data event....", __FUNCTION__, pid); - ctx.Events().SetEvents (RNBContext::event_proc_profile_data); - // Wait for the main thread to consume this notification if it requested we wait for it - ctx.Events().WaitForResetAck(RNBContext::event_proc_profile_data); - } - - if (pid_status_event & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) - { - nub_state_t pid_state = DNBProcessGetState(pid); - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (pid=%4.4x) got process state change: %s", __FUNCTION__, pid, DNBStateAsString(pid_state)); + } - // Let the main thread know there is a process state change to see - ctx.Events().SetEvents (RNBContext::event_proc_state_changed); - // Wait for the main thread to consume this notification if it requested we wait for it - ctx.Events().WaitForResetAck(RNBContext::event_proc_state_changed); - - switch (pid_state) - { - case eStateStopped: - break; - - case eStateInvalid: - case eStateExited: - case eStateDetached: - done = true; - break; - default: - break; - } - } - - // Reset any events that we consumed. - DNBProcessResetEvents(pid, pid_status_event); - - } + // Reset any events that we consumed. + DNBProcessResetEvents(pid, pid_status_event); } - DNBLogThreadedIf(LOG_RNB_PROC, "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", __FUNCTION__, arg, pid); - ctx.Events().ResetEvents(event_proc_thread_running); - ctx.Events().SetEvents(event_proc_thread_exiting); - return NULL; + } + DNBLogThreadedIf(LOG_RNB_PROC, + "RNBContext::%s (arg=%p, pid=%4.4x): thread exiting...", + __FUNCTION__, arg, pid); + ctx.Events().ResetEvents(event_proc_thread_running); + ctx.Events().SetEvents(event_proc_thread_exiting); + return NULL; } - -const char* -RNBContext::EventsAsString (nub_event_t events, std::string& s) -{ - s.clear(); - if (events & event_proc_state_changed) - s += "proc_state_changed "; - if (events & event_proc_thread_running) - s += "proc_thread_running "; - if (events & event_proc_thread_exiting) - s += "proc_thread_exiting "; - if (events & event_proc_stdio_available) - s += "proc_stdio_available "; - if (events & event_proc_profile_data) - s += "proc_profile_data "; - if (events & event_darwin_log_data_available) - s += "darwin_log_data_available "; - if (events & event_read_packet_available) - s += "read_packet_available "; - if (events & event_read_thread_running) - s += "read_thread_running "; - if (events & event_read_thread_running) - s += "read_thread_running "; - return s.c_str(); +const char *RNBContext::EventsAsString(nub_event_t events, std::string &s) { + s.clear(); + if (events & event_proc_state_changed) + s += "proc_state_changed "; + if (events & event_proc_thread_running) + s += "proc_thread_running "; + if (events & event_proc_thread_exiting) + s += "proc_thread_exiting "; + if (events & event_proc_stdio_available) + s += "proc_stdio_available "; + if (events & event_proc_profile_data) + s += "proc_profile_data "; + if (events & event_darwin_log_data_available) + s += "darwin_log_data_available "; + if (events & event_read_packet_available) + s += "read_packet_available "; + if (events & event_read_thread_running) + s += "read_thread_running "; + if (events & event_read_thread_running) + s += "read_thread_running "; + return s.c_str(); } -const char * -RNBContext::LaunchStatusAsString (std::string& s) -{ - s.clear(); - - const char *err_str = m_launch_status.AsString(); - if (err_str) - s = err_str; - else - { - char error_num_str[64]; - snprintf(error_num_str, sizeof(error_num_str), "%u", m_launch_status.Error()); - s = error_num_str; - } - return s.c_str(); +const char *RNBContext::LaunchStatusAsString(std::string &s) { + s.clear(); + + const char *err_str = m_launch_status.AsString(); + if (err_str) + s = err_str; + else { + char error_num_str[64]; + snprintf(error_num_str, sizeof(error_num_str), "%u", + m_launch_status.Error()); + s = error_num_str; + } + return s.c_str(); } -bool -RNBContext::ProcessStateRunning() const -{ - nub_state_t pid_state = DNBProcessGetState(m_pid); - return pid_state == eStateRunning || pid_state == eStateStepping; +bool RNBContext::ProcessStateRunning() const { + nub_state_t pid_state = DNBProcessGetState(m_pid); + return pid_state == eStateRunning || pid_state == eStateStepping; } diff --git a/lldb/tools/debugserver/source/RNBContext.h b/lldb/tools/debugserver/source/RNBContext.h index 83237ebccd9..6fe7a299573 100644 --- a/lldb/tools/debugserver/source/RNBContext.h +++ b/lldb/tools/debugserver/source/RNBContext.h @@ -14,148 +14,150 @@ #ifndef __RNBContext_h__ #define __RNBContext_h__ -#include "RNBDefs.h" #include "DNBError.h" #include "PThreadEvent.h" -#include <vector> +#include "RNBDefs.h" #include <string> +#include <vector> -class RNBContext -{ +class RNBContext { public: - enum - { - event_proc_state_changed = 0x001, - event_proc_thread_running = 0x002, // Sticky - event_proc_thread_exiting = 0x004, - event_proc_stdio_available = 0x008, - event_proc_profile_data = 0x010, - event_read_packet_available = 0x020, - event_read_thread_running = 0x040, // Sticky - event_read_thread_exiting = 0x080, - event_darwin_log_data_available = 0x100, - - normal_event_bits = event_proc_state_changed | - event_proc_thread_exiting | - event_proc_stdio_available | - event_proc_profile_data | - event_read_packet_available | - event_read_thread_exiting | - event_darwin_log_data_available, - - sticky_event_bits = event_proc_thread_running | - event_read_thread_running, - - - all_event_bits = sticky_event_bits | normal_event_bits - } event_t; - //------------------------------------------------------------------ - // Constructors and Destructors - //------------------------------------------------------------------ - RNBContext () : - m_pid(INVALID_NUB_PROCESS), - m_pid_stop_count(0), - m_events(0, all_event_bits), - m_pid_pthread(), - m_launch_status(), - m_arg_vec (), - m_env_vec (), - m_detach_on_error(false) - { - } - - virtual ~RNBContext(); - - - nub_process_t ProcessID() const { return m_pid; } - bool HasValidProcessID() const { return m_pid != INVALID_NUB_PROCESS; } - void SetProcessID (nub_process_t pid); - nub_size_t GetProcessStopCount () const { return m_pid_stop_count; } - bool SetProcessStopCount (nub_size_t count) - { - // Returns true if this class' notion of the PID state changed - if (m_pid_stop_count == count) - return false; // Didn't change - m_pid_stop_count = count; - return true; // The stop count has changed. - } - - bool ProcessStateRunning() const; - PThreadEvent& Events( ) { return m_events; } - nub_event_t AllEventBits() const { return all_event_bits; } - nub_event_t NormalEventBits() const { return normal_event_bits; } - nub_event_t StickyEventBits() const { return sticky_event_bits; } - const char* EventsAsString (nub_event_t events, std::string& s); - - size_t ArgumentCount () const { return m_arg_vec.size(); } - const char * ArgumentAtIndex (size_t index); - void PushArgument (const char *arg) { if (arg) m_arg_vec.push_back (arg); } - void ClearArgv () { m_arg_vec.erase (m_arg_vec.begin(), m_arg_vec.end()); } - - size_t EnvironmentCount () const { return m_env_vec.size(); } - const char * EnvironmentAtIndex (size_t index); - void PushEnvironment (const char *arg) { if (arg) m_env_vec.push_back (arg); } - void ClearEnvironment () { m_env_vec.erase (m_env_vec.begin(), m_env_vec.end()); } - DNBError& LaunchStatus () { return m_launch_status; } - const char * LaunchStatusAsString (std::string& s); - nub_launch_flavor_t LaunchFlavor () const { return m_launch_flavor; } - void SetLaunchFlavor (nub_launch_flavor_t flavor) { m_launch_flavor = flavor; } - - const char * GetWorkingDirectory () const - { - if (!m_working_directory.empty()) - return m_working_directory.c_str(); - return NULL; - } - - bool SetWorkingDirectory (const char *path); - - std::string& GetSTDIN () { return m_stdin; } - std::string& GetSTDOUT () { return m_stdout; } - std::string& GetSTDERR () { return m_stderr; } - std::string& GetWorkingDir () { return m_working_dir; } - - const char * GetSTDINPath() { return m_stdin.empty() ? NULL : m_stdin.c_str(); } - const char * GetSTDOUTPath() { return m_stdout.empty() ? NULL : m_stdout.c_str(); } - const char * GetSTDERRPath() { return m_stderr.empty() ? NULL : m_stderr.c_str(); } - const char * GetWorkingDirPath() { return m_working_dir.empty() ? NULL : m_working_dir.c_str(); } - - void PushProcessEvent (const char *p) { m_process_event.assign(p); } - const char * GetProcessEvent () { return m_process_event.c_str(); } - - void SetDetachOnError(bool detach) { m_detach_on_error = detach; } - bool GetDetachOnError () { return m_detach_on_error; } - + enum { + event_proc_state_changed = 0x001, + event_proc_thread_running = 0x002, // Sticky + event_proc_thread_exiting = 0x004, + event_proc_stdio_available = 0x008, + event_proc_profile_data = 0x010, + event_read_packet_available = 0x020, + event_read_thread_running = 0x040, // Sticky + event_read_thread_exiting = 0x080, + event_darwin_log_data_available = 0x100, + + normal_event_bits = event_proc_state_changed | event_proc_thread_exiting | + event_proc_stdio_available | event_proc_profile_data | + event_read_packet_available | + event_read_thread_exiting | + event_darwin_log_data_available, + + sticky_event_bits = event_proc_thread_running | event_read_thread_running, + + all_event_bits = sticky_event_bits | normal_event_bits + } event_t; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + RNBContext() + : m_pid(INVALID_NUB_PROCESS), m_pid_stop_count(0), + m_events(0, all_event_bits), m_pid_pthread(), m_launch_status(), + m_arg_vec(), m_env_vec(), m_detach_on_error(false) {} + + virtual ~RNBContext(); + + nub_process_t ProcessID() const { return m_pid; } + bool HasValidProcessID() const { return m_pid != INVALID_NUB_PROCESS; } + void SetProcessID(nub_process_t pid); + nub_size_t GetProcessStopCount() const { return m_pid_stop_count; } + bool SetProcessStopCount(nub_size_t count) { + // Returns true if this class' notion of the PID state changed + if (m_pid_stop_count == count) + return false; // Didn't change + m_pid_stop_count = count; + return true; // The stop count has changed. + } + + bool ProcessStateRunning() const; + PThreadEvent &Events() { return m_events; } + nub_event_t AllEventBits() const { return all_event_bits; } + nub_event_t NormalEventBits() const { return normal_event_bits; } + nub_event_t StickyEventBits() const { return sticky_event_bits; } + const char *EventsAsString(nub_event_t events, std::string &s); + + size_t ArgumentCount() const { return m_arg_vec.size(); } + const char *ArgumentAtIndex(size_t index); + void PushArgument(const char *arg) { + if (arg) + m_arg_vec.push_back(arg); + } + void ClearArgv() { m_arg_vec.erase(m_arg_vec.begin(), m_arg_vec.end()); } + + size_t EnvironmentCount() const { return m_env_vec.size(); } + const char *EnvironmentAtIndex(size_t index); + void PushEnvironment(const char *arg) { + if (arg) + m_env_vec.push_back(arg); + } + void ClearEnvironment() { + m_env_vec.erase(m_env_vec.begin(), m_env_vec.end()); + } + DNBError &LaunchStatus() { return m_launch_status; } + const char *LaunchStatusAsString(std::string &s); + nub_launch_flavor_t LaunchFlavor() const { return m_launch_flavor; } + void SetLaunchFlavor(nub_launch_flavor_t flavor) { m_launch_flavor = flavor; } + + const char *GetWorkingDirectory() const { + if (!m_working_directory.empty()) + return m_working_directory.c_str(); + return NULL; + } + + bool SetWorkingDirectory(const char *path); + + std::string &GetSTDIN() { return m_stdin; } + std::string &GetSTDOUT() { return m_stdout; } + std::string &GetSTDERR() { return m_stderr; } + std::string &GetWorkingDir() { return m_working_dir; } + + const char *GetSTDINPath() { + return m_stdin.empty() ? NULL : m_stdin.c_str(); + } + const char *GetSTDOUTPath() { + return m_stdout.empty() ? NULL : m_stdout.c_str(); + } + const char *GetSTDERRPath() { + return m_stderr.empty() ? NULL : m_stderr.c_str(); + } + const char *GetWorkingDirPath() { + return m_working_dir.empty() ? NULL : m_working_dir.c_str(); + } + + void PushProcessEvent(const char *p) { m_process_event.assign(p); } + const char *GetProcessEvent() { return m_process_event.c_str(); } + + void SetDetachOnError(bool detach) { m_detach_on_error = detach; } + bool GetDetachOnError() { return m_detach_on_error; } + protected: - //------------------------------------------------------------------ - // Classes that inherit from RNBContext can see and modify these - //------------------------------------------------------------------ - nub_process_t m_pid; - std::string m_stdin; - std::string m_stdout; - std::string m_stderr; - std::string m_working_dir; - nub_size_t m_pid_stop_count; - PThreadEvent m_events; // Threaded events that we can wait for - pthread_t m_pid_pthread; - nub_launch_flavor_t m_launch_flavor; // How to launch our inferior process - DNBError m_launch_status; // This holds the status from the last launch attempt. - std::vector<std::string> m_arg_vec; - std::vector<std::string> m_env_vec; // This will be unparsed - entries FOO=value - std::string m_working_directory; - std::string m_process_event; - bool m_detach_on_error; - - void StartProcessStatusThread(); - void StopProcessStatusThread(); - static void* ThreadFunctionProcessStatus(void *arg); + //------------------------------------------------------------------ + // Classes that inherit from RNBContext can see and modify these + //------------------------------------------------------------------ + nub_process_t m_pid; + std::string m_stdin; + std::string m_stdout; + std::string m_stderr; + std::string m_working_dir; + nub_size_t m_pid_stop_count; + PThreadEvent m_events; // Threaded events that we can wait for + pthread_t m_pid_pthread; + nub_launch_flavor_t m_launch_flavor; // How to launch our inferior process + DNBError + m_launch_status; // This holds the status from the last launch attempt. + std::vector<std::string> m_arg_vec; + std::vector<std::string> + m_env_vec; // This will be unparsed - entries FOO=value + std::string m_working_directory; + std::string m_process_event; + bool m_detach_on_error; + + void StartProcessStatusThread(); + void StopProcessStatusThread(); + static void *ThreadFunctionProcessStatus(void *arg); private: - //------------------------------------------------------------------ - // Outlaw copy and assignment operators - //------------------------------------------------------------------ - RNBContext(const RNBContext& rhs); - RNBContext& operator=(const RNBContext& rhs); + //------------------------------------------------------------------ + // Outlaw copy and assignment operators + //------------------------------------------------------------------ + RNBContext(const RNBContext &rhs); + RNBContext &operator=(const RNBContext &rhs); }; #endif // #ifndef __RNBContext_h__ diff --git a/lldb/tools/debugserver/source/RNBDefs.h b/lldb/tools/debugserver/source/RNBDefs.h index cefa986f8ca..5714099f5fc 100644 --- a/lldb/tools/debugserver/source/RNBDefs.h +++ b/lldb/tools/debugserver/source/RNBDefs.h @@ -17,52 +17,55 @@ #include "DNBDefs.h" #include <memory> -#define CONCAT2(a,b) a ## b -#define CONCAT(a,b) CONCAT2(a,b) +#define CONCAT2(a, b) a##b +#define CONCAT(a, b) CONCAT2(a, b) #define STRINGIZE2(x) #x #define STRINGIZE(x) STRINGIZE2(x) -#if !defined (DEBUGSERVER_PROGRAM_SYMBOL) +#if !defined(DEBUGSERVER_PROGRAM_SYMBOL) #define DEBUGSERVER_PROGRAM_SYMBOL debugserver #endif -#if !defined (DEBUGSERVER_PROGRAM_NAME) +#if !defined(DEBUGSERVER_PROGRAM_NAME) #define DEBUGSERVER_PROGRAM_NAME STRINGIZE(DEBUGSERVER_PROGRAM_SYMBOL) #endif #ifndef DEBUGSERVER_VERSION_NUM -extern "C" const unsigned char CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionString)[]; -#define DEBUGSERVER_VERSION_NUM CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionNumber) +extern "C" const unsigned char CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, + VersionString)[]; +#define DEBUGSERVER_VERSION_NUM \ + CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionNumber) #endif #ifndef DEBUGSERVER_VERSION_STR extern "C" const double CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionNumber); -#define DEBUGSERVER_VERSION_STR CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionString) +#define DEBUGSERVER_VERSION_STR \ + CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionString) #endif -#if defined (__i386__) +#if defined(__i386__) -#define RNB_ARCH "i386" +#define RNB_ARCH "i386" -#elif defined (__x86_64__) +#elif defined(__x86_64__) -#define RNB_ARCH "x86_64" +#define RNB_ARCH "x86_64" -#elif defined (__ppc64__) +#elif defined(__ppc64__) -#define RNB_ARCH "ppc64" +#define RNB_ARCH "ppc64" -#elif defined (__powerpc__) || defined (__ppc__) +#elif defined(__powerpc__) || defined(__ppc__) -#define RNB_ARCH "ppc" +#define RNB_ARCH "ppc" -#elif defined (__arm64__) || defined (__aarch64__) +#elif defined(__arm64__) || defined(__aarch64__) -#define RNB_ARCH "arm64" +#define RNB_ARCH "arm64" -#elif defined (__arm__) +#elif defined(__arm__) -#define RNB_ARCH "armv7" +#define RNB_ARCH "armv7" #else @@ -73,25 +76,23 @@ extern "C" const double CONCAT(DEBUGSERVER_PROGRAM_SYMBOL, VersionNumber); class RNBRemote; typedef std::shared_ptr<RNBRemote> RNBRemoteSP; -typedef enum -{ - rnb_success = 0, - rnb_err = 1, - rnb_not_connected = 2 -} rnb_err_t; +typedef enum { rnb_success = 0, rnb_err = 1, rnb_not_connected = 2 } rnb_err_t; // Log bits // reserve low bits for DNB -#define LOG_RNB_MINIMAL ((LOG_LO_USER) << 0) // Minimal logging (min verbosity) -#define LOG_RNB_MEDIUM ((LOG_LO_USER) << 1) // Medium logging (med verbosity) -#define LOG_RNB_MAX ((LOG_LO_USER) << 2) // Max logging (max verbosity) -#define LOG_RNB_COMM ((LOG_LO_USER) << 3) // Log communications (RNBSocket) -#define LOG_RNB_REMOTE ((LOG_LO_USER) << 4) // Log remote (RNBRemote) -#define LOG_RNB_EVENTS ((LOG_LO_USER) << 5) // Log events (PThreadEvents) -#define LOG_RNB_PROC ((LOG_LO_USER) << 6) // Log process state (Process thread) -#define LOG_RNB_PACKETS ((LOG_LO_USER) << 7) // Log gdb remote packets -#define LOG_RNB_ALL (~((LOG_LO_USER) - 1)) -#define LOG_RNB_DEFAULT (LOG_RNB_ALL) +#define LOG_RNB_MINIMAL \ + ((LOG_LO_USER) << 0) // Minimal logging (min verbosity) +#define LOG_RNB_MEDIUM \ + ((LOG_LO_USER) << 1) // Medium logging (med verbosity) +#define LOG_RNB_MAX ((LOG_LO_USER) << 2) // Max logging (max verbosity) +#define LOG_RNB_COMM ((LOG_LO_USER) << 3) // Log communications (RNBSocket) +#define LOG_RNB_REMOTE ((LOG_LO_USER) << 4) // Log remote (RNBRemote) +#define LOG_RNB_EVENTS \ + ((LOG_LO_USER) << 5) // Log events (PThreadEvents) +#define LOG_RNB_PROC ((LOG_LO_USER) << 6) // Log process state (Process thread) +#define LOG_RNB_PACKETS ((LOG_LO_USER) << 7) // Log gdb remote packets +#define LOG_RNB_ALL (~((LOG_LO_USER)-1)) +#define LOG_RNB_DEFAULT (LOG_RNB_ALL) extern RNBRemoteSP g_remoteSP; diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp index e737913c0d4..6ee84eed27d 100644 --- a/lldb/tools/debugserver/source/RNBRemote.cpp +++ b/lldb/tools/debugserver/source/RNBRemote.cpp @@ -14,46 +14,46 @@ #include "RNBRemote.h" #include <errno.h> -#include <unistd.h> -#include <signal.h> -#include <mach/exception_types.h> #include <mach-o/loader.h> +#include <mach/exception_types.h> +#include <signal.h> #include <sys/stat.h> #include <sys/sysctl.h> +#include <unistd.h> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <pthread.h> #include <sched.h> #endif -#include "DarwinLogCollector.h" -#include "DarwinLogEvent.h" #include "DNB.h" #include "DNBDataRef.h" #include "DNBLog.h" #include "DNBThreadResumeActions.h" +#include "DarwinLogCollector.h" +#include "DarwinLogEvent.h" +#include "JSON.h" +#include "JSONGenerator.h" #include "JSONGenerator.h" +#include "MacOSX/Genealogy.h" #include "OsLogger.h" #include "RNBContext.h" #include "RNBServices.h" #include "RNBSocket.h" -#include "JSON.h" #include "lldb/Utility/StdStringExtractor.h" -#include "MacOSX/Genealogy.h" -#include "JSONGenerator.h" -#if defined (HAVE_LIBCOMPRESSION) +#if defined(HAVE_LIBCOMPRESSION) #include <compression.h> #endif -#if defined (HAVE_LIBZ) +#if defined(HAVE_LIBZ) #include <zlib.h> #endif +#include <TargetConditionals.h> // for endianness predefines #include <iomanip> #include <sstream> #include <unordered_set> -#include <TargetConditionals.h> // for endianness predefines //---------------------------------------------------------------------- // constants @@ -61,1230 +61,1319 @@ static const std::string OS_LOG_EVENTS_KEY_NAME("events"); static const std::string JSON_ASYNC_TYPE_KEY_NAME("type"); -static const DarwinLogEventVector::size_type - DARWIN_LOG_MAX_EVENTS_PER_PACKET = 10; +static const DarwinLogEventVector::size_type DARWIN_LOG_MAX_EVENTS_PER_PACKET = + 10; //---------------------------------------------------------------------- // std::iostream formatting macros //---------------------------------------------------------------------- -#define RAW_HEXBASE std::setfill('0') << std::hex << std::right -#define HEXBASE '0' << 'x' << RAW_HEXBASE -#define RAWHEX8(x) RAW_HEXBASE << std::setw(2) << ((uint32_t)((uint8_t)x)) -#define RAWHEX16 RAW_HEXBASE << std::setw(4) -#define RAWHEX32 RAW_HEXBASE << std::setw(8) -#define RAWHEX64 RAW_HEXBASE << std::setw(16) -#define HEX8(x) HEXBASE << std::setw(2) << ((uint32_t)(x)) -#define HEX16 HEXBASE << std::setw(4) -#define HEX32 HEXBASE << std::setw(8) -#define HEX64 HEXBASE << std::setw(16) -#define RAW_HEX(x) RAW_HEXBASE << std::setw(sizeof(x)*2) << (x) -#define HEX(x) HEXBASE << std::setw(sizeof(x)*2) << (x) -#define RAWHEX_SIZE(x, sz) RAW_HEXBASE << std::setw((sz)) << (x) +#define RAW_HEXBASE std::setfill('0') << std::hex << std::right +#define HEXBASE '0' << 'x' << RAW_HEXBASE +#define RAWHEX8(x) RAW_HEXBASE << std::setw(2) << ((uint32_t)((uint8_t)x)) +#define RAWHEX16 RAW_HEXBASE << std::setw(4) +#define RAWHEX32 RAW_HEXBASE << std::setw(8) +#define RAWHEX64 RAW_HEXBASE << std::setw(16) +#define HEX8(x) HEXBASE << std::setw(2) << ((uint32_t)(x)) +#define HEX16 HEXBASE << std::setw(4) +#define HEX32 HEXBASE << std::setw(8) +#define HEX64 HEXBASE << std::setw(16) +#define RAW_HEX(x) RAW_HEXBASE << std::setw(sizeof(x) * 2) << (x) +#define HEX(x) HEXBASE << std::setw(sizeof(x) * 2) << (x) +#define RAWHEX_SIZE(x, sz) RAW_HEXBASE << std::setw((sz)) << (x) #define HEX_SIZE(x, sz) HEXBASE << std::setw((sz)) << (x) #define STRING_WIDTH(w) std::setfill(' ') << std::setw(w) -#define LEFT_STRING_WIDTH(s, w) std::left << std::setfill(' ') << std::setw(w) << (s) << std::right -#define DECIMAL std::dec << std::setfill(' ') +#define LEFT_STRING_WIDTH(s, w) \ + std::left << std::setfill(' ') << std::setw(w) << (s) << std::right +#define DECIMAL std::dec << std::setfill(' ') #define DECIMAL_WIDTH(w) DECIMAL << std::setw(w) -#define FLOAT(n, d) std::setfill(' ') << std::setw((n)+(d)+1) << std::setprecision(d) << std::showpoint << std::fixed -#define INDENT_WITH_SPACES(iword_idx) std::setfill(' ') << std::setw((iword_idx)) << "" -#define INDENT_WITH_TABS(iword_idx) std::setfill('\t') << std::setw((iword_idx)) << "" +#define FLOAT(n, d) \ + std::setfill(' ') << std::setw((n) + (d) + 1) << std::setprecision(d) \ + << std::showpoint << std::fixed +#define INDENT_WITH_SPACES(iword_idx) \ + std::setfill(' ') << std::setw((iword_idx)) << "" +#define INDENT_WITH_TABS(iword_idx) \ + std::setfill('\t') << std::setw((iword_idx)) << "" // Class to handle communications via gdb remote protocol. //---------------------------------------------------------------------- // Prototypes //---------------------------------------------------------------------- -static std::string -binary_encode_string (const std::string &s); +static std::string binary_encode_string(const std::string &s); //---------------------------------------------------------------------- // Decode a single hex character and return the hex value as a number or // -1 if "ch" is not a hex character. //---------------------------------------------------------------------- -static inline int -xdigit_to_sint (char ch) -{ - if (ch >= 'a' && ch <= 'f') - return 10 + ch - 'a'; - if (ch >= 'A' && ch <= 'F') - return 10 + ch - 'A'; - if (ch >= '0' && ch <= '9') - return ch - '0'; - return -1; +static inline int xdigit_to_sint(char ch) { + if (ch >= 'a' && ch <= 'f') + return 10 + ch - 'a'; + if (ch >= 'A' && ch <= 'F') + return 10 + ch - 'A'; + if (ch >= '0' && ch <= '9') + return ch - '0'; + return -1; } //---------------------------------------------------------------------- // Decode a single hex ASCII byte. Return -1 on failure, a value 0-255 // on success. //---------------------------------------------------------------------- -static inline int -decoded_hex_ascii_char(const char *p) -{ - const int hi_nibble = xdigit_to_sint(p[0]); - if (hi_nibble == -1) - return -1; - const int lo_nibble = xdigit_to_sint(p[1]); - if (lo_nibble == -1) - return -1; - return (uint8_t)((hi_nibble << 4) + lo_nibble); +static inline int decoded_hex_ascii_char(const char *p) { + const int hi_nibble = xdigit_to_sint(p[0]); + if (hi_nibble == -1) + return -1; + const int lo_nibble = xdigit_to_sint(p[1]); + if (lo_nibble == -1) + return -1; + return (uint8_t)((hi_nibble << 4) + lo_nibble); } //---------------------------------------------------------------------- // Decode a hex ASCII string back into a string //---------------------------------------------------------------------- -static std::string -decode_hex_ascii_string(const char *p, uint32_t max_length = UINT32_MAX) -{ - std::string arg; - if (p) - { - for (const char *c = p; ((c - p)/2) < max_length; c += 2) - { - int ch = decoded_hex_ascii_char(c); - if (ch == -1) - break; - else - arg.push_back(ch); - } +static std::string decode_hex_ascii_string(const char *p, + uint32_t max_length = UINT32_MAX) { + std::string arg; + if (p) { + for (const char *c = p; ((c - p) / 2) < max_length; c += 2) { + int ch = decoded_hex_ascii_char(c); + if (ch == -1) + break; + else + arg.push_back(ch); } - return arg; + } + return arg; } -uint64_t -decode_uint64 (const char *p, int base, char **end = nullptr, uint64_t fail_value = 0) -{ - nub_addr_t addr = strtoull (p, end, 16); - if (addr == 0 && errno != 0) - return fail_value; - return addr; +uint64_t decode_uint64(const char *p, int base, char **end = nullptr, + uint64_t fail_value = 0) { + nub_addr_t addr = strtoull(p, end, 16); + if (addr == 0 && errno != 0) + return fail_value; + return addr; } -extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args); +extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, + va_list args); -#if defined (__APPLE__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) +#if defined(__APPLE__) && \ + (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) // from System.framework/Versions/B/PrivateHeaders/sys/codesign.h extern "C" { -#define CS_OPS_STATUS 0 /* return status */ -#define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ -int csops(pid_t pid, unsigned int ops, void * useraddr, size_t usersize); +#define CS_OPS_STATUS 0 /* return status */ +#define CS_RESTRICT 0x0000800 /* tell dyld to treat restricted */ +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); // from rootless.h -bool rootless_allows_task_for_pid (pid_t pid); +bool rootless_allows_task_for_pid(pid_t pid); // from sys/csr.h typedef uint32_t csr_config_t; -#define CSR_ALLOW_TASK_FOR_PID (1 << 2) +#define CSR_ALLOW_TASK_FOR_PID (1 << 2) int csr_check(csr_config_t mask); } #endif -RNBRemote::RNBRemote () : - m_ctx (), - m_comm (), - m_arch (), - m_continue_thread(-1), - m_thread(-1), - m_mutex(), - m_dispatch_queue_offsets (), - m_dispatch_queue_offsets_addr (INVALID_NUB_ADDRESS), - m_qSymbol_index (UINT32_MAX), - m_packets_recvd(0), - m_packets(), - m_rx_packets(), - m_rx_partial_data(), - m_rx_pthread(0), - m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4), - m_extended_mode(false), - m_noack_mode(false), - m_thread_suffix_supported (false), - m_list_threads_in_stop_reply (false), - m_compression_minsize (384), - m_enable_compression_next_send_packet (false), - m_compression_mode (compression_types::none) -{ - DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__); - CreatePacketTable (); -} - - -RNBRemote::~RNBRemote() -{ - DNBLogThreadedIf (LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__); - StopReadRemoteDataThread(); -} - -void -RNBRemote::CreatePacketTable () -{ - // Step required to add new packets: - // 1 - Add new enumeration to RNBRemote::PacketEnum - // 2 - Create the RNBRemote::HandlePacket_ function if a new function is needed - // 3 - Register the Packet definition with any needed callbacks in this function - // - If no response is needed for a command, then use NULL for the normal callback - // - If the packet is not supported while the target is running, use NULL for the async callback - // 4 - If the packet is a standard packet (starts with a '$' character - // followed by the payload and then '#' and checksum, then you are done - // else go on to step 5 - // 5 - if the packet is a fixed length packet: - // - modify the switch statement for the first character in the payload - // in RNBRemote::CommDataReceived so it doesn't reject the new packet - // type as invalid - // - modify the switch statement for the first character in the payload - // in RNBRemote::GetPacketPayload and make sure the payload of the packet - // is returned correctly - - std::vector <Packet> &t = m_packets; - t.push_back (Packet (ack, NULL, NULL, "+", "ACK")); - t.push_back (Packet (nack, NULL, NULL, "-", "!ACK")); - t.push_back (Packet (read_memory, &RNBRemote::HandlePacket_m, NULL, "m", "Read memory")); - t.push_back (Packet (read_register, &RNBRemote::HandlePacket_p, NULL, "p", "Read one register")); - t.push_back (Packet (read_general_regs, &RNBRemote::HandlePacket_g, NULL, "g", "Read registers")); - t.push_back (Packet (write_memory, &RNBRemote::HandlePacket_M, NULL, "M", "Write memory")); - t.push_back (Packet (write_register, &RNBRemote::HandlePacket_P, NULL, "P", "Write one register")); - t.push_back (Packet (write_general_regs, &RNBRemote::HandlePacket_G, NULL, "G", "Write registers")); - t.push_back (Packet (insert_mem_bp, &RNBRemote::HandlePacket_z, NULL, "Z0", "Insert memory breakpoint")); - t.push_back (Packet (remove_mem_bp, &RNBRemote::HandlePacket_z, NULL, "z0", "Remove memory breakpoint")); - t.push_back (Packet (single_step, &RNBRemote::HandlePacket_s, NULL, "s", "Single step")); - t.push_back (Packet (cont, &RNBRemote::HandlePacket_c, NULL, "c", "continue")); - t.push_back (Packet (single_step_with_sig, &RNBRemote::HandlePacket_S, NULL, "S", "Single step with signal")); - t.push_back (Packet (set_thread, &RNBRemote::HandlePacket_H, NULL, "H", "Set thread")); - t.push_back (Packet (halt, &RNBRemote::HandlePacket_last_signal, &RNBRemote::HandlePacket_stop_process, "\x03", "^C")); -// t.push_back (Packet (use_extended_mode, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "!", "Use extended mode")); - t.push_back (Packet (why_halted, &RNBRemote::HandlePacket_last_signal, NULL, "?", "Why did target halt")); - t.push_back (Packet (set_argv, &RNBRemote::HandlePacket_A, NULL, "A", "Set argv")); -// t.push_back (Packet (set_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "B", "Set/clear breakpoint")); - t.push_back (Packet (continue_with_sig, &RNBRemote::HandlePacket_C, NULL, "C", "Continue with signal")); - t.push_back (Packet (detach, &RNBRemote::HandlePacket_D, NULL, "D", "Detach gdb from remote system")); -// t.push_back (Packet (step_inferior_one_cycle, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "i", "Step inferior by one clock cycle")); -// t.push_back (Packet (signal_and_step_inf_one_cycle, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "I", "Signal inferior, then step one clock cycle")); - t.push_back (Packet (kill, &RNBRemote::HandlePacket_k, NULL, "k", "Kill")); -// t.push_back (Packet (restart, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "R", "Restart inferior")); -// t.push_back (Packet (search_mem_backwards, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "t", "Search memory backwards")); - t.push_back (Packet (thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T", "Is thread alive")); - t.push_back (Packet (query_supported_features, &RNBRemote::HandlePacket_qSupported, NULL, "qSupported", "Query about supported features")); - t.push_back (Packet (vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach", "Attach to a new process")); - t.push_back (Packet (vattachwait, &RNBRemote::HandlePacket_v, NULL, "vAttachWait", "Wait for a process to start up then attach to it")); - t.push_back (Packet (vattachorwait, &RNBRemote::HandlePacket_v, NULL, "vAttachOrWait", "Attach to the process or if it doesn't exist, wait for the process to start up then attach to it")); - t.push_back (Packet (vattachname, &RNBRemote::HandlePacket_v, NULL, "vAttachName", "Attach to an existing process by name")); - t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont;", "Verbose resume with thread actions")); - t.push_back (Packet (vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, "vCont?", "List valid continue-with-thread-actions actions")); - t.push_back (Packet (read_data_from_memory, &RNBRemote::HandlePacket_x, NULL, "x", "Read data from memory")); - t.push_back (Packet (write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, "X", "Write data to memory")); -// t.push_back (Packet (insert_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z1", "Insert hardware breakpoint")); -// t.push_back (Packet (remove_hardware_bp, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z1", "Remove hardware breakpoint")); - t.push_back (Packet (insert_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, "Z2", "Insert write watchpoint")); - t.push_back (Packet (remove_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, "z2", "Remove write watchpoint")); - t.push_back (Packet (insert_read_watch_bp, &RNBRemote::HandlePacket_z, NULL, "Z3", "Insert read watchpoint")); - t.push_back (Packet (remove_read_watch_bp, &RNBRemote::HandlePacket_z, NULL, "z3", "Remove read watchpoint")); - t.push_back (Packet (insert_access_watch_bp, &RNBRemote::HandlePacket_z, NULL, "Z4", "Insert access watchpoint")); - t.push_back (Packet (remove_access_watch_bp, &RNBRemote::HandlePacket_z, NULL, "z4", "Remove access watchpoint")); - t.push_back (Packet (query_monitor, &RNBRemote::HandlePacket_qRcmd, NULL, "qRcmd", "Monitor command")); - t.push_back (Packet (query_current_thread_id, &RNBRemote::HandlePacket_qC, NULL, "qC", "Query current thread ID")); - t.push_back (Packet (query_echo, &RNBRemote::HandlePacket_qEcho, NULL, "qEcho:", "Echo the packet back to allow the debugger to sync up with this server")); - t.push_back (Packet (query_get_pid, &RNBRemote::HandlePacket_qGetPid, NULL, "qGetPid", "Query process id")); - t.push_back (Packet (query_thread_ids_first, &RNBRemote::HandlePacket_qThreadInfo, NULL, "qfThreadInfo", "Get list of active threads (first req)")); - t.push_back (Packet (query_thread_ids_subsequent, &RNBRemote::HandlePacket_qThreadInfo, NULL, "qsThreadInfo", "Get list of active threads (subsequent req)")); - // APPLE LOCAL: qThreadStopInfo - // syntax: qThreadStopInfoTTTT - // TTTT is hex thread ID - t.push_back (Packet (query_thread_stop_info, &RNBRemote::HandlePacket_qThreadStopInfo, NULL, "qThreadStopInfo", "Get detailed info on why the specified thread stopped")); - t.push_back (Packet (query_thread_extra_info, &RNBRemote::HandlePacket_qThreadExtraInfo,NULL, "qThreadExtraInfo", "Get printable status of a thread")); -// t.push_back (Packet (query_image_offsets, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qOffsets", "Report offset of loaded program")); - t.push_back (Packet (query_launch_success, &RNBRemote::HandlePacket_qLaunchSuccess,NULL, "qLaunchSuccess", "Report the success or failure of the launch attempt")); - t.push_back (Packet (query_register_info, &RNBRemote::HandlePacket_qRegisterInfo, NULL, "qRegisterInfo", "Dynamically discover remote register context information.")); - t.push_back (Packet (query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr,NULL, "qShlibInfoAddr", "Returns the address that contains info needed for getting shared library notifications")); - t.push_back (Packet (query_step_packet_supported, &RNBRemote::HandlePacket_qStepPacketSupported,NULL, "qStepPacketSupported", "Replys with OK if the 's' packet is supported.")); - t.push_back (Packet (query_vattachorwait_supported, &RNBRemote::HandlePacket_qVAttachOrWaitSupported,NULL, "qVAttachOrWaitSupported", "Replys with OK if the 'vAttachOrWait' packet is supported.")); - t.push_back (Packet (query_sync_thread_state_supported, &RNBRemote::HandlePacket_qSyncThreadStateSupported,NULL, "qSyncThreadStateSupported", "Replys with OK if the 'QSyncThreadState:' packet is supported.")); - t.push_back (Packet (query_host_info, &RNBRemote::HandlePacket_qHostInfo , NULL, "qHostInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); - t.push_back (Packet (query_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion , NULL, "qGDBServerVersion", "Replies with multiple 'key:value;' tuples appended to each other.")); - t.push_back (Packet (query_process_info, &RNBRemote::HandlePacket_qProcessInfo , NULL, "qProcessInfo", "Replies with multiple 'key:value;' tuples appended to each other.")); - t.push_back (Packet (query_symbol_lookup, &RNBRemote::HandlePacket_qSymbol , NULL, "qSymbol:", "Notify that host debugger is ready to do symbol lookups")); - t.push_back (Packet (json_query_thread_extended_info,&RNBRemote::HandlePacket_jThreadExtendedInfo , NULL, "jThreadExtendedInfo", "Replies with JSON data of thread extended information.")); - t.push_back (Packet (json_query_get_loaded_dynamic_libraries_infos, &RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos, NULL, "jGetLoadedDynamicLibrariesInfos", "Replies with JSON data of all the shared libraries loaded in this process.")); - t.push_back (Packet (json_query_threads_info, &RNBRemote::HandlePacket_jThreadsInfo , NULL, "jThreadsInfo", "Replies with JSON data with information about all threads.")); - t.push_back (Packet (json_query_get_shared_cache_info, &RNBRemote::HandlePacket_jGetSharedCacheInfo, NULL, "jGetSharedCacheInfo", "Replies with JSON data about the location and uuid of the shared cache in the inferior process.")); - t.push_back (Packet (start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode , NULL, "QStartNoAckMode", "Request that " DEBUGSERVER_PROGRAM_NAME " stop acking remote protocol packets")); - t.push_back (Packet (prefix_reg_packets_with_tid, &RNBRemote::HandlePacket_QThreadSuffixSupported , NULL, "QThreadSuffixSupported", "Check if thread specific packets (register packets 'g', 'G', 'p', and 'P') support having the thread ID appended to the end of the command")); - t.push_back (Packet (set_logging_mode, &RNBRemote::HandlePacket_QSetLogging , NULL, "QSetLogging:", "Check if register packets ('g', 'G', 'p', and 'P' support having the thread ID prefix")); - t.push_back (Packet (set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize , NULL, "QSetMaxPacketSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle")); - t.push_back (Packet (set_max_payload_size, &RNBRemote::HandlePacket_QSetMaxPayloadSize , NULL, "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized payload gdb can handle")); - t.push_back (Packet (set_environment_variable, &RNBRemote::HandlePacket_QEnvironment , NULL, "QEnvironment:", "Add an environment variable to the inferior's environment")); - t.push_back (Packet (set_environment_variable_hex, &RNBRemote::HandlePacket_QEnvironmentHexEncoded , NULL, "QEnvironmentHexEncoded:", "Add an environment variable to the inferior's environment")); - t.push_back (Packet (set_launch_arch, &RNBRemote::HandlePacket_QLaunchArch , NULL, "QLaunchArch:", "Set the architecture to use when launching a process for hosts that can run multiple architecture slices from universal files.")); - t.push_back (Packet (set_disable_aslr, &RNBRemote::HandlePacket_QSetDisableASLR , NULL, "QSetDisableASLR:", "Set whether to disable ASLR when launching the process with the set argv ('A') packet")); - t.push_back (Packet (set_stdin, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDIN:", "Set the standard input for a process to be launched with the 'A' packet")); - t.push_back (Packet (set_stdout, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDOUT:", "Set the standard output for a process to be launched with the 'A' packet")); - t.push_back (Packet (set_stderr, &RNBRemote::HandlePacket_QSetSTDIO , NULL, "QSetSTDERR:", "Set the standard error for a process to be launched with the 'A' packet")); - t.push_back (Packet (set_working_dir, &RNBRemote::HandlePacket_QSetWorkingDir , NULL, "QSetWorkingDir:", "Set the working directory for a process to be launched with the 'A' packet")); - t.push_back (Packet (set_list_threads_in_stop_reply,&RNBRemote::HandlePacket_QListThreadsInStopReply , NULL, "QListThreadsInStopReply", "Set if the 'threads' key should be added to the stop reply packets with a list of all thread IDs.")); - t.push_back (Packet (sync_thread_state, &RNBRemote::HandlePacket_QSyncThreadState , NULL, "QSyncThreadState:", "Do whatever is necessary to make sure 'thread' is in a safe state to call functions on.")); -// t.push_back (Packet (pass_signals_to_inferior, &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify which signals are passed to the inferior")); - t.push_back (Packet (allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, NULL, "_M", "Allocate memory in the inferior process.")); - t.push_back (Packet (deallocate_memory, &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", "Deallocate memory in the inferior process.")); - t.push_back (Packet (save_register_state, &RNBRemote::HandlePacket_SaveRegisterState, NULL, "QSaveRegisterState", "Save the register state for the current thread and return a decimal save ID.")); - t.push_back (Packet (restore_register_state, &RNBRemote::HandlePacket_RestoreRegisterState, NULL, "QRestoreRegisterState:", "Restore the register state given a save ID previously returned from a call to QSaveRegisterState.")); - t.push_back (Packet (memory_region_info, &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, "qMemoryRegionInfo", "Return size and attributes of a memory region that contains the given address")); - t.push_back (Packet (get_profile_data, &RNBRemote::HandlePacket_GetProfileData, NULL, "qGetProfileData", "Return profiling data of the current target.")); - t.push_back (Packet (set_enable_profiling, &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, "QSetEnableAsyncProfiling", "Enable or disable the profiling of current target.")); - t.push_back (Packet (enable_compression, &RNBRemote::HandlePacket_QEnableCompression, NULL, "QEnableCompression:", "Enable compression for the remainder of the connection")); - t.push_back (Packet (watchpoint_support_info, &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL, "qWatchpointSupportInfo", "Return the number of supported hardware watchpoints")); - t.push_back (Packet (set_process_event, &RNBRemote::HandlePacket_QSetProcessEvent, NULL, "QSetProcessEvent:", "Set a process event, to be passed to the process, can be set before the process is started, or after.")); - t.push_back (Packet (set_detach_on_error, &RNBRemote::HandlePacket_QSetDetachOnError, NULL, "QSetDetachOnError:", "Set whether debugserver will detach (1) or kill (0) from the process it is controlling if it loses connection to lldb.")); - t.push_back (Packet (speed_test, &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:", "Test the maximum speed at which packet can be sent/received.")); - t.push_back (Packet (query_transfer, &RNBRemote::HandlePacket_qXfer, NULL, "qXfer:", "Support the qXfer packet.")); - t.push_back (Packet (query_supported_async_json_packets, &RNBRemote::HandlePacket_qStructuredDataPlugins, NULL, "qStructuredDataPlugins", "Query for the structured data plugins supported by the remote.")); - t.push_back (Packet (configure_darwin_log, &RNBRemote::HandlePacket_QConfigureDarwinLog, NULL, "QConfigureDarwinLog:", "Configure the DarwinLog structured data plugin support.")); -} - -void -RNBRemote::FlushSTDIO () -{ - if (m_ctx.HasValidProcessID()) - { - nub_process_t pid = m_ctx.ProcessID(); - char buf[256]; - nub_size_t count; - do - { - count = DNBProcessGetAvailableSTDOUT(pid, buf, sizeof(buf)); - if (count > 0) - { - SendSTDOUTPacket (buf, count); - } - } while (count > 0); +RNBRemote::RNBRemote() + : m_ctx(), m_comm(), m_arch(), m_continue_thread(-1), m_thread(-1), + m_mutex(), m_dispatch_queue_offsets(), + m_dispatch_queue_offsets_addr(INVALID_NUB_ADDRESS), + m_qSymbol_index(UINT32_MAX), m_packets_recvd(0), m_packets(), + m_rx_packets(), m_rx_partial_data(), m_rx_pthread(0), + m_max_payload_size(DEFAULT_GDB_REMOTE_PROTOCOL_BUFSIZE - 4), + m_extended_mode(false), m_noack_mode(false), + m_thread_suffix_supported(false), m_list_threads_in_stop_reply(false), + m_compression_minsize(384), m_enable_compression_next_send_packet(false), + m_compression_mode(compression_types::none) { + DNBLogThreadedIf(LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__); + CreatePacketTable(); +} + +RNBRemote::~RNBRemote() { + DNBLogThreadedIf(LOG_RNB_REMOTE, "%s", __PRETTY_FUNCTION__); + StopReadRemoteDataThread(); +} + +void RNBRemote::CreatePacketTable() { + // Step required to add new packets: + // 1 - Add new enumeration to RNBRemote::PacketEnum + // 2 - Create the RNBRemote::HandlePacket_ function if a new function is + // needed + // 3 - Register the Packet definition with any needed callbacks in this + // function + // - If no response is needed for a command, then use NULL for the + // normal callback + // - If the packet is not supported while the target is running, use + // NULL for the async callback + // 4 - If the packet is a standard packet (starts with a '$' character + // followed by the payload and then '#' and checksum, then you are done + // else go on to step 5 + // 5 - if the packet is a fixed length packet: + // - modify the switch statement for the first character in the payload + // in RNBRemote::CommDataReceived so it doesn't reject the new packet + // type as invalid + // - modify the switch statement for the first character in the payload + // in RNBRemote::GetPacketPayload and make sure the payload of the + // packet + // is returned correctly + + std::vector<Packet> &t = m_packets; + t.push_back(Packet(ack, NULL, NULL, "+", "ACK")); + t.push_back(Packet(nack, NULL, NULL, "-", "!ACK")); + t.push_back(Packet(read_memory, &RNBRemote::HandlePacket_m, NULL, "m", + "Read memory")); + t.push_back(Packet(read_register, &RNBRemote::HandlePacket_p, NULL, "p", + "Read one register")); + t.push_back(Packet(read_general_regs, &RNBRemote::HandlePacket_g, NULL, "g", + "Read registers")); + t.push_back(Packet(write_memory, &RNBRemote::HandlePacket_M, NULL, "M", + "Write memory")); + t.push_back(Packet(write_register, &RNBRemote::HandlePacket_P, NULL, "P", + "Write one register")); + t.push_back(Packet(write_general_regs, &RNBRemote::HandlePacket_G, NULL, "G", + "Write registers")); + t.push_back(Packet(insert_mem_bp, &RNBRemote::HandlePacket_z, NULL, "Z0", + "Insert memory breakpoint")); + t.push_back(Packet(remove_mem_bp, &RNBRemote::HandlePacket_z, NULL, "z0", + "Remove memory breakpoint")); + t.push_back(Packet(single_step, &RNBRemote::HandlePacket_s, NULL, "s", + "Single step")); + t.push_back(Packet(cont, &RNBRemote::HandlePacket_c, NULL, "c", "continue")); + t.push_back(Packet(single_step_with_sig, &RNBRemote::HandlePacket_S, NULL, + "S", "Single step with signal")); + t.push_back( + Packet(set_thread, &RNBRemote::HandlePacket_H, NULL, "H", "Set thread")); + t.push_back(Packet(halt, &RNBRemote::HandlePacket_last_signal, + &RNBRemote::HandlePacket_stop_process, "\x03", "^C")); + // t.push_back (Packet (use_extended_mode, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "!", "Use extended mode")); + t.push_back(Packet(why_halted, &RNBRemote::HandlePacket_last_signal, NULL, + "?", "Why did target halt")); + t.push_back( + Packet(set_argv, &RNBRemote::HandlePacket_A, NULL, "A", "Set argv")); + // t.push_back (Packet (set_bp, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "B", "Set/clear + // breakpoint")); + t.push_back(Packet(continue_with_sig, &RNBRemote::HandlePacket_C, NULL, "C", + "Continue with signal")); + t.push_back(Packet(detach, &RNBRemote::HandlePacket_D, NULL, "D", + "Detach gdb from remote system")); + // t.push_back (Packet (step_inferior_one_cycle, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "i", "Step inferior by one + // clock cycle")); + // t.push_back (Packet (signal_and_step_inf_one_cycle, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "I", "Signal inferior, then + // step one clock cycle")); + t.push_back(Packet(kill, &RNBRemote::HandlePacket_k, NULL, "k", "Kill")); + // t.push_back (Packet (restart, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "R", "Restart inferior")); + // t.push_back (Packet (search_mem_backwards, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "t", "Search memory + // backwards")); + t.push_back(Packet(thread_alive_p, &RNBRemote::HandlePacket_T, NULL, "T", + "Is thread alive")); + t.push_back(Packet(query_supported_features, + &RNBRemote::HandlePacket_qSupported, NULL, "qSupported", + "Query about supported features")); + t.push_back(Packet(vattach, &RNBRemote::HandlePacket_v, NULL, "vAttach", + "Attach to a new process")); + t.push_back(Packet(vattachwait, &RNBRemote::HandlePacket_v, NULL, + "vAttachWait", + "Wait for a process to start up then attach to it")); + t.push_back(Packet(vattachorwait, &RNBRemote::HandlePacket_v, NULL, + "vAttachOrWait", "Attach to the process or if it doesn't " + "exist, wait for the process to start up " + "then attach to it")); + t.push_back(Packet(vattachname, &RNBRemote::HandlePacket_v, NULL, + "vAttachName", "Attach to an existing process by name")); + t.push_back(Packet(vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, + "vCont;", "Verbose resume with thread actions")); + t.push_back(Packet(vcont_list_actions, &RNBRemote::HandlePacket_v, NULL, + "vCont?", + "List valid continue-with-thread-actions actions")); + t.push_back(Packet(read_data_from_memory, &RNBRemote::HandlePacket_x, NULL, + "x", "Read data from memory")); + t.push_back(Packet(write_data_to_memory, &RNBRemote::HandlePacket_X, NULL, + "X", "Write data to memory")); + // t.push_back (Packet (insert_hardware_bp, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "Z1", "Insert hardware + // breakpoint")); + // t.push_back (Packet (remove_hardware_bp, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "z1", "Remove hardware + // breakpoint")); + t.push_back(Packet(insert_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "Z2", "Insert write watchpoint")); + t.push_back(Packet(remove_write_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "z2", "Remove write watchpoint")); + t.push_back(Packet(insert_read_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "Z3", "Insert read watchpoint")); + t.push_back(Packet(remove_read_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "z3", "Remove read watchpoint")); + t.push_back(Packet(insert_access_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "Z4", "Insert access watchpoint")); + t.push_back(Packet(remove_access_watch_bp, &RNBRemote::HandlePacket_z, NULL, + "z4", "Remove access watchpoint")); + t.push_back(Packet(query_monitor, &RNBRemote::HandlePacket_qRcmd, NULL, + "qRcmd", "Monitor command")); + t.push_back(Packet(query_current_thread_id, &RNBRemote::HandlePacket_qC, NULL, + "qC", "Query current thread ID")); + t.push_back(Packet(query_echo, &RNBRemote::HandlePacket_qEcho, NULL, "qEcho:", + "Echo the packet back to allow the debugger to sync up " + "with this server")); + t.push_back(Packet(query_get_pid, &RNBRemote::HandlePacket_qGetPid, NULL, + "qGetPid", "Query process id")); + t.push_back(Packet(query_thread_ids_first, + &RNBRemote::HandlePacket_qThreadInfo, NULL, "qfThreadInfo", + "Get list of active threads (first req)")); + t.push_back(Packet(query_thread_ids_subsequent, + &RNBRemote::HandlePacket_qThreadInfo, NULL, "qsThreadInfo", + "Get list of active threads (subsequent req)")); + // APPLE LOCAL: qThreadStopInfo + // syntax: qThreadStopInfoTTTT + // TTTT is hex thread ID + t.push_back(Packet(query_thread_stop_info, + &RNBRemote::HandlePacket_qThreadStopInfo, NULL, + "qThreadStopInfo", + "Get detailed info on why the specified thread stopped")); + t.push_back(Packet(query_thread_extra_info, + &RNBRemote::HandlePacket_qThreadExtraInfo, NULL, + "qThreadExtraInfo", "Get printable status of a thread")); + // t.push_back (Packet (query_image_offsets, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "qOffsets", "Report offset + // of loaded program")); + t.push_back(Packet( + query_launch_success, &RNBRemote::HandlePacket_qLaunchSuccess, NULL, + "qLaunchSuccess", "Report the success or failure of the launch attempt")); + t.push_back( + Packet(query_register_info, &RNBRemote::HandlePacket_qRegisterInfo, NULL, + "qRegisterInfo", + "Dynamically discover remote register context information.")); + t.push_back(Packet( + query_shlib_notify_info_addr, &RNBRemote::HandlePacket_qShlibInfoAddr, + NULL, "qShlibInfoAddr", "Returns the address that contains info needed " + "for getting shared library notifications")); + t.push_back(Packet(query_step_packet_supported, + &RNBRemote::HandlePacket_qStepPacketSupported, NULL, + "qStepPacketSupported", + "Replys with OK if the 's' packet is supported.")); + t.push_back( + Packet(query_vattachorwait_supported, + &RNBRemote::HandlePacket_qVAttachOrWaitSupported, NULL, + "qVAttachOrWaitSupported", + "Replys with OK if the 'vAttachOrWait' packet is supported.")); + t.push_back( + Packet(query_sync_thread_state_supported, + &RNBRemote::HandlePacket_qSyncThreadStateSupported, NULL, + "qSyncThreadStateSupported", + "Replys with OK if the 'QSyncThreadState:' packet is supported.")); + t.push_back(Packet( + query_host_info, &RNBRemote::HandlePacket_qHostInfo, NULL, "qHostInfo", + "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back(Packet( + query_gdb_server_version, &RNBRemote::HandlePacket_qGDBServerVersion, + NULL, "qGDBServerVersion", + "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back(Packet( + query_process_info, &RNBRemote::HandlePacket_qProcessInfo, NULL, + "qProcessInfo", + "Replies with multiple 'key:value;' tuples appended to each other.")); + t.push_back(Packet( + query_symbol_lookup, &RNBRemote::HandlePacket_qSymbol, NULL, "qSymbol:", + "Notify that host debugger is ready to do symbol lookups")); + t.push_back(Packet(json_query_thread_extended_info, + &RNBRemote::HandlePacket_jThreadExtendedInfo, NULL, + "jThreadExtendedInfo", + "Replies with JSON data of thread extended information.")); + t.push_back(Packet(json_query_get_loaded_dynamic_libraries_infos, + &RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos, + NULL, "jGetLoadedDynamicLibrariesInfos", + "Replies with JSON data of all the shared libraries " + "loaded in this process.")); + t.push_back( + Packet(json_query_threads_info, &RNBRemote::HandlePacket_jThreadsInfo, + NULL, "jThreadsInfo", + "Replies with JSON data with information about all threads.")); + t.push_back(Packet(json_query_get_shared_cache_info, + &RNBRemote::HandlePacket_jGetSharedCacheInfo, NULL, + "jGetSharedCacheInfo", "Replies with JSON data about the " + "location and uuid of the shared " + "cache in the inferior process.")); + t.push_back(Packet(start_noack_mode, &RNBRemote::HandlePacket_QStartNoAckMode, + NULL, "QStartNoAckMode", + "Request that " DEBUGSERVER_PROGRAM_NAME + " stop acking remote protocol packets")); + t.push_back(Packet(prefix_reg_packets_with_tid, + &RNBRemote::HandlePacket_QThreadSuffixSupported, NULL, + "QThreadSuffixSupported", + "Check if thread specific packets (register packets 'g', " + "'G', 'p', and 'P') support having the thread ID appended " + "to the end of the command")); + t.push_back(Packet(set_logging_mode, &RNBRemote::HandlePacket_QSetLogging, + NULL, "QSetLogging:", "Check if register packets ('g', " + "'G', 'p', and 'P' support having " + "the thread ID prefix")); + t.push_back(Packet( + set_max_packet_size, &RNBRemote::HandlePacket_QSetMaxPacketSize, NULL, + "QSetMaxPacketSize:", + "Tell " DEBUGSERVER_PROGRAM_NAME " the max sized packet gdb can handle")); + t.push_back(Packet( + set_max_payload_size, &RNBRemote::HandlePacket_QSetMaxPayloadSize, NULL, + "QSetMaxPayloadSize:", "Tell " DEBUGSERVER_PROGRAM_NAME + " the max sized payload gdb can handle")); + t.push_back( + Packet(set_environment_variable, &RNBRemote::HandlePacket_QEnvironment, + NULL, "QEnvironment:", + "Add an environment variable to the inferior's environment")); + t.push_back( + Packet(set_environment_variable_hex, + &RNBRemote::HandlePacket_QEnvironmentHexEncoded, NULL, + "QEnvironmentHexEncoded:", + "Add an environment variable to the inferior's environment")); + t.push_back(Packet(set_launch_arch, &RNBRemote::HandlePacket_QLaunchArch, + NULL, "QLaunchArch:", "Set the architecture to use when " + "launching a process for hosts that " + "can run multiple architecture " + "slices from universal files.")); + t.push_back(Packet(set_disable_aslr, &RNBRemote::HandlePacket_QSetDisableASLR, + NULL, "QSetDisableASLR:", + "Set whether to disable ASLR when launching the process " + "with the set argv ('A') packet")); + t.push_back(Packet(set_stdin, &RNBRemote::HandlePacket_QSetSTDIO, NULL, + "QSetSTDIN:", "Set the standard input for a process to be " + "launched with the 'A' packet")); + t.push_back(Packet(set_stdout, &RNBRemote::HandlePacket_QSetSTDIO, NULL, + "QSetSTDOUT:", "Set the standard output for a process to " + "be launched with the 'A' packet")); + t.push_back(Packet(set_stderr, &RNBRemote::HandlePacket_QSetSTDIO, NULL, + "QSetSTDERR:", "Set the standard error for a process to " + "be launched with the 'A' packet")); + t.push_back(Packet(set_working_dir, &RNBRemote::HandlePacket_QSetWorkingDir, + NULL, "QSetWorkingDir:", "Set the working directory for a " + "process to be launched with the " + "'A' packet")); + t.push_back(Packet(set_list_threads_in_stop_reply, + &RNBRemote::HandlePacket_QListThreadsInStopReply, NULL, + "QListThreadsInStopReply", + "Set if the 'threads' key should be added to the stop " + "reply packets with a list of all thread IDs.")); + t.push_back(Packet( + sync_thread_state, &RNBRemote::HandlePacket_QSyncThreadState, NULL, + "QSyncThreadState:", "Do whatever is necessary to make sure 'thread' is " + "in a safe state to call functions on.")); + // t.push_back (Packet (pass_signals_to_inferior, + // &RNBRemote::HandlePacket_UNIMPLEMENTED, NULL, "QPassSignals:", "Specify + // which signals are passed to the inferior")); + t.push_back(Packet(allocate_memory, &RNBRemote::HandlePacket_AllocateMemory, + NULL, "_M", "Allocate memory in the inferior process.")); + t.push_back(Packet(deallocate_memory, + &RNBRemote::HandlePacket_DeallocateMemory, NULL, "_m", + "Deallocate memory in the inferior process.")); + t.push_back(Packet( + save_register_state, &RNBRemote::HandlePacket_SaveRegisterState, NULL, + "QSaveRegisterState", "Save the register state for the current thread " + "and return a decimal save ID.")); + t.push_back(Packet(restore_register_state, + &RNBRemote::HandlePacket_RestoreRegisterState, NULL, + "QRestoreRegisterState:", + "Restore the register state given a save ID previously " + "returned from a call to QSaveRegisterState.")); + t.push_back(Packet( + memory_region_info, &RNBRemote::HandlePacket_MemoryRegionInfo, NULL, + "qMemoryRegionInfo", "Return size and attributes of a memory region that " + "contains the given address")); + t.push_back(Packet(get_profile_data, &RNBRemote::HandlePacket_GetProfileData, + NULL, "qGetProfileData", + "Return profiling data of the current target.")); + t.push_back(Packet(set_enable_profiling, + &RNBRemote::HandlePacket_SetEnableAsyncProfiling, NULL, + "QSetEnableAsyncProfiling", + "Enable or disable the profiling of current target.")); + t.push_back(Packet(enable_compression, + &RNBRemote::HandlePacket_QEnableCompression, NULL, + "QEnableCompression:", + "Enable compression for the remainder of the connection")); + t.push_back(Packet(watchpoint_support_info, + &RNBRemote::HandlePacket_WatchpointSupportInfo, NULL, + "qWatchpointSupportInfo", + "Return the number of supported hardware watchpoints")); + t.push_back(Packet(set_process_event, + &RNBRemote::HandlePacket_QSetProcessEvent, NULL, + "QSetProcessEvent:", "Set a process event, to be passed " + "to the process, can be set before " + "the process is started, or after.")); + t.push_back( + Packet(set_detach_on_error, &RNBRemote::HandlePacket_QSetDetachOnError, + NULL, "QSetDetachOnError:", + "Set whether debugserver will detach (1) or kill (0) from the " + "process it is controlling if it loses connection to lldb.")); + t.push_back(Packet( + speed_test, &RNBRemote::HandlePacket_qSpeedTest, NULL, "qSpeedTest:", + "Test the maximum speed at which packet can be sent/received.")); + t.push_back(Packet(query_transfer, &RNBRemote::HandlePacket_qXfer, NULL, + "qXfer:", "Support the qXfer packet.")); + t.push_back( + Packet(query_supported_async_json_packets, + &RNBRemote::HandlePacket_qStructuredDataPlugins, NULL, + "qStructuredDataPlugins", + "Query for the structured data plugins supported by the remote.")); + t.push_back( + Packet(configure_darwin_log, &RNBRemote::HandlePacket_QConfigureDarwinLog, + NULL, "QConfigureDarwinLog:", + "Configure the DarwinLog structured data plugin support.")); +} + +void RNBRemote::FlushSTDIO() { + if (m_ctx.HasValidProcessID()) { + nub_process_t pid = m_ctx.ProcessID(); + char buf[256]; + nub_size_t count; + do { + count = DNBProcessGetAvailableSTDOUT(pid, buf, sizeof(buf)); + if (count > 0) { + SendSTDOUTPacket(buf, count); + } + } while (count > 0); - do - { - count = DNBProcessGetAvailableSTDERR(pid, buf, sizeof(buf)); - if (count > 0) - { - SendSTDERRPacket (buf, count); - } - } while (count > 0); - } + do { + count = DNBProcessGetAvailableSTDERR(pid, buf, sizeof(buf)); + if (count > 0) { + SendSTDERRPacket(buf, count); + } + } while (count > 0); + } } -void -RNBRemote::SendAsyncProfileData () -{ - if (m_ctx.HasValidProcessID()) - { - nub_process_t pid = m_ctx.ProcessID(); - char buf[1024]; - nub_size_t count; - do - { - count = DNBProcessGetAvailableProfileData(pid, buf, sizeof(buf)); - if (count > 0) - { - SendAsyncProfileDataPacket (buf, count); - } - } while (count > 0); - } +void RNBRemote::SendAsyncProfileData() { + if (m_ctx.HasValidProcessID()) { + nub_process_t pid = m_ctx.ProcessID(); + char buf[1024]; + nub_size_t count; + do { + count = DNBProcessGetAvailableProfileData(pid, buf, sizeof(buf)); + if (count > 0) { + SendAsyncProfileDataPacket(buf, count); + } + } while (count > 0); + } } -void -RNBRemote::SendAsyncDarwinLogData () -{ - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): enter", +void RNBRemote::SendAsyncDarwinLogData() { + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): enter", __FUNCTION__); + + if (!m_ctx.HasValidProcessID()) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): ignoring due to" + "invalid process id", __FUNCTION__); + return; + } - if (!m_ctx.HasValidProcessID()) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): ignoring due to" - "invalid process id", __FUNCTION__); - return; - } + nub_process_t pid = m_ctx.ProcessID(); + DarwinLogEventVector::size_type entry_count = 0; - nub_process_t pid = m_ctx.ProcessID(); - DarwinLogEventVector::size_type entry_count = 0; + // NOTE: the current looping structure here does nothing + // to guarantee that we can send off async packets faster + // than we generate them. It will keep sending as long + // as there's data to send. + do { + DarwinLogEventVector events = DNBProcessGetAvailableDarwinLogEvents(pid); + entry_count = events.size(); - // NOTE: the current looping structure here does nothing - // to guarantee that we can send off async packets faster - // than we generate them. It will keep sending as long - // as there's data to send. - do - { - DarwinLogEventVector events = - DNBProcessGetAvailableDarwinLogEvents(pid); - entry_count = events.size(); - - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop enter", - __FUNCTION__); + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop enter", + __FUNCTION__); - for (DarwinLogEventVector::size_type base_entry = 0; - base_entry < entry_count; - base_entry += DARWIN_LOG_MAX_EVENTS_PER_PACKET) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): inner loop enter", - __FUNCTION__); - - // We limit the total number of entries we pack - // into a single JSON async packet just so it - // doesn't get too large. - JSONGenerator::Dictionary async_dictionary; - - // Specify the type of the JSON async data we're sending. - async_dictionary.AddStringItem( - JSON_ASYNC_TYPE_KEY_NAME, "DarwinLog"); - - // Create an array entry in the dictionary to hold all - // the events going in this packet. - JSONGenerator::ArraySP events_array(new JSONGenerator::Array()); - async_dictionary.AddItem(OS_LOG_EVENTS_KEY_NAME, events_array); - - // We bundle up to DARWIN_LOG_MAX_EVENTS_PER_PACKET events in - // a single packet. - const auto inner_loop_bound = - std::min(base_entry + DARWIN_LOG_MAX_EVENTS_PER_PACKET, - entry_count); - for (DarwinLogEventVector::size_type i = base_entry; - i < inner_loop_bound; ++i) - { - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): adding " - "entry index %lu to the JSON packet", - __FUNCTION__, i); - events_array->AddItem(events[i]); - } + for (DarwinLogEventVector::size_type base_entry = 0; + base_entry < entry_count; + base_entry += DARWIN_LOG_MAX_EVENTS_PER_PACKET) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): inner loop enter", + __FUNCTION__); + + // We limit the total number of entries we pack + // into a single JSON async packet just so it + // doesn't get too large. + JSONGenerator::Dictionary async_dictionary; + + // Specify the type of the JSON async data we're sending. + async_dictionary.AddStringItem(JSON_ASYNC_TYPE_KEY_NAME, "DarwinLog"); + + // Create an array entry in the dictionary to hold all + // the events going in this packet. + JSONGenerator::ArraySP events_array(new JSONGenerator::Array()); + async_dictionary.AddItem(OS_LOG_EVENTS_KEY_NAME, events_array); + + // We bundle up to DARWIN_LOG_MAX_EVENTS_PER_PACKET events in + // a single packet. + const auto inner_loop_bound = + std::min(base_entry + DARWIN_LOG_MAX_EVENTS_PER_PACKET, entry_count); + for (DarwinLogEventVector::size_type i = base_entry; i < inner_loop_bound; + ++i) { + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): adding " + "entry index %lu to the JSON packet", + __FUNCTION__, i); + events_array->AddItem(events[i]); + } - // Send off the packet. - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): sending JSON " - "packet, %lu entries remain", __FUNCTION__, - entry_count - inner_loop_bound); - SendAsyncJSONPacket(async_dictionary); - } + // Send off the packet. + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): sending JSON " + "packet, %lu entries remain", + __FUNCTION__, entry_count - inner_loop_bound); + SendAsyncJSONPacket(async_dictionary); + } - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop exit", - __FUNCTION__); + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): outer loop exit", + __FUNCTION__); - } while (entry_count > 0); + } while (entry_count > 0); - DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): exit", - __PRETTY_FUNCTION__); + DNBLogThreadedIf(LOG_DARWIN_LOG, "RNBRemote::%s(): exit", + __PRETTY_FUNCTION__); } -rnb_err_t -RNBRemote::SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer) -{ - std::ostringstream packet_sstrm; - // Append the header cstr if there was one - if (header && header[0]) - packet_sstrm << header; - nub_size_t i; - const uint8_t *ubuf8 = (const uint8_t *)buf; - for (i=0; i<buf_len; i++) - { - packet_sstrm << RAWHEX8(ubuf8[i]); - } - // Append the footer cstr if there was one - if (footer && footer[0]) - packet_sstrm << footer; +rnb_err_t RNBRemote::SendHexEncodedBytePacket(const char *header, + const void *buf, size_t buf_len, + const char *footer) { + std::ostringstream packet_sstrm; + // Append the header cstr if there was one + if (header && header[0]) + packet_sstrm << header; + nub_size_t i; + const uint8_t *ubuf8 = (const uint8_t *)buf; + for (i = 0; i < buf_len; i++) { + packet_sstrm << RAWHEX8(ubuf8[i]); + } + // Append the footer cstr if there was one + if (footer && footer[0]) + packet_sstrm << footer; - return SendPacket(packet_sstrm.str()); + return SendPacket(packet_sstrm.str()); } -rnb_err_t -RNBRemote::SendSTDOUTPacket (char *buf, nub_size_t buf_size) -{ - if (buf_size == 0) - return rnb_success; - return SendHexEncodedBytePacket("O", buf, buf_size, NULL); +rnb_err_t RNBRemote::SendSTDOUTPacket(char *buf, nub_size_t buf_size) { + if (buf_size == 0) + return rnb_success; + return SendHexEncodedBytePacket("O", buf, buf_size, NULL); } -rnb_err_t -RNBRemote::SendSTDERRPacket (char *buf, nub_size_t buf_size) -{ - if (buf_size == 0) - return rnb_success; - return SendHexEncodedBytePacket("O", buf, buf_size, NULL); +rnb_err_t RNBRemote::SendSTDERRPacket(char *buf, nub_size_t buf_size) { + if (buf_size == 0) + return rnb_success; + return SendHexEncodedBytePacket("O", buf, buf_size, NULL); } // This makes use of asynchronous bit 'A' in the gdb remote protocol. -rnb_err_t -RNBRemote::SendAsyncProfileDataPacket (char *buf, nub_size_t buf_size) -{ - if (buf_size == 0) - return rnb_success; - - std::string packet("A"); - packet.append(buf, buf_size); - return SendPacket(packet); +rnb_err_t RNBRemote::SendAsyncProfileDataPacket(char *buf, + nub_size_t buf_size) { + if (buf_size == 0) + return rnb_success; + + std::string packet("A"); + packet.append(buf, buf_size); + return SendPacket(packet); } rnb_err_t -RNBRemote::SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary) -{ - std::ostringstream stream; - // We're choosing something that is easy to spot if we somehow get one - // of these coming out at the wrong time (i.e. when the remote side - // is not waiting for a process control completion response). - stream << "JSON-async:"; - dictionary.Dump(stream); - const std::string payload = binary_encode_string(stream.str()); - return SendPacket(payload); +RNBRemote::SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary) { + std::ostringstream stream; + // We're choosing something that is easy to spot if we somehow get one + // of these coming out at the wrong time (i.e. when the remote side + // is not waiting for a process control completion response). + stream << "JSON-async:"; + dictionary.Dump(stream); + const std::string payload = binary_encode_string(stream.str()); + return SendPacket(payload); } // Given a std::string packet contents to send, possibly encode/compress it. // If compression is enabled, the returned std::string will be in one of two // forms: -// +// // N<original packet contents uncompressed> -// C<size of original decompressed packet>:<packet compressed with the requested compression scheme> +// C<size of original decompressed packet>:<packet compressed with the +// requested compression scheme> // // If compression is not requested, the original packet contents are returned -std::string -RNBRemote::CompressString (const std::string &orig) -{ - std::string compressed; - compression_types compression_type = GetCompressionType(); - if (compression_type != compression_types::none) - { - bool compress_this_packet = false; +std::string RNBRemote::CompressString(const std::string &orig) { + std::string compressed; + compression_types compression_type = GetCompressionType(); + if (compression_type != compression_types::none) { + bool compress_this_packet = false; - if (orig.size() > m_compression_minsize) - { - compress_this_packet = true; - } + if (orig.size() > m_compression_minsize) { + compress_this_packet = true; + } - if (compress_this_packet) - { - const size_t encoded_data_buf_size = orig.size() + 128; - std::vector<uint8_t> encoded_data (encoded_data_buf_size); - size_t compressed_size = 0; + if (compress_this_packet) { + const size_t encoded_data_buf_size = orig.size() + 128; + std::vector<uint8_t> encoded_data(encoded_data_buf_size); + size_t compressed_size = 0; -#if defined (HAVE_LIBCOMPRESSION) - if (compression_decode_buffer && compression_type == compression_types::lz4) - { - compressed_size = compression_encode_buffer (encoded_data.data(), - encoded_data_buf_size, - (uint8_t*) orig.c_str(), - orig.size(), - nullptr, - COMPRESSION_LZ4_RAW); - } - if (compression_decode_buffer && compression_type == compression_types::zlib_deflate) - { - compressed_size = compression_encode_buffer (encoded_data.data(), - encoded_data_buf_size, - (uint8_t*) orig.c_str(), - orig.size(), - nullptr, - COMPRESSION_ZLIB); - } - if (compression_decode_buffer && compression_type == compression_types::lzma) - { - compressed_size = compression_encode_buffer (encoded_data.data(), - encoded_data_buf_size, - (uint8_t*) orig.c_str(), - orig.size(), - nullptr, - COMPRESSION_LZMA); - } - if (compression_decode_buffer && compression_type == compression_types::lzfse) - { - compressed_size = compression_encode_buffer (encoded_data.data(), - encoded_data_buf_size, - (uint8_t*) orig.c_str(), - orig.size(), - nullptr, - COMPRESSION_LZFSE); - } +#if defined(HAVE_LIBCOMPRESSION) + if (compression_decode_buffer && + compression_type == compression_types::lz4) { + compressed_size = compression_encode_buffer( + encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(), + orig.size(), nullptr, COMPRESSION_LZ4_RAW); + } + if (compression_decode_buffer && + compression_type == compression_types::zlib_deflate) { + compressed_size = compression_encode_buffer( + encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(), + orig.size(), nullptr, COMPRESSION_ZLIB); + } + if (compression_decode_buffer && + compression_type == compression_types::lzma) { + compressed_size = compression_encode_buffer( + encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(), + orig.size(), nullptr, COMPRESSION_LZMA); + } + if (compression_decode_buffer && + compression_type == compression_types::lzfse) { + compressed_size = compression_encode_buffer( + encoded_data.data(), encoded_data_buf_size, (uint8_t *)orig.c_str(), + orig.size(), nullptr, COMPRESSION_LZFSE); + } #endif -#if defined (HAVE_LIBZ) - if (compressed_size == 0 && compression_type == compression_types::zlib_deflate) - { - z_stream stream; - memset (&stream, 0, sizeof (z_stream)); - stream.next_in = (Bytef *) orig.c_str(); - stream.avail_in = (uInt) orig.size(); - stream.next_out = (Bytef *) encoded_data.data(); - stream.avail_out = (uInt) encoded_data_buf_size; - stream.zalloc = Z_NULL; - stream.zfree = Z_NULL; - stream.opaque = Z_NULL; - deflateInit2 (&stream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); - int compress_status = deflate (&stream, Z_FINISH); - deflateEnd (&stream); - if (compress_status == Z_STREAM_END && stream.total_out > 0) - { - compressed_size = stream.total_out; - } - } +#if defined(HAVE_LIBZ) + if (compressed_size == 0 && + compression_type == compression_types::zlib_deflate) { + z_stream stream; + memset(&stream, 0, sizeof(z_stream)); + stream.next_in = (Bytef *)orig.c_str(); + stream.avail_in = (uInt)orig.size(); + stream.next_out = (Bytef *)encoded_data.data(); + stream.avail_out = (uInt)encoded_data_buf_size; + stream.zalloc = Z_NULL; + stream.zfree = Z_NULL; + stream.opaque = Z_NULL; + deflateInit2(&stream, 5, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); + int compress_status = deflate(&stream, Z_FINISH); + deflateEnd(&stream); + if (compress_status == Z_STREAM_END && stream.total_out > 0) { + compressed_size = stream.total_out; + } + } #endif - if (compressed_size > 0) - { - compressed.clear (); - compressed.reserve (compressed_size); - compressed = "C"; - char numbuf[16]; - snprintf (numbuf, sizeof (numbuf), "%zu:", orig.size()); - numbuf[sizeof (numbuf) - 1] = '\0'; - compressed.append (numbuf); - - for (size_t i = 0; i < compressed_size; i++) - { - uint8_t byte = encoded_data[i]; - if (byte == '#' || byte == '$' || byte == '}' || byte == '*' || byte == '\0') - { - compressed.push_back (0x7d); - compressed.push_back (byte ^ 0x20); - } - else - { - compressed.push_back (byte); - } - } - } - else - { - compressed = "N" + orig; - } - } - else - { - compressed = "N" + orig; + if (compressed_size > 0) { + compressed.clear(); + compressed.reserve(compressed_size); + compressed = "C"; + char numbuf[16]; + snprintf(numbuf, sizeof(numbuf), "%zu:", orig.size()); + numbuf[sizeof(numbuf) - 1] = '\0'; + compressed.append(numbuf); + + for (size_t i = 0; i < compressed_size; i++) { + uint8_t byte = encoded_data[i]; + if (byte == '#' || byte == '$' || byte == '}' || byte == '*' || + byte == '\0') { + compressed.push_back(0x7d); + compressed.push_back(byte ^ 0x20); + } else { + compressed.push_back(byte); + } } + } else { + compressed = "N" + orig; + } + } else { + compressed = "N" + orig; } - else - { - compressed = orig; - } + } else { + compressed = orig; + } - return compressed; + return compressed; } -rnb_err_t -RNBRemote::SendPacket (const std::string &s) -{ - DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s (%s) called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, s.c_str()); +rnb_err_t RNBRemote::SendPacket(const std::string &s) { + DNBLogThreadedIf(LOG_RNB_MAX, "%8d RNBRemote::%s (%s) called", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, s.c_str()); - std::string s_compressed = CompressString (s); + std::string s_compressed = CompressString(s); - std::string sendpacket = "$" + s_compressed + "#"; - int cksum = 0; - char hexbuf[5]; + std::string sendpacket = "$" + s_compressed + "#"; + int cksum = 0; + char hexbuf[5]; - if (m_noack_mode) - { - sendpacket += "00"; - } - else - { - for (size_t i = 0; i != s_compressed.size(); ++i) - cksum += s_compressed[i]; - snprintf (hexbuf, sizeof hexbuf, "%02x", cksum & 0xff); - sendpacket += hexbuf; - } + if (m_noack_mode) { + sendpacket += "00"; + } else { + for (size_t i = 0; i != s_compressed.size(); ++i) + cksum += s_compressed[i]; + snprintf(hexbuf, sizeof hexbuf, "%02x", cksum & 0xff); + sendpacket += hexbuf; + } - rnb_err_t err = m_comm.Write (sendpacket.c_str(), sendpacket.size()); - if (err != rnb_success) - return err; + rnb_err_t err = m_comm.Write(sendpacket.c_str(), sendpacket.size()); + if (err != rnb_success) + return err; - if (m_noack_mode) - return rnb_success; + if (m_noack_mode) + return rnb_success; - std::string reply; - RNBRemote::Packet packet; - err = GetPacket (reply, packet, true); + std::string reply; + RNBRemote::Packet packet; + err = GetPacket(reply, packet, true); - if (err != rnb_success) - { - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s (%s) got error trying to get reply...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, sendpacket.c_str()); - return err; - } + if (err != rnb_success) { + DNBLogThreadedIf(LOG_RNB_REMOTE, + "%8d RNBRemote::%s (%s) got error trying to get reply...", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, sendpacket.c_str()); + return err; + } - DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s (%s) got reply: '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, sendpacket.c_str(), reply.c_str()); + DNBLogThreadedIf(LOG_RNB_MAX, "%8d RNBRemote::%s (%s) got reply: '%s'", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, sendpacket.c_str(), reply.c_str()); - if (packet.type == ack) - return rnb_success; + if (packet.type == ack) + return rnb_success; - // Should we try to resend the packet at this layer? - // if (packet.command == nack) - return rnb_err; + // Should we try to resend the packet at this layer? + // if (packet.command == nack) + return rnb_err; } /* Get a packet via gdb remote protocol. Strip off the prefix/suffix, verify the checksum to make sure a valid packet was received, send an ACK if they match. */ -rnb_err_t -RNBRemote::GetPacketPayload (std::string &return_packet) -{ - //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - - PThreadMutex::Locker locker(m_mutex); - if (m_rx_packets.empty()) - { - // Only reset the remote command available event if we have no more packets - m_ctx.Events().ResetEvents ( RNBContext::event_read_packet_available ); - //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s error: no packets available...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - return rnb_err; - } - - //DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s has %u queued packets", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, m_rx_packets.size()); - return_packet.swap(m_rx_packets.front()); - m_rx_packets.pop_front(); - locker.Reset(); // Release our lock on the mutex - - if (m_rx_packets.empty()) - { - // Reset the remote command available event if we have no more packets - m_ctx.Events().ResetEvents ( RNBContext::event_read_packet_available ); - } - - //DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s: '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str()); - - switch (return_packet[0]) - { - case '+': - case '-': - case '\x03': - break; - - case '$': - { - long packet_checksum = 0; - if (!m_noack_mode) - { - for (size_t i = return_packet.size() - 2; i < return_packet.size(); ++i) - { - char checksum_char = tolower (return_packet[i]); - if (!isxdigit (checksum_char)) - { - m_comm.Write ("-", 1); - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s error: packet with invalid checksum characters: %s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str()); - return rnb_err; - } - } - packet_checksum = strtol (&return_packet[return_packet.size() - 2], NULL, 16); - } - - return_packet.erase(0,1); // Strip the leading '$' - return_packet.erase(return_packet.size() - 3);// Strip the #XX checksum - - if (!m_noack_mode) - { - // Compute the checksum - int computed_checksum = 0; - for (std::string::iterator it = return_packet.begin (); - it != return_packet.end (); - ++it) - { - computed_checksum += *it; - } - - if (packet_checksum == (computed_checksum & 0xff)) - { - //DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str()); - m_comm.Write ("+", 1); - } - else - { - DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s' (error: packet checksum mismatch (0x%2.2lx != 0x%2.2x))", - (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), - __FUNCTION__, - return_packet.c_str(), - packet_checksum, - computed_checksum); - m_comm.Write ("-", 1); - return rnb_err; - } - } +rnb_err_t RNBRemote::GetPacketPayload(std::string &return_packet) { + // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s called", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); + + PThreadMutex::Locker locker(m_mutex); + if (m_rx_packets.empty()) { + // Only reset the remote command available event if we have no more packets + m_ctx.Events().ResetEvents(RNBContext::event_read_packet_available); + // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s error: no packets + // available...", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + // __FUNCTION__); + return rnb_err; + } + + // DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s has %u queued packets", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, + // m_rx_packets.size()); + return_packet.swap(m_rx_packets.front()); + m_rx_packets.pop_front(); + locker.Reset(); // Release our lock on the mutex + + if (m_rx_packets.empty()) { + // Reset the remote command available event if we have no more packets + m_ctx.Events().ResetEvents(RNBContext::event_read_packet_available); + } + + // DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s: '%s'", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, + // return_packet.c_str()); + + switch (return_packet[0]) { + case '+': + case '-': + case '\x03': + break; + + case '$': { + long packet_checksum = 0; + if (!m_noack_mode) { + for (size_t i = return_packet.size() - 2; i < return_packet.size(); ++i) { + char checksum_char = tolower(return_packet[i]); + if (!isxdigit(checksum_char)) { + m_comm.Write("-", 1); + DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s error: packet " + "with invalid checksum characters: " + "%s", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, return_packet.c_str()); + return rnb_err; } - break; - - default: - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s tossing unexpected packet???? %s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, return_packet.c_str()); - if (!m_noack_mode) - m_comm.Write ("-", 1); - return rnb_err; + } + packet_checksum = + strtol(&return_packet[return_packet.size() - 2], NULL, 16); } - return rnb_success; -} - -rnb_err_t -RNBRemote::HandlePacket_UNIMPLEMENTED (const char* p) -{ - DNBLogThreadedIf (LOG_RNB_MAX, "%8u RNBRemote::%s(\"%s\")", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p ? p : "NULL"); - return SendPacket (""); -} + return_packet.erase(0, 1); // Strip the leading '$' + return_packet.erase(return_packet.size() - 3); // Strip the #XX checksum -rnb_err_t -RNBRemote::HandlePacket_ILLFORMED (const char *file, int line, const char *p, const char *description) -{ - DNBLogThreadedIf (LOG_RNB_PACKETS, "%8u %s:%i ILLFORMED: '%s' (%s)", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), file, line, __FUNCTION__, p); - return SendPacket ("E03"); -} - -rnb_err_t -RNBRemote::GetPacket (std::string &packet_payload, RNBRemote::Packet& packet_info, bool wait) -{ - std::string payload; - rnb_err_t err = GetPacketPayload (payload); - if (err != rnb_success) - { - PThreadEvent& events = m_ctx.Events(); - nub_event_t set_events = events.GetEventBits(); - // TODO: add timeout version of GetPacket?? We would then need to pass - // that timeout value along to DNBProcessTimedWaitForEvent. - if (!wait || ((set_events & RNBContext::event_read_thread_running) == 0)) - return err; - - const nub_event_t events_to_wait_for = RNBContext::event_read_packet_available | RNBContext::event_read_thread_exiting; - - while ((set_events = events.WaitForSetEvents(events_to_wait_for)) != 0) - { - if (set_events & RNBContext::event_read_packet_available) - { - // Try the queue again now that we got an event - err = GetPacketPayload (payload); - if (err == rnb_success) - break; - } - - if (set_events & RNBContext::event_read_thread_exiting) - err = rnb_not_connected; - - if (err == rnb_not_connected) - return err; - - } while (err == rnb_err); + if (!m_noack_mode) { + // Compute the checksum + int computed_checksum = 0; + for (std::string::iterator it = return_packet.begin(); + it != return_packet.end(); ++it) { + computed_checksum += *it; + } - if (set_events == 0) - err = rnb_not_connected; + if (packet_checksum == (computed_checksum & 0xff)) { + // DNBLogThreadedIf (LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for + // '%s'", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + // __FUNCTION__, return_packet.c_str()); + m_comm.Write("+", 1); + } else { + DNBLogThreadedIf( + LOG_RNB_MEDIUM, "%8u RNBRemote::%s sending ACK for '%s' (error: " + "packet checksum mismatch (0x%2.2lx != 0x%2.2x))", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, + return_packet.c_str(), packet_checksum, computed_checksum); + m_comm.Write("-", 1); + return rnb_err; + } } + } break; - if (err == rnb_success) - { - Packet::iterator it; - for (it = m_packets.begin (); it != m_packets.end (); ++it) - { - if (payload.compare (0, it->abbrev.size(), it->abbrev) == 0) - break; - } - - // A packet we don't have an entry for. This can happen when we - // get a packet that we don't know about or support. We just reply - // accordingly and go on. - if (it == m_packets.end ()) - { - DNBLogThreadedIf (LOG_RNB_PACKETS, "unimplemented packet: '%s'", payload.c_str()); - HandlePacket_UNIMPLEMENTED(payload.c_str()); - return rnb_err; - } - else - { - packet_info = *it; - packet_payload = payload; - } - } - return err; -} + default: + DNBLogThreadedIf(LOG_RNB_REMOTE, + "%8u RNBRemote::%s tossing unexpected packet???? %s", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, return_packet.c_str()); + if (!m_noack_mode) + m_comm.Write("-", 1); + return rnb_err; + } + + return rnb_success; +} + +rnb_err_t RNBRemote::HandlePacket_UNIMPLEMENTED(const char *p) { + DNBLogThreadedIf(LOG_RNB_MAX, "%8u RNBRemote::%s(\"%s\")", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, p ? p : "NULL"); + return SendPacket(""); +} + +rnb_err_t RNBRemote::HandlePacket_ILLFORMED(const char *file, int line, + const char *p, + const char *description) { + DNBLogThreadedIf(LOG_RNB_PACKETS, "%8u %s:%i ILLFORMED: '%s' (%s)", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), file, + line, __FUNCTION__, p); + return SendPacket("E03"); +} + +rnb_err_t RNBRemote::GetPacket(std::string &packet_payload, + RNBRemote::Packet &packet_info, bool wait) { + std::string payload; + rnb_err_t err = GetPacketPayload(payload); + if (err != rnb_success) { + PThreadEvent &events = m_ctx.Events(); + nub_event_t set_events = events.GetEventBits(); + // TODO: add timeout version of GetPacket?? We would then need to pass + // that timeout value along to DNBProcessTimedWaitForEvent. + if (!wait || ((set_events & RNBContext::event_read_thread_running) == 0)) + return err; + + const nub_event_t events_to_wait_for = + RNBContext::event_read_packet_available | + RNBContext::event_read_thread_exiting; + + while ((set_events = events.WaitForSetEvents(events_to_wait_for)) != 0) { + if (set_events & RNBContext::event_read_packet_available) { + // Try the queue again now that we got an event + err = GetPacketPayload(payload); + if (err == rnb_success) + break; + } -rnb_err_t -RNBRemote::HandleAsyncPacket(PacketEnum *type) -{ - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - static DNBTimer g_packetTimer(true); - rnb_err_t err = rnb_err; - std::string packet_data; - RNBRemote::Packet packet_info; - err = GetPacket (packet_data, packet_info, false); - - if (err == rnb_success) - { - if (!packet_data.empty() && isprint(packet_data[0])) - DNBLogThreadedIf (LOG_RNB_REMOTE | LOG_RNB_PACKETS, "HandleAsyncPacket (\"%s\");", packet_data.c_str()); - else - DNBLogThreadedIf (LOG_RNB_REMOTE | LOG_RNB_PACKETS, "HandleAsyncPacket (%s);", packet_info.printable_name.c_str()); + if (set_events & RNBContext::event_read_thread_exiting) + err = rnb_not_connected; - HandlePacketCallback packet_callback = packet_info.async; - if (packet_callback != NULL) - { - if (type != NULL) - *type = packet_info.type; - return (this->*packet_callback)(packet_data.c_str()); - } + if (err == rnb_not_connected) + return err; } + while (err == rnb_err) + ; - return err; -} + if (set_events == 0) + err = rnb_not_connected; + } -rnb_err_t -RNBRemote::HandleReceivedPacket(PacketEnum *type) -{ - static DNBTimer g_packetTimer(true); - - // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - rnb_err_t err = rnb_err; - std::string packet_data; - RNBRemote::Packet packet_info; - err = GetPacket (packet_data, packet_info, false); - - if (err == rnb_success) - { - DNBLogThreadedIf (LOG_RNB_REMOTE, "HandleReceivedPacket (\"%s\");", packet_data.c_str()); - HandlePacketCallback packet_callback = packet_info.normal; - if (packet_callback != NULL) - { - if (type != NULL) - *type = packet_info.type; - return (this->*packet_callback)(packet_data.c_str()); - } - else - { - // Do not fall through to end of this function, if we have valid - // packet_info and it has a NULL callback, then we need to respect - // that it may not want any response or anything to be done. - return err; - } + if (err == rnb_success) { + Packet::iterator it; + for (it = m_packets.begin(); it != m_packets.end(); ++it) { + if (payload.compare(0, it->abbrev.size(), it->abbrev) == 0) + break; } - return rnb_err; -} -void -RNBRemote::CommDataReceived(const std::string& new_data) -{ - // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - { - // Put the packet data into the buffer in a thread safe fashion - PThreadMutex::Locker locker(m_mutex); - - std::string data; - // See if we have any left over data from a previous call to this - // function? - if (!m_rx_partial_data.empty()) - { - // We do, so lets start with that data - data.swap(m_rx_partial_data); - } - // Append the new incoming data - data += new_data; - - // Parse up the packets into gdb remote packets - size_t idx = 0; - const size_t data_size = data.size(); - - while (idx < data_size) - { - // end_idx must be one past the last valid packet byte. Start - // it off with an invalid value that is the same as the current - // index. - size_t end_idx = idx; + // A packet we don't have an entry for. This can happen when we + // get a packet that we don't know about or support. We just reply + // accordingly and go on. + if (it == m_packets.end()) { + DNBLogThreadedIf(LOG_RNB_PACKETS, "unimplemented packet: '%s'", + payload.c_str()); + HandlePacket_UNIMPLEMENTED(payload.c_str()); + return rnb_err; + } else { + packet_info = *it; + packet_payload = payload; + } + } + return err; +} + +rnb_err_t RNBRemote::HandleAsyncPacket(PacketEnum *type) { + DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__); + static DNBTimer g_packetTimer(true); + rnb_err_t err = rnb_err; + std::string packet_data; + RNBRemote::Packet packet_info; + err = GetPacket(packet_data, packet_info, false); + + if (err == rnb_success) { + if (!packet_data.empty() && isprint(packet_data[0])) + DNBLogThreadedIf(LOG_RNB_REMOTE | LOG_RNB_PACKETS, + "HandleAsyncPacket (\"%s\");", packet_data.c_str()); + else + DNBLogThreadedIf(LOG_RNB_REMOTE | LOG_RNB_PACKETS, + "HandleAsyncPacket (%s);", + packet_info.printable_name.c_str()); + + HandlePacketCallback packet_callback = packet_info.async; + if (packet_callback != NULL) { + if (type != NULL) + *type = packet_info.type; + return (this->*packet_callback)(packet_data.c_str()); + } + } + + return err; +} + +rnb_err_t RNBRemote::HandleReceivedPacket(PacketEnum *type) { + static DNBTimer g_packetTimer(true); + + // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); + rnb_err_t err = rnb_err; + std::string packet_data; + RNBRemote::Packet packet_info; + err = GetPacket(packet_data, packet_info, false); + + if (err == rnb_success) { + DNBLogThreadedIf(LOG_RNB_REMOTE, "HandleReceivedPacket (\"%s\");", + packet_data.c_str()); + HandlePacketCallback packet_callback = packet_info.normal; + if (packet_callback != NULL) { + if (type != NULL) + *type = packet_info.type; + return (this->*packet_callback)(packet_data.c_str()); + } else { + // Do not fall through to end of this function, if we have valid + // packet_info and it has a NULL callback, then we need to respect + // that it may not want any response or anything to be done. + return err; + } + } + return rnb_err; +} + +void RNBRemote::CommDataReceived(const std::string &new_data) { + // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); + { + // Put the packet data into the buffer in a thread safe fashion + PThreadMutex::Locker locker(m_mutex); - switch (data[idx]) - { - case '+': // Look for ack - case '-': // Look for cancel - case '\x03': // ^C to halt target - end_idx = idx + 1; // The command is one byte long... - break; - - case '$': - // Look for a standard gdb packet? - end_idx = data.find('#', idx + 1); - if (end_idx == std::string::npos || end_idx + 3 > data_size) - { - end_idx = std::string::npos; - } - else - { - // Add two for the checksum bytes and 1 to point to the - // byte just past the end of this packet - end_idx += 3; - } - break; - - default: - break; - } + std::string data; + // See if we have any left over data from a previous call to this + // function? + if (!m_rx_partial_data.empty()) { + // We do, so lets start with that data + data.swap(m_rx_partial_data); + } + // Append the new incoming data + data += new_data; + + // Parse up the packets into gdb remote packets + size_t idx = 0; + const size_t data_size = data.size(); + + while (idx < data_size) { + // end_idx must be one past the last valid packet byte. Start + // it off with an invalid value that is the same as the current + // index. + size_t end_idx = idx; + + switch (data[idx]) { + case '+': // Look for ack + case '-': // Look for cancel + case '\x03': // ^C to halt target + end_idx = idx + 1; // The command is one byte long... + break; - if (end_idx == std::string::npos) - { - // Not all data may be here for the packet yet, save it for - // next time through this function. - m_rx_partial_data += data.substr(idx); - //DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s saving data for later[%u, npos): '%s'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, idx, m_rx_partial_data.c_str()); - idx = end_idx; - } - else - if (idx < end_idx) - { - m_packets_recvd++; - // Hack to get rid of initial '+' ACK??? - if (m_packets_recvd == 1 && (end_idx == idx + 1) && data[idx] == '+') - { - //DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s throwing first ACK away....[%u, npos): '+'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, idx); - } - else - { - // We have a valid packet... - m_rx_packets.push_back(data.substr(idx, end_idx - idx)); - DNBLogThreadedIf (LOG_RNB_PACKETS, "getpkt: %s", m_rx_packets.back().c_str()); - } - idx = end_idx; - } - else - { - DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s tossing junk byte at %c",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, data[idx]); - idx = idx + 1; - } + case '$': + // Look for a standard gdb packet? + end_idx = data.find('#', idx + 1); + if (end_idx == std::string::npos || end_idx + 3 > data_size) { + end_idx = std::string::npos; + } else { + // Add two for the checksum bytes and 1 to point to the + // byte just past the end of this packet + end_idx += 3; } - } - - if (!m_rx_packets.empty()) - { - // Let the main thread know we have received a packet - - //DNBLogThreadedIf (LOG_RNB_EVENTS, "%8d RNBRemote::%s called events.SetEvent(RNBContext::event_read_packet_available)", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - PThreadEvent& events = m_ctx.Events(); - events.SetEvents (RNBContext::event_read_packet_available); - } -} + break; -rnb_err_t -RNBRemote::GetCommData () -{ - // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - std::string comm_data; - rnb_err_t err = m_comm.Read (comm_data); - if (err == rnb_success) - { - if (!comm_data.empty()) - CommDataReceived (comm_data); - } - return err; -} + default: + break; + } -void -RNBRemote::StartReadRemoteDataThread() -{ - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - PThreadEvent& events = m_ctx.Events(); - if ((events.GetEventBits() & RNBContext::event_read_thread_running) == 0) - { - events.ResetEvents (RNBContext::event_read_thread_exiting); - int err = ::pthread_create (&m_rx_pthread, NULL, ThreadFunctionReadRemoteData, this); - if (err == 0) - { - // Our thread was successfully kicked off, wait for it to - // set the started event so we can safely continue - events.WaitForSetEvents (RNBContext::event_read_thread_running); - } - else - { - events.ResetEvents (RNBContext::event_read_thread_running); - events.SetEvents (RNBContext::event_read_thread_exiting); + if (end_idx == std::string::npos) { + // Not all data may be here for the packet yet, save it for + // next time through this function. + m_rx_partial_data += data.substr(idx); + // DNBLogThreadedIf (LOG_RNB_MAX, "%8d RNBRemote::%s saving data for + // later[%u, npos): + // '%s'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + // __FUNCTION__, idx, m_rx_partial_data.c_str()); + idx = end_idx; + } else if (idx < end_idx) { + m_packets_recvd++; + // Hack to get rid of initial '+' ACK??? + if (m_packets_recvd == 1 && (end_idx == idx + 1) && data[idx] == '+') { + // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s throwing first + // ACK away....[%u, npos): + // '+'",(uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + // __FUNCTION__, idx); + } else { + // We have a valid packet... + m_rx_packets.push_back(data.substr(idx, end_idx - idx)); + DNBLogThreadedIf(LOG_RNB_PACKETS, "getpkt: %s", + m_rx_packets.back().c_str()); } + idx = end_idx; + } else { + DNBLogThreadedIf(LOG_RNB_MAX, + "%8d RNBRemote::%s tossing junk byte at %c", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, data[idx]); + idx = idx + 1; + } } -} - -void -RNBRemote::StopReadRemoteDataThread() -{ - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s called", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); - PThreadEvent& events = m_ctx.Events(); - if ((events.GetEventBits() & RNBContext::event_read_thread_running) == RNBContext::event_read_thread_running) - { - m_comm.Disconnect(true); - struct timespec timeout_abstime; - DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); - - // Wait for 2 seconds for the remote data thread to exit - if (events.WaitForSetEvents(RNBContext::event_read_thread_exiting, &timeout_abstime) == 0) - { - // Kill the remote data thread??? - } + } + + if (!m_rx_packets.empty()) { + // Let the main thread know we have received a packet + + // DNBLogThreadedIf (LOG_RNB_EVENTS, "%8d RNBRemote::%s called + // events.SetEvent(RNBContext::event_read_packet_available)", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); + PThreadEvent &events = m_ctx.Events(); + events.SetEvents(RNBContext::event_read_packet_available); + } +} + +rnb_err_t RNBRemote::GetCommData() { + // DNBLogThreadedIf (LOG_RNB_REMOTE, "%8d RNBRemote::%s called", + // (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__); + std::string comm_data; + rnb_err_t err = m_comm.Read(comm_data); + if (err == rnb_success) { + if (!comm_data.empty()) + CommDataReceived(comm_data); + } + return err; +} + +void RNBRemote::StartReadRemoteDataThread() { + DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s called", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__); + PThreadEvent &events = m_ctx.Events(); + if ((events.GetEventBits() & RNBContext::event_read_thread_running) == 0) { + events.ResetEvents(RNBContext::event_read_thread_exiting); + int err = ::pthread_create(&m_rx_pthread, NULL, + ThreadFunctionReadRemoteData, this); + if (err == 0) { + // Our thread was successfully kicked off, wait for it to + // set the started event so we can safely continue + events.WaitForSetEvents(RNBContext::event_read_thread_running); + } else { + events.ResetEvents(RNBContext::event_read_thread_running); + events.SetEvents(RNBContext::event_read_thread_exiting); + } + } +} + +void RNBRemote::StopReadRemoteDataThread() { + DNBLogThreadedIf(LOG_RNB_REMOTE, "%8u RNBRemote::%s called", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__); + PThreadEvent &events = m_ctx.Events(); + if ((events.GetEventBits() & RNBContext::event_read_thread_running) == + RNBContext::event_read_thread_running) { + m_comm.Disconnect(true); + struct timespec timeout_abstime; + DNBTimer::OffsetTimeOfDay(&timeout_abstime, 2, 0); + + // Wait for 2 seconds for the remote data thread to exit + if (events.WaitForSetEvents(RNBContext::event_read_thread_exiting, + &timeout_abstime) == 0) { + // Kill the remote data thread??? + } + } +} + +void *RNBRemote::ThreadFunctionReadRemoteData(void *arg) { + // Keep a shared pointer reference so this doesn't go away on us before the + // thread is killed. + DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread starting...", + __FUNCTION__, arg); + RNBRemoteSP remoteSP(g_remoteSP); + if (remoteSP.get() != NULL) { + +#if defined(__APPLE__) + pthread_setname_np("read gdb-remote packets thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); } -} - - -void* -RNBRemote::ThreadFunctionReadRemoteData(void *arg) -{ - // Keep a shared pointer reference so this doesn't go away on us before the thread is killed. - DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread starting...", __FUNCTION__, arg); - RNBRemoteSP remoteSP(g_remoteSP); - if (remoteSP.get() != NULL) - { - -#if defined (__APPLE__) - pthread_setname_np ("read gdb-remote packets thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } #endif #endif - RNBRemote* remote = remoteSP.get(); - PThreadEvent& events = remote->Context().Events(); - events.SetEvents (RNBContext::event_read_thread_running); - // START: main receive remote command thread loop - bool done = false; - while (!done) - { - rnb_err_t err = remote->GetCommData(); + RNBRemote *remote = remoteSP.get(); + PThreadEvent &events = remote->Context().Events(); + events.SetEvents(RNBContext::event_read_thread_running); + // START: main receive remote command thread loop + bool done = false; + while (!done) { + rnb_err_t err = remote->GetCommData(); - switch (err) - { - case rnb_success: - break; - - case rnb_err: - DNBLogThreadedIf (LOG_RNB_REMOTE, "RNBSocket::GetCommData returned error %u", err); - done = true; - break; - - case rnb_not_connected: - DNBLogThreadedIf (LOG_RNB_REMOTE, "RNBSocket::GetCommData returned not connected..."); - done = true; - break; - } - } - // START: main receive remote command thread loop - events.ResetEvents (RNBContext::event_read_thread_running); - events.SetEvents (RNBContext::event_read_thread_exiting); + switch (err) { + case rnb_success: + break; + + case rnb_err: + DNBLogThreadedIf(LOG_RNB_REMOTE, + "RNBSocket::GetCommData returned error %u", err); + done = true; + break; + + case rnb_not_connected: + DNBLogThreadedIf(LOG_RNB_REMOTE, + "RNBSocket::GetCommData returned not connected..."); + done = true; + break; + } } - DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread exiting...", __FUNCTION__, arg); - return NULL; + // START: main receive remote command thread loop + events.ResetEvents(RNBContext::event_read_thread_running); + events.SetEvents(RNBContext::event_read_thread_exiting); + } + DNBLogThreadedIf(LOG_RNB_REMOTE, "RNBRemote::%s (%p): thread exiting...", + __FUNCTION__, arg); + return NULL; } - // If we fail to get back a valid CPU type for the remote process, // make a best guess for the CPU type based on the currently running // debugserver binary -- the debugger may not handle the case of an // un-specified process CPU type correctly. -static cpu_type_t -best_guess_cpu_type () -{ -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - if (sizeof (char *) == 8) - { - return CPU_TYPE_ARM64; - } - else - { - return CPU_TYPE_ARM; - } -#elif defined (__i386__) || defined (__x86_64__) - if (sizeof (char*) == 8) - { - return CPU_TYPE_X86_64; - } - else - { - return CPU_TYPE_I386; - } +static cpu_type_t best_guess_cpu_type() { +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + if (sizeof(char *) == 8) { + return CPU_TYPE_ARM64; + } else { + return CPU_TYPE_ARM; + } +#elif defined(__i386__) || defined(__x86_64__) + if (sizeof(char *) == 8) { + return CPU_TYPE_X86_64; + } else { + return CPU_TYPE_I386; + } #endif - return 0; + return 0; } - /* Read the bytes in STR which are GDB Remote Protocol binary encoded bytes (8-bit bytes). - This encoding uses 0x7d ('}') as an escape character for + This encoding uses 0x7d ('}') as an escape character for 0x7d ('}'), 0x23 ('#'), 0x24 ('$'), 0x2a ('*'). LEN is the number of bytes to be processed. If a character is escaped, it is 2 characters for LEN. A LEN of -1 means decode-until-nul-byte (end of string). */ -std::vector<uint8_t> -decode_binary_data (const char *str, size_t len) -{ - std::vector<uint8_t> bytes; - if (len == 0) - { - return bytes; - } - if (len == (size_t)-1) - len = strlen (str); +std::vector<uint8_t> decode_binary_data(const char *str, size_t len) { + std::vector<uint8_t> bytes; + if (len == 0) { + return bytes; + } + if (len == (size_t)-1) + len = strlen(str); - while (len--) - { - unsigned char c = *str++; - if (c == 0x7d && len > 0) - { - len--; - c = *str++ ^ 0x20; - } - bytes.push_back (c); + while (len--) { + unsigned char c = *str++; + if (c == 0x7d && len > 0) { + len--; + c = *str++ ^ 0x20; } - return bytes; + bytes.push_back(c); + } + return bytes; } // Quote any meta characters in a std::string as per the binary // packet convention in the gdb-remote protocol. -static std::string -binary_encode_string (const std::string &s) -{ - std::string output; - const size_t s_size = s.size(); - const char *s_chars = s.c_str(); +static std::string binary_encode_string(const std::string &s) { + std::string output; + const size_t s_size = s.size(); + const char *s_chars = s.c_str(); - for (size_t i = 0; i < s_size; i++) - { - unsigned char ch = *(s_chars + i); - if (ch == '#' || ch == '$' || ch == '}' || ch == '*') - { - output.push_back ('}'); // 0x7d - output.push_back (ch ^ 0x20); - } - else - { - output.push_back (ch); - } + for (size_t i = 0; i < s_size; i++) { + unsigned char ch = *(s_chars + i); + if (ch == '#' || ch == '$' || ch == '}' || ch == '*') { + output.push_back('}'); // 0x7d + output.push_back(ch ^ 0x20); + } else { + output.push_back(ch); } - return output; + } + return output; } // If the value side of a key-value pair in JSON is a string, // and that string has a " character in it, the " character must // be escaped. -std::string -json_string_quote_metachars (const std::string &s) -{ - if (s.find('"') == std::string::npos) - return s; - - std::string output; - const size_t s_size = s.size(); - const char *s_chars = s.c_str(); - for (size_t i = 0; i < s_size; i++) - { - unsigned char ch = *(s_chars + i); - if (ch == '"') - { - output.push_back ('\\'); - } - output.push_back (ch); - } - return output; -} - -typedef struct register_map_entry -{ - uint32_t debugserver_regnum; // debugserver register number - uint32_t offset; // Offset in bytes into the register context data with no padding between register values - DNBRegisterInfo nub_info; // debugnub register info - std::vector<uint32_t> value_regnums; - std::vector<uint32_t> invalidate_regnums; +std::string json_string_quote_metachars(const std::string &s) { + if (s.find('"') == std::string::npos) + return s; + + std::string output; + const size_t s_size = s.size(); + const char *s_chars = s.c_str(); + for (size_t i = 0; i < s_size; i++) { + unsigned char ch = *(s_chars + i); + if (ch == '"') { + output.push_back('\\'); + } + output.push_back(ch); + } + return output; +} + +typedef struct register_map_entry { + uint32_t debugserver_regnum; // debugserver register number + uint32_t offset; // Offset in bytes into the register context data with no + // padding between register values + DNBRegisterInfo nub_info; // debugnub register info + std::vector<uint32_t> value_regnums; + std::vector<uint32_t> invalidate_regnums; } register_map_entry_t; - - // If the notion of registers differs from what is handed out by the // architecture, then flavors can be defined here. @@ -1292,148 +1381,130 @@ static std::vector<register_map_entry_t> g_dynamic_register_map; static register_map_entry_t *g_reg_entries = NULL; static size_t g_num_reg_entries = 0; -void -RNBRemote::Initialize() -{ - DNBInitialize(); -} - - -bool -RNBRemote::InitializeRegisters (bool force) -{ - pid_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return false; +void RNBRemote::Initialize() { DNBInitialize(); } - DNBLogThreadedIf (LOG_RNB_PROC, "RNBRemote::%s() getting native registers from DNB interface", __FUNCTION__); - // Discover the registers by querying the DNB interface and letting it - // state the registers that it would like to export. This allows the - // registers to be discovered using multiple qRegisterInfo calls to get - // all register information after the architecture for the process is - // determined. - if (force) - { - g_dynamic_register_map.clear(); - g_reg_entries = NULL; - g_num_reg_entries = 0; - } - - if (g_dynamic_register_map.empty()) - { - nub_size_t num_reg_sets = 0; - const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo (&num_reg_sets); - - assert (num_reg_sets > 0 && reg_sets != NULL); +bool RNBRemote::InitializeRegisters(bool force) { + pid_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return false; - uint32_t regnum = 0; - uint32_t reg_data_offset = 0; - typedef std::map<std::string, uint32_t> NameToRegNum; - NameToRegNum name_to_regnum; - for (nub_size_t set = 0; set < num_reg_sets; ++set) - { - if (reg_sets[set].registers == NULL) - continue; + DNBLogThreadedIf( + LOG_RNB_PROC, + "RNBRemote::%s() getting native registers from DNB interface", + __FUNCTION__); + // Discover the registers by querying the DNB interface and letting it + // state the registers that it would like to export. This allows the + // registers to be discovered using multiple qRegisterInfo calls to get + // all register information after the architecture for the process is + // determined. + if (force) { + g_dynamic_register_map.clear(); + g_reg_entries = NULL; + g_num_reg_entries = 0; + } + + if (g_dynamic_register_map.empty()) { + nub_size_t num_reg_sets = 0; + const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo(&num_reg_sets); + + assert(num_reg_sets > 0 && reg_sets != NULL); + + uint32_t regnum = 0; + uint32_t reg_data_offset = 0; + typedef std::map<std::string, uint32_t> NameToRegNum; + NameToRegNum name_to_regnum; + for (nub_size_t set = 0; set < num_reg_sets; ++set) { + if (reg_sets[set].registers == NULL) + continue; + + for (uint32_t reg = 0; reg < reg_sets[set].num_registers; ++reg) { + register_map_entry_t reg_entry = { + regnum++, // register number starts at zero and goes up with no gaps + reg_data_offset, // Offset into register context data, no gaps + // between registers + reg_sets[set].registers[reg], // DNBRegisterInfo + {}, + {}, + }; - for (uint32_t reg=0; reg < reg_sets[set].num_registers; ++reg) - { - register_map_entry_t reg_entry = { - regnum++, // register number starts at zero and goes up with no gaps - reg_data_offset, // Offset into register context data, no gaps between registers - reg_sets[set].registers[reg], // DNBRegisterInfo - {}, - {}, - }; + name_to_regnum[reg_entry.nub_info.name] = reg_entry.debugserver_regnum; - name_to_regnum[reg_entry.nub_info.name] = reg_entry.debugserver_regnum; + if (reg_entry.nub_info.value_regs == NULL) { + reg_data_offset += reg_entry.nub_info.size; + } - if (reg_entry.nub_info.value_regs == NULL) - { - reg_data_offset += reg_entry.nub_info.size; - } + g_dynamic_register_map.push_back(reg_entry); + } + } - g_dynamic_register_map.push_back (reg_entry); + // Now we must find any registers whose values are in other registers and + // fix up + // the offsets since we removed all gaps... + for (auto ®_entry : g_dynamic_register_map) { + if (reg_entry.nub_info.value_regs) { + uint32_t new_offset = UINT32_MAX; + for (size_t i = 0; reg_entry.nub_info.value_regs[i] != NULL; ++i) { + const char *name = reg_entry.nub_info.value_regs[i]; + auto pos = name_to_regnum.find(name); + if (pos != name_to_regnum.end()) { + regnum = pos->second; + reg_entry.value_regnums.push_back(regnum); + if (regnum < g_dynamic_register_map.size()) { + // The offset for value_regs registers is the offset within the + // register with the lowest offset + const uint32_t reg_offset = + g_dynamic_register_map[regnum].offset + + reg_entry.nub_info.offset; + if (new_offset > reg_offset) + new_offset = reg_offset; } + } } - - // Now we must find any registers whose values are in other registers and fix up - // the offsets since we removed all gaps... - for (auto ®_entry: g_dynamic_register_map) - { - if (reg_entry.nub_info.value_regs) - { - uint32_t new_offset = UINT32_MAX; - for (size_t i=0; reg_entry.nub_info.value_regs[i] != NULL; ++i) - { - const char *name = reg_entry.nub_info.value_regs[i]; - auto pos = name_to_regnum.find(name); - if (pos != name_to_regnum.end()) - { - regnum = pos->second; - reg_entry.value_regnums.push_back(regnum); - if (regnum < g_dynamic_register_map.size()) - { - // The offset for value_regs registers is the offset within the register with the lowest offset - const uint32_t reg_offset = g_dynamic_register_map[regnum].offset + reg_entry.nub_info.offset; - if (new_offset > reg_offset) - new_offset = reg_offset; - } - } - } - - if (new_offset != UINT32_MAX) - { - reg_entry.offset = new_offset; - } - else - { - DNBLogThreaded("no offset was calculated entry for register %s", reg_entry.nub_info.name); - reg_entry.offset = UINT32_MAX; - } - } - if (reg_entry.nub_info.update_regs) - { - for (size_t i=0; reg_entry.nub_info.update_regs[i] != NULL; ++i) - { - const char *name = reg_entry.nub_info.update_regs[i]; - auto pos = name_to_regnum.find(name); - if (pos != name_to_regnum.end()) - { - regnum = pos->second; - reg_entry.invalidate_regnums.push_back(regnum); - } - } - } + if (new_offset != UINT32_MAX) { + reg_entry.offset = new_offset; + } else { + DNBLogThreaded("no offset was calculated entry for register %s", + reg_entry.nub_info.name); + reg_entry.offset = UINT32_MAX; } - - -// for (auto ®_entry: g_dynamic_register_map) -// { -// DNBLogThreaded("%4i: size = %3u, pseudo = %i, name = %s", -// reg_entry.offset, -// reg_entry.nub_info.size, -// reg_entry.nub_info.value_regs != NULL, -// reg_entry.nub_info.name); -// } - - g_reg_entries = g_dynamic_register_map.data(); - g_num_reg_entries = g_dynamic_register_map.size(); + } + + if (reg_entry.nub_info.update_regs) { + for (size_t i = 0; reg_entry.nub_info.update_regs[i] != NULL; ++i) { + const char *name = reg_entry.nub_info.update_regs[i]; + auto pos = name_to_regnum.find(name); + if (pos != name_to_regnum.end()) { + regnum = pos->second; + reg_entry.invalidate_regnums.push_back(regnum); + } + } + } } - return true; + + // for (auto ®_entry: g_dynamic_register_map) + // { + // DNBLogThreaded("%4i: size = %3u, pseudo = %i, name = %s", + // reg_entry.offset, + // reg_entry.nub_info.size, + // reg_entry.nub_info.value_regs != NULL, + // reg_entry.nub_info.name); + // } + + g_reg_entries = g_dynamic_register_map.data(); + g_num_reg_entries = g_dynamic_register_map.size(); + } + return true; } /* The inferior has stopped executing; send a packet to gdb to let it know. */ -void -RNBRemote::NotifyThatProcessStopped (void) -{ - RNBRemote::HandlePacket_last_signal (NULL); - return; +void RNBRemote::NotifyThatProcessStopped(void) { + RNBRemote::HandlePacket_last_signal(NULL); + return; } - /* 'A arglen,argnum,arg,...' Update the inferior context CTX with the program name and arg list. @@ -1450,534 +1521,524 @@ RNBRemote::NotifyThatProcessStopped (void) Note that "argnum" and "arglen" are numbers in base 10. Again, that's not documented either way but I'm assuming it's so. */ -rnb_err_t -RNBRemote::HandlePacket_A (const char *p) -{ - if (p == NULL || *p == '\0') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Null packet for 'A' pkt"); +rnb_err_t RNBRemote::HandlePacket_A(const char *p) { + if (p == NULL || *p == '\0') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Null packet for 'A' pkt"); + } + p++; + if (*p == '\0' || !isdigit(*p)) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "arglen not specified on 'A' pkt"); + } + + /* I promise I don't modify it anywhere in this function. strtoul()'s + 2nd arg has to be non-const which makes it problematic to step + through the string easily. */ + char *buf = const_cast<char *>(p); + + RNBContext &ctx = Context(); + + while (*buf != '\0') { + unsigned long arglen, argnum; + std::string arg; + char *c; + + errno = 0; + arglen = strtoul(buf, &c, 10); + if (errno != 0 && arglen == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "arglen not a number on 'A' pkt"); } - p++; - if (*p == '\0' || !isdigit (*p)) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "arglen not specified on 'A' pkt"); + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "arglen not followed by comma on 'A' pkt"); } + buf = c + 1; - /* I promise I don't modify it anywhere in this function. strtoul()'s - 2nd arg has to be non-const which makes it problematic to step - through the string easily. */ - char *buf = const_cast<char *>(p); - - RNBContext& ctx = Context(); - - while (*buf != '\0') - { - unsigned long arglen, argnum; - std::string arg; - char *c; - - errno = 0; - arglen = strtoul (buf, &c, 10); - if (errno != 0 && arglen == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "arglen not a number on 'A' pkt"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "arglen not followed by comma on 'A' pkt"); - } - buf = c + 1; - - errno = 0; - argnum = strtoul (buf, &c, 10); - if (errno != 0 && argnum == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "argnum not a number on 'A' pkt"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "arglen not followed by comma on 'A' pkt"); - } - buf = c + 1; - - c = buf; - buf = buf + arglen; - while (c < buf && *c != '\0' && c + 1 < buf && *(c + 1) != '\0') - { - char smallbuf[3]; - smallbuf[0] = *c; - smallbuf[1] = *(c + 1); - smallbuf[2] = '\0'; - - errno = 0; - int ch = static_cast<int>(strtoul (smallbuf, NULL, 16)); - if (errno != 0 && ch == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'A' pkt"); - } - - arg.push_back(ch); - c += 2; - } + errno = 0; + argnum = strtoul(buf, &c, 10); + if (errno != 0 && argnum == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "argnum not a number on 'A' pkt"); + } + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "arglen not followed by comma on 'A' pkt"); + } + buf = c + 1; + + c = buf; + buf = buf + arglen; + while (c < buf && *c != '\0' && c + 1 < buf && *(c + 1) != '\0') { + char smallbuf[3]; + smallbuf[0] = *c; + smallbuf[1] = *(c + 1); + smallbuf[2] = '\0'; + + errno = 0; + int ch = static_cast<int>(strtoul(smallbuf, NULL, 16)); + if (errno != 0 && ch == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "non-hex char in arg on 'A' pkt"); + } - ctx.PushArgument (arg.c_str()); - if (*buf == ',') - buf++; + arg.push_back(ch); + c += 2; } - SendPacket ("OK"); - return rnb_success; + ctx.PushArgument(arg.c_str()); + if (*buf == ',') + buf++; + } + SendPacket("OK"); + + return rnb_success; } /* 'H c t' Set the thread for subsequent actions; 'c' for step/continue ops, 'g' for other ops. -1 means all threads, 0 means any thread. */ -rnb_err_t -RNBRemote::HandlePacket_H (const char *p) -{ - p++; // skip 'H' - if (*p != 'c' && *p != 'g') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Missing 'c' or 'g' type in H packet"); - } +rnb_err_t RNBRemote::HandlePacket_H(const char *p) { + p++; // skip 'H' + if (*p != 'c' && *p != 'g') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Missing 'c' or 'g' type in H packet"); + } - if (!m_ctx.HasValidProcessID()) - { - // We allow gdb to connect to a server that hasn't started running - // the target yet. gdb still wants to ask questions about it and - // freaks out if it gets an error. So just return OK here. - } + if (!m_ctx.HasValidProcessID()) { + // We allow gdb to connect to a server that hasn't started running + // the target yet. gdb still wants to ask questions about it and + // freaks out if it gets an error. So just return OK here. + } - errno = 0; - nub_thread_t tid = strtoul (p + 1, NULL, 16); - if (errno != 0 && tid == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid thread number in H packet"); - } - if (*p == 'c') - SetContinueThread (tid); - if (*p == 'g') - SetCurrentThread (tid); + errno = 0; + nub_thread_t tid = strtoul(p + 1, NULL, 16); + if (errno != 0 && tid == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid thread number in H packet"); + } + if (*p == 'c') + SetContinueThread(tid); + if (*p == 'g') + SetCurrentThread(tid); - return SendPacket ("OK"); + return SendPacket("OK"); } +rnb_err_t RNBRemote::HandlePacket_qLaunchSuccess(const char *p) { + if (m_ctx.HasValidProcessID() || m_ctx.LaunchStatus().Error() == 0) + return SendPacket("OK"); + std::ostringstream ret_str; + std::string status_str; + ret_str << "E" << m_ctx.LaunchStatusAsString(status_str); -rnb_err_t -RNBRemote::HandlePacket_qLaunchSuccess (const char *p) -{ - if (m_ctx.HasValidProcessID() || m_ctx.LaunchStatus().Error() == 0) - return SendPacket("OK"); - std::ostringstream ret_str; - std::string status_str; - ret_str << "E" << m_ctx.LaunchStatusAsString(status_str); - - return SendPacket (ret_str.str()); + return SendPacket(ret_str.str()); } -rnb_err_t -RNBRemote::HandlePacket_qShlibInfoAddr (const char *p) -{ - if (m_ctx.HasValidProcessID()) - { - nub_addr_t shlib_info_addr = DNBProcessGetSharedLibraryInfoAddress(m_ctx.ProcessID()); - if (shlib_info_addr != INVALID_NUB_ADDRESS) - { - std::ostringstream ostrm; - ostrm << RAW_HEXBASE << shlib_info_addr; - return SendPacket (ostrm.str ()); - } +rnb_err_t RNBRemote::HandlePacket_qShlibInfoAddr(const char *p) { + if (m_ctx.HasValidProcessID()) { + nub_addr_t shlib_info_addr = + DNBProcessGetSharedLibraryInfoAddress(m_ctx.ProcessID()); + if (shlib_info_addr != INVALID_NUB_ADDRESS) { + std::ostringstream ostrm; + ostrm << RAW_HEXBASE << shlib_info_addr; + return SendPacket(ostrm.str()); } - return SendPacket ("E44"); + } + return SendPacket("E44"); } -rnb_err_t -RNBRemote::HandlePacket_qStepPacketSupported (const char *p) -{ - // Normally the "s" packet is mandatory, yet in gdb when using ARM, they - // get around the need for this packet by implementing software single - // stepping from gdb. Current versions of debugserver do support the "s" - // packet, yet some older versions do not. We need a way to tell if this - // packet is supported so we can disable software single stepping in gdb - // for remote targets (so the "s" packet will get used). - return SendPacket("OK"); +rnb_err_t RNBRemote::HandlePacket_qStepPacketSupported(const char *p) { + // Normally the "s" packet is mandatory, yet in gdb when using ARM, they + // get around the need for this packet by implementing software single + // stepping from gdb. Current versions of debugserver do support the "s" + // packet, yet some older versions do not. We need a way to tell if this + // packet is supported so we can disable software single stepping in gdb + // for remote targets (so the "s" packet will get used). + return SendPacket("OK"); } -rnb_err_t -RNBRemote::HandlePacket_qSyncThreadStateSupported (const char *p) -{ - // We support attachOrWait meaning attach if the process exists, otherwise wait to attach. - return SendPacket("OK"); +rnb_err_t RNBRemote::HandlePacket_qSyncThreadStateSupported(const char *p) { + // We support attachOrWait meaning attach if the process exists, otherwise + // wait to attach. + return SendPacket("OK"); } -rnb_err_t -RNBRemote::HandlePacket_qVAttachOrWaitSupported (const char *p) -{ - // We support attachOrWait meaning attach if the process exists, otherwise wait to attach. - return SendPacket("OK"); +rnb_err_t RNBRemote::HandlePacket_qVAttachOrWaitSupported(const char *p) { + // We support attachOrWait meaning attach if the process exists, otherwise + // wait to attach. + return SendPacket("OK"); } -rnb_err_t -RNBRemote::HandlePacket_qThreadStopInfo (const char *p) -{ - p += strlen ("qThreadStopInfo"); - nub_thread_t tid = strtoul(p, 0, 16); - return SendStopReplyPacketForThread (tid); +rnb_err_t RNBRemote::HandlePacket_qThreadStopInfo(const char *p) { + p += strlen("qThreadStopInfo"); + nub_thread_t tid = strtoul(p, 0, 16); + return SendStopReplyPacketForThread(tid); } -rnb_err_t -RNBRemote::HandlePacket_qThreadInfo (const char *p) -{ - // We allow gdb to connect to a server that hasn't started running - // the target yet. gdb still wants to ask questions about it and - // freaks out if it gets an error. So just return OK here. - nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("OK"); - - // Only "qfThreadInfo" and "qsThreadInfo" get into this function so - // we only need to check the second byte to tell which is which - if (p[1] == 'f') - { - nub_size_t numthreads = DNBProcessGetNumThreads (pid); - std::ostringstream ostrm; - ostrm << "m"; - bool first = true; - for (nub_size_t i = 0; i < numthreads; ++i) - { - if (first) - first = false; - else - ostrm << ","; - nub_thread_t th = DNBProcessGetThreadAtIndex (pid, i); - ostrm << std::hex << th; - } - return SendPacket (ostrm.str ()); - } - else - { - return SendPacket ("l"); - } -} - -rnb_err_t -RNBRemote::HandlePacket_qThreadExtraInfo (const char *p) -{ - // We allow gdb to connect to a server that hasn't started running - // the target yet. gdb still wants to ask questions about it and - // freaks out if it gets an error. So just return OK here. - nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("OK"); - - /* This is supposed to return a string like 'Runnable' or - 'Blocked on Mutex'. - The returned string is formatted like the "A" packet - a - sequence of letters encoded in as 2-hex-chars-per-letter. */ - p += strlen ("qThreadExtraInfo"); - if (*p++ != ',') - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Illformed qThreadExtraInfo packet"); - errno = 0; - nub_thread_t tid = strtoul (p, NULL, 16); - if (errno != 0 && tid == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid thread number in qThreadExtraInfo packet"); - } +rnb_err_t RNBRemote::HandlePacket_qThreadInfo(const char *p) { + // We allow gdb to connect to a server that hasn't started running + // the target yet. gdb still wants to ask questions about it and + // freaks out if it gets an error. So just return OK here. + nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("OK"); - const char * threadInfo = DNBThreadGetInfo(pid, tid); - if (threadInfo != NULL && threadInfo[0]) - { - return SendHexEncodedBytePacket(NULL, threadInfo, strlen(threadInfo), NULL); - } - else - { - // "OK" == 4f6b - // Return "OK" as a ASCII hex byte stream if things go wrong - return SendPacket ("4f6b"); - } + // Only "qfThreadInfo" and "qsThreadInfo" get into this function so + // we only need to check the second byte to tell which is which + if (p[1] == 'f') { + nub_size_t numthreads = DNBProcessGetNumThreads(pid); + std::ostringstream ostrm; + ostrm << "m"; + bool first = true; + for (nub_size_t i = 0; i < numthreads; ++i) { + if (first) + first = false; + else + ostrm << ","; + nub_thread_t th = DNBProcessGetThreadAtIndex(pid, i); + ostrm << std::hex << th; + } + return SendPacket(ostrm.str()); + } else { + return SendPacket("l"); + } +} + +rnb_err_t RNBRemote::HandlePacket_qThreadExtraInfo(const char *p) { + // We allow gdb to connect to a server that hasn't started running + // the target yet. gdb still wants to ask questions about it and + // freaks out if it gets an error. So just return OK here. + nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("OK"); - return SendPacket (""); + /* This is supposed to return a string like 'Runnable' or + 'Blocked on Mutex'. + The returned string is formatted like the "A" packet - a + sequence of letters encoded in as 2-hex-chars-per-letter. */ + p += strlen("qThreadExtraInfo"); + if (*p++ != ',') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Illformed qThreadExtraInfo packet"); + errno = 0; + nub_thread_t tid = strtoul(p, NULL, 16); + if (errno != 0 && tid == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "Invalid thread number in qThreadExtraInfo packet"); + } + + const char *threadInfo = DNBThreadGetInfo(pid, tid); + if (threadInfo != NULL && threadInfo[0]) { + return SendHexEncodedBytePacket(NULL, threadInfo, strlen(threadInfo), NULL); + } else { + // "OK" == 4f6b + // Return "OK" as a ASCII hex byte stream if things go wrong + return SendPacket("4f6b"); + } + + return SendPacket(""); } - const char *k_space_delimiters = " \t"; -static void -skip_spaces (std::string &line) -{ - if (!line.empty()) - { - size_t space_pos = line.find_first_not_of (k_space_delimiters); - if (space_pos > 0) - line.erase(0, space_pos); - } -} - -static std::string -get_identifier (std::string &line) -{ - std::string word; - skip_spaces (line); - const size_t line_size = line.size(); - size_t end_pos; - for (end_pos = 0; end_pos < line_size; ++end_pos) - { - if (end_pos == 0) - { - if (isalpha(line[end_pos]) || line[end_pos] == '_') - continue; +static void skip_spaces(std::string &line) { + if (!line.empty()) { + size_t space_pos = line.find_first_not_of(k_space_delimiters); + if (space_pos > 0) + line.erase(0, space_pos); + } +} + +static std::string get_identifier(std::string &line) { + std::string word; + skip_spaces(line); + const size_t line_size = line.size(); + size_t end_pos; + for (end_pos = 0; end_pos < line_size; ++end_pos) { + if (end_pos == 0) { + if (isalpha(line[end_pos]) || line[end_pos] == '_') + continue; + } else if (isalnum(line[end_pos]) || line[end_pos] == '_') + continue; + break; + } + word.assign(line, 0, end_pos); + line.erase(0, end_pos); + return word; +} + +static std::string get_operator(std::string &line) { + std::string op; + skip_spaces(line); + if (!line.empty()) { + if (line[0] == '=') { + op = '='; + line.erase(0, 1); + } + } + return op; +} + +static std::string get_value(std::string &line) { + std::string value; + skip_spaces(line); + if (!line.empty()) { + value.swap(line); + } + return value; +} + +extern void FileLogCallback(void *baton, uint32_t flags, const char *format, + va_list args); +extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, + va_list args); + +rnb_err_t RNBRemote::HandlePacket_qRcmd(const char *p) { + const char *c = p + strlen("qRcmd,"); + std::string line; + while (c[0] && c[1]) { + char smallbuf[3] = {c[0], c[1], '\0'}; + errno = 0; + int ch = static_cast<int>(strtoul(smallbuf, NULL, 16)); + if (errno != 0 && ch == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "non-hex char in payload of qRcmd packet"); + line.push_back(ch); + c += 2; + } + if (*c == '\0') { + std::string command = get_identifier(line); + if (command.compare("set") == 0) { + std::string variable = get_identifier(line); + std::string op = get_operator(line); + std::string value = get_value(line); + if (variable.compare("logfile") == 0) { + FILE *log_file = fopen(value.c_str(), "w"); + if (log_file) { + DNBLogSetLogCallback(FileLogCallback, log_file); + return SendPacket("OK"); } - else if (isalnum(line[end_pos]) || line[end_pos] == '_') - continue; - break; - } - word.assign (line, 0, end_pos); - line.erase(0, end_pos); - return word; -} - -static std::string -get_operator (std::string &line) -{ - std::string op; - skip_spaces (line); - if (!line.empty()) - { - if (line[0] == '=') - { - op = '='; - line.erase(0,1); + return SendPacket("E71"); + } else if (variable.compare("logmask") == 0) { + char *end; + errno = 0; + uint32_t logmask = + static_cast<uint32_t>(strtoul(value.c_str(), &end, 0)); + if (errno == 0 && end && *end == '\0') { + DNBLogSetLogMask(logmask); + if (!DNBLogGetLogCallback()) + DNBLogSetLogCallback(ASLLogCallback, NULL); + return SendPacket("OK"); } - } - return op; -} - -static std::string -get_value (std::string &line) -{ - std::string value; - skip_spaces (line); - if (!line.empty()) - { - value.swap(line); - } - return value; -} - -extern void FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args); -extern void ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args); - -rnb_err_t -RNBRemote::HandlePacket_qRcmd (const char *p) -{ - const char *c = p + strlen("qRcmd,"); - std::string line; - while (c[0] && c[1]) - { - char smallbuf[3] = { c[0], c[1], '\0' }; errno = 0; - int ch = static_cast<int>(strtoul (smallbuf, NULL, 16)); - if (errno != 0 && ch == 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in payload of qRcmd packet"); - line.push_back(ch); - c += 2; - } - if (*c == '\0') - { - std::string command = get_identifier(line); - if (command.compare("set") == 0) - { - std::string variable = get_identifier (line); - std::string op = get_operator (line); - std::string value = get_value (line); - if (variable.compare("logfile") == 0) - { - FILE *log_file = fopen(value.c_str(), "w"); - if (log_file) - { - DNBLogSetLogCallback(FileLogCallback, log_file); - return SendPacket ("OK"); - } - return SendPacket ("E71"); - } - else if (variable.compare("logmask") == 0) - { - char *end; - errno = 0; - uint32_t logmask = static_cast<uint32_t>(strtoul (value.c_str(), &end, 0)); - if (errno == 0 && end && *end == '\0') - { - DNBLogSetLogMask (logmask); - if (!DNBLogGetLogCallback()) - DNBLogSetLogCallback(ASLLogCallback, NULL); - return SendPacket ("OK"); - } - errno = 0; - logmask = static_cast<uint32_t>(strtoul (value.c_str(), &end, 16)); - if (errno == 0 && end && *end == '\0') - { - DNBLogSetLogMask (logmask); - return SendPacket ("OK"); - } - return SendPacket ("E72"); - } - return SendPacket ("E70"); + logmask = static_cast<uint32_t>(strtoul(value.c_str(), &end, 16)); + if (errno == 0 && end && *end == '\0') { + DNBLogSetLogMask(logmask); + return SendPacket("OK"); } - return SendPacket ("E69"); - } - return SendPacket ("E73"); -} - -rnb_err_t -RNBRemote::HandlePacket_qC (const char *p) -{ - nub_thread_t tid; - std::ostringstream rep; - // If we haven't run the process yet, we tell the debugger the - // pid is 0. That way it can know to tell use to run later on. - if (!m_ctx.HasValidProcessID()) - tid = 0; - else - { - // Grab the current thread. - tid = DNBProcessGetCurrentThread (m_ctx.ProcessID()); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - SetCurrentThread (tid); - } - rep << "QC" << std::hex << tid; - return SendPacket (rep.str()); -} - -rnb_err_t -RNBRemote::HandlePacket_qEcho (const char *p) -{ - // Just send the exact same packet back that we received to - // synchronize the response packets after a previous packet - // timed out. This allows the debugger to get back on track - // with responses after a packet timeout. - return SendPacket (p); -} - -rnb_err_t -RNBRemote::HandlePacket_qGetPid (const char *p) -{ - nub_process_t pid; - std::ostringstream rep; - // If we haven't run the process yet, we tell the debugger the - // pid is 0. That way it can know to tell use to run later on. - if (m_ctx.HasValidProcessID()) - pid = m_ctx.ProcessID(); - else - pid = 0; - rep << std::hex << pid; - return SendPacket (rep.str()); + return SendPacket("E72"); + } + return SendPacket("E70"); + } + return SendPacket("E69"); + } + return SendPacket("E73"); +} + +rnb_err_t RNBRemote::HandlePacket_qC(const char *p) { + nub_thread_t tid; + std::ostringstream rep; + // If we haven't run the process yet, we tell the debugger the + // pid is 0. That way it can know to tell use to run later on. + if (!m_ctx.HasValidProcessID()) + tid = 0; + else { + // Grab the current thread. + tid = DNBProcessGetCurrentThread(m_ctx.ProcessID()); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThread(tid); + } + rep << "QC" << std::hex << tid; + return SendPacket(rep.str()); +} + +rnb_err_t RNBRemote::HandlePacket_qEcho(const char *p) { + // Just send the exact same packet back that we received to + // synchronize the response packets after a previous packet + // timed out. This allows the debugger to get back on track + // with responses after a packet timeout. + return SendPacket(p); +} + +rnb_err_t RNBRemote::HandlePacket_qGetPid(const char *p) { + nub_process_t pid; + std::ostringstream rep; + // If we haven't run the process yet, we tell the debugger the + // pid is 0. That way it can know to tell use to run later on. + if (m_ctx.HasValidProcessID()) + pid = m_ctx.ProcessID(); + else + pid = 0; + rep << std::hex << pid; + return SendPacket(rep.str()); } -rnb_err_t -RNBRemote::HandlePacket_qRegisterInfo (const char *p) -{ - if (g_num_reg_entries == 0) - InitializeRegisters (); - - p += strlen ("qRegisterInfo"); - - nub_size_t num_reg_sets = 0; - const DNBRegisterSetInfo *reg_set_info = DNBGetRegisterSetInfo (&num_reg_sets); - uint32_t reg_num = static_cast<uint32_t>(strtoul(p, 0, 16)); - - if (reg_num < g_num_reg_entries) - { - const register_map_entry_t *reg_entry = &g_reg_entries[reg_num]; - std::ostringstream ostrm; - if (reg_entry->nub_info.name) - ostrm << "name:" << reg_entry->nub_info.name << ';'; - if (reg_entry->nub_info.alt) - ostrm << "alt-name:" << reg_entry->nub_info.alt << ';'; +rnb_err_t RNBRemote::HandlePacket_qRegisterInfo(const char *p) { + if (g_num_reg_entries == 0) + InitializeRegisters(); - ostrm << "bitsize:" << std::dec << reg_entry->nub_info.size * 8 << ';'; - ostrm << "offset:" << std::dec << reg_entry->offset << ';'; + p += strlen("qRegisterInfo"); - switch (reg_entry->nub_info.type) - { - case Uint: ostrm << "encoding:uint;"; break; - case Sint: ostrm << "encoding:sint;"; break; - case IEEE754: ostrm << "encoding:ieee754;"; break; - case Vector: ostrm << "encoding:vector;"; break; - } + nub_size_t num_reg_sets = 0; + const DNBRegisterSetInfo *reg_set_info = DNBGetRegisterSetInfo(&num_reg_sets); + uint32_t reg_num = static_cast<uint32_t>(strtoul(p, 0, 16)); - switch (reg_entry->nub_info.format) - { - case Binary: ostrm << "format:binary;"; break; - case Decimal: ostrm << "format:decimal;"; break; - case Hex: ostrm << "format:hex;"; break; - case Float: ostrm << "format:float;"; break; - case VectorOfSInt8: ostrm << "format:vector-sint8;"; break; - case VectorOfUInt8: ostrm << "format:vector-uint8;"; break; - case VectorOfSInt16: ostrm << "format:vector-sint16;"; break; - case VectorOfUInt16: ostrm << "format:vector-uint16;"; break; - case VectorOfSInt32: ostrm << "format:vector-sint32;"; break; - case VectorOfUInt32: ostrm << "format:vector-uint32;"; break; - case VectorOfFloat32: ostrm << "format:vector-float32;"; break; - case VectorOfUInt128: ostrm << "format:vector-uint128;"; break; - }; - - if (reg_set_info && reg_entry->nub_info.set < num_reg_sets) - ostrm << "set:" << reg_set_info[reg_entry->nub_info.set].name << ';'; - - if (reg_entry->nub_info.reg_ehframe != INVALID_NUB_REGNUM) - ostrm << "ehframe:" << std::dec << reg_entry->nub_info.reg_ehframe << ';'; - - if (reg_entry->nub_info.reg_dwarf != INVALID_NUB_REGNUM) - ostrm << "dwarf:" << std::dec << reg_entry->nub_info.reg_dwarf << ';'; + if (reg_num < g_num_reg_entries) { + const register_map_entry_t *reg_entry = &g_reg_entries[reg_num]; + std::ostringstream ostrm; + if (reg_entry->nub_info.name) + ostrm << "name:" << reg_entry->nub_info.name << ';'; + if (reg_entry->nub_info.alt) + ostrm << "alt-name:" << reg_entry->nub_info.alt << ';'; + + ostrm << "bitsize:" << std::dec << reg_entry->nub_info.size * 8 << ';'; + ostrm << "offset:" << std::dec << reg_entry->offset << ';'; + + switch (reg_entry->nub_info.type) { + case Uint: + ostrm << "encoding:uint;"; + break; + case Sint: + ostrm << "encoding:sint;"; + break; + case IEEE754: + ostrm << "encoding:ieee754;"; + break; + case Vector: + ostrm << "encoding:vector;"; + break; + } + + switch (reg_entry->nub_info.format) { + case Binary: + ostrm << "format:binary;"; + break; + case Decimal: + ostrm << "format:decimal;"; + break; + case Hex: + ostrm << "format:hex;"; + break; + case Float: + ostrm << "format:float;"; + break; + case VectorOfSInt8: + ostrm << "format:vector-sint8;"; + break; + case VectorOfUInt8: + ostrm << "format:vector-uint8;"; + break; + case VectorOfSInt16: + ostrm << "format:vector-sint16;"; + break; + case VectorOfUInt16: + ostrm << "format:vector-uint16;"; + break; + case VectorOfSInt32: + ostrm << "format:vector-sint32;"; + break; + case VectorOfUInt32: + ostrm << "format:vector-uint32;"; + break; + case VectorOfFloat32: + ostrm << "format:vector-float32;"; + break; + case VectorOfUInt128: + ostrm << "format:vector-uint128;"; + break; + }; - switch (reg_entry->nub_info.reg_generic) - { - case GENERIC_REGNUM_FP: ostrm << "generic:fp;"; break; - case GENERIC_REGNUM_PC: ostrm << "generic:pc;"; break; - case GENERIC_REGNUM_SP: ostrm << "generic:sp;"; break; - case GENERIC_REGNUM_RA: ostrm << "generic:ra;"; break; - case GENERIC_REGNUM_FLAGS: ostrm << "generic:flags;"; break; - case GENERIC_REGNUM_ARG1: ostrm << "generic:arg1;"; break; - case GENERIC_REGNUM_ARG2: ostrm << "generic:arg2;"; break; - case GENERIC_REGNUM_ARG3: ostrm << "generic:arg3;"; break; - case GENERIC_REGNUM_ARG4: ostrm << "generic:arg4;"; break; - case GENERIC_REGNUM_ARG5: ostrm << "generic:arg5;"; break; - case GENERIC_REGNUM_ARG6: ostrm << "generic:arg6;"; break; - case GENERIC_REGNUM_ARG7: ostrm << "generic:arg7;"; break; - case GENERIC_REGNUM_ARG8: ostrm << "generic:arg8;"; break; - default: break; - } - - if (!reg_entry->value_regnums.empty()) - { - ostrm << "container-regs:"; - for (size_t i=0, n=reg_entry->value_regnums.size(); i < n; ++i) - { - if (i > 0) - ostrm << ','; - ostrm << RAW_HEXBASE << reg_entry->value_regnums[i]; - } - ostrm << ';'; - } + if (reg_set_info && reg_entry->nub_info.set < num_reg_sets) + ostrm << "set:" << reg_set_info[reg_entry->nub_info.set].name << ';'; + + if (reg_entry->nub_info.reg_ehframe != INVALID_NUB_REGNUM) + ostrm << "ehframe:" << std::dec << reg_entry->nub_info.reg_ehframe << ';'; + + if (reg_entry->nub_info.reg_dwarf != INVALID_NUB_REGNUM) + ostrm << "dwarf:" << std::dec << reg_entry->nub_info.reg_dwarf << ';'; + + switch (reg_entry->nub_info.reg_generic) { + case GENERIC_REGNUM_FP: + ostrm << "generic:fp;"; + break; + case GENERIC_REGNUM_PC: + ostrm << "generic:pc;"; + break; + case GENERIC_REGNUM_SP: + ostrm << "generic:sp;"; + break; + case GENERIC_REGNUM_RA: + ostrm << "generic:ra;"; + break; + case GENERIC_REGNUM_FLAGS: + ostrm << "generic:flags;"; + break; + case GENERIC_REGNUM_ARG1: + ostrm << "generic:arg1;"; + break; + case GENERIC_REGNUM_ARG2: + ostrm << "generic:arg2;"; + break; + case GENERIC_REGNUM_ARG3: + ostrm << "generic:arg3;"; + break; + case GENERIC_REGNUM_ARG4: + ostrm << "generic:arg4;"; + break; + case GENERIC_REGNUM_ARG5: + ostrm << "generic:arg5;"; + break; + case GENERIC_REGNUM_ARG6: + ostrm << "generic:arg6;"; + break; + case GENERIC_REGNUM_ARG7: + ostrm << "generic:arg7;"; + break; + case GENERIC_REGNUM_ARG8: + ostrm << "generic:arg8;"; + break; + default: + break; + } - if (!reg_entry->invalidate_regnums.empty()) - { - ostrm << "invalidate-regs:"; - for (size_t i=0, n=reg_entry->invalidate_regnums.size(); i < n; ++i) - { - if (i > 0) - ostrm << ','; - ostrm << RAW_HEXBASE << reg_entry->invalidate_regnums[i]; - } - ostrm << ';'; - } + if (!reg_entry->value_regnums.empty()) { + ostrm << "container-regs:"; + for (size_t i = 0, n = reg_entry->value_regnums.size(); i < n; ++i) { + if (i > 0) + ostrm << ','; + ostrm << RAW_HEXBASE << reg_entry->value_regnums[i]; + } + ostrm << ';'; + } - return SendPacket (ostrm.str ()); + if (!reg_entry->invalidate_regnums.empty()) { + ostrm << "invalidate-regs:"; + for (size_t i = 0, n = reg_entry->invalidate_regnums.size(); i < n; ++i) { + if (i > 0) + ostrm << ','; + ostrm << RAW_HEXBASE << reg_entry->invalidate_regnums[i]; + } + ostrm << ';'; } - return SendPacket ("E45"); -} + return SendPacket(ostrm.str()); + } + return SendPacket("E45"); +} /* This expects a packet formatted like @@ -1989,222 +2050,169 @@ RNBRemote::HandlePacket_qRegisterInfo (const char *p) QSetLogging:bitmask=LOG_ALL;mode=asl; */ -rnb_err_t -set_logging (const char *p) -{ - int bitmask = 0; - while (p && *p != '\0') - { - if (strncmp (p, "bitmask=", sizeof ("bitmask=") - 1) == 0) - { - p += sizeof ("bitmask=") - 1; - while (p && *p != '\0' && *p != ';') - { - if (*p == '|') - p++; - -// to regenerate the LOG_ entries (not including the LOG_RNB entries) -// $ for logname in `grep '^#define LOG_' DNBDefs.h | egrep -v 'LOG_HI|LOG_LO' | awk '{print $2}'` -// do -// echo " else if (strncmp (p, \"$logname\", sizeof (\"$logname\") - 1) == 0)" -// echo " {" -// echo " p += sizeof (\"$logname\") - 1;" -// echo " bitmask |= $logname;" -// echo " }" -// done - if (strncmp (p, "LOG_VERBOSE", sizeof ("LOG_VERBOSE") - 1) == 0) - { - p += sizeof ("LOG_VERBOSE") - 1; - bitmask |= LOG_VERBOSE; - } - else if (strncmp (p, "LOG_PROCESS", sizeof ("LOG_PROCESS") - 1) == 0) - { - p += sizeof ("LOG_PROCESS") - 1; - bitmask |= LOG_PROCESS; - } - else if (strncmp (p, "LOG_THREAD", sizeof ("LOG_THREAD") - 1) == 0) - { - p += sizeof ("LOG_THREAD") - 1; - bitmask |= LOG_THREAD; - } - else if (strncmp (p, "LOG_EXCEPTIONS", sizeof ("LOG_EXCEPTIONS") - 1) == 0) - { - p += sizeof ("LOG_EXCEPTIONS") - 1; - bitmask |= LOG_EXCEPTIONS; - } - else if (strncmp (p, "LOG_SHLIB", sizeof ("LOG_SHLIB") - 1) == 0) - { - p += sizeof ("LOG_SHLIB") - 1; - bitmask |= LOG_SHLIB; - } - else if (strncmp (p, "LOG_MEMORY", sizeof ("LOG_MEMORY") - 1) == 0) - { - p += sizeof ("LOG_MEMORY") - 1; - bitmask |= LOG_MEMORY; - } - else if (strncmp (p, "LOG_MEMORY_DATA_SHORT", sizeof ("LOG_MEMORY_DATA_SHORT") - 1) == 0) - { - p += sizeof ("LOG_MEMORY_DATA_SHORT") - 1; - bitmask |= LOG_MEMORY_DATA_SHORT; - } - else if (strncmp (p, "LOG_MEMORY_DATA_LONG", sizeof ("LOG_MEMORY_DATA_LONG") - 1) == 0) - { - p += sizeof ("LOG_MEMORY_DATA_LONG") - 1; - bitmask |= LOG_MEMORY_DATA_LONG; - } - else if (strncmp (p, "LOG_MEMORY_PROTECTIONS", sizeof ("LOG_MEMORY_PROTECTIONS") - 1) == 0) - { - p += sizeof ("LOG_MEMORY_PROTECTIONS") - 1; - bitmask |= LOG_MEMORY_PROTECTIONS; - } - else if (strncmp (p, "LOG_BREAKPOINTS", sizeof ("LOG_BREAKPOINTS") - 1) == 0) - { - p += sizeof ("LOG_BREAKPOINTS") - 1; - bitmask |= LOG_BREAKPOINTS; - } - else if (strncmp (p, "LOG_EVENTS", sizeof ("LOG_EVENTS") - 1) == 0) - { - p += sizeof ("LOG_EVENTS") - 1; - bitmask |= LOG_EVENTS; - } - else if (strncmp (p, "LOG_WATCHPOINTS", sizeof ("LOG_WATCHPOINTS") - 1) == 0) - { - p += sizeof ("LOG_WATCHPOINTS") - 1; - bitmask |= LOG_WATCHPOINTS; - } - else if (strncmp (p, "LOG_STEP", sizeof ("LOG_STEP") - 1) == 0) - { - p += sizeof ("LOG_STEP") - 1; - bitmask |= LOG_STEP; - } - else if (strncmp (p, "LOG_TASK", sizeof ("LOG_TASK") - 1) == 0) - { - p += sizeof ("LOG_TASK") - 1; - bitmask |= LOG_TASK; - } - else if (strncmp (p, "LOG_ALL", sizeof ("LOG_ALL") - 1) == 0) - { - p += sizeof ("LOG_ALL") - 1; - bitmask |= LOG_ALL; - } - else if (strncmp (p, "LOG_DEFAULT", sizeof ("LOG_DEFAULT") - 1) == 0) - { - p += sizeof ("LOG_DEFAULT") - 1; - bitmask |= LOG_DEFAULT; - } -// end of auto-generated entries - - else if (strncmp (p, "LOG_NONE", sizeof ("LOG_NONE") - 1) == 0) - { - p += sizeof ("LOG_NONE") - 1; - bitmask = 0; - } - else if (strncmp (p, "LOG_RNB_MINIMAL", sizeof ("LOG_RNB_MINIMAL") - 1) == 0) - { - p += sizeof ("LOG_RNB_MINIMAL") - 1; - bitmask |= LOG_RNB_MINIMAL; - } - else if (strncmp (p, "LOG_RNB_MEDIUM", sizeof ("LOG_RNB_MEDIUM") - 1) == 0) - { - p += sizeof ("LOG_RNB_MEDIUM") - 1; - bitmask |= LOG_RNB_MEDIUM; - } - else if (strncmp (p, "LOG_RNB_MAX", sizeof ("LOG_RNB_MAX") - 1) == 0) - { - p += sizeof ("LOG_RNB_MAX") - 1; - bitmask |= LOG_RNB_MAX; - } - else if (strncmp (p, "LOG_RNB_COMM", sizeof ("LOG_RNB_COMM") - 1) == 0) - { - p += sizeof ("LOG_RNB_COMM") - 1; - bitmask |= LOG_RNB_COMM; - } - else if (strncmp (p, "LOG_RNB_REMOTE", sizeof ("LOG_RNB_REMOTE") - 1) == 0) - { - p += sizeof ("LOG_RNB_REMOTE") - 1; - bitmask |= LOG_RNB_REMOTE; - } - else if (strncmp (p, "LOG_RNB_EVENTS", sizeof ("LOG_RNB_EVENTS") - 1) == 0) - { - p += sizeof ("LOG_RNB_EVENTS") - 1; - bitmask |= LOG_RNB_EVENTS; - } - else if (strncmp (p, "LOG_RNB_PROC", sizeof ("LOG_RNB_PROC") - 1) == 0) - { - p += sizeof ("LOG_RNB_PROC") - 1; - bitmask |= LOG_RNB_PROC; - } - else if (strncmp (p, "LOG_RNB_PACKETS", sizeof ("LOG_RNB_PACKETS") - 1) == 0) - { - p += sizeof ("LOG_RNB_PACKETS") - 1; - bitmask |= LOG_RNB_PACKETS; - } - else if (strncmp (p, "LOG_RNB_ALL", sizeof ("LOG_RNB_ALL") - 1) == 0) - { - p += sizeof ("LOG_RNB_ALL") - 1; - bitmask |= LOG_RNB_ALL; - } - else if (strncmp (p, "LOG_RNB_DEFAULT", sizeof ("LOG_RNB_DEFAULT") - 1) == 0) - { - p += sizeof ("LOG_RNB_DEFAULT") - 1; - bitmask |= LOG_RNB_DEFAULT; - } - else if (strncmp (p, "LOG_DARWIN_LOG", sizeof ("LOG_DARWIN_LOG") - 1) == 0) - { - p += sizeof ("LOG_DARWIN_LOG") - 1; - bitmask |= LOG_DARWIN_LOG; - } - else if (strncmp (p, "LOG_RNB_NONE", sizeof ("LOG_RNB_NONE") - 1) == 0) - { - p += sizeof ("LOG_RNB_NONE") - 1; - bitmask = 0; - } - else - { - /* Unrecognized logging bit; ignore it. */ - const char *c = strchr (p, '|'); - if (c) - { - p = c; - } - else - { - c = strchr (p, ';'); - if (c) - { - p = c; - } - else - { - // Improperly terminated word; just go to end of str - p = strchr (p, '\0'); - } - } - } - } - // Did we get a properly formatted logging bitmask? - if (p && *p == ';') - { - // Enable DNB logging. - // Use the existing log callback if one was already configured. - if (!DNBLogGetLogCallback()) - { - // Use the os_log()-based logger if available; otherwise, - // fallback to ASL. - auto log_callback = OsLogger::GetLogFunction(); - if (log_callback) - DNBLogSetLogCallback(log_callback, nullptr); - else - DNBLogSetLogCallback(ASLLogCallback, nullptr); - } - - // Update logging to use the configured log channel bitmask. - DNBLogSetLogMask (bitmask); - p++; +rnb_err_t set_logging(const char *p) { + int bitmask = 0; + while (p && *p != '\0') { + if (strncmp(p, "bitmask=", sizeof("bitmask=") - 1) == 0) { + p += sizeof("bitmask=") - 1; + while (p && *p != '\0' && *p != ';') { + if (*p == '|') + p++; + + // to regenerate the LOG_ entries (not including the LOG_RNB entries) + // $ for logname in `grep '^#define LOG_' DNBDefs.h | egrep -v + // 'LOG_HI|LOG_LO' | awk '{print $2}'` + // do + // echo " else if (strncmp (p, \"$logname\", sizeof + // (\"$logname\") - 1) == 0)" + // echo " {" + // echo " p += sizeof (\"$logname\") - 1;" + // echo " bitmask |= $logname;" + // echo " }" + // done + if (strncmp(p, "LOG_VERBOSE", sizeof("LOG_VERBOSE") - 1) == 0) { + p += sizeof("LOG_VERBOSE") - 1; + bitmask |= LOG_VERBOSE; + } else if (strncmp(p, "LOG_PROCESS", sizeof("LOG_PROCESS") - 1) == 0) { + p += sizeof("LOG_PROCESS") - 1; + bitmask |= LOG_PROCESS; + } else if (strncmp(p, "LOG_THREAD", sizeof("LOG_THREAD") - 1) == 0) { + p += sizeof("LOG_THREAD") - 1; + bitmask |= LOG_THREAD; + } else if (strncmp(p, "LOG_EXCEPTIONS", sizeof("LOG_EXCEPTIONS") - 1) == + 0) { + p += sizeof("LOG_EXCEPTIONS") - 1; + bitmask |= LOG_EXCEPTIONS; + } else if (strncmp(p, "LOG_SHLIB", sizeof("LOG_SHLIB") - 1) == 0) { + p += sizeof("LOG_SHLIB") - 1; + bitmask |= LOG_SHLIB; + } else if (strncmp(p, "LOG_MEMORY", sizeof("LOG_MEMORY") - 1) == 0) { + p += sizeof("LOG_MEMORY") - 1; + bitmask |= LOG_MEMORY; + } else if (strncmp(p, "LOG_MEMORY_DATA_SHORT", + sizeof("LOG_MEMORY_DATA_SHORT") - 1) == 0) { + p += sizeof("LOG_MEMORY_DATA_SHORT") - 1; + bitmask |= LOG_MEMORY_DATA_SHORT; + } else if (strncmp(p, "LOG_MEMORY_DATA_LONG", + sizeof("LOG_MEMORY_DATA_LONG") - 1) == 0) { + p += sizeof("LOG_MEMORY_DATA_LONG") - 1; + bitmask |= LOG_MEMORY_DATA_LONG; + } else if (strncmp(p, "LOG_MEMORY_PROTECTIONS", + sizeof("LOG_MEMORY_PROTECTIONS") - 1) == 0) { + p += sizeof("LOG_MEMORY_PROTECTIONS") - 1; + bitmask |= LOG_MEMORY_PROTECTIONS; + } else if (strncmp(p, "LOG_BREAKPOINTS", + sizeof("LOG_BREAKPOINTS") - 1) == 0) { + p += sizeof("LOG_BREAKPOINTS") - 1; + bitmask |= LOG_BREAKPOINTS; + } else if (strncmp(p, "LOG_EVENTS", sizeof("LOG_EVENTS") - 1) == 0) { + p += sizeof("LOG_EVENTS") - 1; + bitmask |= LOG_EVENTS; + } else if (strncmp(p, "LOG_WATCHPOINTS", + sizeof("LOG_WATCHPOINTS") - 1) == 0) { + p += sizeof("LOG_WATCHPOINTS") - 1; + bitmask |= LOG_WATCHPOINTS; + } else if (strncmp(p, "LOG_STEP", sizeof("LOG_STEP") - 1) == 0) { + p += sizeof("LOG_STEP") - 1; + bitmask |= LOG_STEP; + } else if (strncmp(p, "LOG_TASK", sizeof("LOG_TASK") - 1) == 0) { + p += sizeof("LOG_TASK") - 1; + bitmask |= LOG_TASK; + } else if (strncmp(p, "LOG_ALL", sizeof("LOG_ALL") - 1) == 0) { + p += sizeof("LOG_ALL") - 1; + bitmask |= LOG_ALL; + } else if (strncmp(p, "LOG_DEFAULT", sizeof("LOG_DEFAULT") - 1) == 0) { + p += sizeof("LOG_DEFAULT") - 1; + bitmask |= LOG_DEFAULT; + } + // end of auto-generated entries + + else if (strncmp(p, "LOG_NONE", sizeof("LOG_NONE") - 1) == 0) { + p += sizeof("LOG_NONE") - 1; + bitmask = 0; + } else if (strncmp(p, "LOG_RNB_MINIMAL", + sizeof("LOG_RNB_MINIMAL") - 1) == 0) { + p += sizeof("LOG_RNB_MINIMAL") - 1; + bitmask |= LOG_RNB_MINIMAL; + } else if (strncmp(p, "LOG_RNB_MEDIUM", sizeof("LOG_RNB_MEDIUM") - 1) == + 0) { + p += sizeof("LOG_RNB_MEDIUM") - 1; + bitmask |= LOG_RNB_MEDIUM; + } else if (strncmp(p, "LOG_RNB_MAX", sizeof("LOG_RNB_MAX") - 1) == 0) { + p += sizeof("LOG_RNB_MAX") - 1; + bitmask |= LOG_RNB_MAX; + } else if (strncmp(p, "LOG_RNB_COMM", sizeof("LOG_RNB_COMM") - 1) == + 0) { + p += sizeof("LOG_RNB_COMM") - 1; + bitmask |= LOG_RNB_COMM; + } else if (strncmp(p, "LOG_RNB_REMOTE", sizeof("LOG_RNB_REMOTE") - 1) == + 0) { + p += sizeof("LOG_RNB_REMOTE") - 1; + bitmask |= LOG_RNB_REMOTE; + } else if (strncmp(p, "LOG_RNB_EVENTS", sizeof("LOG_RNB_EVENTS") - 1) == + 0) { + p += sizeof("LOG_RNB_EVENTS") - 1; + bitmask |= LOG_RNB_EVENTS; + } else if (strncmp(p, "LOG_RNB_PROC", sizeof("LOG_RNB_PROC") - 1) == + 0) { + p += sizeof("LOG_RNB_PROC") - 1; + bitmask |= LOG_RNB_PROC; + } else if (strncmp(p, "LOG_RNB_PACKETS", + sizeof("LOG_RNB_PACKETS") - 1) == 0) { + p += sizeof("LOG_RNB_PACKETS") - 1; + bitmask |= LOG_RNB_PACKETS; + } else if (strncmp(p, "LOG_RNB_ALL", sizeof("LOG_RNB_ALL") - 1) == 0) { + p += sizeof("LOG_RNB_ALL") - 1; + bitmask |= LOG_RNB_ALL; + } else if (strncmp(p, "LOG_RNB_DEFAULT", + sizeof("LOG_RNB_DEFAULT") - 1) == 0) { + p += sizeof("LOG_RNB_DEFAULT") - 1; + bitmask |= LOG_RNB_DEFAULT; + } else if (strncmp(p, "LOG_DARWIN_LOG", sizeof("LOG_DARWIN_LOG") - 1) == + 0) { + p += sizeof("LOG_DARWIN_LOG") - 1; + bitmask |= LOG_DARWIN_LOG; + } else if (strncmp(p, "LOG_RNB_NONE", sizeof("LOG_RNB_NONE") - 1) == + 0) { + p += sizeof("LOG_RNB_NONE") - 1; + bitmask = 0; + } else { + /* Unrecognized logging bit; ignore it. */ + const char *c = strchr(p, '|'); + if (c) { + p = c; + } else { + c = strchr(p, ';'); + if (c) { + p = c; + } else { + // Improperly terminated word; just go to end of str + p = strchr(p, '\0'); } + } + } + } + // Did we get a properly formatted logging bitmask? + if (p && *p == ';') { + // Enable DNB logging. + // Use the existing log callback if one was already configured. + if (!DNBLogGetLogCallback()) { + // Use the os_log()-based logger if available; otherwise, + // fallback to ASL. + auto log_callback = OsLogger::GetLogFunction(); + if (log_callback) + DNBLogSetLogCallback(log_callback, nullptr); + else + DNBLogSetLogCallback(ASLLogCallback, nullptr); } - // We're not going to support logging to a file for now. All logging - // goes through ASL or the previously arranged log callback. + + // Update logging to use the configured log channel bitmask. + DNBLogSetLogMask(bitmask); + p++; + } + } +// We're not going to support logging to a file for now. All logging +// goes through ASL or the previously arranged log callback. #if 0 else if (strncmp (p, "mode=", sizeof ("mode=") - 1) == 0) { @@ -2261,1022 +2269,930 @@ set_logging (const char *p) p = c + 1; } #endif /* #if 0 to enforce ASL logging only. */ - else - { - // Ignore unknown argument - const char *c = strchr (p, ';'); - if (c) - p = c + 1; - else - p = strchr (p, '\0'); - } + else { + // Ignore unknown argument + const char *c = strchr(p, ';'); + if (c) + p = c + 1; + else + p = strchr(p, '\0'); } + } - return rnb_success; + return rnb_success; } -rnb_err_t -RNBRemote::HandlePacket_QThreadSuffixSupported (const char *p) -{ - m_thread_suffix_supported = true; - return SendPacket ("OK"); +rnb_err_t RNBRemote::HandlePacket_QThreadSuffixSupported(const char *p) { + m_thread_suffix_supported = true; + return SendPacket("OK"); } -rnb_err_t -RNBRemote::HandlePacket_QStartNoAckMode (const char *p) -{ - // Send the OK packet first so the correct checksum is appended... - rnb_err_t result = SendPacket ("OK"); - m_noack_mode = true; - return result; +rnb_err_t RNBRemote::HandlePacket_QStartNoAckMode(const char *p) { + // Send the OK packet first so the correct checksum is appended... + rnb_err_t result = SendPacket("OK"); + m_noack_mode = true; + return result; } +rnb_err_t RNBRemote::HandlePacket_QSetLogging(const char *p) { + p += sizeof("QSetLogging:") - 1; + rnb_err_t result = set_logging(p); + if (result == rnb_success) + return SendPacket("OK"); + else + return SendPacket("E35"); +} + +rnb_err_t RNBRemote::HandlePacket_QSetDisableASLR(const char *p) { + extern int g_disable_aslr; + p += sizeof("QSetDisableASLR:") - 1; + switch (*p) { + case '0': + g_disable_aslr = 0; + break; + case '1': + g_disable_aslr = 1; + break; + default: + return SendPacket("E56"); + } + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_QSetSTDIO(const char *p) { + // Only set stdin/out/err if we don't already have a process + if (!m_ctx.HasValidProcessID()) { + bool success = false; + // Check the seventh character since the packet will be one of: + // QSetSTDIN + // QSetSTDOUT + // QSetSTDERR + StdStringExtractor packet(p); + packet.SetFilePos(7); + char ch = packet.GetChar(); + while (packet.GetChar() != ':') + /* Do nothing. */; + + switch (ch) { + case 'I': // STDIN + packet.GetHexByteString(m_ctx.GetSTDIN()); + success = !m_ctx.GetSTDIN().empty(); + break; + + case 'O': // STDOUT + packet.GetHexByteString(m_ctx.GetSTDOUT()); + success = !m_ctx.GetSTDOUT().empty(); + break; + + case 'E': // STDERR + packet.GetHexByteString(m_ctx.GetSTDERR()); + success = !m_ctx.GetSTDERR().empty(); + break; -rnb_err_t -RNBRemote::HandlePacket_QSetLogging (const char *p) -{ - p += sizeof ("QSetLogging:") - 1; - rnb_err_t result = set_logging (p); - if (result == rnb_success) - return SendPacket ("OK"); - else - return SendPacket ("E35"); -} - -rnb_err_t -RNBRemote::HandlePacket_QSetDisableASLR (const char *p) -{ - extern int g_disable_aslr; - p += sizeof ("QSetDisableASLR:") - 1; - switch (*p) - { - case '0': g_disable_aslr = 0; break; - case '1': g_disable_aslr = 1; break; default: - return SendPacket ("E56"); - } - return SendPacket ("OK"); -} - -rnb_err_t -RNBRemote::HandlePacket_QSetSTDIO (const char *p) -{ - // Only set stdin/out/err if we don't already have a process - if (!m_ctx.HasValidProcessID()) - { - bool success = false; - // Check the seventh character since the packet will be one of: - // QSetSTDIN - // QSetSTDOUT - // QSetSTDERR - StdStringExtractor packet(p); - packet.SetFilePos (7); - char ch = packet.GetChar(); - while (packet.GetChar() != ':') - /* Do nothing. */; - - switch (ch) - { - case 'I': // STDIN - packet.GetHexByteString (m_ctx.GetSTDIN()); - success = !m_ctx.GetSTDIN().empty(); - break; - - case 'O': // STDOUT - packet.GetHexByteString (m_ctx.GetSTDOUT()); - success = !m_ctx.GetSTDOUT().empty(); - break; - - case 'E': // STDERR - packet.GetHexByteString (m_ctx.GetSTDERR()); - success = !m_ctx.GetSTDERR().empty(); - break; - - default: - break; - } - if (success) - return SendPacket ("OK"); - return SendPacket ("E57"); - } - return SendPacket ("E58"); -} - -rnb_err_t -RNBRemote::HandlePacket_QSetWorkingDir (const char *p) -{ - // Only set the working directory if we don't already have a process - if (!m_ctx.HasValidProcessID()) - { - StdStringExtractor packet(p += sizeof ("QSetWorkingDir:") - 1); - if (packet.GetHexByteString (m_ctx.GetWorkingDir())) - { - struct stat working_dir_stat; - if (::stat(m_ctx.GetWorkingDirPath(), &working_dir_stat) == -1) - { - m_ctx.GetWorkingDir().clear(); - return SendPacket ("E61"); // Working directory doesn't exist... - } - else if ((working_dir_stat.st_mode & S_IFMT) == S_IFDIR) - { - return SendPacket ("OK"); - } - else - { - m_ctx.GetWorkingDir().clear(); - return SendPacket ("E62"); // Working directory isn't a directory... - } - } - return SendPacket ("E59"); // Invalid path - } - return SendPacket ("E60"); // Already had a process, too late to set working dir -} - -rnb_err_t -RNBRemote::HandlePacket_QSyncThreadState (const char *p) -{ - if (!m_ctx.HasValidProcessID()) - { - // We allow gdb to connect to a server that hasn't started running - // the target yet. gdb still wants to ask questions about it and - // freaks out if it gets an error. So just return OK here. - return SendPacket ("OK"); - } - - errno = 0; - p += strlen("QSyncThreadState:"); - nub_thread_t tid = strtoul (p, NULL, 16); - if (errno != 0 && tid == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid thread number in QSyncThreadState packet"); - } - if (DNBProcessSyncThreadState(m_ctx.ProcessID(), tid)) + break; + } + if (success) + return SendPacket("OK"); + return SendPacket("E57"); + } + return SendPacket("E58"); +} + +rnb_err_t RNBRemote::HandlePacket_QSetWorkingDir(const char *p) { + // Only set the working directory if we don't already have a process + if (!m_ctx.HasValidProcessID()) { + StdStringExtractor packet(p += sizeof("QSetWorkingDir:") - 1); + if (packet.GetHexByteString(m_ctx.GetWorkingDir())) { + struct stat working_dir_stat; + if (::stat(m_ctx.GetWorkingDirPath(), &working_dir_stat) == -1) { + m_ctx.GetWorkingDir().clear(); + return SendPacket("E61"); // Working directory doesn't exist... + } else if ((working_dir_stat.st_mode & S_IFMT) == S_IFDIR) { return SendPacket("OK"); - else - return SendPacket ("E61"); -} - -rnb_err_t -RNBRemote::HandlePacket_QSetDetachOnError (const char *p) -{ - p += sizeof ("QSetDetachOnError:") - 1; - bool should_detach = true; - switch (*p) - { - case '0': should_detach = false; break; - case '1': should_detach = true; break; - default: - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid value for QSetDetachOnError - should be 0 or 1"); - break; + } else { + m_ctx.GetWorkingDir().clear(); + return SendPacket("E62"); // Working directory isn't a directory... + } } - - m_ctx.SetDetachOnError(should_detach); - return SendPacket ("OK"); + return SendPacket("E59"); // Invalid path + } + return SendPacket( + "E60"); // Already had a process, too late to set working dir } -rnb_err_t -RNBRemote::HandlePacket_qStructuredDataPlugins(const char *p) -{ - // We'll return a JSON array of supported packet types. - // The type is significant. For each of the supported - // packet types that have been enabled, there will be a - // 'J' async packet sent to the client with payload data. - // This payload data will be a JSON dictionary, and the - // top level dictionary will contain a string field with - // its value set to the relevant packet type from this list. - JSONGenerator::Array supported_json_packets; - - // Check for DarwinLog (libtrace os_log/activity support). - if (DarwinLogCollector::IsSupported()) - supported_json_packets.AddItem(JSONGenerator::StringSP( - new JSONGenerator::String("DarwinLog"))); - - // Send back the array. - std::ostringstream stream; - supported_json_packets.Dump(stream); - return SendPacket(stream.str()); -} - -rnb_err_t -RNBRemote::HandlePacket_QConfigureDarwinLog(const char *p) -{ - if (!DarwinLogCollector::IsSupported()) - { - // We should never have been given this request. - return SendPacket ("E89"); - } - - // Ensure we have a process. We expect a separate configure request for - // each process launched/attached. - const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("E94"); - - // Get the configuration dictionary. - p += strlen("QConfigureDarwinLog:"); - - // The configuration dictionary is binary encoded. - std::vector<uint8_t> unescaped_config_data = decode_binary_data(p, -1); - std::string unescaped_config_string((const char*)&unescaped_config_data[0], - unescaped_config_data.size()); - DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLog: received config data: \"%s\"", - unescaped_config_string.c_str()); - auto configuration_sp = - JSONParser(unescaped_config_string.c_str()).ParseJSONValue(); - if (!configuration_sp) - { - // Malformed request - we require configuration data - // indicating whether we're enabling or disabling. - return SendPacket("E90"); - } - - if (!JSONObject::classof(configuration_sp.get())) - { - // Configuration data is not of the right type. - return SendPacket("E91"); - } - JSONObject &config_dict = *static_cast<JSONObject*>(configuration_sp.get()); - - // Check if we're enabling or disabling. - auto enabled_sp = config_dict.GetObject("enabled"); - if (!enabled_sp) - { - // Missing required "enabled" field. - return SendPacket("E92"); - } - if (!JSONTrue::classof(enabled_sp.get()) && - !JSONFalse::classof(enabled_sp.get())) - { - // Should be a boolean type, but wasn't. - return SendPacket("E93"); - } - const bool enabling = JSONTrue::classof(enabled_sp.get()); - - // TODO - handle other configuration parameters here. - - // Shut down any active activity stream for the process. - DarwinLogCollector::CancelStreamForProcess(pid); - - if (enabling) - { - // Look up the procecess. - if (!DarwinLogCollector::StartCollectingForProcess(pid, config_dict)) - return SendPacket("E95"); - } - +rnb_err_t RNBRemote::HandlePacket_QSyncThreadState(const char *p) { + if (!m_ctx.HasValidProcessID()) { + // We allow gdb to connect to a server that hasn't started running + // the target yet. gdb still wants to ask questions about it and + // freaks out if it gets an error. So just return OK here. return SendPacket("OK"); -} - -rnb_err_t -RNBRemote::HandlePacket_QListThreadsInStopReply (const char *p) -{ - // If this packet is received, it allows us to send an extra key/value - // pair in the stop reply packets where we will list all of the thread IDs - // separated by commas: - // - // "threads:10a,10b,10c;" - // - // This will get included in the stop reply packet as something like: - // - // "T11thread:10a;00:00000000;01:00010203:threads:10a,10b,10c;" - // - // This can save two packets on each stop: qfThreadInfo/qsThreadInfo and - // speed things up a bit. - // - // Send the OK packet first so the correct checksum is appended... - rnb_err_t result = SendPacket ("OK"); - m_list_threads_in_stop_reply = true; - - return result; -} - - -rnb_err_t -RNBRemote::HandlePacket_QSetMaxPayloadSize (const char *p) -{ - /* The number of characters in a packet payload that gdb is - prepared to accept. The packet-start char, packet-end char, - 2 checksum chars and terminating null character are not included - in this size. */ - p += sizeof ("QSetMaxPayloadSize:") - 1; - errno = 0; - uint32_t size = static_cast<uint32_t>(strtoul (p, NULL, 16)); - if (errno != 0 && size == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in QSetMaxPayloadSize packet"); - } - m_max_payload_size = size; - return SendPacket ("OK"); -} - -rnb_err_t -RNBRemote::HandlePacket_QSetMaxPacketSize (const char *p) -{ - /* This tells us the largest packet that gdb can handle. - i.e. the size of gdb's packet-reading buffer. - QSetMaxPayloadSize is preferred because it is less ambiguous. */ - p += sizeof ("QSetMaxPacketSize:") - 1; + } + + errno = 0; + p += strlen("QSyncThreadState:"); + nub_thread_t tid = strtoul(p, NULL, 16); + if (errno != 0 && tid == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "Invalid thread number in QSyncThreadState packet"); + } + if (DNBProcessSyncThreadState(m_ctx.ProcessID(), tid)) + return SendPacket("OK"); + else + return SendPacket("E61"); +} + +rnb_err_t RNBRemote::HandlePacket_QSetDetachOnError(const char *p) { + p += sizeof("QSetDetachOnError:") - 1; + bool should_detach = true; + switch (*p) { + case '0': + should_detach = false; + break; + case '1': + should_detach = true; + break; + default: + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "Invalid value for QSetDetachOnError - should be 0 or 1"); + break; + } + + m_ctx.SetDetachOnError(should_detach); + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_qStructuredDataPlugins(const char *p) { + // We'll return a JSON array of supported packet types. + // The type is significant. For each of the supported + // packet types that have been enabled, there will be a + // 'J' async packet sent to the client with payload data. + // This payload data will be a JSON dictionary, and the + // top level dictionary will contain a string field with + // its value set to the relevant packet type from this list. + JSONGenerator::Array supported_json_packets; + + // Check for DarwinLog (libtrace os_log/activity support). + if (DarwinLogCollector::IsSupported()) + supported_json_packets.AddItem( + JSONGenerator::StringSP(new JSONGenerator::String("DarwinLog"))); + + // Send back the array. + std::ostringstream stream; + supported_json_packets.Dump(stream); + return SendPacket(stream.str()); +} + +rnb_err_t RNBRemote::HandlePacket_QConfigureDarwinLog(const char *p) { + if (!DarwinLogCollector::IsSupported()) { + // We should never have been given this request. + return SendPacket("E89"); + } + + // Ensure we have a process. We expect a separate configure request for + // each process launched/attached. + const nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E94"); + + // Get the configuration dictionary. + p += strlen("QConfigureDarwinLog:"); + + // The configuration dictionary is binary encoded. + std::vector<uint8_t> unescaped_config_data = decode_binary_data(p, -1); + std::string unescaped_config_string((const char *)&unescaped_config_data[0], + unescaped_config_data.size()); + DNBLogThreadedIf(LOG_DARWIN_LOG, "DarwinLog: received config data: \"%s\"", + unescaped_config_string.c_str()); + auto configuration_sp = + JSONParser(unescaped_config_string.c_str()).ParseJSONValue(); + if (!configuration_sp) { + // Malformed request - we require configuration data + // indicating whether we're enabling or disabling. + return SendPacket("E90"); + } + + if (!JSONObject::classof(configuration_sp.get())) { + // Configuration data is not of the right type. + return SendPacket("E91"); + } + JSONObject &config_dict = *static_cast<JSONObject *>(configuration_sp.get()); + + // Check if we're enabling or disabling. + auto enabled_sp = config_dict.GetObject("enabled"); + if (!enabled_sp) { + // Missing required "enabled" field. + return SendPacket("E92"); + } + if (!JSONTrue::classof(enabled_sp.get()) && + !JSONFalse::classof(enabled_sp.get())) { + // Should be a boolean type, but wasn't. + return SendPacket("E93"); + } + const bool enabling = JSONTrue::classof(enabled_sp.get()); + + // TODO - handle other configuration parameters here. + + // Shut down any active activity stream for the process. + DarwinLogCollector::CancelStreamForProcess(pid); + + if (enabling) { + // Look up the procecess. + if (!DarwinLogCollector::StartCollectingForProcess(pid, config_dict)) + return SendPacket("E95"); + } + + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_QListThreadsInStopReply(const char *p) { + // If this packet is received, it allows us to send an extra key/value + // pair in the stop reply packets where we will list all of the thread IDs + // separated by commas: + // + // "threads:10a,10b,10c;" + // + // This will get included in the stop reply packet as something like: + // + // "T11thread:10a;00:00000000;01:00010203:threads:10a,10b,10c;" + // + // This can save two packets on each stop: qfThreadInfo/qsThreadInfo and + // speed things up a bit. + // + // Send the OK packet first so the correct checksum is appended... + rnb_err_t result = SendPacket("OK"); + m_list_threads_in_stop_reply = true; + + return result; +} + +rnb_err_t RNBRemote::HandlePacket_QSetMaxPayloadSize(const char *p) { + /* The number of characters in a packet payload that gdb is + prepared to accept. The packet-start char, packet-end char, + 2 checksum chars and terminating null character are not included + in this size. */ + p += sizeof("QSetMaxPayloadSize:") - 1; + errno = 0; + uint32_t size = static_cast<uint32_t>(strtoul(p, NULL, 16)); + if (errno != 0 && size == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "Invalid length in QSetMaxPayloadSize packet"); + } + m_max_payload_size = size; + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_QSetMaxPacketSize(const char *p) { + /* This tells us the largest packet that gdb can handle. + i.e. the size of gdb's packet-reading buffer. + QSetMaxPayloadSize is preferred because it is less ambiguous. */ + p += sizeof("QSetMaxPacketSize:") - 1; + errno = 0; + uint32_t size = static_cast<uint32_t>(strtoul(p, NULL, 16)); + if (errno != 0 && size == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in QSetMaxPacketSize packet"); + } + m_max_payload_size = size - 5; + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_QEnvironment(const char *p) { + /* This sets the environment for the target program. The packet is of the + form: + + QEnvironment:VARIABLE=VALUE + + */ + + DNBLogThreadedIf( + LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p); + + p += sizeof("QEnvironment:") - 1; + RNBContext &ctx = Context(); + + ctx.PushEnvironment(p); + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_QEnvironmentHexEncoded(const char *p) { + /* This sets the environment for the target program. The packet is of the + form: + + QEnvironmentHexEncoded:VARIABLE=VALUE + + The VARIABLE=VALUE part is sent hex-encoded so characters like '#' with + special + meaning in the remote protocol won't break it. + */ + + DNBLogThreadedIf(LOG_RNB_REMOTE, + "%8u RNBRemote::%s Handling QEnvironmentHexEncoded: \"%s\"", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), + __FUNCTION__, p); + + p += sizeof("QEnvironmentHexEncoded:") - 1; + + std::string arg; + const char *c; + c = p; + while (*c != '\0') { + if (*(c + 1) == '\0') { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "non-hex char in arg on 'QEnvironmentHexEncoded' pkt"); + } + char smallbuf[3]; + smallbuf[0] = *c; + smallbuf[1] = *(c + 1); + smallbuf[2] = '\0'; errno = 0; - uint32_t size = static_cast<uint32_t>(strtoul (p, NULL, 16)); - if (errno != 0 && size == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in QSetMaxPacketSize packet"); + int ch = static_cast<int>(strtoul(smallbuf, NULL, 16)); + if (errno != 0 && ch == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "non-hex char in arg on 'QEnvironmentHexEncoded' pkt"); } - m_max_payload_size = size - 5; - return SendPacket ("OK"); -} - - - - -rnb_err_t -RNBRemote::HandlePacket_QEnvironment (const char *p) -{ - /* This sets the environment for the target program. The packet is of the form: - - QEnvironment:VARIABLE=VALUE - - */ - - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironment: \"%s\"", - (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p); - - p += sizeof ("QEnvironment:") - 1; - RNBContext& ctx = Context(); - - ctx.PushEnvironment (p); - return SendPacket ("OK"); -} - -rnb_err_t -RNBRemote::HandlePacket_QEnvironmentHexEncoded (const char *p) -{ - /* This sets the environment for the target program. The packet is of the form: - - QEnvironmentHexEncoded:VARIABLE=VALUE - - The VARIABLE=VALUE part is sent hex-encoded so characters like '#' with special - meaning in the remote protocol won't break it. - */ - - DNBLogThreadedIf (LOG_RNB_REMOTE, "%8u RNBRemote::%s Handling QEnvironmentHexEncoded: \"%s\"", - (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, p); - - p += sizeof ("QEnvironmentHexEncoded:") - 1; - - std::string arg; - const char *c; - c = p; - while (*c != '\0') - { - if (*(c + 1) == '\0') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'QEnvironmentHexEncoded' pkt"); - } - char smallbuf[3]; - smallbuf[0] = *c; - smallbuf[1] = *(c + 1); - smallbuf[2] = '\0'; - errno = 0; - int ch = static_cast<int>(strtoul (smallbuf, NULL, 16)); - if (errno != 0 && ch == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'QEnvironmentHexEncoded' pkt"); - } - arg.push_back(ch); - c += 2; - } - - RNBContext& ctx = Context(); - if (arg.length() > 0) - ctx.PushEnvironment (arg.c_str()); - - return SendPacket ("OK"); -} + arg.push_back(ch); + c += 2; + } + RNBContext &ctx = Context(); + if (arg.length() > 0) + ctx.PushEnvironment(arg.c_str()); -rnb_err_t -RNBRemote::HandlePacket_QLaunchArch (const char *p) -{ - p += sizeof ("QLaunchArch:") - 1; - if (DNBSetArchitecture(p)) - return SendPacket ("OK"); - return SendPacket ("E63"); + return SendPacket("OK"); } -rnb_err_t -RNBRemote::HandlePacket_QSetProcessEvent (const char *p) -{ - p += sizeof ("QSetProcessEvent:") - 1; - // If the process is running, then send the event to the process, otherwise - // store it in the context. - if (Context().HasValidProcessID()) - { - if (DNBProcessSendEvent (Context().ProcessID(), p)) - return SendPacket("OK"); - else - return SendPacket ("E80"); - } - else - { - Context().PushProcessEvent(p); - } - return SendPacket ("OK"); +rnb_err_t RNBRemote::HandlePacket_QLaunchArch(const char *p) { + p += sizeof("QLaunchArch:") - 1; + if (DNBSetArchitecture(p)) + return SendPacket("OK"); + return SendPacket("E63"); } -void -append_hex_value (std::ostream& ostrm, const void *buf, size_t buf_size, bool swap) -{ - int i; - const uint8_t *p = (const uint8_t *)buf; - if (swap) - { - for (i = static_cast<int>(buf_size)-1; i >= 0; i--) - ostrm << RAWHEX8(p[i]); - } +rnb_err_t RNBRemote::HandlePacket_QSetProcessEvent(const char *p) { + p += sizeof("QSetProcessEvent:") - 1; + // If the process is running, then send the event to the process, otherwise + // store it in the context. + if (Context().HasValidProcessID()) { + if (DNBProcessSendEvent(Context().ProcessID(), p)) + return SendPacket("OK"); else - { - for (size_t i = 0; i < buf_size; i++) - ostrm << RAWHEX8(p[i]); - } -} - -void -append_hexified_string (std::ostream& ostrm, const std::string &string) -{ - size_t string_size = string.size(); - const char *string_buf = string.c_str(); - for (size_t i = 0; i < string_size; i++) - { - ostrm << RAWHEX8(*(string_buf + i)); - } -} - - - -void -register_value_in_hex_fixed_width (std::ostream& ostrm, - nub_process_t pid, - nub_thread_t tid, - const register_map_entry_t* reg, - const DNBRegisterValue *reg_value_ptr) -{ - if (reg != NULL) - { - DNBRegisterValue reg_value; - if (reg_value_ptr == NULL) - { - if (DNBThreadGetRegisterValueByID (pid, tid, reg->nub_info.set, reg->nub_info.reg, ®_value)) - reg_value_ptr = ®_value; - } - - if (reg_value_ptr) - { - append_hex_value (ostrm, reg_value_ptr->value.v_uint8, reg->nub_info.size, false); - } - else - { - // If we fail to read a register value, check if it has a default - // fail value. If it does, return this instead in case some of - // the registers are not available on the current system. - if (reg->nub_info.size > 0) - { - std::basic_string<uint8_t> zeros(reg->nub_info.size, '\0'); - append_hex_value (ostrm, zeros.data(), zeros.size(), false); - } - } - } -} - - -void -debugserver_regnum_with_fixed_width_hex_register_value (std::ostream& ostrm, - nub_process_t pid, - nub_thread_t tid, - const register_map_entry_t* reg, - const DNBRegisterValue *reg_value_ptr) -{ - // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX - // gdb register number, and VVVVVVVV is the correct number of hex bytes - // as ASCII for the register value. - if (reg != NULL) - { - ostrm << RAWHEX8(reg->debugserver_regnum) << ':'; - register_value_in_hex_fixed_width (ostrm, pid, tid, reg, reg_value_ptr); - ostrm << ';'; + return SendPacket("E80"); + } else { + Context().PushProcessEvent(p); + } + return SendPacket("OK"); +} + +void append_hex_value(std::ostream &ostrm, const void *buf, size_t buf_size, + bool swap) { + int i; + const uint8_t *p = (const uint8_t *)buf; + if (swap) { + for (i = static_cast<int>(buf_size) - 1; i >= 0; i--) + ostrm << RAWHEX8(p[i]); + } else { + for (size_t i = 0; i < buf_size; i++) + ostrm << RAWHEX8(p[i]); + } +} + +void append_hexified_string(std::ostream &ostrm, const std::string &string) { + size_t string_size = string.size(); + const char *string_buf = string.c_str(); + for (size_t i = 0; i < string_size; i++) { + ostrm << RAWHEX8(*(string_buf + i)); + } +} + +void register_value_in_hex_fixed_width(std::ostream &ostrm, nub_process_t pid, + nub_thread_t tid, + const register_map_entry_t *reg, + const DNBRegisterValue *reg_value_ptr) { + if (reg != NULL) { + DNBRegisterValue reg_value; + if (reg_value_ptr == NULL) { + if (DNBThreadGetRegisterValueByID(pid, tid, reg->nub_info.set, + reg->nub_info.reg, ®_value)) + reg_value_ptr = ®_value; + } + + if (reg_value_ptr) { + append_hex_value(ostrm, reg_value_ptr->value.v_uint8, reg->nub_info.size, + false); + } else { + // If we fail to read a register value, check if it has a default + // fail value. If it does, return this instead in case some of + // the registers are not available on the current system. + if (reg->nub_info.size > 0) { + std::basic_string<uint8_t> zeros(reg->nub_info.size, '\0'); + append_hex_value(ostrm, zeros.data(), zeros.size(), false); + } } -} - - -void -RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo (nub_process_t pid, - nub_addr_t dispatch_qaddr, - nub_addr_t &dispatch_queue_t, - std::string &queue_name, - uint64_t &queue_width, - uint64_t &queue_serialnum) const -{ - queue_name.clear(); - queue_width = 0; - queue_serialnum = 0; - - if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS && dispatch_qaddr != 0) - { - dispatch_queue_t = DNBProcessMemoryReadPointer (pid, dispatch_qaddr); - if (dispatch_queue_t) - { - queue_width = DNBProcessMemoryReadInteger (pid, dispatch_queue_t + dqo_width, dqo_width_size, 0); - queue_serialnum = DNBProcessMemoryReadInteger (pid, dispatch_queue_t + dqo_serialnum, dqo_serialnum_size, 0); - - if (dqo_version >= 4) - { - // libdispatch versions 4+, pointer to dispatch name is in the - // queue structure. - nub_addr_t pointer_to_label_address = dispatch_queue_t + dqo_label; - nub_addr_t label_addr = DNBProcessMemoryReadPointer (pid, pointer_to_label_address); - if (label_addr) - queue_name = DNBProcessMemoryReadCString(pid, label_addr); - } - else - { - // libdispatch versions 1-3, dispatch name is a fixed width char array - // in the queue structure. - queue_name = DNBProcessMemoryReadCStringFixed(pid, dispatch_queue_t + dqo_label, dqo_label_size); - } - } + } +} + +void debugserver_regnum_with_fixed_width_hex_register_value( + std::ostream &ostrm, nub_process_t pid, nub_thread_t tid, + const register_map_entry_t *reg, const DNBRegisterValue *reg_value_ptr) { + // Output the register number as 'NN:VVVVVVVV;' where NN is a 2 bytes HEX + // gdb register number, and VVVVVVVV is the correct number of hex bytes + // as ASCII for the register value. + if (reg != NULL) { + ostrm << RAWHEX8(reg->debugserver_regnum) << ':'; + register_value_in_hex_fixed_width(ostrm, pid, tid, reg, reg_value_ptr); + ostrm << ';'; + } +} + +void RNBRemote::DispatchQueueOffsets::GetThreadQueueInfo( + nub_process_t pid, nub_addr_t dispatch_qaddr, nub_addr_t &dispatch_queue_t, + std::string &queue_name, uint64_t &queue_width, + uint64_t &queue_serialnum) const { + queue_name.clear(); + queue_width = 0; + queue_serialnum = 0; + + if (IsValid() && dispatch_qaddr != INVALID_NUB_ADDRESS && + dispatch_qaddr != 0) { + dispatch_queue_t = DNBProcessMemoryReadPointer(pid, dispatch_qaddr); + if (dispatch_queue_t) { + queue_width = DNBProcessMemoryReadInteger( + pid, dispatch_queue_t + dqo_width, dqo_width_size, 0); + queue_serialnum = DNBProcessMemoryReadInteger( + pid, dispatch_queue_t + dqo_serialnum, dqo_serialnum_size, 0); + + if (dqo_version >= 4) { + // libdispatch versions 4+, pointer to dispatch name is in the + // queue structure. + nub_addr_t pointer_to_label_address = dispatch_queue_t + dqo_label; + nub_addr_t label_addr = + DNBProcessMemoryReadPointer(pid, pointer_to_label_address); + if (label_addr) + queue_name = DNBProcessMemoryReadCString(pid, label_addr); + } else { + // libdispatch versions 1-3, dispatch name is a fixed width char array + // in the queue structure. + queue_name = DNBProcessMemoryReadCStringFixed( + pid, dispatch_queue_t + dqo_label, dqo_label_size); + } } + } } -struct StackMemory -{ - uint8_t bytes[2*sizeof(nub_addr_t)]; - nub_size_t length; +struct StackMemory { + uint8_t bytes[2 * sizeof(nub_addr_t)]; + nub_size_t length; }; typedef std::map<nub_addr_t, StackMemory> StackMemoryMap; +static void ReadStackMemory(nub_process_t pid, nub_thread_t tid, + StackMemoryMap &stack_mmap, + uint32_t backtrace_limit = 256) { + DNBRegisterValue reg_value; + if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, + GENERIC_REGNUM_FP, ®_value)) { + uint32_t frame_count = 0; + uint64_t fp = 0; + if (reg_value.info.size == 4) + fp = reg_value.value.uint32; + else + fp = reg_value.value.uint64; + while (fp != 0) { + // Make sure we never recurse more than 256 times so we don't recurse too + // far or + // store up too much memory in the expedited cache + if (++frame_count > backtrace_limit) + break; -static void -ReadStackMemory (nub_process_t pid, nub_thread_t tid, StackMemoryMap &stack_mmap, uint32_t backtrace_limit = 256) -{ - DNBRegisterValue reg_value; - if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_FP, ®_value)) - { - uint32_t frame_count = 0; - uint64_t fp = 0; - if (reg_value.info.size == 4) - fp = reg_value.value.uint32; - else - fp = reg_value.value.uint64; - while (fp != 0) - { - // Make sure we never recurse more than 256 times so we don't recurse too far or - // store up too much memory in the expedited cache - if (++frame_count > backtrace_limit) - break; - - const nub_size_t read_size = reg_value.info.size*2; - StackMemory stack_memory; - stack_memory.length = read_size; - if (DNBProcessMemoryRead(pid, fp, read_size, stack_memory.bytes) != read_size) - break; - // Make sure we don't try to put the same stack memory in more than once - if (stack_mmap.find(fp) != stack_mmap.end()) - break; - // Put the entry into the cache - stack_mmap[fp] = stack_memory; - // Dereference the frame pointer to get to the previous frame pointer - if (reg_value.info.size == 4) - fp = ((uint32_t *)stack_memory.bytes)[0]; - else - fp = ((uint64_t *)stack_memory.bytes)[0]; - } + const nub_size_t read_size = reg_value.info.size * 2; + StackMemory stack_memory; + stack_memory.length = read_size; + if (DNBProcessMemoryRead(pid, fp, read_size, stack_memory.bytes) != + read_size) + break; + // Make sure we don't try to put the same stack memory in more than once + if (stack_mmap.find(fp) != stack_mmap.end()) + break; + // Put the entry into the cache + stack_mmap[fp] = stack_memory; + // Dereference the frame pointer to get to the previous frame pointer + if (reg_value.info.size == 4) + fp = ((uint32_t *)stack_memory.bytes)[0]; + else + fp = ((uint64_t *)stack_memory.bytes)[0]; } + } } -rnb_err_t -RNBRemote::SendStopReplyPacketForThread (nub_thread_t tid) -{ - const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket("E50"); - - struct DNBThreadStopInfo tid_stop_info; - - /* Fill the remaining space in this packet with as many registers - as we can stuff in there. */ - - if (DNBThreadGetStopReason (pid, tid, &tid_stop_info)) - { - const bool did_exec = tid_stop_info.reason == eStopTypeExec; - if (did_exec) - { - RNBRemote::InitializeRegisters(true); - - // Reset any symbols that need resetting when we exec - m_dispatch_queue_offsets_addr = INVALID_NUB_ADDRESS; - m_dispatch_queue_offsets.Clear(); - } +rnb_err_t RNBRemote::SendStopReplyPacketForThread(nub_thread_t tid) { + const nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E50"); - std::ostringstream ostrm; - // Output the T packet with the thread - ostrm << 'T'; - int signum = tid_stop_info.details.signal.signo; - DNBLogThreadedIf (LOG_RNB_PROC, "%8d %s got signal signo = %u, exc_type = %u", (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, signum, tid_stop_info.details.exception.type); + struct DNBThreadStopInfo tid_stop_info; - // Translate any mach exceptions to gdb versions, unless they are - // common exceptions like a breakpoint or a soft signal. - switch (tid_stop_info.details.exception.type) - { - default: signum = 0; break; - case EXC_BREAKPOINT: signum = SIGTRAP; break; - case EXC_BAD_ACCESS: signum = TARGET_EXC_BAD_ACCESS; break; - case EXC_BAD_INSTRUCTION: signum = TARGET_EXC_BAD_INSTRUCTION; break; - case EXC_ARITHMETIC: signum = TARGET_EXC_ARITHMETIC; break; - case EXC_EMULATION: signum = TARGET_EXC_EMULATION; break; - case EXC_SOFTWARE: - if (tid_stop_info.details.exception.data_count == 2 && - tid_stop_info.details.exception.data[0] == EXC_SOFT_SIGNAL) - signum = static_cast<int>(tid_stop_info.details.exception.data[1]); - else - signum = TARGET_EXC_SOFTWARE; - break; - } + /* Fill the remaining space in this packet with as many registers + as we can stuff in there. */ - ostrm << RAWHEX8(signum & 0xff); + if (DNBThreadGetStopReason(pid, tid, &tid_stop_info)) { + const bool did_exec = tid_stop_info.reason == eStopTypeExec; + if (did_exec) { + RNBRemote::InitializeRegisters(true); - ostrm << std::hex << "thread:" << tid << ';'; + // Reset any symbols that need resetting when we exec + m_dispatch_queue_offsets_addr = INVALID_NUB_ADDRESS; + m_dispatch_queue_offsets.Clear(); + } - const char *thread_name = DNBThreadGetName (pid, tid); - if (thread_name && thread_name[0]) - { - size_t thread_name_len = strlen(thread_name); - + std::ostringstream ostrm; + // Output the T packet with the thread + ostrm << 'T'; + int signum = tid_stop_info.details.signal.signo; + DNBLogThreadedIf( + LOG_RNB_PROC, "%8d %s got signal signo = %u, exc_type = %u", + (uint32_t)m_comm.Timer().ElapsedMicroSeconds(true), __FUNCTION__, + signum, tid_stop_info.details.exception.type); + + // Translate any mach exceptions to gdb versions, unless they are + // common exceptions like a breakpoint or a soft signal. + switch (tid_stop_info.details.exception.type) { + default: + signum = 0; + break; + case EXC_BREAKPOINT: + signum = SIGTRAP; + break; + case EXC_BAD_ACCESS: + signum = TARGET_EXC_BAD_ACCESS; + break; + case EXC_BAD_INSTRUCTION: + signum = TARGET_EXC_BAD_INSTRUCTION; + break; + case EXC_ARITHMETIC: + signum = TARGET_EXC_ARITHMETIC; + break; + case EXC_EMULATION: + signum = TARGET_EXC_EMULATION; + break; + case EXC_SOFTWARE: + if (tid_stop_info.details.exception.data_count == 2 && + tid_stop_info.details.exception.data[0] == EXC_SOFT_SIGNAL) + signum = static_cast<int>(tid_stop_info.details.exception.data[1]); + else + signum = TARGET_EXC_SOFTWARE; + break; + } + + ostrm << RAWHEX8(signum & 0xff); + + ostrm << std::hex << "thread:" << tid << ';'; + + const char *thread_name = DNBThreadGetName(pid, tid); + if (thread_name && thread_name[0]) { + size_t thread_name_len = strlen(thread_name); + + if (::strcspn(thread_name, "$#+-;:") == thread_name_len) + ostrm << std::hex << "name:" << thread_name << ';'; + else { + // the thread name contains special chars, send as hex bytes + ostrm << std::hex << "hexname:"; + uint8_t *u_thread_name = (uint8_t *)thread_name; + for (size_t i = 0; i < thread_name_len; i++) + ostrm << RAWHEX8(u_thread_name[i]); + ostrm << ';'; + } + } - if (::strcspn (thread_name, "$#+-;:") == thread_name_len) - ostrm << std::hex << "name:" << thread_name << ';'; - else - { - // the thread name contains special chars, send as hex bytes - ostrm << std::hex << "hexname:"; - uint8_t *u_thread_name = (uint8_t *)thread_name; - for (size_t i = 0; i < thread_name_len; i++) - ostrm << RAWHEX8(u_thread_name[i]); - ostrm << ';'; + // 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) { + const nub_size_t numthreads = DNBProcessGetNumThreads(pid); + if (numthreads > 0) { + std::vector<uint64_t> pc_values; + ostrm << std::hex << "threads:"; + for (nub_size_t i = 0; i < numthreads; ++i) { + nub_thread_t th = DNBProcessGetThreadAtIndex(pid, i); + if (i > 0) + ostrm << ','; + ostrm << std::hex << th; + DNBRegisterValue pc_regval; + if (DNBThreadGetRegisterValueByID(pid, th, REGISTER_SET_GENERIC, + GENERIC_REGNUM_PC, &pc_regval)) { + uint64_t pc = INVALID_NUB_ADDRESS; + if (pc_regval.value.uint64 != INVALID_NUB_ADDRESS) { + if (pc_regval.info.size == 4) { + pc = pc_regval.value.uint32; + } else if (pc_regval.info.size == 8) { + pc = pc_regval.value.uint64; + } + if (pc != INVALID_NUB_ADDRESS) { + pc_values.push_back(pc); + } } + } } + ostrm << ';'; - // 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) - { - const nub_size_t numthreads = DNBProcessGetNumThreads (pid); - if (numthreads > 0) - { - std::vector<uint64_t> pc_values; - ostrm << std::hex << "threads:"; - for (nub_size_t i = 0; i < numthreads; ++i) - { - nub_thread_t th = DNBProcessGetThreadAtIndex (pid, i); - if (i > 0) - ostrm << ','; - ostrm << std::hex << th; - DNBRegisterValue pc_regval; - if (DNBThreadGetRegisterValueByID (pid, th, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, &pc_regval)) - { - uint64_t pc = INVALID_NUB_ADDRESS; - if (pc_regval.value.uint64 != INVALID_NUB_ADDRESS) - { - if (pc_regval.info.size == 4) - { - pc = pc_regval.value.uint32; - } - else if (pc_regval.info.size == 8) - { - pc = pc_regval.value.uint64; - } - if (pc != INVALID_NUB_ADDRESS) - { - pc_values.push_back (pc); - } - } - } - } - ostrm << ';'; - - // If we failed to get any of the thread pc values, the size of our vector will not - // be the same as the # of threads. Don't provide any expedited thread pc values in - // that case. This should not happen. - if (pc_values.size() == numthreads) - { - ostrm << std::hex << "thread-pcs:"; - for (nub_size_t i = 0; i < numthreads; ++i) - { - if (i > 0) - ostrm << ','; - ostrm << std::hex << pc_values[i]; - } - ostrm << ';'; - } - } - - // 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 (numthreads > 1) - { - const bool threads_with_valid_stop_info_only = true; - JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(threads_with_valid_stop_info_only); - if (threads_info_sp) - { - ostrm << std::hex << "jstopinfo:"; - std::ostringstream json_strm; - threads_info_sp->Dump (json_strm); - append_hexified_string (ostrm, json_strm.str()); - ostrm << ';'; - } - } + // If we failed to get any of the thread pc values, the size of our + // vector will not + // be the same as the # of threads. Don't provide any expedited thread + // pc values in + // that case. This should not happen. + if (pc_values.size() == numthreads) { + ostrm << std::hex << "thread-pcs:"; + for (nub_size_t i = 0; i < numthreads; ++i) { + if (i > 0) + ostrm << ','; + ostrm << std::hex << pc_values[i]; + } + ostrm << ';'; } + } - if (g_num_reg_entries == 0) - InitializeRegisters (); - - if (g_reg_entries != NULL) - { - DNBRegisterValue reg_value; - for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) - { - // Expedite all registers in the first register set that aren't - // contained in other registers - if (g_reg_entries[reg].nub_info.set == 1 && - g_reg_entries[reg].nub_info.value_regs == NULL) - { - if (!DNBThreadGetRegisterValueByID (pid, tid, g_reg_entries[reg].nub_info.set, g_reg_entries[reg].nub_info.reg, ®_value)) - continue; - - debugserver_regnum_with_fixed_width_hex_register_value (ostrm, pid, tid, &g_reg_entries[reg], ®_value); - } - } - } - - if (did_exec) - { - ostrm << "reason:exec;"; - } - else if (tid_stop_info.details.exception.type) - { - ostrm << "metype:" << std::hex << tid_stop_info.details.exception.type << ';'; - ostrm << "mecount:" << std::hex << tid_stop_info.details.exception.data_count << ';'; - for (nub_size_t i = 0; i < tid_stop_info.details.exception.data_count; ++i) - ostrm << "medata:" << std::hex << tid_stop_info.details.exception.data[i] << ';'; + // 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 (numthreads > 1) { + const bool threads_with_valid_stop_info_only = true; + JSONGenerator::ObjectSP threads_info_sp = + GetJSONThreadsInfo(threads_with_valid_stop_info_only); + if (threads_info_sp) { + ostrm << std::hex << "jstopinfo:"; + std::ostringstream json_strm; + threads_info_sp->Dump(json_strm); + append_hexified_string(ostrm, json_strm.str()); + ostrm << ';'; } + } + } - // Add expedited stack memory so stack backtracing doesn't need to read anything from the - // frame pointer chain. - StackMemoryMap stack_mmap; - ReadStackMemory (pid, tid, stack_mmap, 2); - if (!stack_mmap.empty()) - { - for (const auto &stack_memory : stack_mmap) - { - ostrm << "memory:" << HEXBASE << stack_memory.first << '='; - append_hex_value (ostrm, stack_memory.second.bytes, stack_memory.second.length, false); - ostrm << ';'; - } + if (g_num_reg_entries == 0) + InitializeRegisters(); + + if (g_reg_entries != NULL) { + DNBRegisterValue reg_value; + for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) { + // Expedite all registers in the first register set that aren't + // contained in other registers + if (g_reg_entries[reg].nub_info.set == 1 && + g_reg_entries[reg].nub_info.value_regs == NULL) { + if (!DNBThreadGetRegisterValueByID( + pid, tid, g_reg_entries[reg].nub_info.set, + g_reg_entries[reg].nub_info.reg, ®_value)) + continue; + + debugserver_regnum_with_fixed_width_hex_register_value( + ostrm, pid, tid, &g_reg_entries[reg], ®_value); } + } + } - return SendPacket (ostrm.str ()); + if (did_exec) { + ostrm << "reason:exec;"; + } else if (tid_stop_info.details.exception.type) { + ostrm << "metype:" << std::hex << tid_stop_info.details.exception.type + << ';'; + ostrm << "mecount:" << std::hex + << tid_stop_info.details.exception.data_count << ';'; + for (nub_size_t i = 0; i < tid_stop_info.details.exception.data_count; + ++i) + ostrm << "medata:" << std::hex + << tid_stop_info.details.exception.data[i] << ';'; + } + + // Add expedited stack memory so stack backtracing doesn't need to read + // anything from the + // frame pointer chain. + StackMemoryMap stack_mmap; + ReadStackMemory(pid, tid, stack_mmap, 2); + if (!stack_mmap.empty()) { + for (const auto &stack_memory : stack_mmap) { + ostrm << "memory:" << HEXBASE << stack_memory.first << '='; + append_hex_value(ostrm, stack_memory.second.bytes, + stack_memory.second.length, false); + ostrm << ';'; + } } - return SendPacket("E51"); + + return SendPacket(ostrm.str()); + } + return SendPacket("E51"); } /* '?' The stop reply packet - tell gdb what the status of the inferior is. Often called the questionmark_packet. */ -rnb_err_t -RNBRemote::HandlePacket_last_signal (const char *unused) -{ - if (!m_ctx.HasValidProcessID()) - { - // Inferior is not yet specified/running - return SendPacket ("E02"); - } - - nub_process_t pid = m_ctx.ProcessID(); - nub_state_t pid_state = DNBProcessGetState (pid); - - switch (pid_state) - { - case eStateAttaching: - case eStateLaunching: - case eStateRunning: - case eStateStepping: - case eStateDetached: - return rnb_success; // Ignore - - case eStateSuspended: - case eStateStopped: - case eStateCrashed: - { - nub_thread_t tid = DNBProcessGetCurrentThread (pid); - // Make sure we set the current thread so g and p packets return - // the data the gdb will expect. - SetCurrentThread (tid); - - SendStopReplyPacketForThread (tid); - } - break; - - case eStateInvalid: - case eStateUnloaded: - case eStateExited: - { - char pid_exited_packet[16] = ""; - int pid_status = 0; - // Process exited with exit status - if (!DNBProcessGetExitStatus(pid, &pid_status)) - pid_status = 0; - - if (pid_status) - { - if (WIFEXITED (pid_status)) - snprintf (pid_exited_packet, sizeof(pid_exited_packet), "W%02x", WEXITSTATUS (pid_status)); - else if (WIFSIGNALED (pid_status)) - snprintf (pid_exited_packet, sizeof(pid_exited_packet), "X%02x", WEXITSTATUS (pid_status)); - else if (WIFSTOPPED (pid_status)) - snprintf (pid_exited_packet, sizeof(pid_exited_packet), "S%02x", WSTOPSIG (pid_status)); - } - - // If we have an empty exit packet, lets fill one in to be safe. - if (!pid_exited_packet[0]) - { - strncpy (pid_exited_packet, "W00", sizeof(pid_exited_packet)-1); - pid_exited_packet[sizeof(pid_exited_packet)-1] = '\0'; - } - - const char *exit_info = DNBProcessGetExitInfo (pid); - if (exit_info != NULL && *exit_info != '\0') - { - std::ostringstream exit_packet; - exit_packet << pid_exited_packet; - exit_packet << ';'; - exit_packet << RAW_HEXBASE << "description"; - exit_packet << ':'; - for (size_t i = 0; exit_info[i] != '\0'; i++) - exit_packet << RAWHEX8(exit_info[i]); - exit_packet << ';'; - return SendPacket (exit_packet.str()); - } - else - return SendPacket (pid_exited_packet); - } - break; - } - return rnb_success; -} - -rnb_err_t -RNBRemote::HandlePacket_M (const char *p) -{ - if (p == NULL || p[0] == '\0' || strlen (p) < 3) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Too short M packet"); - } - - char *c; - p++; - errno = 0; - nub_addr_t addr = strtoull (p, &c, 16); - if (errno != 0 && addr == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in M packet"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in M packet"); - } +rnb_err_t RNBRemote::HandlePacket_last_signal(const char *unused) { + if (!m_ctx.HasValidProcessID()) { + // Inferior is not yet specified/running + return SendPacket("E02"); + } + + nub_process_t pid = m_ctx.ProcessID(); + nub_state_t pid_state = DNBProcessGetState(pid); + + switch (pid_state) { + case eStateAttaching: + case eStateLaunching: + case eStateRunning: + case eStateStepping: + case eStateDetached: + return rnb_success; // Ignore + + case eStateSuspended: + case eStateStopped: + case eStateCrashed: { + nub_thread_t tid = DNBProcessGetCurrentThread(pid); + // Make sure we set the current thread so g and p packets return + // the data the gdb will expect. + SetCurrentThread(tid); + + SendStopReplyPacketForThread(tid); + } break; + + case eStateInvalid: + case eStateUnloaded: + case eStateExited: { + char pid_exited_packet[16] = ""; + int pid_status = 0; + // Process exited with exit status + if (!DNBProcessGetExitStatus(pid, &pid_status)) + pid_status = 0; + + if (pid_status) { + if (WIFEXITED(pid_status)) + snprintf(pid_exited_packet, sizeof(pid_exited_packet), "W%02x", + WEXITSTATUS(pid_status)); + else if (WIFSIGNALED(pid_status)) + snprintf(pid_exited_packet, sizeof(pid_exited_packet), "X%02x", + WEXITSTATUS(pid_status)); + else if (WIFSTOPPED(pid_status)) + snprintf(pid_exited_packet, sizeof(pid_exited_packet), "S%02x", + WSTOPSIG(pid_status)); + } + + // If we have an empty exit packet, lets fill one in to be safe. + if (!pid_exited_packet[0]) { + strncpy(pid_exited_packet, "W00", sizeof(pid_exited_packet) - 1); + pid_exited_packet[sizeof(pid_exited_packet) - 1] = '\0'; + } + + const char *exit_info = DNBProcessGetExitInfo(pid); + if (exit_info != NULL && *exit_info != '\0') { + std::ostringstream exit_packet; + exit_packet << pid_exited_packet; + exit_packet << ';'; + exit_packet << RAW_HEXBASE << "description"; + exit_packet << ':'; + for (size_t i = 0; exit_info[i] != '\0'; i++) + exit_packet << RAWHEX8(exit_info[i]); + exit_packet << ';'; + return SendPacket(exit_packet.str()); + } else + return SendPacket(pid_exited_packet); + } break; + } + return rnb_success; +} + +rnb_err_t RNBRemote::HandlePacket_M(const char *p) { + if (p == NULL || p[0] == '\0' || strlen(p) < 3) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short M packet"); + } + + char *c; + p++; + errno = 0; + nub_addr_t addr = strtoull(p, &c, 16); + if (errno != 0 && addr == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid address in M packet"); + } + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma sep missing in M packet"); + } + + /* Advance 'p' to the length part of the packet. */ + p += (c - p) + 1; + + errno = 0; + unsigned long length = strtoul(p, &c, 16); + if (errno != 0 && length == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in M packet"); + } + if (length == 0) { + return SendPacket("OK"); + } + + if (*c != ':') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Missing colon in M packet"); + } + /* Advance 'p' to the data part of the packet. */ + p += (c - p) + 1; + + size_t datalen = strlen(p); + if (datalen & 0x1) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Uneven # of hex chars for data in M packet"); + } + if (datalen == 0) { + return SendPacket("OK"); + } - /* Advance 'p' to the length part of the packet. */ - p += (c - p) + 1; + uint8_t *buf = (uint8_t *)alloca(datalen / 2); + uint8_t *i = buf; + while (*p != '\0' && *(p + 1) != '\0') { + char hexbuf[3]; + hexbuf[0] = *p; + hexbuf[1] = *(p + 1); + hexbuf[2] = '\0'; errno = 0; - unsigned long length = strtoul (p, &c, 16); - if (errno != 0 && length == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in M packet"); - } - if (length == 0) - { - return SendPacket ("OK"); - } - - if (*c != ':') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Missing colon in M packet"); - } - /* Advance 'p' to the data part of the packet. */ - p += (c - p) + 1; - - size_t datalen = strlen (p); - if (datalen & 0x1) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Uneven # of hex chars for data in M packet"); - } - if (datalen == 0) - { - return SendPacket ("OK"); - } - - uint8_t *buf = (uint8_t *) alloca (datalen / 2); - uint8_t *i = buf; - - while (*p != '\0' && *(p + 1) != '\0') - { - char hexbuf[3]; - hexbuf[0] = *p; - hexbuf[1] = *(p + 1); - hexbuf[2] = '\0'; - errno = 0; - uint8_t byte = strtoul (hexbuf, NULL, 16); - if (errno != 0 && byte == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid hex byte in M packet"); - } - *i++ = byte; - p += 2; - } - - nub_size_t wrote = DNBProcessMemoryWrite (m_ctx.ProcessID(), addr, length, buf); - if (wrote != length) - return SendPacket ("E09"); - else - return SendPacket ("OK"); + uint8_t byte = strtoul(hexbuf, NULL, 16); + if (errno != 0 && byte == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid hex byte in M packet"); + } + *i++ = byte; + p += 2; + } + + nub_size_t wrote = + DNBProcessMemoryWrite(m_ctx.ProcessID(), addr, length, buf); + if (wrote != length) + return SendPacket("E09"); + else + return SendPacket("OK"); } - -rnb_err_t -RNBRemote::HandlePacket_m (const char *p) -{ - if (p == NULL || p[0] == '\0' || strlen (p) < 3) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Too short m packet"); - } - - char *c; - p++; - errno = 0; - nub_addr_t addr = strtoull (p, &c, 16); - if (errno != 0 && addr == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in m packet"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in m packet"); - } - - /* Advance 'p' to the length part of the packet. */ - p += (c - p) + 1; - - errno = 0; - auto length = strtoul (p, NULL, 16); - if (errno != 0 && length == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in m packet"); - } - if (length == 0) - { - return SendPacket (""); - } - - std::string buf(length, '\0'); - if (buf.empty()) - { - return SendPacket ("E78"); - } - nub_size_t bytes_read = DNBProcessMemoryRead (m_ctx.ProcessID(), addr, buf.size(), &buf[0]); - if (bytes_read == 0) - { - return SendPacket ("E08"); - } - - // "The reply may contain fewer bytes than requested if the server was able - // to read only part of the region of memory." - length = bytes_read; - - std::ostringstream ostrm; - for (unsigned long i = 0; i < length; i++) - ostrm << RAWHEX8(buf[i]); - return SendPacket (ostrm.str ()); +rnb_err_t RNBRemote::HandlePacket_m(const char *p) { + if (p == NULL || p[0] == '\0' || strlen(p) < 3) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short m packet"); + } + + char *c; + p++; + errno = 0; + nub_addr_t addr = strtoull(p, &c, 16); + if (errno != 0 && addr == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid address in m packet"); + } + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma sep missing in m packet"); + } + + /* Advance 'p' to the length part of the packet. */ + p += (c - p) + 1; + + errno = 0; + auto length = strtoul(p, NULL, 16); + if (errno != 0 && length == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in m packet"); + } + if (length == 0) { + return SendPacket(""); + } + + std::string buf(length, '\0'); + if (buf.empty()) { + return SendPacket("E78"); + } + nub_size_t bytes_read = + DNBProcessMemoryRead(m_ctx.ProcessID(), addr, buf.size(), &buf[0]); + if (bytes_read == 0) { + return SendPacket("E08"); + } + + // "The reply may contain fewer bytes than requested if the server was able + // to read only part of the region of memory." + length = bytes_read; + + std::ostringstream ostrm; + for (unsigned long i = 0; i < length; i++) + ostrm << RAWHEX8(buf[i]); + return SendPacket(ostrm.str()); } // Read memory, sent it up as binary data. @@ -3284,137 +3200,127 @@ RNBRemote::HandlePacket_m (const char *p) // ADDR and LEN are both base 16. // Responds with 'OK' for zero-length request -// or +// or // // DATA // // where DATA is the binary data payload. -rnb_err_t -RNBRemote::HandlePacket_x (const char *p) -{ - if (p == NULL || p[0] == '\0' || strlen (p) < 3) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Too short X packet"); - } - - char *c; - p++; - errno = 0; - nub_addr_t addr = strtoull (p, &c, 16); - if (errno != 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in X packet"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in X packet"); - } - - /* Advance 'p' to the number of bytes to be read. */ - p += (c - p) + 1; - - errno = 0; - auto length = strtoul (p, NULL, 16); - if (errno != 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in x packet"); - } - - // zero length read means this is a test of whether that packet is implemented or not. - if (length == 0) - { - return SendPacket ("OK"); - } - - std::vector<uint8_t> buf (length); - - if (buf.capacity() != length) - { - return SendPacket ("E79"); - } - nub_size_t bytes_read = DNBProcessMemoryRead (m_ctx.ProcessID(), addr, buf.size(), &buf[0]); - if (bytes_read == 0) - { - return SendPacket ("E80"); - } - - std::vector<uint8_t> buf_quoted; - buf_quoted.reserve (bytes_read + 30); - for (nub_size_t i = 0; i < bytes_read; i++) - { - if (buf[i] == '#' || buf[i] == '$' || buf[i] == '}' || buf[i] == '*') - { - buf_quoted.push_back(0x7d); - buf_quoted.push_back(buf[i] ^ 0x20); - } - else - { - buf_quoted.push_back(buf[i]); - } - } - length = buf_quoted.size(); - - std::ostringstream ostrm; - for (unsigned long i = 0; i < length; i++) - ostrm << buf_quoted[i]; - - return SendPacket (ostrm.str ()); -} - -rnb_err_t -RNBRemote::HandlePacket_X (const char *p) -{ - if (p == NULL || p[0] == '\0' || strlen (p) < 3) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Too short X packet"); - } - - char *c; - p++; - errno = 0; - nub_addr_t addr = strtoull (p, &c, 16); - if (errno != 0 && addr == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in X packet"); - } - if (*c != ',') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma sep missing in X packet"); - } - - /* Advance 'p' to the length part of the packet. NB this is the length of the packet - including any escaped chars. The data payload may be a little bit smaller after - decoding. */ - p += (c - p) + 1; - - errno = 0; - auto length = strtoul (p, NULL, 16); - if (errno != 0 && length == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in X packet"); - } - - // I think gdb sends a zero length write request to test whether this - // packet is accepted. - if (length == 0) - { - return SendPacket ("OK"); - } +rnb_err_t RNBRemote::HandlePacket_x(const char *p) { + if (p == NULL || p[0] == '\0' || strlen(p) < 3) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short X packet"); + } + + char *c; + p++; + errno = 0; + nub_addr_t addr = strtoull(p, &c, 16); + if (errno != 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid address in X packet"); + } + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma sep missing in X packet"); + } + + /* Advance 'p' to the number of bytes to be read. */ + p += (c - p) + 1; + + errno = 0; + auto length = strtoul(p, NULL, 16); + if (errno != 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in x packet"); + } + + // zero length read means this is a test of whether that packet is implemented + // or not. + if (length == 0) { + return SendPacket("OK"); + } + + std::vector<uint8_t> buf(length); + + if (buf.capacity() != length) { + return SendPacket("E79"); + } + nub_size_t bytes_read = + DNBProcessMemoryRead(m_ctx.ProcessID(), addr, buf.size(), &buf[0]); + if (bytes_read == 0) { + return SendPacket("E80"); + } + + std::vector<uint8_t> buf_quoted; + buf_quoted.reserve(bytes_read + 30); + for (nub_size_t i = 0; i < bytes_read; i++) { + if (buf[i] == '#' || buf[i] == '$' || buf[i] == '}' || buf[i] == '*') { + buf_quoted.push_back(0x7d); + buf_quoted.push_back(buf[i] ^ 0x20); + } else { + buf_quoted.push_back(buf[i]); + } + } + length = buf_quoted.size(); + + std::ostringstream ostrm; + for (unsigned long i = 0; i < length; i++) + ostrm << buf_quoted[i]; + + return SendPacket(ostrm.str()); +} + +rnb_err_t RNBRemote::HandlePacket_X(const char *p) { + if (p == NULL || p[0] == '\0' || strlen(p) < 3) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Too short X packet"); + } + + char *c; + p++; + errno = 0; + nub_addr_t addr = strtoull(p, &c, 16); + if (errno != 0 && addr == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid address in X packet"); + } + if (*c != ',') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma sep missing in X packet"); + } + + /* Advance 'p' to the length part of the packet. NB this is the length of the + packet + including any escaped chars. The data payload may be a little bit smaller + after + decoding. */ + p += (c - p) + 1; + + errno = 0; + auto length = strtoul(p, NULL, 16); + if (errno != 0 && length == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in X packet"); + } + + // I think gdb sends a zero length write request to test whether this + // packet is accepted. + if (length == 0) { + return SendPacket("OK"); + } - std::vector<uint8_t> data = decode_binary_data (c, -1); - std::vector<uint8_t>::const_iterator it; - uint8_t *buf = (uint8_t *) alloca (data.size ()); - uint8_t *i = buf; - for (it = data.begin (); it != data.end (); ++it) - { - *i++ = *it; - } + std::vector<uint8_t> data = decode_binary_data(c, -1); + std::vector<uint8_t>::const_iterator it; + uint8_t *buf = (uint8_t *)alloca(data.size()); + uint8_t *i = buf; + for (it = data.begin(); it != data.end(); ++it) { + *i++ = *it; + } - nub_size_t wrote = DNBProcessMemoryWrite (m_ctx.ProcessID(), addr, data.size(), buf); - if (wrote != data.size ()) - return SendPacket ("E08"); - return SendPacket ("OK"); + nub_size_t wrote = + DNBProcessMemoryWrite(m_ctx.ProcessID(), addr, data.size(), buf); + if (wrote != data.size()) + return SendPacket("E08"); + return SendPacket("OK"); } /* 'g' -- read registers @@ -3423,108 +3329,99 @@ RNBRemote::HandlePacket_X (const char *p) Should the setting of the Hg packet determine which thread's registers are returned? */ -rnb_err_t -RNBRemote::HandlePacket_g (const char *p) -{ - std::ostringstream ostrm; - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E11"); - } - - if (g_num_reg_entries == 0) - InitializeRegisters (); - - nub_process_t pid = m_ctx.ProcessID (); - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p + 1); - if (tid == INVALID_NUB_THREAD) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in p packet"); - - // Get the register context size first by calling with NULL buffer - nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0); - if (reg_ctx_size) - { - // Now allocate enough space for the entire register context - std::vector<uint8_t> reg_ctx; - reg_ctx.resize(reg_ctx_size); - // Now read the register context - reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, ®_ctx[0], reg_ctx.size()); - if (reg_ctx_size) - { - append_hex_value (ostrm, reg_ctx.data(), reg_ctx.size(), false); - return SendPacket (ostrm.str ()); - } - } - return SendPacket ("E74"); +rnb_err_t RNBRemote::HandlePacket_g(const char *p) { + std::ostringstream ostrm; + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E11"); + } + + if (g_num_reg_entries == 0) + InitializeRegisters(); + + nub_process_t pid = m_ctx.ProcessID(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p + 1); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in p packet"); + + // Get the register context size first by calling with NULL buffer + nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0); + if (reg_ctx_size) { + // Now allocate enough space for the entire register context + std::vector<uint8_t> reg_ctx; + reg_ctx.resize(reg_ctx_size); + // Now read the register context + reg_ctx_size = + DNBThreadGetRegisterContext(pid, tid, ®_ctx[0], reg_ctx.size()); + if (reg_ctx_size) { + append_hex_value(ostrm, reg_ctx.data(), reg_ctx.size(), false); + return SendPacket(ostrm.str()); + } + } + return SendPacket("E74"); } /* 'G XXX...' -- write registers How is the thread for these specified, beyond "the current thread"? Does gdb actually use the Hg packet to set this? */ -rnb_err_t -RNBRemote::HandlePacket_G (const char *p) -{ - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E11"); - } - - if (g_num_reg_entries == 0) - InitializeRegisters (); - - StdStringExtractor packet(p); - packet.SetFilePos(1); // Skip the 'G' - - nub_process_t pid = m_ctx.ProcessID(); - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); - if (tid == INVALID_NUB_THREAD) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in p packet"); - - // Get the register context size first by calling with NULL buffer - nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0); - if (reg_ctx_size) - { - // Now allocate enough space for the entire register context - std::vector<uint8_t> reg_ctx; - reg_ctx.resize(reg_ctx_size); - - const nub_size_t bytes_extracted = packet.GetHexBytes (®_ctx[0], reg_ctx.size(), 0xcc); - if (bytes_extracted == reg_ctx.size()) - { - // Now write the register context - reg_ctx_size = DNBThreadSetRegisterContext(pid, tid, reg_ctx.data(), reg_ctx.size()); - if (reg_ctx_size == reg_ctx.size()) - return SendPacket ("OK"); - else - return SendPacket ("E55"); - } - else - { - DNBLogError("RNBRemote::HandlePacket_G(%s): extracted %llu of %llu bytes, size mismatch\n", p, (uint64_t)bytes_extracted, (uint64_t)reg_ctx_size); - return SendPacket ("E64"); - } - } - return SendPacket ("E65"); -} - -static bool -RNBRemoteShouldCancelCallback (void *not_used) -{ - RNBRemoteSP remoteSP(g_remoteSP); - if (remoteSP.get() != NULL) - { - RNBRemote* remote = remoteSP.get(); - if (remote->Comm().IsConnected()) - return false; - else - return true; - } - return true; +rnb_err_t RNBRemote::HandlePacket_G(const char *p) { + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E11"); + } + + if (g_num_reg_entries == 0) + InitializeRegisters(); + + StdStringExtractor packet(p); + packet.SetFilePos(1); // Skip the 'G' + + nub_process_t pid = m_ctx.ProcessID(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in p packet"); + + // Get the register context size first by calling with NULL buffer + nub_size_t reg_ctx_size = DNBThreadGetRegisterContext(pid, tid, NULL, 0); + if (reg_ctx_size) { + // Now allocate enough space for the entire register context + std::vector<uint8_t> reg_ctx; + reg_ctx.resize(reg_ctx_size); + + const nub_size_t bytes_extracted = + packet.GetHexBytes(®_ctx[0], reg_ctx.size(), 0xcc); + if (bytes_extracted == reg_ctx.size()) { + // Now write the register context + reg_ctx_size = + DNBThreadSetRegisterContext(pid, tid, reg_ctx.data(), reg_ctx.size()); + if (reg_ctx_size == reg_ctx.size()) + return SendPacket("OK"); + else + return SendPacket("E55"); + } else { + DNBLogError("RNBRemote::HandlePacket_G(%s): extracted %llu of %llu " + "bytes, size mismatch\n", + p, (uint64_t)bytes_extracted, (uint64_t)reg_ctx_size); + return SendPacket("E64"); + } + } + return SendPacket("E65"); +} + +static bool RNBRemoteShouldCancelCallback(void *not_used) { + RNBRemoteSP remoteSP(g_remoteSP); + if (remoteSP.get() != NULL) { + RNBRemote *remote = remoteSP.get(); + if (remote->Comm().IsConnected()) + return false; + else + return true; + } + return true; } - -// FORMAT: _MXXXXXX,PPP +// FORMAT: _MXXXXXX,PPP // XXXXXX: big endian hex chars // PPP: permissions can be any combo of r w x chars // @@ -3537,74 +3434,73 @@ RNBRemoteShouldCancelCallback (void *not_used) // _M123000,rwx // _M123000,xw -rnb_err_t -RNBRemote::HandlePacket_AllocateMemory (const char *p) -{ - StdStringExtractor packet (p); - packet.SetFilePos(2); // Skip the "_M" - - nub_addr_t size = packet.GetHexMaxU64 (StdStringExtractor::BigEndian, 0); - if (size != 0) - { - if (packet.GetChar() == ',') - { - uint32_t permissions = 0; - char ch; - bool success = true; - while (success && (ch = packet.GetChar()) != '\0') - { - switch (ch) - { - case 'r': permissions |= eMemoryPermissionsReadable; break; - case 'w': permissions |= eMemoryPermissionsWritable; break; - case 'x': permissions |= eMemoryPermissionsExecutable; break; - default: success = false; break; - } - } - - if (success) - { - nub_addr_t addr = DNBProcessMemoryAllocate (m_ctx.ProcessID(), size, permissions); - if (addr != INVALID_NUB_ADDRESS) - { - std::ostringstream ostrm; - ostrm << RAW_HEXBASE << addr; - return SendPacket (ostrm.str ()); - } - } +rnb_err_t RNBRemote::HandlePacket_AllocateMemory(const char *p) { + StdStringExtractor packet(p); + packet.SetFilePos(2); // Skip the "_M" + + nub_addr_t size = packet.GetHexMaxU64(StdStringExtractor::BigEndian, 0); + if (size != 0) { + if (packet.GetChar() == ',') { + uint32_t permissions = 0; + char ch; + bool success = true; + while (success && (ch = packet.GetChar()) != '\0') { + switch (ch) { + case 'r': + permissions |= eMemoryPermissionsReadable; + break; + case 'w': + permissions |= eMemoryPermissionsWritable; + break; + case 'x': + permissions |= eMemoryPermissionsExecutable; + break; + default: + success = false; + break; + } + } + + if (success) { + nub_addr_t addr = + DNBProcessMemoryAllocate(m_ctx.ProcessID(), size, permissions); + if (addr != INVALID_NUB_ADDRESS) { + std::ostringstream ostrm; + ostrm << RAW_HEXBASE << addr; + return SendPacket(ostrm.str()); } + } } - return SendPacket ("E53"); + } + return SendPacket("E53"); } -// FORMAT: _mXXXXXX +// FORMAT: _mXXXXXX // XXXXXX: address that was previously allocated // // RESPONSE: XXXXXX // OK: address was deallocated // EXX: error code // -// EXAMPLES: +// EXAMPLES: // _m123000 -rnb_err_t -RNBRemote::HandlePacket_DeallocateMemory (const char *p) -{ - StdStringExtractor packet (p); - packet.SetFilePos(2); // Skip the "_m" - nub_addr_t addr = packet.GetHexMaxU64 (StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS); +rnb_err_t RNBRemote::HandlePacket_DeallocateMemory(const char *p) { + StdStringExtractor packet(p); + packet.SetFilePos(2); // Skip the "_m" + nub_addr_t addr = + packet.GetHexMaxU64(StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS); - if (addr != INVALID_NUB_ADDRESS) - { - if (DNBProcessMemoryDeallocate (m_ctx.ProcessID(), addr)) - return SendPacket ("OK"); - } - return SendPacket ("E54"); + if (addr != INVALID_NUB_ADDRESS) { + if (DNBProcessMemoryDeallocate(m_ctx.ProcessID(), addr)) + return SendPacket("OK"); + } + return SendPacket("E54"); } - // FORMAT: QSaveRegisterState;thread:TTTT; (when thread suffix is supported) -// FORMAT: QSaveRegisterState (when thread suffix is NOT supported) +// FORMAT: QSaveRegisterState (when thread suffix is NOT +// supported) // TTTT: thread ID in hex // // RESPONSE: @@ -3614,36 +3510,36 @@ RNBRemote::HandlePacket_DeallocateMemory (const char *p) // // EXAMPLES: // QSaveRegisterState;thread:1E34; (when thread suffix is supported) -// QSaveRegisterState (when thread suffix is NOT supported) +// QSaveRegisterState (when thread suffix is NOT +// supported) -rnb_err_t -RNBRemote::HandlePacket_SaveRegisterState (const char *p) -{ - nub_process_t pid = m_ctx.ProcessID (); - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); - if (tid == INVALID_NUB_THREAD) - { - if (m_thread_suffix_supported) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet"); - else - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet"); - } - - // Get the register context size first by calling with NULL buffer - const uint32_t save_id = DNBThreadSaveRegisterState(pid, tid); - if (save_id != 0) - { - char response[64]; - snprintf (response, sizeof(response), "%u", save_id); - return SendPacket (response); - } +rnb_err_t RNBRemote::HandlePacket_SaveRegisterState(const char *p) { + nub_process_t pid = m_ctx.ProcessID(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p); + if (tid == INVALID_NUB_THREAD) { + if (m_thread_suffix_supported) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "No thread specified in QSaveRegisterState packet"); else - { - return SendPacket ("E75"); - } -} -// FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT; (when thread suffix is supported) -// FORMAT: QRestoreRegisterState:SAVEID (when thread suffix is NOT supported) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread was is set with the Hg packet"); + } + + // Get the register context size first by calling with NULL buffer + const uint32_t save_id = DNBThreadSaveRegisterState(pid, tid); + if (save_id != 0) { + char response[64]; + snprintf(response, sizeof(response), "%u", save_id); + return SendPacket(response); + } else { + return SendPacket("E75"); + } +} +// FORMAT: QRestoreRegisterState:SAVEID;thread:TTTT; (when thread suffix is +// supported) +// FORMAT: QRestoreRegisterState:SAVEID (when thread suffix is NOT +// supported) // TTTT: thread ID in hex // SAVEID: a decimal number that represents the save ID that was // returned from a call to "QSaveRegisterState" @@ -3653,109 +3549,113 @@ RNBRemote::HandlePacket_SaveRegisterState (const char *p) // EXX: error code // // EXAMPLES: -// QRestoreRegisterState:1;thread:1E34; (when thread suffix is supported) -// QRestoreRegisterState:1 (when thread suffix is NOT supported) - -rnb_err_t -RNBRemote::HandlePacket_RestoreRegisterState (const char *p) -{ - nub_process_t pid = m_ctx.ProcessID (); - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); - if (tid == INVALID_NUB_THREAD) - { - if (m_thread_suffix_supported) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in QSaveRegisterState packet"); - else - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet"); - } - - StdStringExtractor packet (p); - packet.SetFilePos(strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:" - const uint32_t save_id = packet.GetU32(0); - - if (save_id != 0) - { - // Get the register context size first by calling with NULL buffer - if (DNBThreadRestoreRegisterState(pid, tid, save_id)) - return SendPacket ("OK"); - else - return SendPacket ("E77"); - } - return SendPacket ("E76"); -} +// QRestoreRegisterState:1;thread:1E34; (when thread suffix is +// supported) +// QRestoreRegisterState:1 (when thread suffix is NOT +// supported) + +rnb_err_t RNBRemote::HandlePacket_RestoreRegisterState(const char *p) { + nub_process_t pid = m_ctx.ProcessID(); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p); + if (tid == INVALID_NUB_THREAD) { + if (m_thread_suffix_supported) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "No thread specified in QSaveRegisterState packet"); + else + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread was is set with the Hg packet"); + } -static bool -GetProcessNameFrom_vAttach (const char *&p, std::string &attach_name) -{ - bool return_val = true; - while (*p != '\0') - { - char smallbuf[3]; - smallbuf[0] = *p; - smallbuf[1] = *(p + 1); - smallbuf[2] = '\0'; + StdStringExtractor packet(p); + packet.SetFilePos( + strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:" + const uint32_t save_id = packet.GetU32(0); - errno = 0; - int ch = static_cast<int>(strtoul (smallbuf, NULL, 16)); - if (errno != 0 && ch == 0) - { - return_val = false; - break; - } - - attach_name.push_back(ch); - p += 2; - } - return return_val; + if (save_id != 0) { + // Get the register context size first by calling with NULL buffer + if (DNBThreadRestoreRegisterState(pid, tid, save_id)) + return SendPacket("OK"); + else + return SendPacket("E77"); + } + return SendPacket("E76"); } -rnb_err_t -RNBRemote::HandlePacket_qSupported (const char *p) -{ - uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet size--debugger can always use less - char buf[256]; - snprintf (buf, sizeof(buf), "qXfer:features:read+;PacketSize=%x;qEcho+", max_packet_size); - - // By default, don't enable compression. It's only worth doing when we are working - // with a low speed communication channel. - bool enable_compression = false; - (void)enable_compression; +static bool GetProcessNameFrom_vAttach(const char *&p, + std::string &attach_name) { + bool return_val = true; + while (*p != '\0') { + char smallbuf[3]; + smallbuf[0] = *p; + smallbuf[1] = *(p + 1); + smallbuf[2] = '\0'; - // Enable compression when debugserver is running on a watchOS device where communication may be over Bluetooth. -#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 - enable_compression = true; + errno = 0; + int ch = static_cast<int>(strtoul(smallbuf, NULL, 16)); + if (errno != 0 && ch == 0) { + return_val = false; + break; + } + + attach_name.push_back(ch); + p += 2; + } + return return_val; +} + +rnb_err_t RNBRemote::HandlePacket_qSupported(const char *p) { + uint32_t max_packet_size = 128 * 1024; // 128KBytes is a reasonable max packet + // size--debugger can always use less + char buf[256]; + snprintf(buf, sizeof(buf), "qXfer:features:read+;PacketSize=%x;qEcho+", + max_packet_size); + + // By default, don't enable compression. It's only worth doing when we are + // working + // with a low speed communication channel. + bool enable_compression = false; + (void)enable_compression; + +// Enable compression when debugserver is running on a watchOS device where +// communication may be over Bluetooth. +#if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + enable_compression = true; #endif -#if defined (HAVE_LIBCOMPRESSION) - // libcompression is weak linked so test if compression_decode_buffer() is available - if (enable_compression && compression_decode_buffer != NULL) - { - strcat (buf, ";SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;DefaultCompressionMinSize="); - char numbuf[16]; - snprintf (numbuf, sizeof (numbuf), "%zu", m_compression_minsize); - numbuf[sizeof (numbuf) - 1] = '\0'; - strcat (buf, numbuf); - } -#elif defined (HAVE_LIBZ) - if (enable_compression) - { - strcat (buf, ";SupportedCompressions=zlib-deflate;DefaultCompressionMinSize="); - char numbuf[16]; - snprintf (numbuf, sizeof (numbuf), "%zu", m_compression_minsize); - numbuf[sizeof (numbuf) - 1] = '\0'; - strcat (buf, numbuf); - } +#if defined(HAVE_LIBCOMPRESSION) + // libcompression is weak linked so test if compression_decode_buffer() is + // available + if (enable_compression && compression_decode_buffer != NULL) { + strcat(buf, ";SupportedCompressions=lzfse,zlib-deflate,lz4,lzma;" + "DefaultCompressionMinSize="); + char numbuf[16]; + snprintf(numbuf, sizeof(numbuf), "%zu", m_compression_minsize); + numbuf[sizeof(numbuf) - 1] = '\0'; + strcat(buf, numbuf); + } +#elif defined(HAVE_LIBZ) + if (enable_compression) { + strcat(buf, + ";SupportedCompressions=zlib-deflate;DefaultCompressionMinSize="); + char numbuf[16]; + snprintf(numbuf, sizeof(numbuf), "%zu", m_compression_minsize); + numbuf[sizeof(numbuf) - 1] = '\0'; + strcat(buf, numbuf); + } #endif - return SendPacket (buf); + return SendPacket(buf); } /* vAttach;pid - Attach to a new process with the specified process ID. pid is a hexadecimal integer + Attach to a new process with the specified process ID. pid is a hexadecimal + integer identifying the process. If the stub is currently controlling a process, it is - killed. The attached process is stopped.This packet is only available in extended + killed. The attached process is stopped.This packet is only available in + extended mode (see extended mode). Reply: @@ -3763,1351 +3663,1317 @@ RNBRemote::HandlePacket_qSupported (const char *p) "Any Stop Reply Packet" for success */ -rnb_err_t -RNBRemote::HandlePacket_v (const char *p) -{ - if (strcmp (p, "vCont;c") == 0) - { - // Simple continue - return RNBRemote::HandlePacket_c("c"); - } - else if (strcmp (p, "vCont;s") == 0) - { - // Simple step - return RNBRemote::HandlePacket_s("s"); - } - else if (strstr (p, "vCont") == p) - { - DNBThreadResumeActions thread_actions; - char *c = (char *)(p += strlen("vCont")); - char *c_end = c + strlen(c); - if (*c == '?') - return SendPacket ("vCont;c;C;s;S"); +rnb_err_t RNBRemote::HandlePacket_v(const char *p) { + if (strcmp(p, "vCont;c") == 0) { + // Simple continue + return RNBRemote::HandlePacket_c("c"); + } else if (strcmp(p, "vCont;s") == 0) { + // Simple step + return RNBRemote::HandlePacket_s("s"); + } else if (strstr(p, "vCont") == p) { + DNBThreadResumeActions thread_actions; + char *c = (char *)(p += strlen("vCont")); + char *c_end = c + strlen(c); + if (*c == '?') + return SendPacket("vCont;c;C;s;S"); + + while (c < c_end && *c == ';') { + ++c; // Skip the semi-colon + DNBThreadResumeAction thread_action; + thread_action.tid = INVALID_NUB_THREAD; + thread_action.state = eStateInvalid; + thread_action.signal = 0; + thread_action.addr = INVALID_NUB_ADDRESS; + + char action = *c++; + + switch (action) { + case 'C': + errno = 0; + thread_action.signal = static_cast<int>(strtoul(c, &c, 16)); + if (errno != 0) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "Could not parse signal in vCont packet"); + // Fall through to next case... - while (c < c_end && *c == ';') - { - ++c; // Skip the semi-colon - DNBThreadResumeAction thread_action; - thread_action.tid = INVALID_NUB_THREAD; - thread_action.state = eStateInvalid; - thread_action.signal = 0; - thread_action.addr = INVALID_NUB_ADDRESS; + case 'c': + // Continue + thread_action.state = eStateRunning; + break; - char action = *c++; + case 'S': + errno = 0; + thread_action.signal = static_cast<int>(strtoul(c, &c, 16)); + if (errno != 0) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "Could not parse signal in vCont packet"); + // Fall through to next case... - switch (action) - { - case 'C': - errno = 0; - thread_action.signal = static_cast<int>(strtoul (c, &c, 16)); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse signal in vCont packet"); - // Fall through to next case... - - case 'c': - // Continue - thread_action.state = eStateRunning; - break; - - case 'S': - errno = 0; - thread_action.signal = static_cast<int>(strtoul (c, &c, 16)); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse signal in vCont packet"); - // Fall through to next case... - - case 's': - // Step - thread_action.state = eStateStepping; - break; - - default: - HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Unsupported action in vCont packet"); - break; - } - if (*c == ':') - { - errno = 0; - thread_action.tid = strtoul (++c, &c, 16); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse thread number in vCont packet"); - } + case 's': + // Step + thread_action.state = eStateStepping; + break; - thread_actions.Append (thread_action); - } + default: + HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Unsupported action in vCont packet"); + break; + } + if (*c == ':') { + errno = 0; + thread_action.tid = strtoul(++c, &c, 16); + if (errno != 0) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "Could not parse thread number in vCont packet"); + } - // If a default action for all other threads wasn't mentioned - // then we should stop the threads - thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); - DNBProcessResume(m_ctx.ProcessID(), thread_actions.GetFirst (), thread_actions.GetSize()); - return rnb_success; + thread_actions.Append(thread_action); } - else if (strstr (p, "vAttach") == p) - { - nub_process_t attach_pid = INVALID_NUB_PROCESS; // attach_pid will be set to 0 if the attach fails - nub_process_t pid_attaching_to = INVALID_NUB_PROCESS; // pid_attaching_to is the original pid specified - char err_str[1024]={'\0'}; - std::string attach_name; - - if (strstr (p, "vAttachWait;") == p) - { - p += strlen("vAttachWait;"); - if (!GetProcessNameFrom_vAttach(p, attach_name)) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt"); - } - const bool ignore_existing = true; - attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); - } - else if (strstr (p, "vAttachOrWait;") == p) - { - p += strlen("vAttachOrWait;"); - if (!GetProcessNameFrom_vAttach(p, attach_name)) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachOrWait' pkt"); - } - const bool ignore_existing = false; - attach_pid = DNBProcessAttachWait(attach_name.c_str (), m_ctx.LaunchFlavor(), ignore_existing, NULL, 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); - } - else if (strstr (p, "vAttachName;") == p) - { - p += strlen("vAttachName;"); - if (!GetProcessNameFrom_vAttach(p, attach_name)) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt"); - } + // If a default action for all other threads wasn't mentioned + // then we should stop the threads + thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + DNBProcessResume(m_ctx.ProcessID(), thread_actions.GetFirst(), + thread_actions.GetSize()); + return rnb_success; + } else if (strstr(p, "vAttach") == p) { + nub_process_t attach_pid = + INVALID_NUB_PROCESS; // attach_pid will be set to 0 if the attach fails + nub_process_t pid_attaching_to = + INVALID_NUB_PROCESS; // pid_attaching_to is the original pid specified + char err_str[1024] = {'\0'}; + std::string attach_name; + + if (strstr(p, "vAttachWait;") == p) { + p += strlen("vAttachWait;"); + if (!GetProcessNameFrom_vAttach(p, attach_name)) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachWait' pkt"); + } + const bool ignore_existing = true; + attach_pid = DNBProcessAttachWait( + attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, + 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + + } else if (strstr(p, "vAttachOrWait;") == p) { + p += strlen("vAttachOrWait;"); + if (!GetProcessNameFrom_vAttach(p, attach_name)) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "non-hex char in arg on 'vAttachOrWait' pkt"); + } + const bool ignore_existing = false; + attach_pid = DNBProcessAttachWait( + attach_name.c_str(), m_ctx.LaunchFlavor(), ignore_existing, NULL, + 1000, err_str, sizeof(err_str), RNBRemoteShouldCancelCallback); + } else if (strstr(p, "vAttachName;") == p) { + p += strlen("vAttachName;"); + if (!GetProcessNameFrom_vAttach(p, attach_name)) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "non-hex char in arg on 'vAttachName' pkt"); + } - attach_pid = DNBProcessAttachByName (attach_name.c_str(), NULL, err_str, sizeof(err_str)); + attach_pid = DNBProcessAttachByName(attach_name.c_str(), NULL, err_str, + sizeof(err_str)); + + } else if (strstr(p, "vAttach;") == p) { + p += strlen("vAttach;"); + char *end = NULL; + pid_attaching_to = static_cast<int>( + strtoul(p, &end, 16)); // PID will be in hex, so use base 16 to decode + if (p != end && *end == '\0') { + // Wait at most 30 second for attach + struct timespec attach_timeout_abstime; + DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0); + attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime, + err_str, sizeof(err_str)); + } + } else { + return HandlePacket_UNIMPLEMENTED(p); + } + + if (attach_pid != INVALID_NUB_PROCESS) { + if (m_ctx.ProcessID() != attach_pid) + m_ctx.SetProcessID(attach_pid); + // Send a stop reply packet to indicate we successfully attached! + NotifyThatProcessStopped(); + return rnb_success; + } else { + m_ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + m_ctx.LaunchStatus().SetErrorString(err_str); + else + m_ctx.LaunchStatus().SetErrorString("attach failed"); + +#if defined(__APPLE__) && \ + (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) + if (pid_attaching_to == INVALID_NUB_PROCESS && !attach_name.empty()) { + pid_attaching_to = DNBProcessGetPIDByName(attach_name.c_str()); + } + if (pid_attaching_to != INVALID_NUB_PROCESS && + strcmp(err_str, "No such process") != 0) { + // csr_check(CSR_ALLOW_TASK_FOR_PID) will be nonzero if System Integrity + // Protection is in effect. + if (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0) { + bool attach_failed_due_to_sip = false; + + if (rootless_allows_task_for_pid(pid_attaching_to) == 0) { + attach_failed_due_to_sip = true; + } - } - else if (strstr (p, "vAttach;") == p) - { - p += strlen("vAttach;"); - char *end = NULL; - pid_attaching_to = static_cast<int>(strtoul (p, &end, 16)); // PID will be in hex, so use base 16 to decode - if (p != end && *end == '\0') - { - // Wait at most 30 second for attach - struct timespec attach_timeout_abstime; - DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, 30, 0); - attach_pid = DNBProcessAttach(pid_attaching_to, &attach_timeout_abstime, err_str, sizeof(err_str)); + if (attach_failed_due_to_sip == false) { + int csops_flags = 0; + int retval = ::csops(pid_attaching_to, CS_OPS_STATUS, &csops_flags, + sizeof(csops_flags)); + if (retval != -1 && (csops_flags & CS_RESTRICT)) { + attach_failed_due_to_sip = true; } + } + if (attach_failed_due_to_sip) { + SendPacket("E87"); // E87 is the magic value which says that we are + // not allowed to attach + DNBLogError("Attach failed because process does not allow " + "attaching: \"%s\".", + err_str); + return rnb_err; + } } - else - { - return HandlePacket_UNIMPLEMENTED(p); - } - - - if (attach_pid != INVALID_NUB_PROCESS) - { - if (m_ctx.ProcessID() != attach_pid) - m_ctx.SetProcessID(attach_pid); - // Send a stop reply packet to indicate we successfully attached! - NotifyThatProcessStopped (); - return rnb_success; - } - else - { - m_ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - m_ctx.LaunchStatus().SetErrorString(err_str); - else - m_ctx.LaunchStatus().SetErrorString("attach failed"); + } -#if defined (__APPLE__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 101000) - if (pid_attaching_to == INVALID_NUB_PROCESS && !attach_name.empty()) - { - pid_attaching_to = DNBProcessGetPIDByName (attach_name.c_str()); - } - if (pid_attaching_to != INVALID_NUB_PROCESS && strcmp (err_str, "No such process") != 0) - { - // csr_check(CSR_ALLOW_TASK_FOR_PID) will be nonzero if System Integrity Protection is in effect. - if (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0) - { - bool attach_failed_due_to_sip = false; - - if (rootless_allows_task_for_pid (pid_attaching_to) == 0) - { - attach_failed_due_to_sip = true; - } - - if (attach_failed_due_to_sip == false) - { - int csops_flags = 0; - int retval = ::csops (pid_attaching_to, CS_OPS_STATUS, &csops_flags, sizeof (csops_flags)); - if (retval != -1 && (csops_flags & CS_RESTRICT)) - { - attach_failed_due_to_sip = true; - } - } - if (attach_failed_due_to_sip) - { - SendPacket ("E87"); // E87 is the magic value which says that we are not allowed to attach - DNBLogError ("Attach failed because process does not allow attaching: \"%s\".", err_str); - return rnb_err; - } - } - } - #endif - SendPacket ("E01"); // E01 is our magic error value for attach failed. - DNBLogError ("Attach failed: \"%s\".", err_str); - return rnb_err; - } + SendPacket("E01"); // E01 is our magic error value for attach failed. + DNBLogError("Attach failed: \"%s\".", err_str); + return rnb_err; } + } - // All other failures come through here - return HandlePacket_UNIMPLEMENTED(p); + // All other failures come through here + return HandlePacket_UNIMPLEMENTED(p); } /* 'T XX' -- status of thread Check if the specified thread is alive. The thread number is in hex? */ -rnb_err_t -RNBRemote::HandlePacket_T (const char *p) -{ - p++; - if (p == NULL || *p == '\0') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in T packet"); - } - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E15"); - } - errno = 0; - nub_thread_t tid = strtoul (p, NULL, 16); - if (errno != 0 && tid == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse thread number in T packet"); - } - - nub_state_t state = DNBThreadGetState (m_ctx.ProcessID(), tid); - if (state == eStateInvalid || state == eStateExited || state == eStateCrashed) - { - return SendPacket ("E16"); - } - - return SendPacket ("OK"); -} - - -rnb_err_t -RNBRemote::HandlePacket_z (const char *p) -{ - if (p == NULL || *p == '\0') - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in z packet"); - - if (!m_ctx.HasValidProcessID()) - return SendPacket ("E15"); - - char packet_cmd = *p++; - char break_type = *p++; - - if (*p++ != ',') - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma separator missing in z packet"); - - char *c = NULL; - nub_process_t pid = m_ctx.ProcessID(); - errno = 0; - nub_addr_t addr = strtoull (p, &c, 16); - if (errno != 0 && addr == 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in z packet"); - p = c; - if (*p++ != ',') - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Comma separator missing in z packet"); - - errno = 0; - auto byte_size = strtoul (p, &c, 16); - if (errno != 0 && byte_size == 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid length in z packet"); - - if (packet_cmd == 'Z') - { - // set - switch (break_type) - { - case '0': // set software breakpoint - case '1': // set hardware breakpoint - { - // gdb can send multiple Z packets for the same address and - // these calls must be ref counted. - bool hardware = (break_type == '1'); - - if (DNBBreakpointSet (pid, addr, byte_size, hardware)) - { - // We successfully created a breakpoint, now lets full out - // a ref count structure with the breakID and add it to our - // map. - return SendPacket ("OK"); - } - else - { - // We failed to set the software breakpoint - return SendPacket ("E09"); - } - } - break; - - case '2': // set write watchpoint - case '3': // set read watchpoint - case '4': // set access watchpoint - { - bool hardware = true; - uint32_t watch_flags = 0; - if (break_type == '2') - watch_flags = WATCH_TYPE_WRITE; - else if (break_type == '3') - watch_flags = WATCH_TYPE_READ; - else - watch_flags = WATCH_TYPE_READ | WATCH_TYPE_WRITE; - - if (DNBWatchpointSet (pid, addr, byte_size, watch_flags, hardware)) - { - return SendPacket ("OK"); - } - else - { - // We failed to set the watchpoint - return SendPacket ("E09"); - } - } - break; +rnb_err_t RNBRemote::HandlePacket_T(const char *p) { + p++; + if (p == NULL || *p == '\0') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in T packet"); + } + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E15"); + } + errno = 0; + nub_thread_t tid = strtoul(p, NULL, 16); + if (errno != 0 && tid == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse thread number in T packet"); + } + + nub_state_t state = DNBThreadGetState(m_ctx.ProcessID(), tid); + if (state == eStateInvalid || state == eStateExited || + state == eStateCrashed) { + return SendPacket("E16"); + } + + return SendPacket("OK"); +} + +rnb_err_t RNBRemote::HandlePacket_z(const char *p) { + if (p == NULL || *p == '\0') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in z packet"); + + if (!m_ctx.HasValidProcessID()) + return SendPacket("E15"); + + char packet_cmd = *p++; + char break_type = *p++; + + if (*p++ != ',') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma separator missing in z packet"); + + char *c = NULL; + nub_process_t pid = m_ctx.ProcessID(); + errno = 0; + nub_addr_t addr = strtoull(p, &c, 16); + if (errno != 0 && addr == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid address in z packet"); + p = c; + if (*p++ != ',') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Comma separator missing in z packet"); + + errno = 0; + auto byte_size = strtoul(p, &c, 16); + if (errno != 0 && byte_size == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Invalid length in z packet"); + + if (packet_cmd == 'Z') { + // set + switch (break_type) { + case '0': // set software breakpoint + case '1': // set hardware breakpoint + { + // gdb can send multiple Z packets for the same address and + // these calls must be ref counted. + bool hardware = (break_type == '1'); + + if (DNBBreakpointSet(pid, addr, byte_size, hardware)) { + // We successfully created a breakpoint, now lets full out + // a ref count structure with the breakID and add it to our + // map. + return SendPacket("OK"); + } else { + // We failed to set the software breakpoint + return SendPacket("E09"); + } + } break; + + case '2': // set write watchpoint + case '3': // set read watchpoint + case '4': // set access watchpoint + { + bool hardware = true; + uint32_t watch_flags = 0; + if (break_type == '2') + watch_flags = WATCH_TYPE_WRITE; + else if (break_type == '3') + watch_flags = WATCH_TYPE_READ; + else + watch_flags = WATCH_TYPE_READ | WATCH_TYPE_WRITE; + + if (DNBWatchpointSet(pid, addr, byte_size, watch_flags, hardware)) { + return SendPacket("OK"); + } else { + // We failed to set the watchpoint + return SendPacket("E09"); + } + } break; - default: - break; - } - } - else if (packet_cmd == 'z') - { - // remove - switch (break_type) - { - case '0': // remove software breakpoint - case '1': // remove hardware breakpoint - if (DNBBreakpointClear (pid, addr)) - { - return SendPacket ("OK"); - } - else - { - return SendPacket ("E08"); - } - break; + default: + break; + } + } else if (packet_cmd == 'z') { + // remove + switch (break_type) { + case '0': // remove software breakpoint + case '1': // remove hardware breakpoint + if (DNBBreakpointClear(pid, addr)) { + return SendPacket("OK"); + } else { + return SendPacket("E08"); + } + break; - case '2': // remove write watchpoint - case '3': // remove read watchpoint - case '4': // remove access watchpoint - if (DNBWatchpointClear (pid, addr)) - { - return SendPacket ("OK"); - } - else - { - return SendPacket ("E08"); - } - break; + case '2': // remove write watchpoint + case '3': // remove read watchpoint + case '4': // remove access watchpoint + if (DNBWatchpointClear(pid, addr)) { + return SendPacket("OK"); + } else { + return SendPacket("E08"); + } + break; - default: - break; - } + default: + break; } - return HandlePacket_UNIMPLEMENTED(p); + } + return HandlePacket_UNIMPLEMENTED(p); } // Extract the thread number from the thread suffix that might be appended to -// thread specific packets. This will only be enabled if m_thread_suffix_supported +// thread specific packets. This will only be enabled if +// m_thread_suffix_supported // is true. -nub_thread_t -RNBRemote::ExtractThreadIDFromThreadSuffix (const char *p) -{ - if (m_thread_suffix_supported) - { - nub_thread_t tid = INVALID_NUB_THREAD; - if (p) - { - const char *tid_cstr = strstr (p, "thread:"); - if (tid_cstr) - { - tid_cstr += strlen ("thread:"); - tid = strtoul(tid_cstr, NULL, 16); - } - } - return tid; +nub_thread_t RNBRemote::ExtractThreadIDFromThreadSuffix(const char *p) { + if (m_thread_suffix_supported) { + nub_thread_t tid = INVALID_NUB_THREAD; + if (p) { + const char *tid_cstr = strstr(p, "thread:"); + if (tid_cstr) { + tid_cstr += strlen("thread:"); + tid = strtoul(tid_cstr, NULL, 16); + } } - return GetCurrentThread(); - + return tid; + } + return GetCurrentThread(); } /* 'p XX' print the contents of register X */ -rnb_err_t -RNBRemote::HandlePacket_p (const char *p) -{ - if (g_num_reg_entries == 0) - InitializeRegisters (); - - if (p == NULL || *p == '\0') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in p packet"); - } - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E15"); - } - nub_process_t pid = m_ctx.ProcessID(); - errno = 0; - char *tid_cstr = NULL; - uint32_t reg = static_cast<uint32_t>(strtoul (p + 1, &tid_cstr, 16)); - if (errno != 0 && reg == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse register number in p packet"); - } - - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (tid_cstr); - if (tid == INVALID_NUB_THREAD) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in p packet"); - - const register_map_entry_t *reg_entry; - - if (reg < g_num_reg_entries) - reg_entry = &g_reg_entries[reg]; - else - reg_entry = NULL; - - std::ostringstream ostrm; - if (reg_entry == NULL) - { - DNBLogError("RNBRemote::HandlePacket_p(%s): unknown register number %u requested\n", p, reg); - ostrm << "00000000"; - } - else if (reg_entry->nub_info.reg == (uint32_t)-1) - { - if (reg_entry->nub_info.size > 0) - { - std::basic_string<uint8_t> zeros(reg_entry->nub_info.size, '\0'); - append_hex_value(ostrm, zeros.data(), zeros.size(), false); - } - } - else - { - register_value_in_hex_fixed_width (ostrm, pid, tid, reg_entry, NULL); - } - return SendPacket (ostrm.str()); +rnb_err_t RNBRemote::HandlePacket_p(const char *p) { + if (g_num_reg_entries == 0) + InitializeRegisters(); + + if (p == NULL || *p == '\0') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in p packet"); + } + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E15"); + } + nub_process_t pid = m_ctx.ProcessID(); + errno = 0; + char *tid_cstr = NULL; + uint32_t reg = static_cast<uint32_t>(strtoul(p + 1, &tid_cstr, 16)); + if (errno != 0 && reg == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "Could not parse register number in p packet"); + } + + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(tid_cstr); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in p packet"); + + const register_map_entry_t *reg_entry; + + if (reg < g_num_reg_entries) + reg_entry = &g_reg_entries[reg]; + else + reg_entry = NULL; + + std::ostringstream ostrm; + if (reg_entry == NULL) { + DNBLogError( + "RNBRemote::HandlePacket_p(%s): unknown register number %u requested\n", + p, reg); + ostrm << "00000000"; + } else if (reg_entry->nub_info.reg == (uint32_t)-1) { + if (reg_entry->nub_info.size > 0) { + std::basic_string<uint8_t> zeros(reg_entry->nub_info.size, '\0'); + append_hex_value(ostrm, zeros.data(), zeros.size(), false); + } + } else { + register_value_in_hex_fixed_width(ostrm, pid, tid, reg_entry, NULL); + } + return SendPacket(ostrm.str()); } /* 'Pnn=rrrrr' Set register number n to value r. n and r are hex strings. */ -rnb_err_t -RNBRemote::HandlePacket_P (const char *p) -{ - if (g_num_reg_entries == 0) - InitializeRegisters (); +rnb_err_t RNBRemote::HandlePacket_P(const char *p) { + if (g_num_reg_entries == 0) + InitializeRegisters(); - if (p == NULL || *p == '\0') - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Empty P packet"); - } - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E28"); - } + if (p == NULL || *p == '\0') { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, "Empty P packet"); + } + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E28"); + } - nub_process_t pid = m_ctx.ProcessID(); + nub_process_t pid = m_ctx.ProcessID(); - StdStringExtractor packet (p); + StdStringExtractor packet(p); - const char cmd_char = packet.GetChar(); - // Register ID is always in big endian - const uint32_t reg = packet.GetHexMaxU32 (false, UINT32_MAX); - const char equal_char = packet.GetChar(); + const char cmd_char = packet.GetChar(); + // Register ID is always in big endian + const uint32_t reg = packet.GetHexMaxU32(false, UINT32_MAX); + const char equal_char = packet.GetChar(); - if (cmd_char != 'P') - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Improperly formed P packet"); + if (cmd_char != 'P') + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Improperly formed P packet"); - if (reg == UINT32_MAX) - return SendPacket ("E29"); + if (reg == UINT32_MAX) + return SendPacket("E29"); - if (equal_char != '=') - return SendPacket ("E30"); + if (equal_char != '=') + return SendPacket("E30"); - const register_map_entry_t *reg_entry; + const register_map_entry_t *reg_entry; - if (reg >= g_num_reg_entries) - return SendPacket("E47"); + if (reg >= g_num_reg_entries) + return SendPacket("E47"); - reg_entry = &g_reg_entries[reg]; + reg_entry = &g_reg_entries[reg]; - if (reg_entry->nub_info.set == (uint32_t)-1 && reg_entry->nub_info.reg == (uint32_t)-1) - { - DNBLogError("RNBRemote::HandlePacket_P(%s): unknown register number %u requested\n", p, reg); - return SendPacket("E48"); - } + if (reg_entry->nub_info.set == (uint32_t)-1 && + reg_entry->nub_info.reg == (uint32_t)-1) { + DNBLogError( + "RNBRemote::HandlePacket_P(%s): unknown register number %u requested\n", + p, reg); + return SendPacket("E48"); + } - DNBRegisterValue reg_value; - reg_value.info = reg_entry->nub_info; - packet.GetHexBytes (reg_value.value.v_sint8, reg_entry->nub_info.size, 0xcc); + DNBRegisterValue reg_value; + reg_value.info = reg_entry->nub_info; + packet.GetHexBytes(reg_value.value.v_sint8, reg_entry->nub_info.size, 0xcc); - nub_thread_t tid = ExtractThreadIDFromThreadSuffix (p); - if (tid == INVALID_NUB_THREAD) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread specified in p packet"); + nub_thread_t tid = ExtractThreadIDFromThreadSuffix(p); + if (tid == INVALID_NUB_THREAD) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "No thread specified in p packet"); - if (!DNBThreadSetRegisterValueByID (pid, tid, reg_entry->nub_info.set, reg_entry->nub_info.reg, ®_value)) - { - return SendPacket ("E32"); - } - return SendPacket ("OK"); + if (!DNBThreadSetRegisterValueByID(pid, tid, reg_entry->nub_info.set, + reg_entry->nub_info.reg, ®_value)) { + return SendPacket("E32"); + } + return SendPacket("OK"); } /* 'c [addr]' Continue, optionally from a specified address. */ -rnb_err_t -RNBRemote::HandlePacket_c (const char *p) -{ - const nub_process_t pid = m_ctx.ProcessID(); - - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("E23"); +rnb_err_t RNBRemote::HandlePacket_c(const char *p) { + const nub_process_t pid = m_ctx.ProcessID(); - DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateRunning, 0, INVALID_NUB_ADDRESS }; + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E23"); - if (*(p + 1) != '\0') - { - action.tid = GetContinueThread(); - errno = 0; - action.addr = strtoull (p + 1, NULL, 16); - if (errno != 0 && action.addr == 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse address in c packet"); - } + DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateRunning, 0, + INVALID_NUB_ADDRESS}; - DNBThreadResumeActions thread_actions; - thread_actions.Append(action); - thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); - if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize())) - return SendPacket ("E25"); - // Don't send an "OK" packet; response is the stopped/exited message. - return rnb_success; + if (*(p + 1) != '\0') { + action.tid = GetContinueThread(); + errno = 0; + action.addr = strtoull(p + 1, NULL, 16); + if (errno != 0 && action.addr == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse address in c packet"); + } + + DNBThreadResumeActions thread_actions; + thread_actions.Append(action); + thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, 0); + if (!DNBProcessResume(pid, thread_actions.GetFirst(), + thread_actions.GetSize())) + return SendPacket("E25"); + // Don't send an "OK" packet; response is the stopped/exited message. + return rnb_success; +} + +rnb_err_t RNBRemote::HandlePacket_MemoryRegionInfo(const char *p) { + /* This packet will find memory attributes (e.g. readable, writable, + executable, stack, jitted code) + for the memory region containing a given address and return that + information. + + Users of this packet must be prepared for three results: + + Region information is returned + Region information is unavailable for this address because the address + is in unmapped memory + Region lookup cannot be performed on this platform or process is not + yet launched + This packet isn't implemented + + Examples of use: + qMemoryRegionInfo:3a55140 + start:3a50000,size:100000,permissions:rwx + + qMemoryRegionInfo:0 + error:address in unmapped region + + qMemoryRegionInfo:3a551140 (on a different platform) + error:region lookup cannot be performed + + qMemoryRegionInfo + OK // this packet is implemented by the remote nub + */ + + p += sizeof("qMemoryRegionInfo") - 1; + if (*p == '\0') + return SendPacket("OK"); + if (*p++ != ':') + return SendPacket("E67"); + if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) + p += 2; + + errno = 0; + uint64_t address = strtoul(p, NULL, 16); + if (errno != 0 && address == 0) { + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, "Invalid address in qMemoryRegionInfo packet"); + } + + DNBRegionInfo region_info = {0, 0, 0}; + DNBProcessMemoryRegionInfo(m_ctx.ProcessID(), address, ®ion_info); + std::ostringstream ostrm; + + // start:3a50000,size:100000,permissions:rwx + ostrm << "start:" << std::hex << region_info.addr << ';'; + + if (region_info.size > 0) + ostrm << "size:" << std::hex << region_info.size << ';'; + + if (region_info.permissions) { + ostrm << "permissions:"; + + if (region_info.permissions & eMemoryPermissionsReadable) + ostrm << 'r'; + if (region_info.permissions & eMemoryPermissionsWritable) + ostrm << 'w'; + if (region_info.permissions & eMemoryPermissionsExecutable) + ostrm << 'x'; + ostrm << ';'; + } + return SendPacket(ostrm.str()); } -rnb_err_t -RNBRemote::HandlePacket_MemoryRegionInfo (const char *p) -{ - /* This packet will find memory attributes (e.g. readable, writable, executable, stack, jitted code) - for the memory region containing a given address and return that information. - - Users of this packet must be prepared for three results: - - Region information is returned - Region information is unavailable for this address because the address is in unmapped memory - Region lookup cannot be performed on this platform or process is not yet launched - This packet isn't implemented - - Examples of use: - qMemoryRegionInfo:3a55140 - start:3a50000,size:100000,permissions:rwx - - qMemoryRegionInfo:0 - error:address in unmapped region - - qMemoryRegionInfo:3a551140 (on a different platform) - error:region lookup cannot be performed - - qMemoryRegionInfo - OK // this packet is implemented by the remote nub - */ - - p += sizeof ("qMemoryRegionInfo") - 1; - if (*p == '\0') - return SendPacket ("OK"); - if (*p++ != ':') - return SendPacket ("E67"); - if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X')) - p += 2; +// qGetProfileData;scan_type:0xYYYYYYY +rnb_err_t RNBRemote::HandlePacket_GetProfileData(const char *p) { + nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("OK"); - errno = 0; - uint64_t address = strtoul (p, NULL, 16); - if (errno != 0 && address == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Invalid address in qMemoryRegionInfo packet"); + StdStringExtractor packet(p += sizeof("qGetProfileData")); + DNBProfileDataScanType scan_type = eProfileAll; + std::string name; + std::string value; + while (packet.GetNameColonValue(name, value)) { + if (name.compare("scan_type") == 0) { + std::istringstream iss(value); + uint32_t int_value = 0; + if (iss >> std::hex >> int_value) { + scan_type = (DNBProfileDataScanType)int_value; + } } + } - DNBRegionInfo region_info = { 0, 0, 0 }; - DNBProcessMemoryRegionInfo (m_ctx.ProcessID(), address, ®ion_info); - std::ostringstream ostrm; + std::string data = DNBProcessGetProfileData(pid, scan_type); + if (!data.empty()) { + return SendPacket(data.c_str()); + } else { + return SendPacket("OK"); + } +} - // start:3a50000,size:100000,permissions:rwx - ostrm << "start:" << std::hex << region_info.addr << ';'; +// QSetEnableAsyncProfiling;enable:[0|1]:interval_usec:XXXXXX;scan_type:0xYYYYYYY +rnb_err_t RNBRemote::HandlePacket_SetEnableAsyncProfiling(const char *p) { + nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("OK"); - if (region_info.size > 0) - ostrm << "size:" << std::hex << region_info.size << ';'; - - if (region_info.permissions) - { - ostrm << "permissions:"; - - if (region_info.permissions & eMemoryPermissionsReadable) - ostrm << 'r'; - if (region_info.permissions & eMemoryPermissionsWritable) - ostrm << 'w'; - if (region_info.permissions & eMemoryPermissionsExecutable) - ostrm << 'x'; - ostrm << ';'; + StdStringExtractor packet(p += sizeof("QSetEnableAsyncProfiling")); + bool enable = false; + uint64_t interval_usec = 0; + DNBProfileDataScanType scan_type = eProfileAll; + std::string name; + std::string value; + while (packet.GetNameColonValue(name, value)) { + if (name.compare("enable") == 0) { + enable = strtoul(value.c_str(), NULL, 10) > 0; + } else if (name.compare("interval_usec") == 0) { + interval_usec = strtoul(value.c_str(), NULL, 10); + } else if (name.compare("scan_type") == 0) { + std::istringstream iss(value); + uint32_t int_value = 0; + if (iss >> std::hex >> int_value) { + scan_type = (DNBProfileDataScanType)int_value; + } } - return SendPacket (ostrm.str()); -} + } -// qGetProfileData;scan_type:0xYYYYYYY -rnb_err_t -RNBRemote::HandlePacket_GetProfileData (const char *p) -{ - nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("OK"); - - StdStringExtractor packet(p += sizeof ("qGetProfileData")); - DNBProfileDataScanType scan_type = eProfileAll; - std::string name; - std::string value; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("scan_type") == 0) - { - std::istringstream iss(value); - uint32_t int_value = 0; - if (iss >> std::hex >> int_value) - { - scan_type = (DNBProfileDataScanType)int_value; - } - } - } - - std::string data = DNBProcessGetProfileData(pid, scan_type); - if (!data.empty()) - { - return SendPacket (data.c_str()); - } - else - { - return SendPacket ("OK"); - } -} + if (interval_usec == 0) { + enable = 0; + } -// QSetEnableAsyncProfiling;enable:[0|1]:interval_usec:XXXXXX;scan_type:0xYYYYYYY -rnb_err_t -RNBRemote::HandlePacket_SetEnableAsyncProfiling (const char *p) -{ - nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("OK"); - - StdStringExtractor packet(p += sizeof ("QSetEnableAsyncProfiling")); - bool enable = false; - uint64_t interval_usec = 0; - DNBProfileDataScanType scan_type = eProfileAll; - std::string name; - std::string value; - while (packet.GetNameColonValue(name, value)) - { - if (name.compare ("enable") == 0) - { - enable = strtoul(value.c_str(), NULL, 10) > 0; - } - else if (name.compare ("interval_usec") == 0) - { - interval_usec = strtoul(value.c_str(), NULL, 10); - } - else if (name.compare ("scan_type") == 0) - { - std::istringstream iss(value); - uint32_t int_value = 0; - if (iss >> std::hex >> int_value) - { - scan_type = (DNBProfileDataScanType)int_value; - } - } - } - - if (interval_usec == 0) - { - enable = 0; - } - - DNBProcessSetEnableAsyncProfiling(pid, enable, interval_usec, scan_type); - return SendPacket ("OK"); + DNBProcessSetEnableAsyncProfiling(pid, enable, interval_usec, scan_type); + return SendPacket("OK"); } -// QEnableCompression:type:<COMPRESSION-TYPE>;minsize:<MINIMUM PACKET SIZE TO COMPRESS>; +// QEnableCompression:type:<COMPRESSION-TYPE>;minsize:<MINIMUM PACKET SIZE TO +// COMPRESS>; // -// type: must be a type previously reported by the qXfer:features: SupportedCompressions list +// type: must be a type previously reported by the qXfer:features: +// SupportedCompressions list // -// minsize: is optional; by default the qXfer:features: DefaultCompressionMinSize value is used -// debugserver may have a better idea of what a good minimum packet size to compress is than lldb. - -rnb_err_t -RNBRemote::HandlePacket_QEnableCompression (const char *p) -{ - p += sizeof ("QEnableCompression:") - 1; - - size_t new_compression_minsize = m_compression_minsize; - const char *new_compression_minsize_str = strstr (p, "minsize:"); - if (new_compression_minsize_str) - { - new_compression_minsize_str += strlen ("minsize:"); - errno = 0; - new_compression_minsize = strtoul (new_compression_minsize_str, NULL, 10); - if (errno != 0 || new_compression_minsize == ULONG_MAX) - { - new_compression_minsize = m_compression_minsize; - } - } - -#if defined (HAVE_LIBCOMPRESSION) - if (compression_decode_buffer != NULL) - { - if (strstr (p, "type:zlib-deflate;") != nullptr) - { - EnableCompressionNextSendPacket (compression_types::zlib_deflate); - m_compression_minsize = new_compression_minsize; - return SendPacket ("OK"); - } - else if (strstr (p, "type:lz4;") != nullptr) - { - EnableCompressionNextSendPacket (compression_types::lz4); - m_compression_minsize = new_compression_minsize; - return SendPacket ("OK"); - } - else if (strstr (p, "type:lzma;") != nullptr) - { - EnableCompressionNextSendPacket (compression_types::lzma); - m_compression_minsize = new_compression_minsize; - return SendPacket ("OK"); - } - else if (strstr (p, "type:lzfse;") != nullptr) - { - EnableCompressionNextSendPacket (compression_types::lzfse); - m_compression_minsize = new_compression_minsize; - return SendPacket ("OK"); - } - } +// minsize: is optional; by default the qXfer:features: +// DefaultCompressionMinSize value is used +// debugserver may have a better idea of what a good minimum packet size to +// compress is than lldb. + +rnb_err_t RNBRemote::HandlePacket_QEnableCompression(const char *p) { + p += sizeof("QEnableCompression:") - 1; + + size_t new_compression_minsize = m_compression_minsize; + const char *new_compression_minsize_str = strstr(p, "minsize:"); + if (new_compression_minsize_str) { + new_compression_minsize_str += strlen("minsize:"); + errno = 0; + new_compression_minsize = strtoul(new_compression_minsize_str, NULL, 10); + if (errno != 0 || new_compression_minsize == ULONG_MAX) { + new_compression_minsize = m_compression_minsize; + } + } + +#if defined(HAVE_LIBCOMPRESSION) + if (compression_decode_buffer != NULL) { + if (strstr(p, "type:zlib-deflate;") != nullptr) { + EnableCompressionNextSendPacket(compression_types::zlib_deflate); + m_compression_minsize = new_compression_minsize; + return SendPacket("OK"); + } else if (strstr(p, "type:lz4;") != nullptr) { + EnableCompressionNextSendPacket(compression_types::lz4); + m_compression_minsize = new_compression_minsize; + return SendPacket("OK"); + } else if (strstr(p, "type:lzma;") != nullptr) { + EnableCompressionNextSendPacket(compression_types::lzma); + m_compression_minsize = new_compression_minsize; + return SendPacket("OK"); + } else if (strstr(p, "type:lzfse;") != nullptr) { + EnableCompressionNextSendPacket(compression_types::lzfse); + m_compression_minsize = new_compression_minsize; + return SendPacket("OK"); + } + } #endif -#if defined (HAVE_LIBZ) - if (strstr (p, "type:zlib-deflate;") != nullptr) - { - EnableCompressionNextSendPacket (compression_types::zlib_deflate); - m_compression_minsize = new_compression_minsize; - return SendPacket ("OK"); - } +#if defined(HAVE_LIBZ) + if (strstr(p, "type:zlib-deflate;") != nullptr) { + EnableCompressionNextSendPacket(compression_types::zlib_deflate); + m_compression_minsize = new_compression_minsize; + return SendPacket("OK"); + } #endif - return SendPacket ("E88"); -} - -rnb_err_t -RNBRemote::HandlePacket_qSpeedTest (const char *p) -{ - p += strlen ("qSpeedTest:response_size:"); - char *end = NULL; - errno = 0; - uint64_t response_size = ::strtoul (p, &end, 16); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Didn't find response_size value at right offset"); - else if (*end == ';') - { - static char g_data[4*1024*1024+16] = "data:"; - memset(g_data + 5, 'a', response_size); - g_data[response_size + 5] = '\0'; - return SendPacket (g_data); - } - else - { - return SendPacket ("E79"); - } -} - -rnb_err_t -RNBRemote::HandlePacket_WatchpointSupportInfo (const char *p) -{ - /* This packet simply returns the number of supported hardware watchpoints. - - Examples of use: - qWatchpointSupportInfo: - num:4 - - qWatchpointSupportInfo - OK // this packet is implemented by the remote nub - */ - - p += sizeof ("qWatchpointSupportInfo") - 1; - if (*p == '\0') - return SendPacket ("OK"); - if (*p++ != ':') - return SendPacket ("E67"); + return SendPacket("E88"); +} + +rnb_err_t RNBRemote::HandlePacket_qSpeedTest(const char *p) { + p += strlen("qSpeedTest:response_size:"); + char *end = NULL; + errno = 0; + uint64_t response_size = ::strtoul(p, &end, 16); + if (errno != 0) + return HandlePacket_ILLFORMED( + __FILE__, __LINE__, p, + "Didn't find response_size value at right offset"); + else if (*end == ';') { + static char g_data[4 * 1024 * 1024 + 16] = "data:"; + memset(g_data + 5, 'a', response_size); + g_data[response_size + 5] = '\0'; + return SendPacket(g_data); + } else { + return SendPacket("E79"); + } +} + +rnb_err_t RNBRemote::HandlePacket_WatchpointSupportInfo(const char *p) { + /* This packet simply returns the number of supported hardware watchpoints. + + Examples of use: + qWatchpointSupportInfo: + num:4 + + qWatchpointSupportInfo + OK // this packet is implemented by the remote nub + */ + + p += sizeof("qWatchpointSupportInfo") - 1; + if (*p == '\0') + return SendPacket("OK"); + if (*p++ != ':') + return SendPacket("E67"); - errno = 0; - uint32_t num = DNBWatchpointGetNumSupportedHWP (m_ctx.ProcessID()); - std::ostringstream ostrm; + errno = 0; + uint32_t num = DNBWatchpointGetNumSupportedHWP(m_ctx.ProcessID()); + std::ostringstream ostrm; - // size:4 - ostrm << "num:" << std::dec << num << ';'; - return SendPacket (ostrm.str()); + // size:4 + ostrm << "num:" << std::dec << num << ';'; + return SendPacket(ostrm.str()); } /* 'C sig [;addr]' Resume with signal sig, optionally at address addr. */ -rnb_err_t -RNBRemote::HandlePacket_C (const char *p) -{ - const nub_process_t pid = m_ctx.ProcessID(); +rnb_err_t RNBRemote::HandlePacket_C(const char *p) { + const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("E36"); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E36"); - DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateRunning, 0, INVALID_NUB_ADDRESS }; - int process_signo = -1; - if (*(p + 1) != '\0') - { - action.tid = GetContinueThread(); - char *end = NULL; - errno = 0; - process_signo = static_cast<int>(strtoul (p + 1, &end, 16)); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse signal in C packet"); - else if (*end == ';') - { - errno = 0; - action.addr = strtoull (end + 1, NULL, 16); - if (errno != 0 && action.addr == 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse address in C packet"); - } - } - - DNBThreadResumeActions thread_actions; - thread_actions.Append (action); - thread_actions.SetDefaultThreadActionIfNeeded (eStateRunning, action.signal); - if (!DNBProcessSignal(pid, process_signo)) - return SendPacket ("E52"); - if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize())) - return SendPacket ("E38"); - /* Don't send an "OK" packet; response is the stopped/exited message. */ - return rnb_success; + DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateRunning, 0, + INVALID_NUB_ADDRESS}; + int process_signo = -1; + if (*(p + 1) != '\0') { + action.tid = GetContinueThread(); + char *end = NULL; + errno = 0; + process_signo = static_cast<int>(strtoul(p + 1, &end, 16)); + if (errno != 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse signal in C packet"); + else if (*end == ';') { + errno = 0; + action.addr = strtoull(end + 1, NULL, 16); + if (errno != 0 && action.addr == 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse address in C packet"); + } + } + + DNBThreadResumeActions thread_actions; + thread_actions.Append(action); + thread_actions.SetDefaultThreadActionIfNeeded(eStateRunning, action.signal); + if (!DNBProcessSignal(pid, process_signo)) + return SendPacket("E52"); + if (!DNBProcessResume(pid, thread_actions.GetFirst(), + thread_actions.GetSize())) + return SendPacket("E38"); + /* Don't send an "OK" packet; response is the stopped/exited message. */ + return rnb_success; } //---------------------------------------------------------------------- // 'D' packet // Detach from gdb. //---------------------------------------------------------------------- -rnb_err_t -RNBRemote::HandlePacket_D (const char *p) -{ - if (m_ctx.HasValidProcessID()) - { - if (DNBProcessDetach(m_ctx.ProcessID())) - SendPacket ("OK"); - else - SendPacket ("E"); - } +rnb_err_t RNBRemote::HandlePacket_D(const char *p) { + if (m_ctx.HasValidProcessID()) { + if (DNBProcessDetach(m_ctx.ProcessID())) + SendPacket("OK"); else - { - SendPacket ("E"); - } - return rnb_success; + SendPacket("E"); + } else { + SendPacket("E"); + } + return rnb_success; } /* 'k' Kill the inferior process. */ -rnb_err_t -RNBRemote::HandlePacket_k (const char *p) -{ - DNBLog ("Got a 'k' packet, killing the inferior process."); - // No response to should be sent to the kill packet - if (m_ctx.HasValidProcessID()) - DNBProcessKill (m_ctx.ProcessID()); - SendPacket ("X09"); - return rnb_success; +rnb_err_t RNBRemote::HandlePacket_k(const char *p) { + DNBLog("Got a 'k' packet, killing the inferior process."); + // No response to should be sent to the kill packet + if (m_ctx.HasValidProcessID()) + DNBProcessKill(m_ctx.ProcessID()); + SendPacket("X09"); + return rnb_success; } -rnb_err_t -RNBRemote::HandlePacket_stop_process (const char *p) -{ -//#define TEST_EXIT_ON_INTERRUPT // This should only be uncommented to test exiting on interrupt +rnb_err_t RNBRemote::HandlePacket_stop_process(const char *p) { +//#define TEST_EXIT_ON_INTERRUPT // This should only be uncommented to test +//exiting on interrupt #if defined(TEST_EXIT_ON_INTERRUPT) - rnb_err_t err = HandlePacket_k (p); - m_comm.Disconnect(true); - return err; + rnb_err_t err = HandlePacket_k(p); + m_comm.Disconnect(true); + return err; #else - if (!DNBProcessInterrupt(m_ctx.ProcessID())) - { - // If we failed to interrupt the process, then send a stop - // reply packet as the process was probably already stopped - DNBLogThreaded ("RNBRemote::HandlePacket_stop_process() sending extra stop reply because DNBProcessInterrupt returned false"); - HandlePacket_last_signal (NULL); - } - return rnb_success; + if (!DNBProcessInterrupt(m_ctx.ProcessID())) { + // If we failed to interrupt the process, then send a stop + // reply packet as the process was probably already stopped + DNBLogThreaded("RNBRemote::HandlePacket_stop_process() sending extra stop " + "reply because DNBProcessInterrupt returned false"); + HandlePacket_last_signal(NULL); + } + return rnb_success; #endif } /* 's' Step the inferior process. */ -rnb_err_t -RNBRemote::HandlePacket_s (const char *p) -{ - const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("E32"); +rnb_err_t RNBRemote::HandlePacket_s(const char *p) { + const nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E32"); - // Hardware supported stepping not supported on arm - nub_thread_t tid = GetContinueThread (); - if (tid == 0 || tid == (nub_thread_t)-1) - tid = GetCurrentThread(); + // Hardware supported stepping not supported on arm + nub_thread_t tid = GetContinueThread(); + if (tid == 0 || tid == (nub_thread_t)-1) + tid = GetCurrentThread(); - if (tid == INVALID_NUB_THREAD) - return SendPacket ("E33"); + if (tid == INVALID_NUB_THREAD) + return SendPacket("E33"); - DNBThreadResumeActions thread_actions; - thread_actions.AppendAction(tid, eStateStepping); + DNBThreadResumeActions thread_actions; + thread_actions.AppendAction(tid, eStateStepping); - // Make all other threads stop when we are stepping - thread_actions.SetDefaultThreadActionIfNeeded (eStateStopped, 0); - if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize())) - return SendPacket ("E49"); - // Don't send an "OK" packet; response is the stopped/exited message. - return rnb_success; + // Make all other threads stop when we are stepping + thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + if (!DNBProcessResume(pid, thread_actions.GetFirst(), + thread_actions.GetSize())) + return SendPacket("E49"); + // Don't send an "OK" packet; response is the stopped/exited message. + return rnb_success; } /* 'S sig [;addr]' Step with signal sig, optionally at address addr. */ -rnb_err_t -RNBRemote::HandlePacket_S (const char *p) -{ - const nub_process_t pid = m_ctx.ProcessID(); - if (pid == INVALID_NUB_PROCESS) - return SendPacket ("E36"); - - DNBThreadResumeAction action = { INVALID_NUB_THREAD, eStateStepping, 0, INVALID_NUB_ADDRESS }; - - if (*(p + 1) != '\0') - { - char *end = NULL; - errno = 0; - action.signal = static_cast<int>(strtoul (p + 1, &end, 16)); - if (errno != 0) - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse signal in S packet"); - else if (*end == ';') - { - errno = 0; - action.addr = strtoull (end + 1, NULL, 16); - if (errno != 0 && action.addr == 0) - { - return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "Could not parse address in S packet"); - } - } - } - - action.tid = GetContinueThread (); - if (action.tid == 0 || action.tid == (nub_thread_t)-1) - return SendPacket ("E40"); - - nub_state_t tstate = DNBThreadGetState (pid, action.tid); - if (tstate == eStateInvalid || tstate == eStateExited) - return SendPacket ("E37"); - - - DNBThreadResumeActions thread_actions; - thread_actions.Append (action); - - // Make all other threads stop when we are stepping - thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); - if (!DNBProcessResume (pid, thread_actions.GetFirst(), thread_actions.GetSize())) - return SendPacket ("E39"); +rnb_err_t RNBRemote::HandlePacket_S(const char *p) { + const nub_process_t pid = m_ctx.ProcessID(); + if (pid == INVALID_NUB_PROCESS) + return SendPacket("E36"); - // Don't send an "OK" packet; response is the stopped/exited message. - return rnb_success; -} + DNBThreadResumeAction action = {INVALID_NUB_THREAD, eStateStepping, 0, + INVALID_NUB_ADDRESS}; -static const char * -GetArchName (const uint32_t cputype, const uint32_t cpusubtype) -{ - switch (cputype) - { - case CPU_TYPE_ARM: - switch (cpusubtype) - { - case 5: return "armv4"; - case 6: return "armv6"; - case 7: return "armv5t"; - case 8: return "xscale"; - case 9: return "armv7"; - case 10: return "armv7f"; - case 11: return "armv7s"; - case 12: return "armv7k"; - case 14: return "armv6m"; - case 15: return "armv7m"; - case 16: return "armv7em"; - default: return "arm"; - } - break; - case CPU_TYPE_ARM64: return "arm64"; - case CPU_TYPE_I386: return "i386"; - case CPU_TYPE_X86_64: - switch (cpusubtype) - { - default: return "x86_64"; - case 8: return "x86_64h"; - } - break; + if (*(p + 1) != '\0') { + char *end = NULL; + errno = 0; + action.signal = static_cast<int>(strtoul(p + 1, &end, 16)); + if (errno != 0) + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse signal in S packet"); + else if (*end == ';') { + errno = 0; + action.addr = strtoull(end + 1, NULL, 16); + if (errno != 0 && action.addr == 0) { + return HandlePacket_ILLFORMED(__FILE__, __LINE__, p, + "Could not parse address in S packet"); + } } - return NULL; -} - -static bool -GetHostCPUType (uint32_t &cputype, uint32_t &cpusubtype, uint32_t &is_64_bit_capable, bool &promoted_to_64) -{ - static uint32_t g_host_cputype = 0; - static uint32_t g_host_cpusubtype = 0; - static uint32_t g_is_64_bit_capable = 0; - static bool g_promoted_to_64 = false; - - if (g_host_cputype == 0) - { - g_promoted_to_64 = false; - size_t len = sizeof(uint32_t); - if (::sysctlbyname("hw.cputype", &g_host_cputype, &len, NULL, 0) == 0) - { - len = sizeof (uint32_t); - if (::sysctlbyname("hw.cpu64bit_capable", &g_is_64_bit_capable, &len, NULL, 0) == 0) - { - if (g_is_64_bit_capable && ((g_host_cputype & CPU_ARCH_ABI64) == 0)) - { - g_promoted_to_64 = true; - g_host_cputype |= CPU_ARCH_ABI64; - } - } - } - - len = sizeof(uint32_t); - if (::sysctlbyname("hw.cpusubtype", &g_host_cpusubtype, &len, NULL, 0) == 0) - { - if (g_promoted_to_64 && - g_host_cputype == CPU_TYPE_X86_64 && g_host_cpusubtype == CPU_SUBTYPE_486) - g_host_cpusubtype = CPU_SUBTYPE_X86_64_ALL; + } + + action.tid = GetContinueThread(); + if (action.tid == 0 || action.tid == (nub_thread_t)-1) + return SendPacket("E40"); + + nub_state_t tstate = DNBThreadGetState(pid, action.tid); + if (tstate == eStateInvalid || tstate == eStateExited) + return SendPacket("E37"); + + DNBThreadResumeActions thread_actions; + thread_actions.Append(action); + + // Make all other threads stop when we are stepping + thread_actions.SetDefaultThreadActionIfNeeded(eStateStopped, 0); + if (!DNBProcessResume(pid, thread_actions.GetFirst(), + thread_actions.GetSize())) + return SendPacket("E39"); + + // Don't send an "OK" packet; response is the stopped/exited message. + return rnb_success; +} + +static const char *GetArchName(const uint32_t cputype, + const uint32_t cpusubtype) { + switch (cputype) { + case CPU_TYPE_ARM: + switch (cpusubtype) { + case 5: + return "armv4"; + case 6: + return "armv6"; + case 7: + return "armv5t"; + case 8: + return "xscale"; + case 9: + return "armv7"; + case 10: + return "armv7f"; + case 11: + return "armv7s"; + case 12: + return "armv7k"; + case 14: + return "armv6m"; + case 15: + return "armv7m"; + case 16: + return "armv7em"; + default: + return "arm"; + } + break; + case CPU_TYPE_ARM64: + return "arm64"; + case CPU_TYPE_I386: + return "i386"; + case CPU_TYPE_X86_64: + switch (cpusubtype) { + default: + return "x86_64"; + case 8: + return "x86_64h"; + } + break; + } + return NULL; +} + +static bool GetHostCPUType(uint32_t &cputype, uint32_t &cpusubtype, + uint32_t &is_64_bit_capable, bool &promoted_to_64) { + static uint32_t g_host_cputype = 0; + static uint32_t g_host_cpusubtype = 0; + static uint32_t g_is_64_bit_capable = 0; + static bool g_promoted_to_64 = false; + + if (g_host_cputype == 0) { + g_promoted_to_64 = false; + size_t len = sizeof(uint32_t); + if (::sysctlbyname("hw.cputype", &g_host_cputype, &len, NULL, 0) == 0) { + len = sizeof(uint32_t); + if (::sysctlbyname("hw.cpu64bit_capable", &g_is_64_bit_capable, &len, + NULL, 0) == 0) { + if (g_is_64_bit_capable && ((g_host_cputype & CPU_ARCH_ABI64) == 0)) { + g_promoted_to_64 = true; + g_host_cputype |= CPU_ARCH_ABI64; } - } - - cputype = g_host_cputype; - cpusubtype = g_host_cpusubtype; - is_64_bit_capable = g_is_64_bit_capable; - promoted_to_64 = g_promoted_to_64; - return g_host_cputype != 0; -} - -rnb_err_t -RNBRemote::HandlePacket_qHostInfo (const char *p) -{ - std::ostringstream strm; - - uint32_t cputype = 0; - uint32_t cpusubtype = 0; - uint32_t is_64_bit_capable = 0; - bool promoted_to_64 = false; - if (GetHostCPUType (cputype, cpusubtype, is_64_bit_capable, promoted_to_64)) - { - strm << "cputype:" << std::dec << cputype << ';'; - strm << "cpusubtype:" << std::dec << cpusubtype << ';'; + } } - // The OS in the triple should be "ios" or "macosx" which doesn't match our - // "Darwin" which gets returned from "kern.ostype", so we need to hardcode - // this for now. - if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) - { -#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1 - strm << "ostype:tvos;"; -#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 - strm << "ostype:watchos;"; + len = sizeof(uint32_t); + if (::sysctlbyname("hw.cpusubtype", &g_host_cpusubtype, &len, NULL, 0) == + 0) { + if (g_promoted_to_64 && g_host_cputype == CPU_TYPE_X86_64 && + g_host_cpusubtype == CPU_SUBTYPE_486) + g_host_cpusubtype = CPU_SUBTYPE_X86_64_ALL; + } + } + + cputype = g_host_cputype; + cpusubtype = g_host_cpusubtype; + is_64_bit_capable = g_is_64_bit_capable; + promoted_to_64 = g_promoted_to_64; + return g_host_cputype != 0; +} + +rnb_err_t RNBRemote::HandlePacket_qHostInfo(const char *p) { + std::ostringstream strm; + + uint32_t cputype = 0; + uint32_t cpusubtype = 0; + uint32_t is_64_bit_capable = 0; + bool promoted_to_64 = false; + if (GetHostCPUType(cputype, cpusubtype, is_64_bit_capable, promoted_to_64)) { + strm << "cputype:" << std::dec << cputype << ';'; + strm << "cpusubtype:" << std::dec << cpusubtype << ';'; + } + + // The OS in the triple should be "ios" or "macosx" which doesn't match our + // "Darwin" which gets returned from "kern.ostype", so we need to hardcode + // this for now. + if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) { +#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + strm << "ostype:tvos;"; +#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + strm << "ostype:watchos;"; #else - strm << "ostype:ios;"; + strm << "ostype:ios;"; #endif - // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes. - strm << "watchpoint_exceptions_received:before;"; - } - else - { - strm << "ostype:macosx;"; - strm << "watchpoint_exceptions_received:after;"; - } -// char ostype[64]; -// len = sizeof(ostype); -// if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0) -// { -// len = strlen(ostype); -// std::transform (ostype, ostype + len, ostype, tolower); -// strm << "ostype:" << std::dec << ostype << ';'; -// } - - strm << "vendor:apple;"; - - uint64_t major, minor, patch; - if (DNBGetOSVersionNumbers (&major, &minor, &patch)) - { - strm << "os_version:" << major << "." << minor; - if (patch != UINT64_MAX) - strm << "." << patch; - strm << ";"; - } - -#if defined (__LITTLE_ENDIAN__) - strm << "endian:little;"; -#elif defined (__BIG_ENDIAN__) - strm << "endian:big;"; -#elif defined (__PDP_ENDIAN__) - strm << "endian:pdp;"; + // On armv7 we use "synchronous" watchpoints which means the exception is + // delivered before the instruction executes. + strm << "watchpoint_exceptions_received:before;"; + } else { + strm << "ostype:macosx;"; + strm << "watchpoint_exceptions_received:after;"; + } + // char ostype[64]; + // len = sizeof(ostype); + // if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0) + // { + // len = strlen(ostype); + // std::transform (ostype, ostype + len, ostype, tolower); + // strm << "ostype:" << std::dec << ostype << ';'; + // } + + strm << "vendor:apple;"; + + uint64_t major, minor, patch; + if (DNBGetOSVersionNumbers(&major, &minor, &patch)) { + strm << "os_version:" << major << "." << minor; + if (patch != UINT64_MAX) + strm << "." << patch; + strm << ";"; + } + +#if defined(__LITTLE_ENDIAN__) + strm << "endian:little;"; +#elif defined(__BIG_ENDIAN__) + strm << "endian:big;"; +#elif defined(__PDP_ENDIAN__) + strm << "endian:pdp;"; #endif - if (promoted_to_64) - strm << "ptrsize:8;"; - else - strm << "ptrsize:" << std::dec << sizeof(void *) << ';'; + if (promoted_to_64) + strm << "ptrsize:8;"; + else + strm << "ptrsize:" << std::dec << sizeof(void *) << ';'; -#if defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 - strm << "default_packet_timeout:10;"; +#if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + strm << "default_packet_timeout:10;"; #endif - return SendPacket (strm.str()); -} - -void -XMLElementStart (std::ostringstream &s, uint32_t indent, const char *name, bool has_attributes) -{ - if (indent) - s << INDENT_WITH_SPACES(indent); - s << '<' << name; - if (!has_attributes) - s << '>' << std::endl; + return SendPacket(strm.str()); } -void -XMLElementStartEndAttributes (std::ostringstream &s, bool empty) -{ - if (empty) - s << '/'; +void XMLElementStart(std::ostringstream &s, uint32_t indent, const char *name, + bool has_attributes) { + if (indent) + s << INDENT_WITH_SPACES(indent); + s << '<' << name; + if (!has_attributes) s << '>' << std::endl; } -void -XMLElementEnd (std::ostringstream &s, uint32_t indent, const char *name) -{ - if (indent) - s << INDENT_WITH_SPACES(indent); - s << '<' << '/' << name << '>' << std::endl; +void XMLElementStartEndAttributes(std::ostringstream &s, bool empty) { + if (empty) + s << '/'; + s << '>' << std::endl; } -void -XMLElementWithStringValue (std::ostringstream &s, uint32_t indent, const char *name, const char *value, bool close = true) -{ - if (value) - { - if (indent) - s << INDENT_WITH_SPACES(indent); - s << '<' << name << '>' << value; - if (close) - XMLElementEnd(s, 0, name); - } +void XMLElementEnd(std::ostringstream &s, uint32_t indent, const char *name) { + if (indent) + s << INDENT_WITH_SPACES(indent); + s << '<' << '/' << name << '>' << std::endl; } -void -XMLElementWithUnsignedValue (std::ostringstream &s, uint32_t indent, const char *name, uint64_t value, bool close = true) -{ +void XMLElementWithStringValue(std::ostringstream &s, uint32_t indent, + const char *name, const char *value, + bool close = true) { + if (value) { if (indent) - s << INDENT_WITH_SPACES(indent); - - s << '<' << name << '>' << DECIMAL << value; + s << INDENT_WITH_SPACES(indent); + s << '<' << name << '>' << value; if (close) - XMLElementEnd(s, 0, name); -} - -void -XMLAttributeString (std::ostringstream &s, const char *name, const char *value, const char *default_value = NULL) -{ - if (value) - { - if (default_value && strcmp(value, default_value) == 0) - return; // No need to emit the attribute because it matches the default value - s <<' ' << name << "=\"" << value << "\""; - } -} - -void -XMLAttributeUnsignedDecimal (std::ostringstream &s, const char *name, uint64_t value) -{ - s <<' ' << name << "=\"" << DECIMAL << value << "\""; -} - -void -GenerateTargetXMLRegister (std::ostringstream &s, - const uint32_t reg_num, - nub_size_t num_reg_sets, - const DNBRegisterSetInfo *reg_set_info, - const register_map_entry_t ®) -{ - const char *default_lldb_encoding = "uint"; - const char *lldb_encoding = default_lldb_encoding; - const char *gdb_group = "general"; - const char *default_gdb_type = "int"; - const char *gdb_type = default_gdb_type; - const char *default_lldb_format = "hex"; - const char *lldb_format = default_lldb_format; - const char *lldb_set = NULL; - - switch (reg.nub_info.type) - { - case Uint: lldb_encoding = "uint"; break; - case Sint: lldb_encoding = "sint"; break; - case IEEE754: lldb_encoding = "ieee754"; if (reg.nub_info.set > 0) gdb_group = "float"; break; - case Vector: lldb_encoding = "vector"; if (reg.nub_info.set > 0) gdb_group = "vector"; break; - } - - switch (reg.nub_info.format) - { - case Binary: lldb_format = "binary"; break; - case Decimal: lldb_format = "decimal"; break; - case Hex: lldb_format = "hex"; break; - case Float: gdb_type = "float"; lldb_format = "float"; break; - case VectorOfSInt8: gdb_type = "float"; lldb_format = "vector-sint8"; break; - case VectorOfUInt8: gdb_type = "float"; lldb_format = "vector-uint8"; break; - case VectorOfSInt16: gdb_type = "float"; lldb_format = "vector-sint16"; break; - case VectorOfUInt16: gdb_type = "float"; lldb_format = "vector-uint16"; break; - case VectorOfSInt32: gdb_type = "float"; lldb_format = "vector-sint32"; break; - case VectorOfUInt32: gdb_type = "float"; lldb_format = "vector-uint32"; break; - case VectorOfFloat32: gdb_type = "float"; lldb_format = "vector-float32"; break; - case VectorOfUInt128: gdb_type = "float"; lldb_format = "vector-uint128"; break; - }; - if (reg_set_info && reg.nub_info.set < num_reg_sets) - lldb_set = reg_set_info[reg.nub_info.set].name; - - uint32_t indent = 2; - - XMLElementStart(s, indent, "reg", true); - XMLAttributeString(s, "name", reg.nub_info.name); - XMLAttributeUnsignedDecimal(s, "regnum", reg_num); - XMLAttributeUnsignedDecimal(s, "offset", reg.offset); - XMLAttributeUnsignedDecimal(s, "bitsize", reg.nub_info.size * 8); - XMLAttributeString(s, "group", gdb_group); - XMLAttributeString(s, "type", gdb_type, default_gdb_type); - XMLAttributeString (s, "altname", reg.nub_info.alt); - XMLAttributeString(s, "encoding", lldb_encoding, default_lldb_encoding); - XMLAttributeString(s, "format", lldb_format, default_lldb_format); - XMLAttributeUnsignedDecimal(s, "group_id", reg.nub_info.set); - if (reg.nub_info.reg_ehframe != INVALID_NUB_REGNUM) - XMLAttributeUnsignedDecimal(s, "ehframe_regnum", reg.nub_info.reg_ehframe); - if (reg.nub_info.reg_dwarf != INVALID_NUB_REGNUM) - XMLAttributeUnsignedDecimal(s, "dwarf_regnum", reg.nub_info.reg_dwarf); - - const char *lldb_generic = NULL; - switch (reg.nub_info.reg_generic) - { - case GENERIC_REGNUM_FP: lldb_generic = "fp"; break; - case GENERIC_REGNUM_PC: lldb_generic = "pc"; break; - case GENERIC_REGNUM_SP: lldb_generic = "sp"; break; - case GENERIC_REGNUM_RA: lldb_generic = "ra"; break; - case GENERIC_REGNUM_FLAGS: lldb_generic = "flags"; break; - case GENERIC_REGNUM_ARG1: lldb_generic = "arg1"; break; - case GENERIC_REGNUM_ARG2: lldb_generic = "arg2"; break; - case GENERIC_REGNUM_ARG3: lldb_generic = "arg3"; break; - case GENERIC_REGNUM_ARG4: lldb_generic = "arg4"; break; - case GENERIC_REGNUM_ARG5: lldb_generic = "arg5"; break; - case GENERIC_REGNUM_ARG6: lldb_generic = "arg6"; break; - case GENERIC_REGNUM_ARG7: lldb_generic = "arg7"; break; - case GENERIC_REGNUM_ARG8: lldb_generic = "arg8"; break; - default: break; - } - XMLAttributeString(s, "generic", lldb_generic); - - - bool empty = reg.value_regnums.empty() && reg.invalidate_regnums.empty(); - if (!empty) - { - if (!reg.value_regnums.empty()) - { - std::ostringstream regnums; - bool first = true; - regnums << DECIMAL; - for (auto regnum : reg.value_regnums) - { - if (!first) - regnums << ','; - regnums << regnum; - first = false; - } - XMLAttributeString(s, "value_regnums", regnums.str().c_str()); - } - - if (!reg.invalidate_regnums.empty()) - { - std::ostringstream regnums; - bool first = true; - regnums << DECIMAL; - for (auto regnum : reg.invalidate_regnums) - { - if (!first) - regnums << ','; - regnums << regnum; - first = false; - } - XMLAttributeString(s, "invalidate_regnums", regnums.str().c_str()); - } - } - XMLElementStartEndAttributes(s, true); -} - -void -GenerateTargetXMLRegisters (std::ostringstream &s) -{ - nub_size_t num_reg_sets = 0; - const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo (&num_reg_sets); - - - uint32_t cputype = DNBGetRegisterCPUType(); - if (cputype) - { - XMLElementStart(s, 0, "feature", true); - std::ostringstream name_strm; - name_strm << "com.apple.debugserver." << GetArchName (cputype, 0); - XMLAttributeString(s, "name", name_strm.str().c_str()); - XMLElementStartEndAttributes(s, false); - for (uint32_t reg_num = 0; reg_num < g_num_reg_entries; ++reg_num) -// for (const auto ®: g_dynamic_register_map) - { - GenerateTargetXMLRegister(s, reg_num, num_reg_sets, reg_sets, g_reg_entries[reg_num]); - } - XMLElementEnd(s, 0, "feature"); - - if (num_reg_sets > 0) - { - XMLElementStart(s, 0, "groups", false); - for (uint32_t set=1; set<num_reg_sets; ++set) - { - XMLElementStart(s, 2, "group", true); - XMLAttributeUnsignedDecimal(s, "id", set); - XMLAttributeString(s, "name", reg_sets[set].name); - XMLElementStartEndAttributes(s, true); - } - XMLElementEnd(s, 0, "groups"); - } + XMLElementEnd(s, 0, name); + } +} + +void XMLElementWithUnsignedValue(std::ostringstream &s, uint32_t indent, + const char *name, uint64_t value, + bool close = true) { + if (indent) + s << INDENT_WITH_SPACES(indent); + + s << '<' << name << '>' << DECIMAL << value; + if (close) + XMLElementEnd(s, 0, name); +} + +void XMLAttributeString(std::ostringstream &s, const char *name, + const char *value, const char *default_value = NULL) { + if (value) { + if (default_value && strcmp(value, default_value) == 0) + return; // No need to emit the attribute because it matches the default + // value + s << ' ' << name << "=\"" << value << "\""; + } +} + +void XMLAttributeUnsignedDecimal(std::ostringstream &s, const char *name, + uint64_t value) { + s << ' ' << name << "=\"" << DECIMAL << value << "\""; +} + +void GenerateTargetXMLRegister(std::ostringstream &s, const uint32_t reg_num, + nub_size_t num_reg_sets, + const DNBRegisterSetInfo *reg_set_info, + const register_map_entry_t ®) { + const char *default_lldb_encoding = "uint"; + const char *lldb_encoding = default_lldb_encoding; + const char *gdb_group = "general"; + const char *default_gdb_type = "int"; + const char *gdb_type = default_gdb_type; + const char *default_lldb_format = "hex"; + const char *lldb_format = default_lldb_format; + const char *lldb_set = NULL; + + switch (reg.nub_info.type) { + case Uint: + lldb_encoding = "uint"; + break; + case Sint: + lldb_encoding = "sint"; + break; + case IEEE754: + lldb_encoding = "ieee754"; + if (reg.nub_info.set > 0) + gdb_group = "float"; + break; + case Vector: + lldb_encoding = "vector"; + if (reg.nub_info.set > 0) + gdb_group = "vector"; + break; + } + + switch (reg.nub_info.format) { + case Binary: + lldb_format = "binary"; + break; + case Decimal: + lldb_format = "decimal"; + break; + case Hex: + lldb_format = "hex"; + break; + case Float: + gdb_type = "float"; + lldb_format = "float"; + break; + case VectorOfSInt8: + gdb_type = "float"; + lldb_format = "vector-sint8"; + break; + case VectorOfUInt8: + gdb_type = "float"; + lldb_format = "vector-uint8"; + break; + case VectorOfSInt16: + gdb_type = "float"; + lldb_format = "vector-sint16"; + break; + case VectorOfUInt16: + gdb_type = "float"; + lldb_format = "vector-uint16"; + break; + case VectorOfSInt32: + gdb_type = "float"; + lldb_format = "vector-sint32"; + break; + case VectorOfUInt32: + gdb_type = "float"; + lldb_format = "vector-uint32"; + break; + case VectorOfFloat32: + gdb_type = "float"; + lldb_format = "vector-float32"; + break; + case VectorOfUInt128: + gdb_type = "float"; + lldb_format = "vector-uint128"; + break; + }; + if (reg_set_info && reg.nub_info.set < num_reg_sets) + lldb_set = reg_set_info[reg.nub_info.set].name; + + uint32_t indent = 2; + + XMLElementStart(s, indent, "reg", true); + XMLAttributeString(s, "name", reg.nub_info.name); + XMLAttributeUnsignedDecimal(s, "regnum", reg_num); + XMLAttributeUnsignedDecimal(s, "offset", reg.offset); + XMLAttributeUnsignedDecimal(s, "bitsize", reg.nub_info.size * 8); + XMLAttributeString(s, "group", gdb_group); + XMLAttributeString(s, "type", gdb_type, default_gdb_type); + XMLAttributeString(s, "altname", reg.nub_info.alt); + XMLAttributeString(s, "encoding", lldb_encoding, default_lldb_encoding); + XMLAttributeString(s, "format", lldb_format, default_lldb_format); + XMLAttributeUnsignedDecimal(s, "group_id", reg.nub_info.set); + if (reg.nub_info.reg_ehframe != INVALID_NUB_REGNUM) + XMLAttributeUnsignedDecimal(s, "ehframe_regnum", reg.nub_info.reg_ehframe); + if (reg.nub_info.reg_dwarf != INVALID_NUB_REGNUM) + XMLAttributeUnsignedDecimal(s, "dwarf_regnum", reg.nub_info.reg_dwarf); + + const char *lldb_generic = NULL; + switch (reg.nub_info.reg_generic) { + case GENERIC_REGNUM_FP: + lldb_generic = "fp"; + break; + case GENERIC_REGNUM_PC: + lldb_generic = "pc"; + break; + case GENERIC_REGNUM_SP: + lldb_generic = "sp"; + break; + case GENERIC_REGNUM_RA: + lldb_generic = "ra"; + break; + case GENERIC_REGNUM_FLAGS: + lldb_generic = "flags"; + break; + case GENERIC_REGNUM_ARG1: + lldb_generic = "arg1"; + break; + case GENERIC_REGNUM_ARG2: + lldb_generic = "arg2"; + break; + case GENERIC_REGNUM_ARG3: + lldb_generic = "arg3"; + break; + case GENERIC_REGNUM_ARG4: + lldb_generic = "arg4"; + break; + case GENERIC_REGNUM_ARG5: + lldb_generic = "arg5"; + break; + case GENERIC_REGNUM_ARG6: + lldb_generic = "arg6"; + break; + case GENERIC_REGNUM_ARG7: + lldb_generic = "arg7"; + break; + case GENERIC_REGNUM_ARG8: + lldb_generic = "arg8"; + break; + default: + break; + } + XMLAttributeString(s, "generic", lldb_generic); + + bool empty = reg.value_regnums.empty() && reg.invalidate_regnums.empty(); + if (!empty) { + if (!reg.value_regnums.empty()) { + std::ostringstream regnums; + bool first = true; + regnums << DECIMAL; + for (auto regnum : reg.value_regnums) { + if (!first) + regnums << ','; + regnums << regnum; + first = false; + } + XMLAttributeString(s, "value_regnums", regnums.str().c_str()); + } + + if (!reg.invalidate_regnums.empty()) { + std::ostringstream regnums; + bool first = true; + regnums << DECIMAL; + for (auto regnum : reg.invalidate_regnums) { + if (!first) + regnums << ','; + regnums << regnum; + first = false; + } + XMLAttributeString(s, "invalidate_regnums", regnums.str().c_str()); + } + } + XMLElementStartEndAttributes(s, true); +} + +void GenerateTargetXMLRegisters(std::ostringstream &s) { + nub_size_t num_reg_sets = 0; + const DNBRegisterSetInfo *reg_sets = DNBGetRegisterSetInfo(&num_reg_sets); + + uint32_t cputype = DNBGetRegisterCPUType(); + if (cputype) { + XMLElementStart(s, 0, "feature", true); + std::ostringstream name_strm; + name_strm << "com.apple.debugserver." << GetArchName(cputype, 0); + XMLAttributeString(s, "name", name_strm.str().c_str()); + XMLElementStartEndAttributes(s, false); + for (uint32_t reg_num = 0; reg_num < g_num_reg_entries; ++reg_num) + // for (const auto ®: g_dynamic_register_map) + { + GenerateTargetXMLRegister(s, reg_num, num_reg_sets, reg_sets, + g_reg_entries[reg_num]); + } + XMLElementEnd(s, 0, "feature"); + + if (num_reg_sets > 0) { + XMLElementStart(s, 0, "groups", false); + for (uint32_t set = 1; set < num_reg_sets; ++set) { + XMLElementStart(s, 2, "group", true); + XMLAttributeUnsignedDecimal(s, "id", set); + XMLAttributeString(s, "name", reg_sets[set].name); + XMLElementStartEndAttributes(s, true); + } + XMLElementEnd(s, 0, "groups"); } + } } static const char *g_target_xml_header = R"(<?xml version="1.0"?> @@ -5117,171 +4983,146 @@ static const char *g_target_xml_footer = "</target>"; static std::string g_target_xml; -void -UpdateTargetXML () -{ - std::ostringstream s; - s << g_target_xml_header << std::endl; - - // Set the architecture - //s << "<architecture>" << arch "</architecture>" << std::endl; - - // Set the OSABI - //s << "<osabi>abi-name</osabi>" +void UpdateTargetXML() { + std::ostringstream s; + s << g_target_xml_header << std::endl; + + // Set the architecture + // s << "<architecture>" << arch "</architecture>" << std::endl; - GenerateTargetXMLRegisters(s); - - s << g_target_xml_footer << std::endl; + // Set the OSABI + // s << "<osabi>abi-name</osabi>" - // Save the XML output in case it gets retrieved in chunks - g_target_xml = s.str(); + GenerateTargetXMLRegisters(s); + + s << g_target_xml_footer << std::endl; + + // Save the XML output in case it gets retrieved in chunks + g_target_xml = s.str(); } -rnb_err_t -RNBRemote::HandlePacket_qXfer (const char *command) -{ - const char *p = command; - p += strlen ("qXfer:"); - const char *sep = strchr(p, ':'); - if (sep) - { - std::string object(p, sep - p); // "auxv", "backtrace", "features", etc - p = sep + 1; - sep = strchr(p, ':'); - if (sep) - { - std::string rw(p, sep - p); // "read" or "write" - p = sep + 1; - sep = strchr(p, ':'); - if (sep) - { - std::string annex(p, sep - p); // "read" or "write" +rnb_err_t RNBRemote::HandlePacket_qXfer(const char *command) { + const char *p = command; + p += strlen("qXfer:"); + const char *sep = strchr(p, ':'); + if (sep) { + std::string object(p, sep - p); // "auxv", "backtrace", "features", etc + p = sep + 1; + sep = strchr(p, ':'); + if (sep) { + std::string rw(p, sep - p); // "read" or "write" + p = sep + 1; + sep = strchr(p, ':'); + if (sep) { + std::string annex(p, sep - p); // "read" or "write" - p = sep + 1; - sep = strchr(p, ','); - if (sep) - { - std::string offset_str(p, sep - p); // read the length as a string - p = sep + 1; - std::string length_str(p); // read the offset as a string - char *end = nullptr; - const uint64_t offset = strtoul(offset_str.c_str(), &end, 16); // convert offset_str to a offset - if (*end == '\0') - { - const uint64_t length = strtoul(length_str.c_str(), &end, 16); // convert length_str to a length - if (*end == '\0') - { - if (object == "features" && - rw == "read" && - annex == "target.xml") - { - std::ostringstream xml_out; - - if (offset == 0) - { - InitializeRegisters (true); - - UpdateTargetXML(); - if (g_target_xml.empty()) - return SendPacket("E83"); - - if (length > g_target_xml.size()) - { - xml_out << 'l'; // No more data - xml_out << binary_encode_string(g_target_xml); - } - else - { - xml_out << 'm'; // More data needs to be read with a subsequent call - xml_out << binary_encode_string(std::string(g_target_xml, offset, length)); - } - } - else - { - // Retrieving target XML in chunks - if (offset < g_target_xml.size()) - { - std::string chunk(g_target_xml, offset, length); - if (chunk.size() < length) - xml_out << 'l'; // No more data - else - xml_out << 'm'; // More data needs to be read with a subsequent call - xml_out << binary_encode_string(chunk.data()); - } - } - return SendPacket(xml_out.str()); - } - // Well formed, put not supported - return HandlePacket_UNIMPLEMENTED (command); - } - } + p = sep + 1; + sep = strchr(p, ','); + if (sep) { + std::string offset_str(p, sep - p); // read the length as a string + p = sep + 1; + std::string length_str(p); // read the offset as a string + char *end = nullptr; + const uint64_t offset = strtoul(offset_str.c_str(), &end, + 16); // convert offset_str to a offset + if (*end == '\0') { + const uint64_t length = strtoul( + length_str.c_str(), &end, 16); // convert length_str to a length + if (*end == '\0') { + if (object == "features" && rw == "read" && + annex == "target.xml") { + std::ostringstream xml_out; + + if (offset == 0) { + InitializeRegisters(true); + + UpdateTargetXML(); + if (g_target_xml.empty()) + return SendPacket("E83"); + + if (length > g_target_xml.size()) { + xml_out << 'l'; // No more data + xml_out << binary_encode_string(g_target_xml); + } else { + xml_out << 'm'; // More data needs to be read with a + // subsequent call + xml_out << binary_encode_string( + std::string(g_target_xml, offset, length)); + } + } else { + // Retrieving target XML in chunks + if (offset < g_target_xml.size()) { + std::string chunk(g_target_xml, offset, length); + if (chunk.size() < length) + xml_out << 'l'; // No more data + else + xml_out << 'm'; // More data needs to be read with a + // subsequent call + xml_out << binary_encode_string(chunk.data()); + } } + return SendPacket(xml_out.str()); + } + // Well formed, put not supported + return HandlePacket_UNIMPLEMENTED(command); } - else - { - SendPacket ("E85"); - } - } - else - { - SendPacket ("E86"); + } } + } else { + SendPacket("E85"); + } + } else { + SendPacket("E86"); } - return SendPacket ("E82"); + } + return SendPacket("E82"); } +rnb_err_t RNBRemote::HandlePacket_qGDBServerVersion(const char *p) { + std::ostringstream strm; -rnb_err_t -RNBRemote::HandlePacket_qGDBServerVersion (const char *p) -{ - std::ostringstream strm; - #if defined(DEBUGSERVER_PROGRAM_NAME) - strm << "name:" DEBUGSERVER_PROGRAM_NAME ";"; + strm << "name:" DEBUGSERVER_PROGRAM_NAME ";"; #else - strm << "name:debugserver;"; + strm << "name:debugserver;"; #endif - strm << "version:" << DEBUGSERVER_VERSION_NUM << ";"; + strm << "version:" << DEBUGSERVER_VERSION_NUM << ";"; - return SendPacket (strm.str()); + return SendPacket(strm.str()); } // A helper function that retrieves a single integer value from // a one-level-deep JSON dictionary of key-value pairs. e.g. // jThreadExtendedInfo:{"plo_pthread_tsd_base_address_offset":0,"plo_pthread_tsd_base_offset":224,"plo_pthread_tsd_entry_size":8,"thread":144305}] // -uint64_t -get_integer_value_for_key_name_from_json (const char *key, const char *json_string) -{ - uint64_t retval = INVALID_NUB_ADDRESS; - std::string key_with_quotes = "\""; - key_with_quotes += key; - key_with_quotes += "\""; - const char *c = strstr (json_string, key_with_quotes.c_str()); - if (c) - { - c += key_with_quotes.size(); - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - - if (*c == ':') - { - c++; - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - - errno = 0; - retval = strtoul (c, NULL, 10); - if (errno != 0) - { - retval = INVALID_NUB_ADDRESS; - } - } +uint64_t get_integer_value_for_key_name_from_json(const char *key, + const char *json_string) { + uint64_t retval = INVALID_NUB_ADDRESS; + std::string key_with_quotes = "\""; + key_with_quotes += key; + key_with_quotes += "\""; + const char *c = strstr(json_string, key_with_quotes.c_str()); + if (c) { + c += key_with_quotes.size(); + + while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + if (*c == ':') { + c++; + + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + errno = 0; + retval = strtoul(c, NULL, 10); + if (errno != 0) { + retval = INVALID_NUB_ADDRESS; + } } - return retval; - + } + return retval; } // A helper function that retrieves a boolean value from @@ -5291,39 +5132,36 @@ get_integer_value_for_key_name_from_json (const char *key, const char *json_stri // Returns true if it was able to find the key name, and sets the 'value' // argument to the value found. -bool -get_boolean_value_for_key_name_from_json (const char *key, const char *json_string, bool &value) -{ - std::string key_with_quotes = "\""; - key_with_quotes += key; - key_with_quotes += "\""; - const char *c = strstr (json_string, key_with_quotes.c_str()); - if (c) - { - c += key_with_quotes.size(); - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - - if (*c == ':') - { - c++; - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - - if (strncmp (c, "true", 4) == 0) - { - value = true; - return true; - } else if (strncmp (c, "false", 5) == 0) - { - value = false; - return true; - } - } +bool get_boolean_value_for_key_name_from_json(const char *key, + const char *json_string, + bool &value) { + std::string key_with_quotes = "\""; + key_with_quotes += key; + key_with_quotes += "\""; + const char *c = strstr(json_string, key_with_quotes.c_str()); + if (c) { + c += key_with_quotes.size(); + + while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + if (*c == ':') { + c++; + + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + if (strncmp(c, "true", 4) == 0) { + value = true; + return true; + } else if (strncmp(c, "false", 5) == 0) { + value = false; + return true; + } } - return false; + } + return false; } // A helper function that reads an array of uint64_t's from @@ -5333,577 +5171,582 @@ get_boolean_value_for_key_name_from_json (const char *key, const char *json_stri // Returns true if it was able to find the key name, false if it did not. // "ints" will have all integers found in the array appended to it. -bool -get_array_of_ints_value_for_key_name_from_json (const char *key, const char *json_string, std::vector<uint64_t> &ints) -{ - std::string key_with_quotes = "\""; - key_with_quotes += key; - key_with_quotes += "\""; - const char *c = strstr (json_string, key_with_quotes.c_str()); - if (c) - { - c += key_with_quotes.size(); +bool get_array_of_ints_value_for_key_name_from_json( + const char *key, const char *json_string, std::vector<uint64_t> &ints) { + std::string key_with_quotes = "\""; + key_with_quotes += key; + key_with_quotes += "\""; + const char *c = strstr(json_string, key_with_quotes.c_str()); + if (c) { + c += key_with_quotes.size(); + + while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + if (*c == ':') { + c++; + + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + + if (*c == '[') { + c++; + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + while (1) { + if (!isdigit(*c)) { + return true; + } - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; + errno = 0; + char *endptr; + uint64_t value = strtoul(c, &endptr, 10); + if (errno == 0) { + ints.push_back(value); + } else { + break; + } + if (endptr == c || endptr == nullptr || *endptr == '\0') { + break; + } + c = endptr; - if (*c == ':') - { + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) c++; - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - - if (*c == '[') - { - c++; - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - while (1) - { - if (!isdigit (*c)) - { - return true; - } - - errno = 0; - char *endptr; - uint64_t value = strtoul (c, &endptr, 10); - if (errno == 0) - { - ints.push_back (value); - } - else - { - break; - } - if (endptr == c || endptr == nullptr || *endptr == '\0') - { - break; - } - c = endptr; - - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - if (*c == ',') - c++; - while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) - c++; - if (*c == ']') - { - return true; - } - } - } + if (*c == ',') + c++; + while (*c != '\0' && + (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r')) + c++; + if (*c == ']') { + return true; + } } + } } - return false; + } + return false; } JSONGenerator::ObjectSP -RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) -{ - JSONGenerator::ArraySP threads_array_sp; - if (m_ctx.HasValidProcessID()) - { - threads_array_sp.reset(new JSONGenerator::Array()); - - nub_process_t pid = m_ctx.ProcessID(); +RNBRemote::GetJSONThreadsInfo(bool threads_with_valid_stop_info_only) { + JSONGenerator::ArraySP threads_array_sp; + if (m_ctx.HasValidProcessID()) { + threads_array_sp.reset(new JSONGenerator::Array()); - nub_size_t numthreads = DNBProcessGetNumThreads (pid); - for (nub_size_t i = 0; i < numthreads; ++i) - { - nub_thread_t tid = DNBProcessGetThreadAtIndex (pid, i); - - struct DNBThreadStopInfo tid_stop_info; - - const bool stop_info_valid = DNBThreadGetStopReason (pid, tid, &tid_stop_info); + nub_process_t pid = m_ctx.ProcessID(); - // If we are doing stop info only, then we only show threads that have a - // valid stop reason - if (threads_with_valid_stop_info_only) - { - if (!stop_info_valid || tid_stop_info.reason == eStopTypeInvalid) - continue; - } + nub_size_t numthreads = DNBProcessGetNumThreads(pid); + for (nub_size_t i = 0; i < numthreads; ++i) { + nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, i); - JSONGenerator::DictionarySP thread_dict_sp(new JSONGenerator::Dictionary()); - thread_dict_sp->AddIntegerItem("tid", tid); + struct DNBThreadStopInfo tid_stop_info; - std::string reason_value("none"); + const bool stop_info_valid = + DNBThreadGetStopReason(pid, tid, &tid_stop_info); - if (stop_info_valid) - { - switch (tid_stop_info.reason) - { - case eStopTypeInvalid: - break; - - case eStopTypeSignal: - if (tid_stop_info.details.signal.signo != 0) - { - thread_dict_sp->AddIntegerItem("signal", tid_stop_info.details.signal.signo); - reason_value = "signal"; - } - break; - - case eStopTypeException: - if (tid_stop_info.details.exception.type != 0) - { - reason_value = "exception"; - thread_dict_sp->AddIntegerItem("metype", tid_stop_info.details.exception.type); - JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array()); - for (nub_size_t i=0; i<tid_stop_info.details.exception.data_count; ++i) - { - medata_array_sp->AddItem(JSONGenerator::IntegerSP(new JSONGenerator::Integer(tid_stop_info.details.exception.data[i]))); - } - thread_dict_sp->AddItem("medata", medata_array_sp); - } - break; - - case eStopTypeExec: - reason_value = "exec"; - break; - } - } + // If we are doing stop info only, then we only show threads that have a + // valid stop reason + if (threads_with_valid_stop_info_only) { + if (!stop_info_valid || tid_stop_info.reason == eStopTypeInvalid) + continue; + } - thread_dict_sp->AddStringItem("reason", reason_value); + JSONGenerator::DictionarySP thread_dict_sp( + new JSONGenerator::Dictionary()); + thread_dict_sp->AddIntegerItem("tid", tid); - if (threads_with_valid_stop_info_only == false) - { - const char *thread_name = DNBThreadGetName (pid, tid); - if (thread_name && thread_name[0]) - thread_dict_sp->AddStringItem("name", thread_name); + std::string reason_value("none"); - thread_identifier_info_data_t thread_ident_info; - if (DNBThreadGetIdentifierInfo (pid, tid, &thread_ident_info)) - { - if (thread_ident_info.dispatch_qaddr != 0) - { - thread_dict_sp->AddIntegerItem("qaddr", thread_ident_info.dispatch_qaddr); - - const DispatchQueueOffsets *dispatch_queue_offsets = GetDispatchQueueOffsets(); - if (dispatch_queue_offsets) - { - std::string queue_name; - uint64_t queue_width = 0; - uint64_t queue_serialnum = 0; - nub_addr_t dispatch_queue_t = INVALID_NUB_ADDRESS; - dispatch_queue_offsets->GetThreadQueueInfo(pid, thread_ident_info.dispatch_qaddr, dispatch_queue_t, queue_name, queue_width, queue_serialnum); - if (dispatch_queue_t == 0 && queue_name.empty() && queue_serialnum == 0) - { - thread_dict_sp->AddBooleanItem ("associated_with_dispatch_queue", false); - } - else - { - thread_dict_sp->AddBooleanItem ("associated_with_dispatch_queue", true); - } - if (dispatch_queue_t != INVALID_NUB_ADDRESS && dispatch_queue_t != 0) - thread_dict_sp->AddIntegerItem("dispatch_queue_t", dispatch_queue_t); - if (!queue_name.empty()) - thread_dict_sp->AddStringItem("qname", queue_name); - if (queue_width == 1) - thread_dict_sp->AddStringItem("qkind", "serial"); - else if (queue_width > 1) - thread_dict_sp->AddStringItem("qkind", "concurrent"); - if (queue_serialnum > 0) - thread_dict_sp->AddIntegerItem("qserialnum", queue_serialnum); - } - } - } - - DNBRegisterValue reg_value; + if (stop_info_valid) { + switch (tid_stop_info.reason) { + case eStopTypeInvalid: + break; - if (g_reg_entries != NULL) - { - JSONGenerator::DictionarySP registers_dict_sp(new JSONGenerator::Dictionary()); - - for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) - { - // Expedite all registers in the first register set that aren't - // contained in other registers - if (g_reg_entries[reg].nub_info.set == 1 && - g_reg_entries[reg].nub_info.value_regs == NULL) - { - if (!DNBThreadGetRegisterValueByID (pid, tid, g_reg_entries[reg].nub_info.set, g_reg_entries[reg].nub_info.reg, ®_value)) - continue; - - std::ostringstream reg_num; - reg_num << std::dec << g_reg_entries[reg].debugserver_regnum; - // Encode native byte ordered bytes as hex ascii - registers_dict_sp->AddBytesAsHexASCIIString(reg_num.str(), reg_value.value.v_uint8, g_reg_entries[reg].nub_info.size); - } - } - thread_dict_sp->AddItem("registers", registers_dict_sp); - } + case eStopTypeSignal: + if (tid_stop_info.details.signal.signo != 0) { + thread_dict_sp->AddIntegerItem("signal", + tid_stop_info.details.signal.signo); + reason_value = "signal"; + } + break; - // Add expedited stack memory so stack backtracing doesn't need to read anything from the - // frame pointer chain. - StackMemoryMap stack_mmap; - ReadStackMemory (pid, tid, stack_mmap); - if (!stack_mmap.empty()) - { - JSONGenerator::ArraySP memory_array_sp(new JSONGenerator::Array()); - - for (const auto &stack_memory : stack_mmap) - { - JSONGenerator::DictionarySP stack_memory_sp(new JSONGenerator::Dictionary()); - stack_memory_sp->AddIntegerItem("address", stack_memory.first); - stack_memory_sp->AddBytesAsHexASCIIString("bytes", stack_memory.second.bytes, stack_memory.second.length); - memory_array_sp->AddItem(stack_memory_sp); - } - thread_dict_sp->AddItem("memory", memory_array_sp); - } + case eStopTypeException: + if (tid_stop_info.details.exception.type != 0) { + reason_value = "exception"; + thread_dict_sp->AddIntegerItem( + "metype", tid_stop_info.details.exception.type); + JSONGenerator::ArraySP medata_array_sp(new JSONGenerator::Array()); + for (nub_size_t i = 0; + i < tid_stop_info.details.exception.data_count; ++i) { + medata_array_sp->AddItem( + JSONGenerator::IntegerSP(new JSONGenerator::Integer( + tid_stop_info.details.exception.data[i]))); } + thread_dict_sp->AddItem("medata", medata_array_sp); + } + break; - threads_array_sp->AddItem(thread_dict_sp); + case eStopTypeExec: + reason_value = "exec"; + break; } - } - return threads_array_sp; -} + } -rnb_err_t -RNBRemote::HandlePacket_jThreadsInfo (const char *p) -{ - JSONGenerator::ObjectSP threads_info_sp; - std::ostringstream json; - std::ostringstream reply_strm; - // If we haven't run the process yet, return an error. - if (m_ctx.HasValidProcessID()) - { - const bool threads_with_valid_stop_info_only = false; - JSONGenerator::ObjectSP threads_info_sp = GetJSONThreadsInfo(threads_with_valid_stop_info_only); + thread_dict_sp->AddStringItem("reason", reason_value); - if (threads_info_sp) - { - std::ostringstream strm; - threads_info_sp->Dump (strm); - std::string binary_packet = binary_encode_string (strm.str()); - if (!binary_packet.empty()) - return SendPacket (binary_packet.c_str()); + if (threads_with_valid_stop_info_only == false) { + const char *thread_name = DNBThreadGetName(pid, tid); + if (thread_name && thread_name[0]) + thread_dict_sp->AddStringItem("name", thread_name); + + thread_identifier_info_data_t thread_ident_info; + if (DNBThreadGetIdentifierInfo(pid, tid, &thread_ident_info)) { + if (thread_ident_info.dispatch_qaddr != 0) { + thread_dict_sp->AddIntegerItem("qaddr", + thread_ident_info.dispatch_qaddr); + + const DispatchQueueOffsets *dispatch_queue_offsets = + GetDispatchQueueOffsets(); + if (dispatch_queue_offsets) { + std::string queue_name; + uint64_t queue_width = 0; + uint64_t queue_serialnum = 0; + nub_addr_t dispatch_queue_t = INVALID_NUB_ADDRESS; + dispatch_queue_offsets->GetThreadQueueInfo( + pid, thread_ident_info.dispatch_qaddr, dispatch_queue_t, + queue_name, queue_width, queue_serialnum); + if (dispatch_queue_t == 0 && queue_name.empty() && + queue_serialnum == 0) { + thread_dict_sp->AddBooleanItem("associated_with_dispatch_queue", + false); + } else { + thread_dict_sp->AddBooleanItem("associated_with_dispatch_queue", + true); + } + if (dispatch_queue_t != INVALID_NUB_ADDRESS && + dispatch_queue_t != 0) + thread_dict_sp->AddIntegerItem("dispatch_queue_t", + dispatch_queue_t); + if (!queue_name.empty()) + thread_dict_sp->AddStringItem("qname", queue_name); + if (queue_width == 1) + thread_dict_sp->AddStringItem("qkind", "serial"); + else if (queue_width > 1) + thread_dict_sp->AddStringItem("qkind", "concurrent"); + if (queue_serialnum > 0) + thread_dict_sp->AddIntegerItem("qserialnum", queue_serialnum); + } + } } - } - return SendPacket ("E85"); -} - -rnb_err_t -RNBRemote::HandlePacket_jThreadExtendedInfo (const char *p) -{ - nub_process_t pid; - std::ostringstream json; - // If we haven't run the process yet, return an error. - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E81"); - } - - pid = m_ctx.ProcessID(); + DNBRegisterValue reg_value; - const char thread_extended_info_str[] = { "jThreadExtendedInfo:{" }; - if (strncmp (p, thread_extended_info_str, sizeof (thread_extended_info_str) - 1) == 0) - { - p += strlen (thread_extended_info_str); - - uint64_t tid = get_integer_value_for_key_name_from_json ("thread", p); - uint64_t plo_pthread_tsd_base_address_offset = get_integer_value_for_key_name_from_json ("plo_pthread_tsd_base_address_offset", p); - uint64_t plo_pthread_tsd_base_offset = get_integer_value_for_key_name_from_json ("plo_pthread_tsd_base_offset", p); - uint64_t plo_pthread_tsd_entry_size = get_integer_value_for_key_name_from_json ("plo_pthread_tsd_entry_size", p); - uint64_t dti_qos_class_index = get_integer_value_for_key_name_from_json ("dti_qos_class_index", p); - // Commented out the two variables below as they are not being used -// uint64_t dti_queue_index = get_integer_value_for_key_name_from_json ("dti_queue_index", p); -// uint64_t dti_voucher_index = get_integer_value_for_key_name_from_json ("dti_voucher_index", p); - - if (tid != INVALID_NUB_ADDRESS) - { - nub_addr_t pthread_t_value = DNBGetPThreadT (pid, tid); + if (g_reg_entries != NULL) { + JSONGenerator::DictionarySP registers_dict_sp( + new JSONGenerator::Dictionary()); + + for (uint32_t reg = 0; reg < g_num_reg_entries; reg++) { + // Expedite all registers in the first register set that aren't + // contained in other registers + if (g_reg_entries[reg].nub_info.set == 1 && + g_reg_entries[reg].nub_info.value_regs == NULL) { + if (!DNBThreadGetRegisterValueByID( + pid, tid, g_reg_entries[reg].nub_info.set, + g_reg_entries[reg].nub_info.reg, ®_value)) + continue; - uint64_t tsd_address = INVALID_NUB_ADDRESS; - if (plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS - && plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS - && plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS) - { - tsd_address = DNBGetTSDAddressForThread (pid, tid, plo_pthread_tsd_base_address_offset, plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); + std::ostringstream reg_num; + reg_num << std::dec << g_reg_entries[reg].debugserver_regnum; + // Encode native byte ordered bytes as hex ascii + registers_dict_sp->AddBytesAsHexASCIIString( + reg_num.str(), reg_value.value.v_uint8, + g_reg_entries[reg].nub_info.size); } + } + thread_dict_sp->AddItem("registers", registers_dict_sp); + } - bool timed_out = false; - Genealogy::ThreadActivitySP thread_activity_sp; - - // If the pthread_t value is invalid, or if we were able to fetch the thread's TSD base - // and got an invalid value back, then we have a thread in early startup or shutdown and - // it's possible that gathering the genealogy information for this thread go badly. - // Ideally fetching this info for a thread in these odd states shouldn't matter - but - // we've seen some problems with these new SPI and threads in edge-casey states. + // Add expedited stack memory so stack backtracing doesn't need to read + // anything from the + // frame pointer chain. + StackMemoryMap stack_mmap; + ReadStackMemory(pid, tid, stack_mmap); + if (!stack_mmap.empty()) { + JSONGenerator::ArraySP memory_array_sp(new JSONGenerator::Array()); + + for (const auto &stack_memory : stack_mmap) { + JSONGenerator::DictionarySP stack_memory_sp( + new JSONGenerator::Dictionary()); + stack_memory_sp->AddIntegerItem("address", stack_memory.first); + stack_memory_sp->AddBytesAsHexASCIIString( + "bytes", stack_memory.second.bytes, stack_memory.second.length); + memory_array_sp->AddItem(stack_memory_sp); + } + thread_dict_sp->AddItem("memory", memory_array_sp); + } + } - double genealogy_fetch_time = 0; - if (pthread_t_value != INVALID_NUB_ADDRESS && tsd_address != INVALID_NUB_ADDRESS) - { - DNBTimer timer(false); - thread_activity_sp = DNBGetGenealogyInfoForThread (pid, tid, timed_out); - genealogy_fetch_time = timer.ElapsedMicroSeconds(false) / 1000000.0; - } + threads_array_sp->AddItem(thread_dict_sp); + } + } + return threads_array_sp; +} + +rnb_err_t RNBRemote::HandlePacket_jThreadsInfo(const char *p) { + JSONGenerator::ObjectSP threads_info_sp; + std::ostringstream json; + std::ostringstream reply_strm; + // If we haven't run the process yet, return an error. + if (m_ctx.HasValidProcessID()) { + const bool threads_with_valid_stop_info_only = false; + JSONGenerator::ObjectSP threads_info_sp = + GetJSONThreadsInfo(threads_with_valid_stop_info_only); + + if (threads_info_sp) { + std::ostringstream strm; + threads_info_sp->Dump(strm); + std::string binary_packet = binary_encode_string(strm.str()); + if (!binary_packet.empty()) + return SendPacket(binary_packet.c_str()); + } + } + return SendPacket("E85"); +} + +rnb_err_t RNBRemote::HandlePacket_jThreadExtendedInfo(const char *p) { + nub_process_t pid; + std::ostringstream json; + // If we haven't run the process yet, return an error. + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E81"); + } + + pid = m_ctx.ProcessID(); + + const char thread_extended_info_str[] = {"jThreadExtendedInfo:{"}; + if (strncmp(p, thread_extended_info_str, + sizeof(thread_extended_info_str) - 1) == 0) { + p += strlen(thread_extended_info_str); + + uint64_t tid = get_integer_value_for_key_name_from_json("thread", p); + uint64_t plo_pthread_tsd_base_address_offset = + get_integer_value_for_key_name_from_json( + "plo_pthread_tsd_base_address_offset", p); + uint64_t plo_pthread_tsd_base_offset = + get_integer_value_for_key_name_from_json("plo_pthread_tsd_base_offset", + p); + uint64_t plo_pthread_tsd_entry_size = + get_integer_value_for_key_name_from_json("plo_pthread_tsd_entry_size", + p); + uint64_t dti_qos_class_index = + get_integer_value_for_key_name_from_json("dti_qos_class_index", p); + // Commented out the two variables below as they are not being used + // uint64_t dti_queue_index = + // get_integer_value_for_key_name_from_json ("dti_queue_index", p); + // uint64_t dti_voucher_index = + // get_integer_value_for_key_name_from_json ("dti_voucher_index", p); + + if (tid != INVALID_NUB_ADDRESS) { + nub_addr_t pthread_t_value = DNBGetPThreadT(pid, tid); + + uint64_t tsd_address = INVALID_NUB_ADDRESS; + if (plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS && + plo_pthread_tsd_base_offset != INVALID_NUB_ADDRESS && + plo_pthread_tsd_entry_size != INVALID_NUB_ADDRESS) { + tsd_address = DNBGetTSDAddressForThread( + pid, tid, plo_pthread_tsd_base_address_offset, + plo_pthread_tsd_base_offset, plo_pthread_tsd_entry_size); + } - std::unordered_set<uint32_t> process_info_indexes; // an array of the process info #'s seen + bool timed_out = false; + Genealogy::ThreadActivitySP thread_activity_sp; + + // If the pthread_t value is invalid, or if we were able to fetch the + // thread's TSD base + // and got an invalid value back, then we have a thread in early startup + // or shutdown and + // it's possible that gathering the genealogy information for this thread + // go badly. + // Ideally fetching this info for a thread in these odd states shouldn't + // matter - but + // we've seen some problems with these new SPI and threads in edge-casey + // states. + + double genealogy_fetch_time = 0; + if (pthread_t_value != INVALID_NUB_ADDRESS && + tsd_address != INVALID_NUB_ADDRESS) { + DNBTimer timer(false); + thread_activity_sp = DNBGetGenealogyInfoForThread(pid, tid, timed_out); + genealogy_fetch_time = timer.ElapsedMicroSeconds(false) / 1000000.0; + } + std::unordered_set<uint32_t> + process_info_indexes; // an array of the process info #'s seen + + json << "{"; + + bool need_to_print_comma = false; + + if (thread_activity_sp && timed_out == false) { + const Genealogy::Activity *activity = + &thread_activity_sp->current_activity; + bool need_vouchers_comma_sep = false; + json << "\"activity_query_timed_out\":false,"; + if (genealogy_fetch_time != 0) { + // If we append the floating point value with << we'll get it in + // scientific + // notation. + char floating_point_ascii_buffer[64]; + floating_point_ascii_buffer[0] = '\0'; + snprintf(floating_point_ascii_buffer, + sizeof(floating_point_ascii_buffer), "%f", + genealogy_fetch_time); + if (strlen(floating_point_ascii_buffer) > 0) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"activity_query_duration\":" + << floating_point_ascii_buffer; + } + } + if (activity->activity_id != 0) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + need_vouchers_comma_sep = true; + json << "\"activity\":{"; + json << "\"start\":" << activity->activity_start << ","; + json << "\"id\":" << activity->activity_id << ","; + json << "\"parent_id\":" << activity->parent_id << ","; + json << "\"name\":\"" + << json_string_quote_metachars(activity->activity_name) << "\","; + json << "\"reason\":\"" + << json_string_quote_metachars(activity->reason) << "\""; + json << "}"; + } + if (thread_activity_sp->messages.size() > 0) { + need_to_print_comma = true; + if (need_vouchers_comma_sep) + json << ","; + need_vouchers_comma_sep = true; + json << "\"trace_messages\":["; + bool printed_one_message = false; + for (auto iter = thread_activity_sp->messages.begin(); + iter != thread_activity_sp->messages.end(); ++iter) { + if (printed_one_message) + json << ","; + else + printed_one_message = true; json << "{"; - - bool need_to_print_comma = false; - - if (thread_activity_sp && timed_out == false) - { - const Genealogy::Activity *activity = &thread_activity_sp->current_activity; - bool need_vouchers_comma_sep = false; - json << "\"activity_query_timed_out\":false,"; - if (genealogy_fetch_time != 0) - { - // If we append the floating point value with << we'll get it in scientific - // notation. - char floating_point_ascii_buffer[64]; - floating_point_ascii_buffer[0] = '\0'; - snprintf (floating_point_ascii_buffer, sizeof (floating_point_ascii_buffer), "%f", genealogy_fetch_time); - if (strlen (floating_point_ascii_buffer) > 0) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"activity_query_duration\":" << floating_point_ascii_buffer; - } - } - if (activity->activity_id != 0) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - need_vouchers_comma_sep = true; - json << "\"activity\":{"; - json << "\"start\":" << activity->activity_start << ","; - json << "\"id\":" << activity->activity_id << ","; - json << "\"parent_id\":" << activity->parent_id << ","; - json << "\"name\":\"" << json_string_quote_metachars (activity->activity_name) << "\","; - json << "\"reason\":\"" << json_string_quote_metachars (activity->reason) << "\""; - json << "}"; - } - if (thread_activity_sp->messages.size() > 0) - { - need_to_print_comma = true; - if (need_vouchers_comma_sep) - json << ","; - need_vouchers_comma_sep = true; - json << "\"trace_messages\":["; - bool printed_one_message = false; - for (auto iter = thread_activity_sp->messages.begin() ; iter != thread_activity_sp->messages.end(); ++iter) - { - if (printed_one_message) - json << ","; - else - printed_one_message = true; - json << "{"; - json << "\"timestamp\":" << iter->timestamp << ","; - json << "\"activity_id\":" << iter->activity_id << ","; - json << "\"trace_id\":" << iter->trace_id << ","; - json << "\"thread\":" << iter->thread << ","; - json << "\"type\":" << (int) iter->type << ","; - json << "\"process_info_index\":" << iter->process_info_index << ","; - process_info_indexes.insert (iter->process_info_index); - json << "\"message\":\"" << json_string_quote_metachars (iter->message) << "\""; - json << "}"; - } - json << "]"; - } - if (thread_activity_sp->breadcrumbs.size() == 1) - { - need_to_print_comma = true; - if (need_vouchers_comma_sep) - json << ","; - need_vouchers_comma_sep = true; - json << "\"breadcrumb\":{"; - for (auto iter = thread_activity_sp->breadcrumbs.begin() ; iter != thread_activity_sp->breadcrumbs.end(); ++iter) - { - json << "\"breadcrumb_id\":" << iter->breadcrumb_id << ","; - json << "\"activity_id\":" << iter->activity_id << ","; - json << "\"timestamp\":" << iter->timestamp << ","; - json << "\"name\":\"" << json_string_quote_metachars (iter->name) << "\""; - } - json << "}"; - } - if (process_info_indexes.size() > 0) - { - need_to_print_comma = true; - if (need_vouchers_comma_sep) - json << ","; - need_vouchers_comma_sep = true; - bool printed_one_process_info = false; - for (auto iter = process_info_indexes.begin(); iter != process_info_indexes.end(); ++iter) - { - if (printed_one_process_info) - json << ","; - Genealogy::ProcessExecutableInfoSP image_info_sp; - uint32_t idx = *iter; - image_info_sp = DNBGetGenealogyImageInfo (pid, idx); - if (image_info_sp) - { - if (!printed_one_process_info) - { - json << "\"process_infos\":["; - printed_one_process_info = true; - } - - json << "{"; - char uuid_buf[37]; - uuid_unparse_upper (image_info_sp->image_uuid, uuid_buf); - json << "\"process_info_index\":" << idx << ","; - json << "\"image_path\":\"" << json_string_quote_metachars (image_info_sp->image_path) << "\","; - json << "\"image_uuid\":\"" << uuid_buf <<"\""; - json << "}"; - } - } - if (printed_one_process_info) - json << "]"; - } + json << "\"timestamp\":" << iter->timestamp << ","; + json << "\"activity_id\":" << iter->activity_id << ","; + json << "\"trace_id\":" << iter->trace_id << ","; + json << "\"thread\":" << iter->thread << ","; + json << "\"type\":" << (int)iter->type << ","; + json << "\"process_info_index\":" << iter->process_info_index + << ","; + process_info_indexes.insert(iter->process_info_index); + json << "\"message\":\"" + << json_string_quote_metachars(iter->message) << "\""; + json << "}"; + } + json << "]"; + } + if (thread_activity_sp->breadcrumbs.size() == 1) { + need_to_print_comma = true; + if (need_vouchers_comma_sep) + json << ","; + need_vouchers_comma_sep = true; + json << "\"breadcrumb\":{"; + for (auto iter = thread_activity_sp->breadcrumbs.begin(); + iter != thread_activity_sp->breadcrumbs.end(); ++iter) { + json << "\"breadcrumb_id\":" << iter->breadcrumb_id << ","; + json << "\"activity_id\":" << iter->activity_id << ","; + json << "\"timestamp\":" << iter->timestamp << ","; + json << "\"name\":\"" << json_string_quote_metachars(iter->name) + << "\""; + } + json << "}"; + } + if (process_info_indexes.size() > 0) { + need_to_print_comma = true; + if (need_vouchers_comma_sep) + json << ","; + need_vouchers_comma_sep = true; + bool printed_one_process_info = false; + for (auto iter = process_info_indexes.begin(); + iter != process_info_indexes.end(); ++iter) { + if (printed_one_process_info) + json << ","; + Genealogy::ProcessExecutableInfoSP image_info_sp; + uint32_t idx = *iter; + image_info_sp = DNBGetGenealogyImageInfo(pid, idx); + if (image_info_sp) { + if (!printed_one_process_info) { + json << "\"process_infos\":["; + printed_one_process_info = true; + } + + json << "{"; + char uuid_buf[37]; + uuid_unparse_upper(image_info_sp->image_uuid, uuid_buf); + json << "\"process_info_index\":" << idx << ","; + json << "\"image_path\":\"" + << json_string_quote_metachars(image_info_sp->image_path) + << "\","; + json << "\"image_uuid\":\"" << uuid_buf << "\""; + json << "}"; } - else - { - if (timed_out) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"activity_query_timed_out\":true"; - if (genealogy_fetch_time != 0) - { - // If we append the floating point value with << we'll get it in scientific - // notation. - char floating_point_ascii_buffer[64]; - floating_point_ascii_buffer[0] = '\0'; - snprintf (floating_point_ascii_buffer, sizeof (floating_point_ascii_buffer), "%f", genealogy_fetch_time); - if (strlen (floating_point_ascii_buffer) > 0) - { - json << ","; - json << "\"activity_query_duration\":" << floating_point_ascii_buffer; - } - } - } + } + if (printed_one_process_info) + json << "]"; + } + } else { + if (timed_out) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"activity_query_timed_out\":true"; + if (genealogy_fetch_time != 0) { + // If we append the floating point value with << we'll get it in + // scientific + // notation. + char floating_point_ascii_buffer[64]; + floating_point_ascii_buffer[0] = '\0'; + snprintf(floating_point_ascii_buffer, + sizeof(floating_point_ascii_buffer), "%f", + genealogy_fetch_time); + if (strlen(floating_point_ascii_buffer) > 0) { + json << ","; + json << "\"activity_query_duration\":" + << floating_point_ascii_buffer; } + } + } + } - if (tsd_address != INVALID_NUB_ADDRESS) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"tsd_address\":" << tsd_address; - - if (dti_qos_class_index != 0 && dti_qos_class_index != UINT64_MAX) - { - ThreadInfo::QoS requested_qos = DNBGetRequestedQoSForThread (pid, tid, tsd_address, dti_qos_class_index); - if (requested_qos.IsValid()) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"requested_qos\":{"; - json << "\"enum_value\":" << requested_qos.enum_value << ","; - json << "\"constant_name\":\"" << json_string_quote_metachars (requested_qos.constant_name) << "\","; - json << "\"printable_name\":\"" << json_string_quote_metachars (requested_qos.printable_name) << "\""; - json << "}"; - } - } - } + if (tsd_address != INVALID_NUB_ADDRESS) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"tsd_address\":" << tsd_address; + + if (dti_qos_class_index != 0 && dti_qos_class_index != UINT64_MAX) { + ThreadInfo::QoS requested_qos = DNBGetRequestedQoSForThread( + pid, tid, tsd_address, dti_qos_class_index); + if (requested_qos.IsValid()) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"requested_qos\":{"; + json << "\"enum_value\":" << requested_qos.enum_value << ","; + json << "\"constant_name\":\"" + << json_string_quote_metachars(requested_qos.constant_name) + << "\","; + json << "\"printable_name\":\"" + << json_string_quote_metachars(requested_qos.printable_name) + << "\""; + json << "}"; + } + } + } - if (pthread_t_value != INVALID_NUB_ADDRESS) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"pthread_t\":" << pthread_t_value; - } + if (pthread_t_value != INVALID_NUB_ADDRESS) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"pthread_t\":" << pthread_t_value; + } - nub_addr_t dispatch_queue_t_value = DNBGetDispatchQueueT (pid, tid); - if (dispatch_queue_t_value != INVALID_NUB_ADDRESS) - { - if (need_to_print_comma) - json << ","; - need_to_print_comma = true; - json << "\"dispatch_queue_t\":" << dispatch_queue_t_value; - } + nub_addr_t dispatch_queue_t_value = DNBGetDispatchQueueT(pid, tid); + if (dispatch_queue_t_value != INVALID_NUB_ADDRESS) { + if (need_to_print_comma) + json << ","; + need_to_print_comma = true; + json << "\"dispatch_queue_t\":" << dispatch_queue_t_value; + } - json << "}"; - std::string json_quoted = binary_encode_string (json.str()); - return SendPacket (json_quoted); - } + json << "}"; + std::string json_quoted = binary_encode_string(json.str()); + return SendPacket(json_quoted); } - return SendPacket ("OK"); + } + return SendPacket("OK"); } // This packet may be called in one of three ways: // // jGetLoadedDynamicLibrariesInfos:{"image_count":40,"image_list_address":4295244704} -// Look for an array of the old dyld_all_image_infos style of binary infos at the image_list_address. -// This an array of {void* load_addr, void* mod_date, void* pathname} +// Look for an array of the old dyld_all_image_infos style of binary infos +// at the image_list_address. +// This an array of {void* load_addr, void* mod_date, void* pathname} // // jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true} -// Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to get a list of all the +// Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to +// get a list of all the // libraries loaded // // jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]} -// Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to get the information +// Use the new style (macOS 10.12, tvOS 10, iOS 10, watchOS 3) dyld SPI to +// get the information // about the libraries loaded at these addresses. // rnb_err_t -RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p) -{ - nub_process_t pid; - // If we haven't run the process yet, return an error. - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E83"); +RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p) { + nub_process_t pid; + // If we haven't run the process yet, return an error. + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E83"); + } + + pid = m_ctx.ProcessID(); + + const char get_loaded_dynamic_libraries_infos_str[] = { + "jGetLoadedDynamicLibrariesInfos:{"}; + if (strncmp(p, get_loaded_dynamic_libraries_infos_str, + sizeof(get_loaded_dynamic_libraries_infos_str) - 1) == 0) { + p += strlen(get_loaded_dynamic_libraries_infos_str); + + JSONGenerator::ObjectSP json_sp; + + std::vector<uint64_t> macho_addresses; + bool fetch_all_solibs = false; + if (get_boolean_value_for_key_name_from_json("fetch_all_solibs", p, + fetch_all_solibs) && + fetch_all_solibs) { + json_sp = DNBGetAllLoadedLibrariesInfos(pid); + } else if (get_array_of_ints_value_for_key_name_from_json( + "solib_addresses", p, macho_addresses)) { + json_sp = DNBGetLibrariesInfoForAddresses(pid, macho_addresses); + } else { + nub_addr_t image_list_address = + get_integer_value_for_key_name_from_json("image_list_address", p); + nub_addr_t image_count = + get_integer_value_for_key_name_from_json("image_count", p); + + if (image_list_address != INVALID_NUB_ADDRESS && + image_count != INVALID_NUB_ADDRESS) { + json_sp = DNBGetLoadedDynamicLibrariesInfos(pid, image_list_address, + image_count); + } } - pid = m_ctx.ProcessID(); - - const char get_loaded_dynamic_libraries_infos_str[] = { "jGetLoadedDynamicLibrariesInfos:{" }; - if (strncmp (p, get_loaded_dynamic_libraries_infos_str, sizeof (get_loaded_dynamic_libraries_infos_str) - 1) == 0) - { - p += strlen (get_loaded_dynamic_libraries_infos_str); - - JSONGenerator::ObjectSP json_sp; - - std::vector<uint64_t> macho_addresses; - bool fetch_all_solibs = false; - if (get_boolean_value_for_key_name_from_json ("fetch_all_solibs", p, fetch_all_solibs) && fetch_all_solibs) - { - json_sp = DNBGetAllLoadedLibrariesInfos (pid); - } - else if (get_array_of_ints_value_for_key_name_from_json ("solib_addresses", p, macho_addresses)) - { - json_sp = DNBGetLibrariesInfoForAddresses (pid, macho_addresses); - } - else - { - nub_addr_t image_list_address = get_integer_value_for_key_name_from_json ("image_list_address", p); - nub_addr_t image_count = get_integer_value_for_key_name_from_json ("image_count", p); - - if (image_list_address != INVALID_NUB_ADDRESS && image_count != INVALID_NUB_ADDRESS) - { - json_sp = DNBGetLoadedDynamicLibrariesInfos (pid, image_list_address, image_count); - } - } - - if (json_sp.get()) - { - std::ostringstream json_str; - json_sp->Dump (json_str); - if (json_str.str().size() > 0) - { - std::string json_str_quoted = binary_encode_string (json_str.str()); - return SendPacket (json_str_quoted.c_str()); - } - else - { - SendPacket ("E84"); - } - } + if (json_sp.get()) { + std::ostringstream json_str; + json_sp->Dump(json_str); + if (json_str.str().size() > 0) { + std::string json_str_quoted = binary_encode_string(json_str.str()); + return SendPacket(json_str_quoted.c_str()); + } else { + SendPacket("E84"); + } } - return SendPacket ("OK"); + } + return SendPacket("OK"); } // This packet does not currently take any arguments. So the behavior is @@ -5911,556 +5754,539 @@ RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p) // send information about the inferior's shared cache // jGetSharedCacheInfo: // send "OK" to indicate that this packet is supported -rnb_err_t -RNBRemote::HandlePacket_jGetSharedCacheInfo (const char *p) -{ - nub_process_t pid; - // If we haven't run the process yet, return an error. - if (!m_ctx.HasValidProcessID()) - { - return SendPacket ("E85"); - } - - pid = m_ctx.ProcessID(); - - const char get_shared_cache_info_str[] = { "jGetSharedCacheInfo:{" }; - if (strncmp (p, get_shared_cache_info_str, sizeof (get_shared_cache_info_str) - 1) == 0) - { - JSONGenerator::ObjectSP json_sp = DNBGetSharedCacheInfo (pid); - - if (json_sp.get()) - { - std::ostringstream json_str; - json_sp->Dump (json_str); - if (json_str.str().size() > 0) - { - std::string json_str_quoted = binary_encode_string (json_str.str()); - return SendPacket (json_str_quoted.c_str()); - } - else - { - SendPacket ("E86"); - } - } +rnb_err_t RNBRemote::HandlePacket_jGetSharedCacheInfo(const char *p) { + nub_process_t pid; + // If we haven't run the process yet, return an error. + if (!m_ctx.HasValidProcessID()) { + return SendPacket("E85"); + } + + pid = m_ctx.ProcessID(); + + const char get_shared_cache_info_str[] = {"jGetSharedCacheInfo:{"}; + if (strncmp(p, get_shared_cache_info_str, + sizeof(get_shared_cache_info_str) - 1) == 0) { + JSONGenerator::ObjectSP json_sp = DNBGetSharedCacheInfo(pid); + + if (json_sp.get()) { + std::ostringstream json_str; + json_sp->Dump(json_str); + if (json_str.str().size() > 0) { + std::string json_str_quoted = binary_encode_string(json_str.str()); + return SendPacket(json_str_quoted.c_str()); + } else { + SendPacket("E86"); + } } - return SendPacket ("OK"); -} - -static bool -MachHeaderIsMainExecutable (nub_process_t pid, uint32_t addr_size, nub_addr_t mach_header_addr, mach_header &mh) -{ - DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx)", pid, addr_size, mach_header_addr); - const nub_size_t bytes_read = DNBProcessMemoryRead(pid, mach_header_addr, sizeof(mh), &mh); - if (bytes_read == sizeof(mh)) - { - DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx): mh = {\n magic = 0x%8.8x\n cpu = 0x%8.8x\n sub = 0x%8.8x\n filetype = %u\n ncmds = %u\n sizeofcmds = 0x%8.8x\n flags = 0x%8.8x }", pid, addr_size, mach_header_addr, mh.magic, mh.cputype, mh.cpusubtype, mh.filetype, mh.ncmds, mh.sizeofcmds, mh.flags); - if ((addr_size == 4 && mh.magic == MH_MAGIC) || - (addr_size == 8 && mh.magic == MH_MAGIC_64)) - { - if (mh.filetype == MH_EXECUTE) - { - DNBLogThreadedIf (LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = %u, mach_header_addr = 0x%16.16llx) -> this is the executable!!!", pid, addr_size, mach_header_addr); - return true; - } - } + } + return SendPacket("OK"); +} + +static bool MachHeaderIsMainExecutable(nub_process_t pid, uint32_t addr_size, + nub_addr_t mach_header_addr, + mach_header &mh) { + DNBLogThreadedIf(LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, " + "addr_size = %u, mach_header_addr = " + "0x%16.16llx)", + pid, addr_size, mach_header_addr); + const nub_size_t bytes_read = + DNBProcessMemoryRead(pid, mach_header_addr, sizeof(mh), &mh); + if (bytes_read == sizeof(mh)) { + DNBLogThreadedIf( + LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = %u, addr_size = " + "%u, mach_header_addr = 0x%16.16llx): mh = {\n magic = " + "0x%8.8x\n cpu = 0x%8.8x\n sub = 0x%8.8x\n filetype = " + "%u\n ncmds = %u\n sizeofcmds = 0x%8.8x\n flags = " + "0x%8.8x }", + pid, addr_size, mach_header_addr, mh.magic, mh.cputype, mh.cpusubtype, + mh.filetype, mh.ncmds, mh.sizeofcmds, mh.flags); + if ((addr_size == 4 && mh.magic == MH_MAGIC) || + (addr_size == 8 && mh.magic == MH_MAGIC_64)) { + if (mh.filetype == MH_EXECUTE) { + DNBLogThreadedIf(LOG_RNB_PROC, "GetMachHeaderForMainExecutable(pid = " + "%u, addr_size = %u, mach_header_addr = " + "0x%16.16llx) -> this is the " + "executable!!!", + pid, addr_size, mach_header_addr); + return true; + } } - return false; -} - -static nub_addr_t -GetMachHeaderForMainExecutable (const nub_process_t pid, const uint32_t addr_size, mach_header &mh) -{ - struct AllImageInfos - { - uint32_t version; - uint32_t dylib_info_count; - uint64_t dylib_info_addr; - }; - - uint64_t mach_header_addr = 0; - - const nub_addr_t shlib_addr = DNBProcessGetSharedLibraryInfoAddress (pid); - uint8_t bytes[256]; - nub_size_t bytes_read = 0; - DNBDataRef data (bytes, sizeof(bytes), false); - DNBDataRef::offset_t offset = 0; - data.SetPointerSize(addr_size); - - //---------------------------------------------------------------------- - // When we are sitting at __dyld_start, the kernel has placed the - // address of the mach header of the main executable on the stack. If we - // read the SP and dereference a pointer, we might find the mach header - // for the executable. We also just make sure there is only 1 thread - // since if we are at __dyld_start we shouldn't have multiple threads. - //---------------------------------------------------------------------- - if (DNBProcessGetNumThreads(pid) == 1) - { - nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, 0); - if (tid != INVALID_NUB_THREAD) - { - DNBRegisterValue sp_value; - if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_SP, &sp_value)) - { - uint64_t sp = addr_size == 8 ? sp_value.value.uint64 : sp_value.value.uint32; - bytes_read = DNBProcessMemoryRead(pid, sp, addr_size, bytes); - if (bytes_read == addr_size) - { - offset = 0; - mach_header_addr = data.GetPointer(&offset); - if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh)) - return mach_header_addr; - } - } + } + return false; +} + +static nub_addr_t GetMachHeaderForMainExecutable(const nub_process_t pid, + const uint32_t addr_size, + mach_header &mh) { + struct AllImageInfos { + uint32_t version; + uint32_t dylib_info_count; + uint64_t dylib_info_addr; + }; + + uint64_t mach_header_addr = 0; + + const nub_addr_t shlib_addr = DNBProcessGetSharedLibraryInfoAddress(pid); + uint8_t bytes[256]; + nub_size_t bytes_read = 0; + DNBDataRef data(bytes, sizeof(bytes), false); + DNBDataRef::offset_t offset = 0; + data.SetPointerSize(addr_size); + + //---------------------------------------------------------------------- + // When we are sitting at __dyld_start, the kernel has placed the + // address of the mach header of the main executable on the stack. If we + // read the SP and dereference a pointer, we might find the mach header + // for the executable. We also just make sure there is only 1 thread + // since if we are at __dyld_start we shouldn't have multiple threads. + //---------------------------------------------------------------------- + if (DNBProcessGetNumThreads(pid) == 1) { + nub_thread_t tid = DNBProcessGetThreadAtIndex(pid, 0); + if (tid != INVALID_NUB_THREAD) { + DNBRegisterValue sp_value; + if (DNBThreadGetRegisterValueByID(pid, tid, REGISTER_SET_GENERIC, + GENERIC_REGNUM_SP, &sp_value)) { + uint64_t sp = + addr_size == 8 ? sp_value.value.uint64 : sp_value.value.uint32; + bytes_read = DNBProcessMemoryRead(pid, sp, addr_size, bytes); + if (bytes_read == addr_size) { + offset = 0; + mach_header_addr = data.GetPointer(&offset); + if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh)) + return mach_header_addr; } + } } - - //---------------------------------------------------------------------- - // Check the dyld_all_image_info structure for a list of mach header - // since it is a very easy thing to check - //---------------------------------------------------------------------- - if (shlib_addr != INVALID_NUB_ADDRESS) - { - bytes_read = DNBProcessMemoryRead(pid, shlib_addr, sizeof(AllImageInfos), bytes); - if (bytes_read > 0) - { - AllImageInfos aii; + } + + //---------------------------------------------------------------------- + // Check the dyld_all_image_info structure for a list of mach header + // since it is a very easy thing to check + //---------------------------------------------------------------------- + if (shlib_addr != INVALID_NUB_ADDRESS) { + bytes_read = + DNBProcessMemoryRead(pid, shlib_addr, sizeof(AllImageInfos), bytes); + if (bytes_read > 0) { + AllImageInfos aii; + offset = 0; + aii.version = data.Get32(&offset); + aii.dylib_info_count = data.Get32(&offset); + if (aii.dylib_info_count > 0) { + aii.dylib_info_addr = data.GetPointer(&offset); + if (aii.dylib_info_addr != 0) { + const size_t image_info_byte_size = 3 * addr_size; + for (uint32_t i = 0; i < aii.dylib_info_count; ++i) { + bytes_read = DNBProcessMemoryRead(pid, aii.dylib_info_addr + + i * image_info_byte_size, + image_info_byte_size, bytes); + if (bytes_read != image_info_byte_size) + break; offset = 0; - aii.version = data.Get32(&offset); - aii.dylib_info_count = data.Get32(&offset); - if (aii.dylib_info_count > 0) - { - aii.dylib_info_addr = data.GetPointer(&offset); - if (aii.dylib_info_addr != 0) - { - const size_t image_info_byte_size = 3 * addr_size; - for (uint32_t i=0; i<aii.dylib_info_count; ++i) - { - bytes_read = DNBProcessMemoryRead(pid, aii.dylib_info_addr + i * image_info_byte_size, image_info_byte_size, bytes); - if (bytes_read != image_info_byte_size) - break; - offset = 0; - mach_header_addr = data.GetPointer(&offset); - if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh)) - return mach_header_addr; - } - } - } - } - } - - //---------------------------------------------------------------------- - // We failed to find the executable's mach header from the all image - // infos and by dereferencing the stack pointer. Now we fall back to - // enumerating the memory regions and looking for regions that are - // executable. - //---------------------------------------------------------------------- - DNBRegionInfo region_info; - mach_header_addr = 0; - while (DNBProcessMemoryRegionInfo(pid, mach_header_addr, ®ion_info)) - { - if (region_info.size == 0) - break; - - if (region_info.permissions & eMemoryPermissionsExecutable) - { - DNBLogThreadedIf (LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx) permissions = %c%c%c: checking region for executable mach header", region_info.addr, region_info.addr + region_info.size, (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-'); - if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh)) - return mach_header_addr; - } - else - { - DNBLogThreadedIf (LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx): permissions = %c%c%c: skipping region", region_info.addr, region_info.addr + region_info.size, (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-'); - } - // Set the address to the next mapped region - mach_header_addr = region_info.addr + region_info.size; - } - bzero (&mh, sizeof(mh)); - return INVALID_NUB_ADDRESS; -} - -rnb_err_t -RNBRemote::HandlePacket_qSymbol (const char *command) -{ - const char *p = command; - p += strlen ("qSymbol:"); - const char *sep = strchr(p, ':'); - - std::string symbol_name; - std::string symbol_value_str; - // Extract the symbol value if there is one - if (sep > p) - symbol_value_str.assign(p, sep - p); - p = sep + 1; - - if (*p) - { - // We have a symbol name - symbol_name = decode_hex_ascii_string(p); - if (!symbol_value_str.empty()) - { - nub_addr_t symbol_value = decode_uint64(symbol_value_str.c_str(), 16); - if (symbol_name == "dispatch_queue_offsets") - m_dispatch_queue_offsets_addr = symbol_value; + mach_header_addr = data.GetPointer(&offset); + if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, + mh)) + return mach_header_addr; + } } - ++m_qSymbol_index; + } } + } + + //---------------------------------------------------------------------- + // We failed to find the executable's mach header from the all image + // infos and by dereferencing the stack pointer. Now we fall back to + // enumerating the memory regions and looking for regions that are + // executable. + //---------------------------------------------------------------------- + DNBRegionInfo region_info; + mach_header_addr = 0; + while (DNBProcessMemoryRegionInfo(pid, mach_header_addr, ®ion_info)) { + if (region_info.size == 0) + break; + + if (region_info.permissions & eMemoryPermissionsExecutable) { + DNBLogThreadedIf( + LOG_RNB_PROC, "[0x%16.16llx - 0x%16.16llx) permissions = %c%c%c: " + "checking region for executable mach header", + region_info.addr, region_info.addr + region_info.size, + (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', + (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', + (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-'); + if (MachHeaderIsMainExecutable(pid, addr_size, mach_header_addr, mh)) + return mach_header_addr; + } else { + DNBLogThreadedIf( + LOG_RNB_PROC, + "[0x%16.16llx - 0x%16.16llx): permissions = %c%c%c: skipping region", + region_info.addr, region_info.addr + region_info.size, + (region_info.permissions & eMemoryPermissionsReadable) ? 'r' : '-', + (region_info.permissions & eMemoryPermissionsWritable) ? 'w' : '-', + (region_info.permissions & eMemoryPermissionsExecutable) ? 'x' : '-'); + } + // Set the address to the next mapped region + mach_header_addr = region_info.addr + region_info.size; + } + bzero(&mh, sizeof(mh)); + return INVALID_NUB_ADDRESS; +} + +rnb_err_t RNBRemote::HandlePacket_qSymbol(const char *command) { + const char *p = command; + p += strlen("qSymbol:"); + const char *sep = strchr(p, ':'); + + std::string symbol_name; + std::string symbol_value_str; + // Extract the symbol value if there is one + if (sep > p) + symbol_value_str.assign(p, sep - p); + p = sep + 1; + + if (*p) { + // We have a symbol name + symbol_name = decode_hex_ascii_string(p); + if (!symbol_value_str.empty()) { + nub_addr_t symbol_value = decode_uint64(symbol_value_str.c_str(), 16); + if (symbol_name == "dispatch_queue_offsets") + m_dispatch_queue_offsets_addr = symbol_value; + } + ++m_qSymbol_index; + } else { + // No symbol name, set our symbol index to zero so we can + // read any symbols that we need + m_qSymbol_index = 0; + } + + symbol_name.clear(); + + if (m_qSymbol_index == 0) { + if (m_dispatch_queue_offsets_addr == INVALID_NUB_ADDRESS) + symbol_name = "dispatch_queue_offsets"; else - { - // No symbol name, set our symbol index to zero so we can - // read any symbols that we need - m_qSymbol_index = 0; - } - - symbol_name.clear(); - - if (m_qSymbol_index == 0) - { - if (m_dispatch_queue_offsets_addr == INVALID_NUB_ADDRESS) - symbol_name = "dispatch_queue_offsets"; - else - ++m_qSymbol_index; - } + ++m_qSymbol_index; + } -// // Lookup next symbol when we have one... -// if (m_qSymbol_index == 1) -// { -// } + // // Lookup next symbol when we have one... + // if (m_qSymbol_index == 1) + // { + // } - - if (symbol_name.empty()) - { - // Done with symbol lookups - return SendPacket ("OK"); - } - else - { - std::ostringstream reply; - reply << "qSymbol:"; - for (size_t i = 0; i < symbol_name.size(); ++i) - reply << RAWHEX8(symbol_name[i]); - return SendPacket (reply.str().c_str()); - } + if (symbol_name.empty()) { + // Done with symbol lookups + return SendPacket("OK"); + } else { + std::ostringstream reply; + reply << "qSymbol:"; + for (size_t i = 0; i < symbol_name.size(); ++i) + reply << RAWHEX8(symbol_name[i]); + return SendPacket(reply.str().c_str()); + } } // Note that all numeric values returned by qProcessInfo are hex encoded, // including the pid and the cpu type. -rnb_err_t -RNBRemote::HandlePacket_qProcessInfo (const char *p) -{ - nub_process_t pid; - std::ostringstream rep; - - // If we haven't run the process yet, return an error. - if (!m_ctx.HasValidProcessID()) - return SendPacket ("E68"); - - pid = m_ctx.ProcessID(); - - rep << "pid:" << std::hex << pid << ';'; - - int procpid_mib[4]; - procpid_mib[0] = CTL_KERN; - procpid_mib[1] = KERN_PROC; - procpid_mib[2] = KERN_PROC_PID; - procpid_mib[3] = pid; - struct kinfo_proc proc_kinfo; - size_t proc_kinfo_size = sizeof(struct kinfo_proc); - - if (::sysctl (procpid_mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) - { - if (proc_kinfo_size > 0) - { - rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';'; - rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid << ';'; - rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid << ';'; - rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid << ';'; - if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0) - rep << "effective-gid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';'; - } - } - - cpu_type_t cputype = DNBProcessGetCPUType (pid); - if (cputype == 0) - { - DNBLog ("Unable to get the process cpu_type, making a best guess."); - cputype = best_guess_cpu_type(); - } - - uint32_t addr_size = 0; - if (cputype != 0) - { - rep << "cputype:" << std::hex << cputype << ";"; - if (cputype & CPU_ARCH_ABI64) - addr_size = 8; - else - addr_size = 4; - } - - bool host_cpu_is_64bit = false; - uint32_t is64bit_capable; - size_t is64bit_capable_len = sizeof (is64bit_capable); - if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, &is64bit_capable_len, NULL, 0) == 0) - host_cpu_is_64bit = is64bit_capable != 0; - - uint32_t cpusubtype; - size_t cpusubtype_len = sizeof(cpusubtype); - if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &cpusubtype_len, NULL, 0) == 0) - { - // If a process is CPU_TYPE_X86, then ignore the cpusubtype that we detected - // from the host and use CPU_SUBTYPE_I386_ALL because we don't want the - // CPU_SUBTYPE_X86_ARCH1 or CPU_SUBTYPE_X86_64_H to be used as the cpu subtype - // for i386... - if (host_cpu_is_64bit) - { - if (cputype == CPU_TYPE_X86) - { - cpusubtype = 3; // CPU_SUBTYPE_I386_ALL - } - else if (cputype == CPU_TYPE_ARM) - { - // We can query a process' cputype but we cannot query a process' cpusubtype. - // If the process has cputype CPU_TYPE_ARM, then it is an armv7 (32-bit process) and we - // need to override the host cpusubtype (which is in the CPU_SUBTYPE_ARM64 subtype namespace) - // with a reasonable CPU_SUBTYPE_ARMV7 subtype. - cpusubtype = 11; // CPU_SUBTYPE_ARM_V7S - } - } - rep << "cpusubtype:" << std::hex << cpusubtype << ';'; +rnb_err_t RNBRemote::HandlePacket_qProcessInfo(const char *p) { + nub_process_t pid; + std::ostringstream rep; + + // If we haven't run the process yet, return an error. + if (!m_ctx.HasValidProcessID()) + return SendPacket("E68"); + + pid = m_ctx.ProcessID(); + + rep << "pid:" << std::hex << pid << ';'; + + int procpid_mib[4]; + procpid_mib[0] = CTL_KERN; + procpid_mib[1] = KERN_PROC; + procpid_mib[2] = KERN_PROC_PID; + procpid_mib[3] = pid; + struct kinfo_proc proc_kinfo; + size_t proc_kinfo_size = sizeof(struct kinfo_proc); + + if (::sysctl(procpid_mib, 4, &proc_kinfo, &proc_kinfo_size, NULL, 0) == 0) { + if (proc_kinfo_size > 0) { + rep << "parent-pid:" << std::hex << proc_kinfo.kp_eproc.e_ppid << ';'; + rep << "real-uid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_ruid + << ';'; + rep << "real-gid:" << std::hex << proc_kinfo.kp_eproc.e_pcred.p_rgid + << ';'; + rep << "effective-uid:" << std::hex << proc_kinfo.kp_eproc.e_ucred.cr_uid + << ';'; + if (proc_kinfo.kp_eproc.e_ucred.cr_ngroups > 0) + rep << "effective-gid:" << std::hex + << proc_kinfo.kp_eproc.e_ucred.cr_groups[0] << ';'; + } + } + + cpu_type_t cputype = DNBProcessGetCPUType(pid); + if (cputype == 0) { + DNBLog("Unable to get the process cpu_type, making a best guess."); + cputype = best_guess_cpu_type(); + } + + uint32_t addr_size = 0; + if (cputype != 0) { + rep << "cputype:" << std::hex << cputype << ";"; + if (cputype & CPU_ARCH_ABI64) + addr_size = 8; + else + addr_size = 4; + } + + bool host_cpu_is_64bit = false; + uint32_t is64bit_capable; + size_t is64bit_capable_len = sizeof(is64bit_capable); + if (sysctlbyname("hw.cpu64bit_capable", &is64bit_capable, + &is64bit_capable_len, NULL, 0) == 0) + host_cpu_is_64bit = is64bit_capable != 0; + + uint32_t cpusubtype; + size_t cpusubtype_len = sizeof(cpusubtype); + if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &cpusubtype_len, NULL, 0) == + 0) { + // If a process is CPU_TYPE_X86, then ignore the cpusubtype that we detected + // from the host and use CPU_SUBTYPE_I386_ALL because we don't want the + // CPU_SUBTYPE_X86_ARCH1 or CPU_SUBTYPE_X86_64_H to be used as the cpu + // subtype + // for i386... + if (host_cpu_is_64bit) { + if (cputype == CPU_TYPE_X86) { + cpusubtype = 3; // CPU_SUBTYPE_I386_ALL + } else if (cputype == CPU_TYPE_ARM) { + // We can query a process' cputype but we cannot query a process' + // cpusubtype. + // If the process has cputype CPU_TYPE_ARM, then it is an armv7 (32-bit + // process) and we + // need to override the host cpusubtype (which is in the + // CPU_SUBTYPE_ARM64 subtype namespace) + // with a reasonable CPU_SUBTYPE_ARMV7 subtype. + cpusubtype = 11; // CPU_SUBTYPE_ARM_V7S + } } + rep << "cpusubtype:" << std::hex << cpusubtype << ';'; + } + + bool os_handled = false; + if (addr_size > 0) { + rep << "ptrsize:" << std::dec << addr_size << ';'; + +#if (defined(__x86_64__) || defined(__i386__)) + // Try and get the OS type by looking at the load commands in the main + // executable and looking for a LC_VERSION_MIN load command. This is the + // most reliable way to determine the "ostype" value when on desktop. + + mach_header mh; + nub_addr_t exe_mach_header_addr = + GetMachHeaderForMainExecutable(pid, addr_size, mh); + if (exe_mach_header_addr != INVALID_NUB_ADDRESS) { + uint64_t load_command_addr = + exe_mach_header_addr + + ((addr_size == 8) ? sizeof(mach_header_64) : sizeof(mach_header)); + load_command lc; + for (uint32_t i = 0; i < mh.ncmds && !os_handled; ++i) { + const nub_size_t bytes_read = + DNBProcessMemoryRead(pid, load_command_addr, sizeof(lc), &lc); + uint32_t raw_cmd = lc.cmd & ~LC_REQ_DYLD; + if (bytes_read != sizeof(lc)) + break; + switch (raw_cmd) { + case LC_VERSION_MIN_IPHONEOS: + os_handled = true; + rep << "ostype:ios;"; + DNBLogThreadedIf(LOG_RNB_PROC, + "LC_VERSION_MIN_IPHONEOS -> 'ostype:ios;'"); + break; - bool os_handled = false; - if (addr_size > 0) - { - rep << "ptrsize:" << std::dec << addr_size << ';'; - -#if (defined (__x86_64__) || defined (__i386__)) - // Try and get the OS type by looking at the load commands in the main - // executable and looking for a LC_VERSION_MIN load command. This is the - // most reliable way to determine the "ostype" value when on desktop. + case LC_VERSION_MIN_MACOSX: + os_handled = true; + rep << "ostype:macosx;"; + DNBLogThreadedIf(LOG_RNB_PROC, + "LC_VERSION_MIN_MACOSX -> 'ostype:macosx;'"); + break; - mach_header mh; - nub_addr_t exe_mach_header_addr = GetMachHeaderForMainExecutable (pid, addr_size, mh); - if (exe_mach_header_addr != INVALID_NUB_ADDRESS) - { - uint64_t load_command_addr = exe_mach_header_addr + ((addr_size == 8) ? sizeof(mach_header_64) : sizeof(mach_header)); - load_command lc; - for (uint32_t i=0; i<mh.ncmds && !os_handled; ++i) - { - const nub_size_t bytes_read = DNBProcessMemoryRead (pid, load_command_addr, sizeof(lc), &lc); - uint32_t raw_cmd = lc.cmd & ~LC_REQ_DYLD; - if (bytes_read != sizeof(lc)) - break; - switch (raw_cmd) - { - case LC_VERSION_MIN_IPHONEOS: - os_handled = true; - rep << "ostype:ios;"; - DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_IPHONEOS -> 'ostype:ios;'"); - break; - - case LC_VERSION_MIN_MACOSX: - os_handled = true; - rep << "ostype:macosx;"; - DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_MACOSX -> 'ostype:macosx;'"); - break; - -#if defined (LC_VERSION_MIN_TVOS) - case LC_VERSION_MIN_TVOS: - os_handled = true; - rep << "ostype:tvos;"; - DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_TVOS -> 'ostype:tvos;'"); - break; +#if defined(LC_VERSION_MIN_TVOS) + case LC_VERSION_MIN_TVOS: + os_handled = true; + rep << "ostype:tvos;"; + DNBLogThreadedIf(LOG_RNB_PROC, + "LC_VERSION_MIN_TVOS -> 'ostype:tvos;'"); + break; #endif -#if defined (LC_VERSION_MIN_WATCHOS) - case LC_VERSION_MIN_WATCHOS: - os_handled = true; - rep << "ostype:watchos;"; - DNBLogThreadedIf (LOG_RNB_PROC, "LC_VERSION_MIN_WATCHOS -> 'ostype:watchos;'"); - break; +#if defined(LC_VERSION_MIN_WATCHOS) + case LC_VERSION_MIN_WATCHOS: + os_handled = true; + rep << "ostype:watchos;"; + DNBLogThreadedIf(LOG_RNB_PROC, + "LC_VERSION_MIN_WATCHOS -> 'ostype:watchos;'"); + break; #endif - default: - break; - } - load_command_addr = load_command_addr + lc.cmdsize; - } + default: + break; } -#endif + load_command_addr = load_command_addr + lc.cmdsize; + } } +#endif + } - // If we weren't able to find the OS in a LC_VERSION_MIN load command, try - // to set it correctly by using the cpu type and other tricks - if (!os_handled) - { - // The OS in the triple should be "ios" or "macosx" which doesn't match our - // "Darwin" which gets returned from "kern.ostype", so we need to hardcode - // this for now. - if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) - { -#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1 - rep << "ostype:tvos;"; -#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 - rep << "ostype:watchos;"; + // If we weren't able to find the OS in a LC_VERSION_MIN load command, try + // to set it correctly by using the cpu type and other tricks + if (!os_handled) { + // The OS in the triple should be "ios" or "macosx" which doesn't match our + // "Darwin" which gets returned from "kern.ostype", so we need to hardcode + // this for now. + if (cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64) { +#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + rep << "ostype:tvos;"; +#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + rep << "ostype:watchos;"; #else - rep << "ostype:ios;"; + rep << "ostype:ios;"; #endif - } - else - { - bool is_ios_simulator = false; - if (cputype == CPU_TYPE_X86 || cputype == CPU_TYPE_X86_64) - { - // Check for iOS simulator binaries by getting the process argument - // and environment and checking for SIMULATOR_UDID in the environment - int proc_args_mib[3] = { CTL_KERN, KERN_PROCARGS2, (int)pid }; - - uint8_t arg_data[8192]; - size_t arg_data_size = sizeof(arg_data); - if (::sysctl (proc_args_mib, 3, arg_data, &arg_data_size , NULL, 0) == 0) - { - DNBDataRef data (arg_data, arg_data_size, false); - DNBDataRef::offset_t offset = 0; - uint32_t argc = data.Get32 (&offset); - const char *cstr; - - cstr = data.GetCStr (&offset); - if (cstr) - { - // Skip NULLs - while (1) - { - const char *p = data.PeekCStr(offset); - if ((p == NULL) || (*p != '\0')) - break; - ++offset; - } - // Now skip all arguments - for (uint32_t i = 0; i < argc; ++i) - { - data.GetCStr(&offset); - } - - // Now iterate across all environment variables - while ((cstr = data.GetCStr(&offset))) - { - if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == 0) - { - is_ios_simulator = true; - break; - } - if (cstr[0] == '\0') - break; - - } - } - } + } else { + bool is_ios_simulator = false; + if (cputype == CPU_TYPE_X86 || cputype == CPU_TYPE_X86_64) { + // Check for iOS simulator binaries by getting the process argument + // and environment and checking for SIMULATOR_UDID in the environment + int proc_args_mib[3] = {CTL_KERN, KERN_PROCARGS2, (int)pid}; + + uint8_t arg_data[8192]; + size_t arg_data_size = sizeof(arg_data); + if (::sysctl(proc_args_mib, 3, arg_data, &arg_data_size, NULL, 0) == + 0) { + DNBDataRef data(arg_data, arg_data_size, false); + DNBDataRef::offset_t offset = 0; + uint32_t argc = data.Get32(&offset); + const char *cstr; + + cstr = data.GetCStr(&offset); + if (cstr) { + // Skip NULLs + while (1) { + const char *p = data.PeekCStr(offset); + if ((p == NULL) || (*p != '\0')) + break; + ++offset; } - if (is_ios_simulator) - { -#if defined (TARGET_OS_TV) && TARGET_OS_TV == 1 - rep << "ostype:tvos;"; -#elif defined (TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 - rep << "ostype:watchos;"; -#else - rep << "ostype:ios;"; -#endif + // Now skip all arguments + for (uint32_t i = 0; i < argc; ++i) { + data.GetCStr(&offset); } - else - { - rep << "ostype:macosx;"; + + // Now iterate across all environment variables + while ((cstr = data.GetCStr(&offset))) { + if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == + 0) { + is_ios_simulator = true; + break; + } + if (cstr[0] == '\0') + break; } + } } + } + if (is_ios_simulator) { +#if defined(TARGET_OS_TV) && TARGET_OS_TV == 1 + rep << "ostype:tvos;"; +#elif defined(TARGET_OS_WATCH) && TARGET_OS_WATCH == 1 + rep << "ostype:watchos;"; +#else + rep << "ostype:ios;"; +#endif + } else { + rep << "ostype:macosx;"; + } } + } - rep << "vendor:apple;"; + rep << "vendor:apple;"; -#if defined (__LITTLE_ENDIAN__) - rep << "endian:little;"; -#elif defined (__BIG_ENDIAN__) - rep << "endian:big;"; -#elif defined (__PDP_ENDIAN__) - rep << "endian:pdp;"; +#if defined(__LITTLE_ENDIAN__) + rep << "endian:little;"; +#elif defined(__BIG_ENDIAN__) + rep << "endian:big;"; +#elif defined(__PDP_ENDIAN__) + rep << "endian:pdp;"; #endif - if (addr_size == 0) - { -#if (defined (__x86_64__) || defined (__i386__)) && defined (x86_THREAD_STATE) - nub_thread_t thread = DNBProcessGetCurrentThreadMachPort (pid); - kern_return_t kr; - x86_thread_state_t gp_regs; - mach_msg_type_number_t gp_count = x86_THREAD_STATE_COUNT; - kr = thread_get_state (static_cast<thread_act_t>(thread), - x86_THREAD_STATE, - (thread_state_t) &gp_regs, - &gp_count); - if (kr == KERN_SUCCESS) - { - if (gp_regs.tsh.flavor == x86_THREAD_STATE64) - rep << "ptrsize:8;"; - else - rep << "ptrsize:4;"; - } -#elif defined (__arm__) + if (addr_size == 0) { +#if (defined(__x86_64__) || defined(__i386__)) && defined(x86_THREAD_STATE) + nub_thread_t thread = DNBProcessGetCurrentThreadMachPort(pid); + kern_return_t kr; + x86_thread_state_t gp_regs; + mach_msg_type_number_t gp_count = x86_THREAD_STATE_COUNT; + kr = thread_get_state(static_cast<thread_act_t>(thread), x86_THREAD_STATE, + (thread_state_t)&gp_regs, &gp_count); + if (kr == KERN_SUCCESS) { + if (gp_regs.tsh.flavor == x86_THREAD_STATE64) + rep << "ptrsize:8;"; + else rep << "ptrsize:4;"; -#elif (defined (__arm64__) || defined (__aarch64__)) && defined (ARM_UNIFIED_THREAD_STATE) - nub_thread_t thread = DNBProcessGetCurrentThreadMachPort (pid); - kern_return_t kr; - arm_unified_thread_state_t gp_regs; - mach_msg_type_number_t gp_count = ARM_UNIFIED_THREAD_STATE_COUNT; - kr = thread_get_state (thread, ARM_UNIFIED_THREAD_STATE, - (thread_state_t) &gp_regs, &gp_count); - if (kr == KERN_SUCCESS) - { - if (gp_regs.ash.flavor == ARM_THREAD_STATE64) - rep << "ptrsize:8;"; - else - rep << "ptrsize:4;"; - } -#endif } - - return SendPacket (rep.str()); -} - -const RNBRemote::DispatchQueueOffsets * -RNBRemote::GetDispatchQueueOffsets() -{ - if (!m_dispatch_queue_offsets.IsValid() && m_dispatch_queue_offsets_addr != INVALID_NUB_ADDRESS && m_ctx.HasValidProcessID()) - { - nub_process_t pid = m_ctx.ProcessID(); - nub_size_t bytes_read = DNBProcessMemoryRead(pid, m_dispatch_queue_offsets_addr, sizeof(m_dispatch_queue_offsets), &m_dispatch_queue_offsets); - if (bytes_read != sizeof(m_dispatch_queue_offsets)) - m_dispatch_queue_offsets.Clear(); +#elif defined(__arm__) + rep << "ptrsize:4;"; +#elif (defined(__arm64__) || defined(__aarch64__)) && \ + defined(ARM_UNIFIED_THREAD_STATE) + nub_thread_t thread = DNBProcessGetCurrentThreadMachPort(pid); + kern_return_t kr; + arm_unified_thread_state_t gp_regs; + mach_msg_type_number_t gp_count = ARM_UNIFIED_THREAD_STATE_COUNT; + kr = thread_get_state(thread, ARM_UNIFIED_THREAD_STATE, + (thread_state_t)&gp_regs, &gp_count); + if (kr == KERN_SUCCESS) { + if (gp_regs.ash.flavor == ARM_THREAD_STATE64) + rep << "ptrsize:8;"; + else + rep << "ptrsize:4;"; } +#endif + } - if (m_dispatch_queue_offsets.IsValid()) - return &m_dispatch_queue_offsets; - else - return nullptr; -} - -void -RNBRemote::EnableCompressionNextSendPacket (compression_types type) -{ - m_compression_mode = type; - m_enable_compression_next_send_packet = true; + return SendPacket(rep.str()); } -compression_types -RNBRemote::GetCompressionType () -{ - // The first packet we send back to the debugger after a QEnableCompression request - // should be uncompressed -- so we can indicate whether the compression was enabled - // or not via OK / Enn returns. After that, all packets sent will be using the - // compression protocol. - - if (m_enable_compression_next_send_packet) - { - // One time, we send back "None" as our compression type - m_enable_compression_next_send_packet = false; - return compression_types::none; - } - return m_compression_mode; +const RNBRemote::DispatchQueueOffsets *RNBRemote::GetDispatchQueueOffsets() { + if (!m_dispatch_queue_offsets.IsValid() && + m_dispatch_queue_offsets_addr != INVALID_NUB_ADDRESS && + m_ctx.HasValidProcessID()) { + nub_process_t pid = m_ctx.ProcessID(); + nub_size_t bytes_read = DNBProcessMemoryRead( + pid, m_dispatch_queue_offsets_addr, sizeof(m_dispatch_queue_offsets), + &m_dispatch_queue_offsets); + if (bytes_read != sizeof(m_dispatch_queue_offsets)) + m_dispatch_queue_offsets.Clear(); + } + + if (m_dispatch_queue_offsets.IsValid()) + return &m_dispatch_queue_offsets; + else + return nullptr; +} + +void RNBRemote::EnableCompressionNextSendPacket(compression_types type) { + m_compression_mode = type; + m_enable_compression_next_send_packet = true; +} + +compression_types RNBRemote::GetCompressionType() { + // The first packet we send back to the debugger after a QEnableCompression + // request + // should be uncompressed -- so we can indicate whether the compression was + // enabled + // or not via OK / Enn returns. After that, all packets sent will be using + // the + // compression protocol. + + if (m_enable_compression_next_send_packet) { + // One time, we send back "None" as our compression type + m_enable_compression_next_send_packet = false; + return compression_types::none; + } + return m_compression_mode; } diff --git a/lldb/tools/debugserver/source/RNBRemote.h b/lldb/tools/debugserver/source/RNBRemote.h index 57c2a22e8df..0c9c9856308 100644 --- a/lldb/tools/debugserver/source/RNBRemote.h +++ b/lldb/tools/debugserver/source/RNBRemote.h @@ -14,15 +14,15 @@ #ifndef __RNBRemote_h__ #define __RNBRemote_h__ -#include "RNBDefs.h" #include "DNB.h" +#include "PThreadMutex.h" #include "RNBContext.h" +#include "RNBDefs.h" #include "RNBSocket.h" -#include "PThreadMutex.h" -#include <string> -#include <vector> #include <deque> #include <map> +#include <string> +#include <vector> class RNBSocket; class RNBContext; @@ -32,411 +32,383 @@ enum event_loop_mode { debug_nub, gdb_remote_protocol, done }; enum class compression_types { zlib_deflate, lz4, lzma, lzfse, none }; -class RNBRemote -{ +class RNBRemote { public: - - typedef enum { - invalid_packet = 0, - ack, // '+' - nack, // '-' - halt, // ^C (async halt) - use_extended_mode, // '!' - why_halted, // '?' - set_argv, // 'A' - set_bp, // 'B' - cont, // 'c' - continue_with_sig, // 'C' - detach, // 'D' - read_general_regs, // 'g' - write_general_regs, // 'G' - set_thread, // 'H' - step_inferior_one_cycle, // 'i' - signal_and_step_inf_one_cycle, // 'I' - kill, // 'k' - read_memory, // 'm' - write_memory, // 'M' - read_register, // 'p' - write_register, // 'P' - restart, // 'R' - single_step, // 's' - single_step_with_sig, // 'S' - search_mem_backwards, // 't' - thread_alive_p, // 'T' - vattach, // 'vAttach;pid' - vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded process name ASCII bytes - vattachorwait, // 'vAttachOrWait:XX...' where XX is one or more hex encoded process name ASCII bytes - vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded process name ASCII bytes - vcont, // 'vCont' - vcont_list_actions, // 'vCont?' - read_data_from_memory, // 'x' - write_data_to_memory, // 'X' - insert_mem_bp, // 'Z0' - remove_mem_bp, // 'z0' - insert_hardware_bp, // 'Z1' - remove_hardware_bp, // 'z1' - insert_write_watch_bp, // 'Z2' - remove_write_watch_bp, // 'z2' - insert_read_watch_bp, // 'Z3' - remove_read_watch_bp, // 'z3' - insert_access_watch_bp, // 'Z4' - remove_access_watch_bp, // 'z4' - - query_monitor, // 'qRcmd' - query_current_thread_id, // 'qC' - query_get_pid, // 'qGetPid' - query_echo, // 'qEcho' - query_thread_ids_first, // 'qfThreadInfo' - query_thread_ids_subsequent, // 'qsThreadInfo' - query_thread_extra_info, // 'qThreadExtraInfo' - query_thread_stop_info, // 'qThreadStopInfo' - query_image_offsets, // 'qOffsets' - query_symbol_lookup, // 'qSymbol' - query_launch_success, // 'qLaunchSuccess' - query_register_info, // 'qRegisterInfo' - query_shlib_notify_info_addr, // 'qShlibInfoAddr' - query_step_packet_supported, // 'qStepPacketSupported' - query_supported_features, // 'qSupported' - query_vattachorwait_supported, // 'qVAttachOrWaitSupported' - query_sync_thread_state_supported,// 'QSyncThreadState' - query_host_info, // 'qHostInfo' - query_gdb_server_version, // 'qGDBServerVersion' - query_process_info, // 'qProcessInfo' - json_query_thread_extended_info,// 'jThreadExtendedInfo' - json_query_get_loaded_dynamic_libraries_infos, // 'jGetLoadedDynamicLibrariesInfos' - json_query_threads_info, // 'jThreadsInfo' - json_query_get_shared_cache_info, // 'jGetSharedCacheInfo' - pass_signals_to_inferior, // 'QPassSignals' - start_noack_mode, // 'QStartNoAckMode' - prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID - set_logging_mode, // 'QSetLogging:' - set_max_packet_size, // 'QSetMaxPacketSize:' - set_max_payload_size, // 'QSetMaxPayloadSize:' - set_environment_variable, // 'QEnvironment:' - set_environment_variable_hex, // 'QEnvironmentHexEncoded:' - set_launch_arch, // 'QLaunchArch:' - set_disable_aslr, // 'QSetDisableASLR:' - set_stdin, // 'QSetSTDIN:' - set_stdout, // 'QSetSTDOUT:' - set_stderr, // 'QSetSTDERR:' - set_working_dir, // 'QSetWorkingDir:' - set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:' - sync_thread_state, // 'QSyncThreadState:' - memory_region_info, // 'qMemoryRegionInfo:' - get_profile_data, // 'qGetProfileData' - set_enable_profiling, // 'QSetEnableAsyncProfiling' - enable_compression, // 'QEnableCompression:' - watchpoint_support_info, // 'qWatchpointSupportInfo:' - allocate_memory, // '_M' - deallocate_memory, // '_m' - set_process_event, // 'QSetProcessEvent:' - save_register_state, // '_g' - restore_register_state, // '_G' - speed_test, // 'qSpeedTest:' - set_detach_on_error, // 'QSetDetachOnError:' - query_transfer, // 'qXfer:' - query_supported_async_json_packets, // 'QSupportedAsyncJSONPackets' - configure_darwin_log, // 'ConfigureDarwinLog:' - unknown_type - } PacketEnum; - - typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p); - - RNBRemote (); - ~RNBRemote (); - - void Initialize(); - - bool InitializeRegisters (bool force = false); - - rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL); - rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL); - - nub_thread_t GetContinueThread () const - { - return m_continue_thread; - } - - void SetContinueThread (nub_thread_t tid) - { - m_continue_thread = tid; - } - - nub_thread_t GetCurrentThread () const - { - if (m_thread == 0 || m_thread == (nub_thread_t)-1) - return DNBProcessGetCurrentThread (m_ctx.ProcessID()); - return m_thread; - } - - void SetCurrentThread (nub_thread_t tid) - { - DNBProcessSetCurrentThread (m_ctx.ProcessID(), tid); - m_thread = tid; - } - - static void* ThreadFunctionReadRemoteData(void *arg); - void StartReadRemoteDataThread (); - void StopReadRemoteDataThread (); - - void NotifyThatProcessStopped (void); - - rnb_err_t HandlePacket_A (const char *p); - rnb_err_t HandlePacket_H (const char *p); - rnb_err_t HandlePacket_qC (const char *p); - rnb_err_t HandlePacket_qRcmd (const char *p); - rnb_err_t HandlePacket_qGetPid (const char *p); - rnb_err_t HandlePacket_qEcho (const char *p); - rnb_err_t HandlePacket_qLaunchSuccess (const char *p); - rnb_err_t HandlePacket_qRegisterInfo (const char *p); - rnb_err_t HandlePacket_qShlibInfoAddr (const char *p); - rnb_err_t HandlePacket_qStepPacketSupported (const char *p); - rnb_err_t HandlePacket_qVAttachOrWaitSupported (const char *p); - rnb_err_t HandlePacket_qSyncThreadStateSupported (const char *p); - rnb_err_t HandlePacket_qThreadInfo (const char *p); - rnb_err_t HandlePacket_jThreadExtendedInfo (const char *p); - rnb_err_t HandlePacket_jGetLoadedDynamicLibrariesInfos (const char *p); - rnb_err_t HandlePacket_jThreadsInfo (const char *p); - rnb_err_t HandlePacket_jGetSharedCacheInfo (const char *p); - rnb_err_t HandlePacket_qThreadExtraInfo (const char *p); - rnb_err_t HandlePacket_qThreadStopInfo (const char *p); - rnb_err_t HandlePacket_qHostInfo (const char *p); - rnb_err_t HandlePacket_qGDBServerVersion (const char *p); - rnb_err_t HandlePacket_qProcessInfo (const char *p); - rnb_err_t HandlePacket_qSymbol (const char *p); - rnb_err_t HandlePacket_QStartNoAckMode (const char *p); - rnb_err_t HandlePacket_QThreadSuffixSupported (const char *p); - rnb_err_t HandlePacket_QSetLogging (const char *p); - rnb_err_t HandlePacket_QSetDisableASLR (const char *p); - rnb_err_t HandlePacket_QSetSTDIO (const char *p); - rnb_err_t HandlePacket_QSetWorkingDir (const char *p); - rnb_err_t HandlePacket_QSetMaxPayloadSize (const char *p); - rnb_err_t HandlePacket_QSetMaxPacketSize (const char *p); - rnb_err_t HandlePacket_QEnvironment (const char *p); - rnb_err_t HandlePacket_QEnvironmentHexEncoded (const char *p); - rnb_err_t HandlePacket_QLaunchArch (const char *p); - rnb_err_t HandlePacket_QListThreadsInStopReply (const char *p); - rnb_err_t HandlePacket_QSyncThreadState (const char *p); - rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID (const char *p); - rnb_err_t HandlePacket_QSetProcessEvent (const char *p); - rnb_err_t HandlePacket_last_signal (const char *p); - rnb_err_t HandlePacket_m (const char *p); - rnb_err_t HandlePacket_M (const char *p); - rnb_err_t HandlePacket_x (const char *p); - rnb_err_t HandlePacket_X (const char *p); - rnb_err_t HandlePacket_g (const char *p); - rnb_err_t HandlePacket_G (const char *p); - rnb_err_t HandlePacket_z (const char *p); - rnb_err_t HandlePacket_T (const char *p); - rnb_err_t HandlePacket_p (const char *p); - rnb_err_t HandlePacket_P (const char *p); - rnb_err_t HandlePacket_c (const char *p); - rnb_err_t HandlePacket_C (const char *p); - rnb_err_t HandlePacket_D (const char *p); - rnb_err_t HandlePacket_k (const char *p); - rnb_err_t HandlePacket_s (const char *p); - rnb_err_t HandlePacket_S (const char *p); - rnb_err_t HandlePacket_qSupported (const char *p); - rnb_err_t HandlePacket_v (const char *p); - rnb_err_t HandlePacket_UNIMPLEMENTED (const char *p); - rnb_err_t HandlePacket_ILLFORMED (const char *file, int line, const char *p, const char *description); - rnb_err_t HandlePacket_AllocateMemory (const char *p); - rnb_err_t HandlePacket_DeallocateMemory (const char *p); - rnb_err_t HandlePacket_SaveRegisterState (const char *p); - rnb_err_t HandlePacket_RestoreRegisterState (const char *p); - rnb_err_t HandlePacket_MemoryRegionInfo (const char *p); - rnb_err_t HandlePacket_GetProfileData(const char *p); - rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p); - rnb_err_t HandlePacket_QEnableCompression(const char *p); - rnb_err_t HandlePacket_WatchpointSupportInfo (const char *p); - rnb_err_t HandlePacket_qSpeedTest (const char *p); - rnb_err_t HandlePacket_qXfer (const char *p); - rnb_err_t HandlePacket_stop_process (const char *p); - rnb_err_t HandlePacket_QSetDetachOnError (const char *p); - rnb_err_t HandlePacket_qStructuredDataPlugins (const char *p); - rnb_err_t HandlePacket_QConfigureDarwinLog (const char *p); - - rnb_err_t SendStopReplyPacketForThread (nub_thread_t tid); - rnb_err_t SendHexEncodedBytePacket (const char *header, const void *buf, size_t buf_len, const char *footer); - rnb_err_t SendSTDOUTPacket (char *buf, nub_size_t buf_size); - rnb_err_t SendSTDERRPacket (char *buf, nub_size_t buf_size); - void FlushSTDIO (); - void SendAsyncProfileData (); - rnb_err_t SendAsyncProfileDataPacket (char *buf, nub_size_t buf_size); - void SendAsyncDarwinLogData (); - rnb_err_t SendAsyncJSONPacket (const JSONGenerator::Dictionary &dictionary); - - RNBContext& Context() { return m_ctx; } - RNBSocket& Comm() { return m_comm; } + typedef enum { + invalid_packet = 0, + ack, // '+' + nack, // '-' + halt, // ^C (async halt) + use_extended_mode, // '!' + why_halted, // '?' + set_argv, // 'A' + set_bp, // 'B' + cont, // 'c' + continue_with_sig, // 'C' + detach, // 'D' + read_general_regs, // 'g' + write_general_regs, // 'G' + set_thread, // 'H' + step_inferior_one_cycle, // 'i' + signal_and_step_inf_one_cycle, // 'I' + kill, // 'k' + read_memory, // 'm' + write_memory, // 'M' + read_register, // 'p' + write_register, // 'P' + restart, // 'R' + single_step, // 's' + single_step_with_sig, // 'S' + search_mem_backwards, // 't' + thread_alive_p, // 'T' + vattach, // 'vAttach;pid' + vattachwait, // 'vAttachWait:XX...' where XX is one or more hex encoded + // process name ASCII bytes + vattachorwait, // 'vAttachOrWait:XX...' where XX is one or more hex encoded + // process name ASCII bytes + vattachname, // 'vAttachName:XX...' where XX is one or more hex encoded + // process name ASCII bytes + vcont, // 'vCont' + vcont_list_actions, // 'vCont?' + read_data_from_memory, // 'x' + write_data_to_memory, // 'X' + insert_mem_bp, // 'Z0' + remove_mem_bp, // 'z0' + insert_hardware_bp, // 'Z1' + remove_hardware_bp, // 'z1' + insert_write_watch_bp, // 'Z2' + remove_write_watch_bp, // 'z2' + insert_read_watch_bp, // 'Z3' + remove_read_watch_bp, // 'z3' + insert_access_watch_bp, // 'Z4' + remove_access_watch_bp, // 'z4' + + query_monitor, // 'qRcmd' + query_current_thread_id, // 'qC' + query_get_pid, // 'qGetPid' + query_echo, // 'qEcho' + query_thread_ids_first, // 'qfThreadInfo' + query_thread_ids_subsequent, // 'qsThreadInfo' + query_thread_extra_info, // 'qThreadExtraInfo' + query_thread_stop_info, // 'qThreadStopInfo' + query_image_offsets, // 'qOffsets' + query_symbol_lookup, // 'qSymbol' + query_launch_success, // 'qLaunchSuccess' + query_register_info, // 'qRegisterInfo' + query_shlib_notify_info_addr, // 'qShlibInfoAddr' + query_step_packet_supported, // 'qStepPacketSupported' + query_supported_features, // 'qSupported' + query_vattachorwait_supported, // 'qVAttachOrWaitSupported' + query_sync_thread_state_supported, // 'QSyncThreadState' + query_host_info, // 'qHostInfo' + query_gdb_server_version, // 'qGDBServerVersion' + query_process_info, // 'qProcessInfo' + json_query_thread_extended_info, // 'jThreadExtendedInfo' + json_query_get_loaded_dynamic_libraries_infos, // 'jGetLoadedDynamicLibrariesInfos' + json_query_threads_info, // 'jThreadsInfo' + json_query_get_shared_cache_info, // 'jGetSharedCacheInfo' + pass_signals_to_inferior, // 'QPassSignals' + start_noack_mode, // 'QStartNoAckMode' + prefix_reg_packets_with_tid, // 'QPrefixRegisterPacketsWithThreadID + set_logging_mode, // 'QSetLogging:' + set_max_packet_size, // 'QSetMaxPacketSize:' + set_max_payload_size, // 'QSetMaxPayloadSize:' + set_environment_variable, // 'QEnvironment:' + set_environment_variable_hex, // 'QEnvironmentHexEncoded:' + set_launch_arch, // 'QLaunchArch:' + set_disable_aslr, // 'QSetDisableASLR:' + set_stdin, // 'QSetSTDIN:' + set_stdout, // 'QSetSTDOUT:' + set_stderr, // 'QSetSTDERR:' + set_working_dir, // 'QSetWorkingDir:' + set_list_threads_in_stop_reply, // 'QListThreadsInStopReply:' + sync_thread_state, // 'QSyncThreadState:' + memory_region_info, // 'qMemoryRegionInfo:' + get_profile_data, // 'qGetProfileData' + set_enable_profiling, // 'QSetEnableAsyncProfiling' + enable_compression, // 'QEnableCompression:' + watchpoint_support_info, // 'qWatchpointSupportInfo:' + allocate_memory, // '_M' + deallocate_memory, // '_m' + set_process_event, // 'QSetProcessEvent:' + save_register_state, // '_g' + restore_register_state, // '_G' + speed_test, // 'qSpeedTest:' + set_detach_on_error, // 'QSetDetachOnError:' + query_transfer, // 'qXfer:' + query_supported_async_json_packets, // 'QSupportedAsyncJSONPackets' + configure_darwin_log, // 'ConfigureDarwinLog:' + unknown_type + } PacketEnum; + + typedef rnb_err_t (RNBRemote::*HandlePacketCallback)(const char *p); + + RNBRemote(); + ~RNBRemote(); + + void Initialize(); + + bool InitializeRegisters(bool force = false); + + rnb_err_t HandleAsyncPacket(PacketEnum *type = NULL); + rnb_err_t HandleReceivedPacket(PacketEnum *type = NULL); + + nub_thread_t GetContinueThread() const { return m_continue_thread; } + + void SetContinueThread(nub_thread_t tid) { m_continue_thread = tid; } + + nub_thread_t GetCurrentThread() const { + if (m_thread == 0 || m_thread == (nub_thread_t)-1) + return DNBProcessGetCurrentThread(m_ctx.ProcessID()); + return m_thread; + } + + void SetCurrentThread(nub_thread_t tid) { + DNBProcessSetCurrentThread(m_ctx.ProcessID(), tid); + m_thread = tid; + } + + static void *ThreadFunctionReadRemoteData(void *arg); + void StartReadRemoteDataThread(); + void StopReadRemoteDataThread(); + + void NotifyThatProcessStopped(void); + + rnb_err_t HandlePacket_A(const char *p); + rnb_err_t HandlePacket_H(const char *p); + rnb_err_t HandlePacket_qC(const char *p); + rnb_err_t HandlePacket_qRcmd(const char *p); + rnb_err_t HandlePacket_qGetPid(const char *p); + rnb_err_t HandlePacket_qEcho(const char *p); + rnb_err_t HandlePacket_qLaunchSuccess(const char *p); + rnb_err_t HandlePacket_qRegisterInfo(const char *p); + rnb_err_t HandlePacket_qShlibInfoAddr(const char *p); + rnb_err_t HandlePacket_qStepPacketSupported(const char *p); + rnb_err_t HandlePacket_qVAttachOrWaitSupported(const char *p); + rnb_err_t HandlePacket_qSyncThreadStateSupported(const char *p); + rnb_err_t HandlePacket_qThreadInfo(const char *p); + rnb_err_t HandlePacket_jThreadExtendedInfo(const char *p); + rnb_err_t HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p); + rnb_err_t HandlePacket_jThreadsInfo(const char *p); + rnb_err_t HandlePacket_jGetSharedCacheInfo(const char *p); + rnb_err_t HandlePacket_qThreadExtraInfo(const char *p); + rnb_err_t HandlePacket_qThreadStopInfo(const char *p); + rnb_err_t HandlePacket_qHostInfo(const char *p); + rnb_err_t HandlePacket_qGDBServerVersion(const char *p); + rnb_err_t HandlePacket_qProcessInfo(const char *p); + rnb_err_t HandlePacket_qSymbol(const char *p); + rnb_err_t HandlePacket_QStartNoAckMode(const char *p); + rnb_err_t HandlePacket_QThreadSuffixSupported(const char *p); + rnb_err_t HandlePacket_QSetLogging(const char *p); + rnb_err_t HandlePacket_QSetDisableASLR(const char *p); + rnb_err_t HandlePacket_QSetSTDIO(const char *p); + rnb_err_t HandlePacket_QSetWorkingDir(const char *p); + rnb_err_t HandlePacket_QSetMaxPayloadSize(const char *p); + rnb_err_t HandlePacket_QSetMaxPacketSize(const char *p); + rnb_err_t HandlePacket_QEnvironment(const char *p); + rnb_err_t HandlePacket_QEnvironmentHexEncoded(const char *p); + rnb_err_t HandlePacket_QLaunchArch(const char *p); + rnb_err_t HandlePacket_QListThreadsInStopReply(const char *p); + rnb_err_t HandlePacket_QSyncThreadState(const char *p); + rnb_err_t HandlePacket_QPrefixRegisterPacketsWithThreadID(const char *p); + rnb_err_t HandlePacket_QSetProcessEvent(const char *p); + rnb_err_t HandlePacket_last_signal(const char *p); + rnb_err_t HandlePacket_m(const char *p); + rnb_err_t HandlePacket_M(const char *p); + rnb_err_t HandlePacket_x(const char *p); + rnb_err_t HandlePacket_X(const char *p); + rnb_err_t HandlePacket_g(const char *p); + rnb_err_t HandlePacket_G(const char *p); + rnb_err_t HandlePacket_z(const char *p); + rnb_err_t HandlePacket_T(const char *p); + rnb_err_t HandlePacket_p(const char *p); + rnb_err_t HandlePacket_P(const char *p); + rnb_err_t HandlePacket_c(const char *p); + rnb_err_t HandlePacket_C(const char *p); + rnb_err_t HandlePacket_D(const char *p); + rnb_err_t HandlePacket_k(const char *p); + rnb_err_t HandlePacket_s(const char *p); + rnb_err_t HandlePacket_S(const char *p); + rnb_err_t HandlePacket_qSupported(const char *p); + rnb_err_t HandlePacket_v(const char *p); + rnb_err_t HandlePacket_UNIMPLEMENTED(const char *p); + rnb_err_t HandlePacket_ILLFORMED(const char *file, int line, const char *p, + const char *description); + rnb_err_t HandlePacket_AllocateMemory(const char *p); + rnb_err_t HandlePacket_DeallocateMemory(const char *p); + rnb_err_t HandlePacket_SaveRegisterState(const char *p); + rnb_err_t HandlePacket_RestoreRegisterState(const char *p); + rnb_err_t HandlePacket_MemoryRegionInfo(const char *p); + rnb_err_t HandlePacket_GetProfileData(const char *p); + rnb_err_t HandlePacket_SetEnableAsyncProfiling(const char *p); + rnb_err_t HandlePacket_QEnableCompression(const char *p); + rnb_err_t HandlePacket_WatchpointSupportInfo(const char *p); + rnb_err_t HandlePacket_qSpeedTest(const char *p); + rnb_err_t HandlePacket_qXfer(const char *p); + rnb_err_t HandlePacket_stop_process(const char *p); + rnb_err_t HandlePacket_QSetDetachOnError(const char *p); + rnb_err_t HandlePacket_qStructuredDataPlugins(const char *p); + rnb_err_t HandlePacket_QConfigureDarwinLog(const char *p); + + rnb_err_t SendStopReplyPacketForThread(nub_thread_t tid); + rnb_err_t SendHexEncodedBytePacket(const char *header, const void *buf, + size_t buf_len, const char *footer); + rnb_err_t SendSTDOUTPacket(char *buf, nub_size_t buf_size); + rnb_err_t SendSTDERRPacket(char *buf, nub_size_t buf_size); + void FlushSTDIO(); + void SendAsyncProfileData(); + rnb_err_t SendAsyncProfileDataPacket(char *buf, nub_size_t buf_size); + void SendAsyncDarwinLogData(); + rnb_err_t SendAsyncJSONPacket(const JSONGenerator::Dictionary &dictionary); + + RNBContext &Context() { return m_ctx; } + RNBSocket &Comm() { return m_comm; } private: - // Outlaw some constructors - RNBRemote (const RNBRemote &); + // Outlaw some constructors + RNBRemote(const RNBRemote &); protected: - - rnb_err_t GetCommData (); - void CommDataReceived(const std::string& data); - struct Packet - { - typedef std::vector<Packet> collection; - typedef collection::iterator iterator; - typedef collection::const_iterator const_iterator; - PacketEnum type; - HandlePacketCallback normal; // Function to call when inferior is halted - HandlePacketCallback async; // Function to call when inferior is running - std::string abbrev; - std::string printable_name; - - bool - IsPlatformPacket () const - { - switch (type) - { - case set_logging_mode: - case query_host_info: - return true; - default: - break; - } - return false; - } - Packet() : - type(invalid_packet), - normal (NULL), - async (NULL), - abbrev (), - printable_name () - { - } - - Packet( PacketEnum in_type, - HandlePacketCallback in_normal, - HandlePacketCallback in_async, - const char *in_abbrev, - const char *in_printable_name) : - type (in_type), - normal (in_normal), - async (in_async), - abbrev (in_abbrev), - printable_name (in_printable_name) - { - } - }; - - - struct DispatchQueueOffsets - { - uint16_t dqo_version; - uint16_t dqo_label; - uint16_t dqo_label_size; - uint16_t dqo_flags; - uint16_t dqo_flags_size; - uint16_t dqo_serialnum; - uint16_t dqo_serialnum_size; - uint16_t dqo_width; - uint16_t dqo_width_size; - uint16_t dqo_running; - uint16_t dqo_running_size; - uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - uint16_t dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X 10.10/iOS 8 - - DispatchQueueOffsets () - { - Clear(); - } - - void - Clear() - { - dqo_version = UINT16_MAX; - dqo_label = UINT16_MAX; - dqo_label_size = UINT16_MAX; - dqo_flags = UINT16_MAX; - dqo_flags_size = UINT16_MAX; - dqo_serialnum = UINT16_MAX; - dqo_serialnum_size = UINT16_MAX; - dqo_width = UINT16_MAX; - dqo_width_size = UINT16_MAX; - dqo_running = UINT16_MAX; - dqo_running_size = UINT16_MAX; - dqo_suspend_cnt = UINT16_MAX; - dqo_suspend_cnt_size = UINT16_MAX; - dqo_target_queue = UINT16_MAX; - dqo_target_queue_size = UINT16_MAX; - dqo_priority = UINT16_MAX; - dqo_priority_size = UINT16_MAX; - } - - bool - IsValid () const - { - return dqo_version != UINT16_MAX; - } - - void - GetThreadQueueInfo (nub_process_t pid, - nub_addr_t dispatch_qaddr, + rnb_err_t GetCommData(); + void CommDataReceived(const std::string &data); + struct Packet { + typedef std::vector<Packet> collection; + typedef collection::iterator iterator; + typedef collection::const_iterator const_iterator; + PacketEnum type; + HandlePacketCallback normal; // Function to call when inferior is halted + HandlePacketCallback async; // Function to call when inferior is running + std::string abbrev; + std::string printable_name; + + bool IsPlatformPacket() const { + switch (type) { + case set_logging_mode: + case query_host_info: + return true; + default: + break; + } + return false; + } + Packet() + : type(invalid_packet), normal(NULL), async(NULL), abbrev(), + printable_name() {} + + Packet(PacketEnum in_type, HandlePacketCallback in_normal, + HandlePacketCallback in_async, const char *in_abbrev, + const char *in_printable_name) + : type(in_type), normal(in_normal), async(in_async), abbrev(in_abbrev), + printable_name(in_printable_name) {} + }; + + struct DispatchQueueOffsets { + uint16_t dqo_version; + uint16_t dqo_label; + uint16_t dqo_label_size; + uint16_t dqo_flags; + uint16_t dqo_flags_size; + uint16_t dqo_serialnum; + uint16_t dqo_serialnum_size; + uint16_t dqo_width; + uint16_t dqo_width_size; + uint16_t dqo_running; + uint16_t dqo_running_size; + uint16_t dqo_suspend_cnt; // version 5 and later, starting with Mac OS X + // 10.10/iOS 8 + uint16_t dqo_suspend_cnt_size; // version 5 and later, starting with Mac OS + // X 10.10/iOS 8 + uint16_t dqo_target_queue; // version 5 and later, starting with Mac OS X + // 10.10/iOS 8 + uint16_t dqo_target_queue_size; // version 5 and later, starting with Mac OS + // X 10.10/iOS 8 + uint16_t + dqo_priority; // version 5 and later, starting with Mac OS X 10.10/iOS 8 + uint16_t dqo_priority_size; // version 5 and later, starting with Mac OS X + // 10.10/iOS 8 + + DispatchQueueOffsets() { Clear(); } + + void Clear() { + dqo_version = UINT16_MAX; + dqo_label = UINT16_MAX; + dqo_label_size = UINT16_MAX; + dqo_flags = UINT16_MAX; + dqo_flags_size = UINT16_MAX; + dqo_serialnum = UINT16_MAX; + dqo_serialnum_size = UINT16_MAX; + dqo_width = UINT16_MAX; + dqo_width_size = UINT16_MAX; + dqo_running = UINT16_MAX; + dqo_running_size = UINT16_MAX; + dqo_suspend_cnt = UINT16_MAX; + dqo_suspend_cnt_size = UINT16_MAX; + dqo_target_queue = UINT16_MAX; + dqo_target_queue_size = UINT16_MAX; + dqo_priority = UINT16_MAX; + dqo_priority_size = UINT16_MAX; + } + + bool IsValid() const { return dqo_version != UINT16_MAX; } + + void GetThreadQueueInfo(nub_process_t pid, nub_addr_t dispatch_qaddr, nub_addr_t &dispatch_queue_t, - std::string &queue_name, - uint64_t &queue_width, + std::string &queue_name, uint64_t &queue_width, uint64_t &queue_serialnum) const; - }; - - rnb_err_t GetPacket (std::string &packet_data, RNBRemote::Packet& packet_info, bool wait); - rnb_err_t SendPacket (const std::string &); - std::string CompressString (const std::string &); - - void CreatePacketTable (); - rnb_err_t GetPacketPayload (std::string &); - - nub_thread_t - ExtractThreadIDFromThreadSuffix (const char *p); - - void - EnableCompressionNextSendPacket (compression_types); - - compression_types - GetCompressionType (); - - const DispatchQueueOffsets * - GetDispatchQueueOffsets(); - - JSONGenerator::ObjectSP - GetJSONThreadsInfo (bool threads_with_valid_stop_info_only); - - RNBContext m_ctx; // process context - RNBSocket m_comm; // communication port - std::string m_arch; - nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all - nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all - PThreadMutex m_mutex; // Mutex that protects - DispatchQueueOffsets m_dispatch_queue_offsets; - nub_addr_t m_dispatch_queue_offsets_addr; - uint32_t m_qSymbol_index; - uint32_t m_packets_recvd; - Packet::collection m_packets; - std::deque<std::string> m_rx_packets; - std::string m_rx_partial_data; // For packets that may come in more than one batch, anything left over can be left here - pthread_t m_rx_pthread; - uint32_t m_max_payload_size; // the maximum sized payload we should send to gdb - bool m_extended_mode; // are we in extended mode? - bool m_noack_mode; // are we in no-ack mode? - bool m_thread_suffix_supported; // Set to true if the 'p', 'P', 'g', and 'G' packets should be prefixed with the thread ID and colon: - // "$pRR;thread:TTTT;" instead of "$pRR" - // "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV" - // "$g;thread:TTTT" instead of "$g" - // "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV" - bool m_list_threads_in_stop_reply; - - size_t m_compression_minsize; // only packets larger than this size will be compressed - bool m_enable_compression_next_send_packet; - - compression_types m_compression_mode; + }; + + rnb_err_t GetPacket(std::string &packet_data, RNBRemote::Packet &packet_info, + bool wait); + rnb_err_t SendPacket(const std::string &); + std::string CompressString(const std::string &); + + void CreatePacketTable(); + rnb_err_t GetPacketPayload(std::string &); + + nub_thread_t ExtractThreadIDFromThreadSuffix(const char *p); + + void EnableCompressionNextSendPacket(compression_types); + + compression_types GetCompressionType(); + + const DispatchQueueOffsets *GetDispatchQueueOffsets(); + + JSONGenerator::ObjectSP + GetJSONThreadsInfo(bool threads_with_valid_stop_info_only); + + RNBContext m_ctx; // process context + RNBSocket m_comm; // communication port + std::string m_arch; + nub_thread_t m_continue_thread; // thread to continue; 0 for any, -1 for all + nub_thread_t m_thread; // thread for other ops; 0 for any, -1 for all + PThreadMutex m_mutex; // Mutex that protects + DispatchQueueOffsets m_dispatch_queue_offsets; + nub_addr_t m_dispatch_queue_offsets_addr; + uint32_t m_qSymbol_index; + uint32_t m_packets_recvd; + Packet::collection m_packets; + std::deque<std::string> m_rx_packets; + std::string m_rx_partial_data; // For packets that may come in more than one + // batch, anything left over can be left here + pthread_t m_rx_pthread; + uint32_t + m_max_payload_size; // the maximum sized payload we should send to gdb + bool m_extended_mode; // are we in extended mode? + bool m_noack_mode; // are we in no-ack mode? + bool m_thread_suffix_supported; // Set to true if the 'p', 'P', 'g', and 'G' + // packets should be prefixed with the thread + // ID and colon: + // "$pRR;thread:TTTT;" instead of "$pRR" + // "$PRR=VVVVVVVV;thread:TTTT;" instead of "$PRR=VVVVVVVV" + // "$g;thread:TTTT" instead of "$g" + // "$GVVVVVVVVVVVVVV;thread:TTTT;#00 instead of "$GVVVVVVVVVVVVVV" + bool m_list_threads_in_stop_reply; + + size_t m_compression_minsize; // only packets larger than this size will be + // compressed + bool m_enable_compression_next_send_packet; + + compression_types m_compression_mode; }; /* We translate the /usr/include/mach/exception_types.h exception types @@ -445,12 +417,12 @@ protected: coded values for TARGET_EXC_BAD_ACCESS et al must match the gdb values in its include/gdb/signals.h. */ -#define TARGET_EXC_BAD_ACCESS 0x91 +#define TARGET_EXC_BAD_ACCESS 0x91 #define TARGET_EXC_BAD_INSTRUCTION 0x92 -#define TARGET_EXC_ARITHMETIC 0x93 -#define TARGET_EXC_EMULATION 0x94 -#define TARGET_EXC_SOFTWARE 0x95 -#define TARGET_EXC_BREAKPOINT 0x96 +#define TARGET_EXC_ARITHMETIC 0x93 +#define TARGET_EXC_EMULATION 0x94 +#define TARGET_EXC_SOFTWARE 0x95 +#define TARGET_EXC_BREAKPOINT 0x96 /* Generally speaking, you can't assume gdb can receive more than 399 bytes at a time with a random gdb. This bufsize constant is only specifying diff --git a/lldb/tools/debugserver/source/RNBServices.cpp b/lldb/tools/debugserver/source/RNBServices.cpp index ebd390267f4..d0b7e099d23 100644 --- a/lldb/tools/debugserver/source/RNBServices.cpp +++ b/lldb/tools/debugserver/source/RNBServices.cpp @@ -13,214 +13,223 @@ #include "RNBServices.h" +#include "CFString.h" +#include "DNBLog.h" +#include "MacOSX/CFUtils.h" #include <CoreFoundation/CoreFoundation.h> #include <libproc.h> -#include <unistd.h> #include <sys/sysctl.h> -#include "CFString.h" +#include <unistd.h> #include <vector> -#include "DNBLog.h" -#include "MacOSX/CFUtils.h" -// For now only SpringBoard has a notion of "Applications" that it can list for us. +// For now only SpringBoard has a notion of "Applications" that it can list for +// us. // So we have to use the SpringBoard API's here. -#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) #include <SpringBoardServices/SpringBoardServices.h> #endif // From DNB.cpp -size_t GetAllInfos (std::vector<struct kinfo_proc>& proc_infos); - -int -GetProcesses (CFMutableArrayRef plistMutableArray, bool all_users) -{ - if (plistMutableArray == NULL) - return -1; - - // Running as root, get all processes - std::vector<struct kinfo_proc> proc_infos; - const size_t num_proc_infos = GetAllInfos(proc_infos); - if (num_proc_infos > 0) - { - const pid_t our_pid = getpid(); - const uid_t our_uid = getuid(); - uint32_t i; - CFAllocatorRef alloc = kCFAllocatorDefault; - - for (i=0; i<num_proc_infos; i++) - { - struct kinfo_proc &proc_info = proc_infos[i]; - - bool kinfo_user_matches; - // Special case, if lldb is being run as root we can attach to anything. - if (all_users) - kinfo_user_matches = true; - else - kinfo_user_matches = proc_info.kp_eproc.e_pcred.p_ruid == our_uid; - - - const pid_t pid = proc_info.kp_proc.p_pid; - // Skip zombie processes and processes with unset status - if (kinfo_user_matches == false || // User is acceptable - pid == our_pid || // Skip this process - pid == 0 || // Skip kernel (kernel pid is zero) - proc_info.kp_proc.p_stat == SZOMB || // Zombies are bad, they like brains... - proc_info.kp_proc.p_flag & P_TRACED || // Being debugged? - proc_info.kp_proc.p_flag & P_WEXIT || // Working on exiting? - proc_info.kp_proc.p_flag & P_TRANSLATED) // Skip translated ppc (Rosetta) - continue; - - // Create a new mutable dictionary for each application - CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - - // Get the process id for the app (if there is one) - const int32_t pid_int32 = pid; - CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc, kCFNumberSInt32Type, &pid_int32)); - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get()); - - // Set the a boolean to indicate if this is the front most - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse); - - const char *pid_basename = proc_info.kp_proc.p_comm; - char proc_path_buf[PATH_MAX]; - - int return_val = proc_pidpath (pid, proc_path_buf, PATH_MAX); - if (return_val > 0) - { - // Okay, now search backwards from that to see if there is a - // slash in the name. Note, even though we got all the args we don't care - // because the list data is just a bunch of concatenated null terminated strings - // so strrchr will start from the end of argv0. - - pid_basename = strrchr(proc_path_buf, '/'); - if (pid_basename) - { - // Skip the '/' - ++pid_basename; - } - else - { - // We didn't find a directory delimiter in the process argv[0], just use what was in there - pid_basename = proc_path_buf; - } - CFString cf_pid_path (proc_path_buf); - if (cf_pid_path.get()) - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, cf_pid_path.get()); - } - - if (pid_basename && pid_basename[0]) - { - CFString pid_name (pid_basename); - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, pid_name.get()); - } - - // Append the application info to the plist array - ::CFArrayAppendValue (plistMutableArray, appInfoDict.get()); - } - } - return 0; -} -int -ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable) -{ - int result = -1; - - CFAllocatorRef alloc = kCFAllocatorDefault; - - // Create a mutable array that we can populate. Specify zero so it can be of any size. - CFReleaser<CFMutableArrayRef> plistMutableArray (::CFArrayCreateMutable (alloc, 0, &kCFTypeArrayCallBacks)); +size_t GetAllInfos(std::vector<struct kinfo_proc> &proc_infos); + +int GetProcesses(CFMutableArrayRef plistMutableArray, bool all_users) { + if (plistMutableArray == NULL) + return -1; + // Running as root, get all processes + std::vector<struct kinfo_proc> proc_infos; + const size_t num_proc_infos = GetAllInfos(proc_infos); + if (num_proc_infos > 0) { + const pid_t our_pid = getpid(); const uid_t our_uid = getuid(); + uint32_t i; + CFAllocatorRef alloc = kCFAllocatorDefault; -#if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) - - if (our_uid == 0) - { - bool all_users = true; - result = GetProcesses (plistMutableArray.get(), all_users); - } - else - { - CFReleaser<CFStringRef> sbsFrontAppID (::SBSCopyFrontmostApplicationDisplayIdentifier ()); - CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable)); - - // Need to check the return value from SBSCopyApplicationDisplayIdentifiers. - CFIndex count = sbsAppIDs.get() ? ::CFArrayGetCount (sbsAppIDs.get()) : 0; - CFIndex i = 0; - for (i = 0; i < count; i++) - { - CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i); - - // Create a new mutable dictionary for each application - CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); - - // Get the process id for the app (if there is one) - pid_t pid = INVALID_NUB_PROCESS; - if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &pid) == true) - { - CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc, kCFNumberSInt32Type, &pid)); - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get()); - } - - // Set the a boolean to indicate if this is the front most - if (sbsFrontAppID.get() && displayIdentifier && (::CFStringCompare (sbsFrontAppID.get(), displayIdentifier, 0) == kCFCompareEqualTo)) - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanTrue); - else - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse); - - - CFReleaser<CFStringRef> executablePath (::SBSCopyExecutablePathForDisplayIdentifier (displayIdentifier)); - if (executablePath.get() != NULL) - { - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, executablePath.get()); - } - - CFReleaser<CFStringRef> iconImagePath (::SBSCopyIconImagePathForDisplayIdentifier (displayIdentifier)) ; - if (iconImagePath.get() != NULL) - { - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, iconImagePath.get()); - } - - CFReleaser<CFStringRef> localizedDisplayName (::SBSCopyLocalizedApplicationNameForDisplayIdentifier (displayIdentifier)); - if (localizedDisplayName.get() != NULL) - { - ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, localizedDisplayName.get()); - } - - // Append the application info to the plist array - ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get()); + for (i = 0; i < num_proc_infos; i++) { + struct kinfo_proc &proc_info = proc_infos[i]; + + bool kinfo_user_matches; + // Special case, if lldb is being run as root we can attach to anything. + if (all_users) + kinfo_user_matches = true; + else + kinfo_user_matches = proc_info.kp_eproc.e_pcred.p_ruid == our_uid; + + const pid_t pid = proc_info.kp_proc.p_pid; + // Skip zombie processes and processes with unset status + if (kinfo_user_matches == false || // User is acceptable + pid == our_pid || // Skip this process + pid == 0 || // Skip kernel (kernel pid is zero) + proc_info.kp_proc.p_stat == + SZOMB || // Zombies are bad, they like brains... + proc_info.kp_proc.p_flag & P_TRACED || // Being debugged? + proc_info.kp_proc.p_flag & P_WEXIT || // Working on exiting? + proc_info.kp_proc.p_flag & + P_TRANSLATED) // Skip translated ppc (Rosetta) + continue; + + // Create a new mutable dictionary for each application + CFReleaser<CFMutableDictionaryRef> appInfoDict( + ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + // Get the process id for the app (if there is one) + const int32_t pid_int32 = pid; + CFReleaser<CFNumberRef> pidCFNumber( + ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid_int32)); + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY, + pidCFNumber.get()); + + // Set the a boolean to indicate if this is the front most + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, + kCFBooleanFalse); + + const char *pid_basename = proc_info.kp_proc.p_comm; + char proc_path_buf[PATH_MAX]; + + int return_val = proc_pidpath(pid, proc_path_buf, PATH_MAX); + if (return_val > 0) { + // Okay, now search backwards from that to see if there is a + // slash in the name. Note, even though we got all the args we don't + // care + // because the list data is just a bunch of concatenated null terminated + // strings + // so strrchr will start from the end of argv0. + + pid_basename = strrchr(proc_path_buf, '/'); + if (pid_basename) { + // Skip the '/' + ++pid_basename; + } else { + // We didn't find a directory delimiter in the process argv[0], just + // use what was in there + pid_basename = proc_path_buf; } + CFString cf_pid_path(proc_path_buf); + if (cf_pid_path.get()) + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PATH_KEY, + cf_pid_path.get()); + } + + if (pid_basename && pid_basename[0]) { + CFString pid_name(pid_basename); + ::CFDictionarySetValue(appInfoDict.get(), + DTSERVICES_APP_DISPLAY_NAME_KEY, pid_name.get()); + } + + // Append the application info to the plist array + ::CFArrayAppendValue(plistMutableArray, appInfoDict.get()); + } + } + return 0; +} +int ListApplications(std::string &plist, bool opt_runningApps, + bool opt_debuggable) { + int result = -1; + + CFAllocatorRef alloc = kCFAllocatorDefault; + + // Create a mutable array that we can populate. Specify zero so it can be of + // any size. + CFReleaser<CFMutableArrayRef> plistMutableArray( + ::CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks)); + + const uid_t our_uid = getuid(); + +#if defined(WITH_SPRINGBOARD) || defined(WITH_BKS) + + if (our_uid == 0) { + bool all_users = true; + result = GetProcesses(plistMutableArray.get(), all_users); + } else { + CFReleaser<CFStringRef> sbsFrontAppID( + ::SBSCopyFrontmostApplicationDisplayIdentifier()); + CFReleaser<CFArrayRef> sbsAppIDs(::SBSCopyApplicationDisplayIdentifiers( + opt_runningApps, opt_debuggable)); + + // Need to check the return value from SBSCopyApplicationDisplayIdentifiers. + CFIndex count = sbsAppIDs.get() ? ::CFArrayGetCount(sbsAppIDs.get()) : 0; + CFIndex i = 0; + for (i = 0; i < count; i++) { + CFStringRef displayIdentifier = + (CFStringRef)::CFArrayGetValueAtIndex(sbsAppIDs.get(), i); + + // Create a new mutable dictionary for each application + CFReleaser<CFMutableDictionaryRef> appInfoDict( + ::CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + // Get the process id for the app (if there is one) + pid_t pid = INVALID_NUB_PROCESS; + if (::SBSProcessIDForDisplayIdentifier((CFStringRef)displayIdentifier, + &pid) == true) { + CFReleaser<CFNumberRef> pidCFNumber( + ::CFNumberCreate(alloc, kCFNumberSInt32Type, &pid)); + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PID_KEY, + pidCFNumber.get()); + } + + // Set the a boolean to indicate if this is the front most + if (sbsFrontAppID.get() && displayIdentifier && + (::CFStringCompare(sbsFrontAppID.get(), displayIdentifier, 0) == + kCFCompareEqualTo)) + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, + kCFBooleanTrue); + else + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, + kCFBooleanFalse); + + CFReleaser<CFStringRef> executablePath( + ::SBSCopyExecutablePathForDisplayIdentifier(displayIdentifier)); + if (executablePath.get() != NULL) { + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_PATH_KEY, + executablePath.get()); + } + + CFReleaser<CFStringRef> iconImagePath( + ::SBSCopyIconImagePathForDisplayIdentifier(displayIdentifier)); + if (iconImagePath.get() != NULL) { + ::CFDictionarySetValue(appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, + iconImagePath.get()); + } + + CFReleaser<CFStringRef> localizedDisplayName( + ::SBSCopyLocalizedApplicationNameForDisplayIdentifier( + displayIdentifier)); + if (localizedDisplayName.get() != NULL) { + ::CFDictionarySetValue(appInfoDict.get(), + DTSERVICES_APP_DISPLAY_NAME_KEY, + localizedDisplayName.get()); + } + + // Append the application info to the plist array + ::CFArrayAppendValue(plistMutableArray.get(), appInfoDict.get()); } + } #else // #if defined (WITH_SPRINGBOARD) || defined (WITH_BKS) - // When root, show all processes - bool all_users = (our_uid == 0); - GetProcesses (plistMutableArray.get(), all_users); + // When root, show all processes + bool all_users = (our_uid == 0); + GetProcesses(plistMutableArray.get(), all_users); #endif - - CFReleaser<CFDataRef> plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get())); - - // write plist to service port - if (plistData.get() != NULL) - { - CFIndex size = ::CFDataGetLength (plistData.get()); - const UInt8 *bytes = ::CFDataGetBytePtr (plistData.get()); - if (bytes != NULL && size > 0) - { - plist.assign((char *)bytes, size); - return 0; // Success - } - else - { - DNBLogError("empty application property list."); - result = -2; - } - } - else - { - DNBLogError("serializing task list."); - result = -3; + + CFReleaser<CFDataRef> plistData( + ::CFPropertyListCreateXMLData(alloc, plistMutableArray.get())); + + // write plist to service port + if (plistData.get() != NULL) { + CFIndex size = ::CFDataGetLength(plistData.get()); + const UInt8 *bytes = ::CFDataGetBytePtr(plistData.get()); + if (bytes != NULL && size > 0) { + plist.assign((char *)bytes, size); + return 0; // Success + } else { + DNBLogError("empty application property list."); + result = -2; } - - return result; + } else { + DNBLogError("serializing task list."); + result = -3; + } + return result; } diff --git a/lldb/tools/debugserver/source/RNBServices.h b/lldb/tools/debugserver/source/RNBServices.h index b0b9c219357..caa2b0fd199 100644 --- a/lldb/tools/debugserver/source/RNBServices.h +++ b/lldb/tools/debugserver/source/RNBServices.h @@ -14,15 +14,16 @@ #ifndef __RNBServices_h__ #define __RNBServices_h__ -#include <string> #include "RNBDefs.h" +#include <string> -#define DTSERVICES_APP_FRONTMOST_KEY CFSTR("isFrontApp") -#define DTSERVICES_APP_PATH_KEY CFSTR("executablePath") -#define DTSERVICES_APP_ICON_PATH_KEY CFSTR("iconPath") +#define DTSERVICES_APP_FRONTMOST_KEY CFSTR("isFrontApp") +#define DTSERVICES_APP_PATH_KEY CFSTR("executablePath") +#define DTSERVICES_APP_ICON_PATH_KEY CFSTR("iconPath") #define DTSERVICES_APP_DISPLAY_NAME_KEY CFSTR("displayName") -#define DTSERVICES_APP_PID_KEY CFSTR("pid") +#define DTSERVICES_APP_PID_KEY CFSTR("pid") -int ListApplications (std::string &plist, bool opt_runningApps, bool opt_debuggable); +int ListApplications(std::string &plist, bool opt_runningApps, + bool opt_debuggable); -#endif // __RNBServices_h__ +#endif // __RNBServices_h__ diff --git a/lldb/tools/debugserver/source/RNBSocket.cpp b/lldb/tools/debugserver/source/RNBSocket.cpp index ce4886ab9df..a8d119e455f 100644 --- a/lldb/tools/debugserver/source/RNBSocket.cpp +++ b/lldb/tools/debugserver/source/RNBSocket.cpp @@ -12,6 +12,8 @@ //===----------------------------------------------------------------------===// #include "RNBSocket.h" +#include "DNBError.h" +#include "DNBLog.h" #include <arpa/inet.h> #include <errno.h> #include <fcntl.h> @@ -19,8 +21,6 @@ #include <netinet/in.h> #include <netinet/tcp.h> #include <termios.h> -#include "DNBLog.h" -#include "DNBError.h" #ifdef WITH_LOCKDOWN #include "lockdown.h" @@ -30,392 +30,357 @@ this function is called to wait for an incoming connection. This function blocks while waiting for that connection. */ -bool -ResolveIPV4HostName (const char *hostname, in_addr_t &addr) -{ - if (hostname == NULL || - hostname[0] == '\0' || - strcmp(hostname, "localhost") == 0 || - strcmp(hostname, "127.0.0.1") == 0) - { - addr = htonl (INADDR_LOOPBACK); +bool ResolveIPV4HostName(const char *hostname, in_addr_t &addr) { + if (hostname == NULL || hostname[0] == '\0' || + strcmp(hostname, "localhost") == 0 || + strcmp(hostname, "127.0.0.1") == 0) { + addr = htonl(INADDR_LOOPBACK); + return true; + } else if (strcmp(hostname, "*") == 0) { + addr = htonl(INADDR_ANY); + return true; + } else { + // See if an IP address was specified as numbers + int inet_pton_result = ::inet_pton(AF_INET, hostname, &addr); + + if (inet_pton_result == 1) + return true; + + struct hostent *host_entry = gethostbyname(hostname); + if (host_entry) { + std::string ip_str( + ::inet_ntoa(*(struct in_addr *)*host_entry->h_addr_list)); + inet_pton_result = ::inet_pton(AF_INET, ip_str.c_str(), &addr); + if (inet_pton_result == 1) return true; } - else if (strcmp(hostname, "*") == 0) - { - addr = htonl (INADDR_ANY); - return true; - } - else - { - // See if an IP address was specified as numbers - int inet_pton_result = ::inet_pton (AF_INET, hostname, &addr); - - if (inet_pton_result == 1) - return true; - - struct hostent *host_entry = gethostbyname (hostname); - if (host_entry) - { - std::string ip_str (::inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list)); - inet_pton_result = ::inet_pton (AF_INET, ip_str.c_str(), &addr); - if (inet_pton_result == 1) - return true; - } - } - return false; + } + return false; } -rnb_err_t -RNBSocket::Listen (const char *listen_host, uint16_t port, PortBoundCallback callback, const void *callback_baton) -{ - //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); - // Disconnect without saving errno - Disconnect (false); - - // Now figure out the hostname that will be attaching and palce it into - struct sockaddr_in listen_addr; - ::memset (&listen_addr, 0, sizeof listen_addr); - listen_addr.sin_len = sizeof listen_addr; - listen_addr.sin_family = AF_INET; - listen_addr.sin_port = htons (port); - listen_addr.sin_addr.s_addr = INADDR_ANY; - - if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr)) - { - DNBLogThreaded("error: failed to resolve connecting host '%s'", listen_host); - return rnb_err; +rnb_err_t RNBSocket::Listen(const char *listen_host, uint16_t port, + PortBoundCallback callback, + const void *callback_baton) { + // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s called", + // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); + // Disconnect without saving errno + Disconnect(false); + + // Now figure out the hostname that will be attaching and palce it into + struct sockaddr_in listen_addr; + ::memset(&listen_addr, 0, sizeof listen_addr); + listen_addr.sin_len = sizeof listen_addr; + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(port); + listen_addr.sin_addr.s_addr = INADDR_ANY; + + if (!ResolveIPV4HostName(listen_host, listen_addr.sin_addr.s_addr)) { + DNBLogThreaded("error: failed to resolve connecting host '%s'", + listen_host); + return rnb_err; + } + + DNBError err; + int listen_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (listen_fd == -1) + err.SetError(errno, DNBError::POSIX); + + if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) + err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol " + "= IPPROTO_TCP ) => socket = %i", + listen_fd); + + if (err.Fail()) + return rnb_err; + + // enable local address reuse + SetSocketOption(listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); + + struct sockaddr_in sa; + ::memset(&sa, 0, sizeof sa); + sa.sin_len = sizeof sa; + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host + // network interface (this is NOT who can + // connect to us) + int error = ::bind(listen_fd, (struct sockaddr *)&sa, sizeof(sa)); + if (error == -1) + err.SetError(errno, DNBError::POSIX); + + if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) + err.LogThreaded( + "::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", + listen_fd); + + if (err.Fail()) { + ClosePort(listen_fd, false); + return rnb_err; + } + + error = ::listen(listen_fd, 5); + if (error == -1) + err.SetError(errno, DNBError::POSIX); + + if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) + err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd); + + if (err.Fail()) { + ClosePort(listen_fd, false); + return rnb_err; + } + + if (callback) { + // We were asked to listen on port zero which means we + // must now read the actual port that was given to us + // as port zero is a special code for "find an open port + // for me". + if (port == 0) { + socklen_t sa_len = sizeof(sa); + if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) { + port = ntohs(sa.sin_port); + callback(callback_baton, port); + } + } else { + callback(callback_baton, port); } - - DNBError err; - int listen_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (listen_fd == -1) - err.SetError(errno, DNBError::POSIX); + } - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::socket ( domain = AF_INET, type = SOCK_STREAM, protocol = IPPROTO_TCP ) => socket = %i", listen_fd); + struct sockaddr_in accept_addr; + ::memset(&accept_addr, 0, sizeof accept_addr); + accept_addr.sin_len = sizeof accept_addr; - if (err.Fail()) - return rnb_err; + bool accept_connection = false; - // enable local address reuse - SetSocketOption (listen_fd, SOL_SOCKET, SO_REUSEADDR, 1); + // Loop until we are happy with our connection + while (!accept_connection) { + socklen_t accept_addr_len = sizeof accept_addr; + m_fd = + ::accept(listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len); - struct sockaddr_in sa; - ::memset (&sa, 0, sizeof sa); - sa.sin_len = sizeof sa; - sa.sin_family = AF_INET; - sa.sin_port = htons (port); - sa.sin_addr.s_addr = INADDR_ANY; // Let incoming connections bind to any host network interface (this is NOT who can connect to us) - int error = ::bind (listen_fd, (struct sockaddr *) &sa, sizeof(sa)); - if (error == -1) - err.SetError(errno, DNBError::POSIX); + if (m_fd == -1) + err.SetError(errno, DNBError::POSIX); if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::bind ( socket = %i, (struct sockaddr *) &sa, sizeof(sa)) )", listen_fd); + err.LogThreaded( + "::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, + &accept_addr, accept_addr_len); if (err.Fail()) - { - ClosePort (listen_fd, false); - return rnb_err; + break; + + if (listen_addr.sin_addr.s_addr == INADDR_ANY) + accept_connection = true; + else { + if (accept_addr_len == listen_addr.sin_len && + accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr) { + accept_connection = true; + } else { + ::close(m_fd); + m_fd = -1; + const uint8_t *accept_ip = + (const uint8_t *)&accept_addr.sin_addr.s_addr; + const uint8_t *listen_ip = + (const uint8_t *)&listen_addr.sin_addr.s_addr; + ::fprintf(stderr, "error: rejecting incoming connection from " + "%u.%u.%u.%u (expecting %u.%u.%u.%u)\n", + accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], + listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + DNBLogThreaded("error: rejecting connection from %u.%u.%u.%u " + "(expecting %u.%u.%u.%u)", + accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], + listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); + } } + } - error = ::listen (listen_fd, 5); - if (error == -1) - err.SetError(errno, DNBError::POSIX); + ClosePort(listen_fd, false); - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::listen ( socket = %i, backlog = 1 )", listen_fd); + if (err.Fail()) { + return rnb_err; + } else { + // Keep our TCP packets coming without any delays. + SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); + } - if (err.Fail()) - { - ClosePort (listen_fd, false); - return rnb_err; - } - - if (callback) - { - // We were asked to listen on port zero which means we - // must now read the actual port that was given to us - // as port zero is a special code for "find an open port - // for me". - if (port == 0) - { - socklen_t sa_len = sizeof (sa); - if (getsockname(listen_fd, (struct sockaddr *)&sa, &sa_len) == 0) - { - port = ntohs (sa.sin_port); - callback (callback_baton, port); - } - } - else - { - callback (callback_baton, port); - } - } + return rnb_success; +} - struct sockaddr_in accept_addr; - ::memset (&accept_addr, 0, sizeof accept_addr); - accept_addr.sin_len = sizeof accept_addr; - - bool accept_connection = false; - - // Loop until we are happy with our connection - while (!accept_connection) - { - socklen_t accept_addr_len = sizeof accept_addr; - m_fd = ::accept (listen_fd, (struct sockaddr *)&accept_addr, &accept_addr_len); - - if (m_fd == -1) - err.SetError(errno, DNBError::POSIX); - - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::accept ( socket = %i, address = %p, address_len = %u )", listen_fd, &accept_addr, accept_addr_len); - - if (err.Fail()) - break; - - if (listen_addr.sin_addr.s_addr == INADDR_ANY) - accept_connection = true; - else - { - if (accept_addr_len == listen_addr.sin_len && - accept_addr.sin_addr.s_addr == listen_addr.sin_addr.s_addr) - { - accept_connection = true; - } - else - { - ::close (m_fd); - m_fd = -1; - const uint8_t *accept_ip = (const uint8_t *)&accept_addr.sin_addr.s_addr; - const uint8_t *listen_ip = (const uint8_t *)&listen_addr.sin_addr.s_addr; - ::fprintf (stderr, - "error: rejecting incoming connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)\n", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - DNBLogThreaded ("error: rejecting connection from %u.%u.%u.%u (expecting %u.%u.%u.%u)", - accept_ip[0], accept_ip[1], accept_ip[2], accept_ip[3], - listen_ip[0], listen_ip[1], listen_ip[2], listen_ip[3]); - } - } - } +rnb_err_t RNBSocket::Connect(const char *host, uint16_t port) { + Disconnect(false); - ClosePort (listen_fd, false); + // Create the socket + m_fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (m_fd == -1) + return rnb_err; - if (err.Fail()) - { - return rnb_err; - } - else - { - // Keep our TCP packets coming without any delays. - SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - } + // Enable local address reuse + SetSocketOption(m_fd, SOL_SOCKET, SO_REUSEADDR, 1); - return rnb_success; -} + struct sockaddr_in sa; + ::memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); -rnb_err_t -RNBSocket::Connect (const char *host, uint16_t port) -{ - Disconnect (false); + if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr)) { + DNBLogThreaded("error: failed to resolve host '%s'", host); + Disconnect(false); + return rnb_err; + } - // Create the socket - m_fd = ::socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (m_fd == -1) - return rnb_err; - - // Enable local address reuse - SetSocketOption (m_fd, SOL_SOCKET, SO_REUSEADDR, 1); - - struct sockaddr_in sa; - ::memset (&sa, 0, sizeof (sa)); - sa.sin_family = AF_INET; - sa.sin_port = htons (port); - - if (!ResolveIPV4HostName(host, sa.sin_addr.s_addr)) - { - DNBLogThreaded("error: failed to resolve host '%s'", host); - Disconnect (false); - return rnb_err; - } - - if (-1 == ::connect (m_fd, (const struct sockaddr *)&sa, sizeof(sa))) - { - Disconnect (false); - return rnb_err; - } - - // Keep our TCP packets coming without any delays. - SetSocketOption (m_fd, IPPROTO_TCP, TCP_NODELAY, 1); - return rnb_success; + if (-1 == ::connect(m_fd, (const struct sockaddr *)&sa, sizeof(sa))) { + Disconnect(false); + return rnb_err; + } + + // Keep our TCP packets coming without any delays. + SetSocketOption(m_fd, IPPROTO_TCP, TCP_NODELAY, 1); + return rnb_success; } -rnb_err_t -RNBSocket::useFD(int fd) -{ - if (fd < 0) { - DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in."); - return rnb_err; - } - - m_fd = fd; - return rnb_success; +rnb_err_t RNBSocket::useFD(int fd) { + if (fd < 0) { + DNBLogThreadedIf(LOG_RNB_COMM, "Bad file descriptor passed in."); + return rnb_err; + } + + m_fd = fd; + return rnb_success; } #ifdef WITH_LOCKDOWN -rnb_err_t -RNBSocket::ConnectToService() -{ - DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME); - // Disconnect from any previous connections - Disconnect(false); - if (::secure_lockdown_checkin (&m_ld_conn, NULL, NULL) != kLDESuccess) - { - DNBLogThreadedIf(LOG_RNB_COMM, "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed"); - m_fd = -1; - return rnb_not_connected; - } - m_fd = ::lockdown_get_socket (m_ld_conn); - if (m_fd == -1) - { - DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed"); - return rnb_not_connected; - } - m_fd_from_lockdown = true; - return rnb_success; +rnb_err_t RNBSocket::ConnectToService() { + DNBLog("Connecting to com.apple.%s service...", DEBUGSERVER_PROGRAM_NAME); + // Disconnect from any previous connections + Disconnect(false); + if (::secure_lockdown_checkin(&m_ld_conn, NULL, NULL) != kLDESuccess) { + DNBLogThreadedIf(LOG_RNB_COMM, + "::secure_lockdown_checkin(&m_fd, NULL, NULL) failed"); + m_fd = -1; + return rnb_not_connected; + } + m_fd = ::lockdown_get_socket(m_ld_conn); + if (m_fd == -1) { + DNBLogThreadedIf(LOG_RNB_COMM, "::lockdown_get_socket() failed"); + return rnb_not_connected; + } + m_fd_from_lockdown = true; + return rnb_success; } #endif -rnb_err_t -RNBSocket::OpenFile (const char *path) -{ - DNBError err; - m_fd = open (path, O_RDWR); - if (m_fd == -1) - { - err.SetError(errno, DNBError::POSIX); - err.LogThreaded ("can't open file '%s'", path); - return rnb_not_connected; +rnb_err_t RNBSocket::OpenFile(const char *path) { + DNBError err; + m_fd = open(path, O_RDWR); + if (m_fd == -1) { + err.SetError(errno, DNBError::POSIX); + err.LogThreaded("can't open file '%s'", path); + return rnb_not_connected; + } else { + struct termios stdin_termios; + + if (::tcgetattr(m_fd, &stdin_termios) == 0) { + stdin_termios.c_lflag &= ~ECHO; // Turn off echoing + stdin_termios.c_lflag &= ~ICANON; // Get one char at a time + ::tcsetattr(m_fd, TCSANOW, &stdin_termios); } - else - { - struct termios stdin_termios; - - if (::tcgetattr (m_fd, &stdin_termios) == 0) - { - stdin_termios.c_lflag &= ~ECHO; // Turn off echoing - stdin_termios.c_lflag &= ~ICANON; // Get one char at a time - ::tcsetattr (m_fd, TCSANOW, &stdin_termios); - } - } - return rnb_success; + } + return rnb_success; } -int -RNBSocket::SetSocketOption(int fd, int level, int option_name, int option_value) -{ - return ::setsockopt(fd, level, option_name, &option_value, sizeof(option_value)); +int RNBSocket::SetSocketOption(int fd, int level, int option_name, + int option_value) { + return ::setsockopt(fd, level, option_name, &option_value, + sizeof(option_value)); } -rnb_err_t -RNBSocket::Disconnect (bool save_errno) -{ +rnb_err_t RNBSocket::Disconnect(bool save_errno) { #ifdef WITH_LOCKDOWN - if (m_fd_from_lockdown) - { - m_fd_from_lockdown = false; - m_fd = -1; - lockdown_disconnect (m_ld_conn); - return rnb_success; - } + if (m_fd_from_lockdown) { + m_fd_from_lockdown = false; + m_fd = -1; + lockdown_disconnect(m_ld_conn); + return rnb_success; + } #endif - return ClosePort (m_fd, save_errno); + return ClosePort(m_fd, save_errno); } - -rnb_err_t -RNBSocket::Read (std::string &p) -{ - char buf[1024]; - p.clear(); - - // Note that BUF is on the stack so we must be careful to keep any - // writes to BUF from overflowing or we'll have security issues. - - if (m_fd == -1) - return rnb_err; - - //DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); - DNBError err; - ssize_t bytesread = read (m_fd, buf, sizeof (buf)); - if (bytesread <= 0) - err.SetError(errno, DNBError::POSIX); - else - p.append(buf, bytesread); - - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof (buf), (uint64_t)bytesread); - - // Our port went away - we have to mark this so IsConnected will return the truth. - if (bytesread == 0) - { - m_fd = -1; - return rnb_not_connected; - } - else if (bytesread == -1) - { - m_fd = -1; - return rnb_err; - } - // Strip spaces from the end of the buffer - while (!p.empty() && isspace (p[p.size() - 1])) - p.erase (p.size () - 1); - - // Most data in the debugserver packets valid printable characters... - DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str()); - return rnb_success; +rnb_err_t RNBSocket::Read(std::string &p) { + char buf[1024]; + p.clear(); + + // Note that BUF is on the stack so we must be careful to keep any + // writes to BUF from overflowing or we'll have security issues. + + if (m_fd == -1) + return rnb_err; + + // DNBLogThreadedIf(LOG_RNB_COMM, "%8u RNBSocket::%s calling read()", + // (uint32_t)m_timer.ElapsedMicroSeconds(true), __FUNCTION__); + DNBError err; + ssize_t bytesread = read(m_fd, buf, sizeof(buf)); + if (bytesread <= 0) + err.SetError(errno, DNBError::POSIX); + else + p.append(buf, bytesread); + + if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) + err.LogThreaded("::read ( %i, %p, %llu ) => %i", m_fd, buf, sizeof(buf), + (uint64_t)bytesread); + + // Our port went away - we have to mark this so IsConnected will return the + // truth. + if (bytesread == 0) { + m_fd = -1; + return rnb_not_connected; + } else if (bytesread == -1) { + m_fd = -1; + return rnb_err; + } + // Strip spaces from the end of the buffer + while (!p.empty() && isspace(p[p.size() - 1])) + p.erase(p.size() - 1); + + // Most data in the debugserver packets valid printable characters... + DNBLogThreadedIf(LOG_RNB_COMM, "read: %s", p.c_str()); + return rnb_success; } -rnb_err_t -RNBSocket::Write (const void *buffer, size_t length) -{ - if (m_fd == -1) - return rnb_err; +rnb_err_t RNBSocket::Write(const void *buffer, size_t length) { + if (m_fd == -1) + return rnb_err; - DNBError err; - ssize_t bytessent = write (m_fd, buffer, length); - if (bytessent < 0) - err.SetError(errno, DNBError::POSIX); + DNBError err; + ssize_t bytessent = write(m_fd, buffer, length); + if (bytessent < 0) + err.SetError(errno, DNBError::POSIX); - if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) - err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", m_fd, buffer, length, (uint64_t)bytessent); + if (err.Fail() || DNBLogCheckLogBit(LOG_RNB_COMM)) + err.LogThreaded("::write ( socket = %i, buffer = %p, length = %llu) => %i", + m_fd, buffer, length, (uint64_t)bytessent); - if (bytessent < 0) - return rnb_err; + if (bytessent < 0) + return rnb_err; - if ((size_t)bytessent != length) - return rnb_err; + if ((size_t)bytessent != length) + return rnb_err; - DNBLogThreadedIf(LOG_RNB_PACKETS, "putpkt: %*s", (int)length, (char *)buffer); // All data is string based in debugserver, so this is safe - DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer); + DNBLogThreadedIf( + LOG_RNB_PACKETS, "putpkt: %*s", (int)length, + (char *) + buffer); // All data is string based in debugserver, so this is safe + DNBLogThreadedIf(LOG_RNB_COMM, "sent: %*s", (int)length, (char *)buffer); - return rnb_success; + return rnb_success; } - -rnb_err_t -RNBSocket::ClosePort (int& fd, bool save_errno) -{ - int close_err = 0; - if (fd > 0) - { - errno = 0; - close_err = close (fd); - fd = -1; - } - return close_err != 0 ? rnb_err : rnb_success; +rnb_err_t RNBSocket::ClosePort(int &fd, bool save_errno) { + int close_err = 0; + if (fd > 0) { + errno = 0; + close_err = close(fd); + fd = -1; + } + return close_err != 0 ? rnb_err : rnb_success; } - - diff --git a/lldb/tools/debugserver/source/RNBSocket.h b/lldb/tools/debugserver/source/RNBSocket.h index 32f4ebeed2a..9f636d85562 100644 --- a/lldb/tools/debugserver/source/RNBSocket.h +++ b/lldb/tools/debugserver/source/RNBSocket.h @@ -14,72 +14,66 @@ #ifndef __RNBSocket_h__ #define __RNBSocket_h__ +#include "DNBTimer.h" #include "RNBDefs.h" +#include <string> #include <sys/socket.h> #include <sys/types.h> -#include <string> -#include "DNBTimer.h" #ifdef WITH_LOCKDOWN #include "lockdown.h" #endif -class RNBSocket -{ +class RNBSocket { public: - typedef void (*PortBoundCallback) (const void *baton, uint16_t port); + typedef void (*PortBoundCallback)(const void *baton, uint16_t port); - RNBSocket () : - m_fd (-1), + RNBSocket() + : m_fd(-1), #ifdef WITH_LOCKDOWN - m_fd_from_lockdown (false), - m_ld_conn (), + m_fd_from_lockdown(false), m_ld_conn(), #endif - m_timer (true) // Make a thread safe timer - { - } - ~RNBSocket (void) - { - Disconnect (false); - } - - rnb_err_t Listen (const char *listen_host, - uint16_t port, - PortBoundCallback callback, - const void *callback_baton); - rnb_err_t Connect (const char *host, uint16_t port); - - rnb_err_t useFD(int fd); + m_timer(true) // Make a thread safe timer + { + } + ~RNBSocket(void) { Disconnect(false); } + + rnb_err_t Listen(const char *listen_host, uint16_t port, + PortBoundCallback callback, const void *callback_baton); + rnb_err_t Connect(const char *host, uint16_t port); + + rnb_err_t useFD(int fd); #ifdef WITH_LOCKDOWN - rnb_err_t ConnectToService(); + rnb_err_t ConnectToService(); #endif - rnb_err_t OpenFile (const char *path); - rnb_err_t Disconnect (bool save_errno); - rnb_err_t Read (std::string &p); - rnb_err_t Write (const void *buffer, size_t length); + rnb_err_t OpenFile(const char *path); + rnb_err_t Disconnect(bool save_errno); + rnb_err_t Read(std::string &p); + rnb_err_t Write(const void *buffer, size_t length); - bool IsConnected () const { return m_fd != -1; } - void SaveErrno (int curr_errno); - DNBTimer& Timer() { return m_timer; } + bool IsConnected() const { return m_fd != -1; } + void SaveErrno(int curr_errno); + DNBTimer &Timer() { return m_timer; } + + static int SetSocketOption(int fd, int level, int option_name, + int option_value); - static int SetSocketOption(int fd, int level, int option_name, int option_value); private: - // Outlaw some constructors - RNBSocket (const RNBSocket &); + // Outlaw some constructors + RNBSocket(const RNBSocket &); protected: - rnb_err_t ClosePort (int& fd, bool save_errno); + rnb_err_t ClosePort(int &fd, bool save_errno); - int m_fd; // Socket we use to communicate once conn established + int m_fd; // Socket we use to communicate once conn established #ifdef WITH_LOCKDOWN - bool m_fd_from_lockdown; - lockdown_connection m_ld_conn; + bool m_fd_from_lockdown; + lockdown_connection m_ld_conn; #endif - DNBTimer m_timer; + DNBTimer m_timer; }; - #endif // #ifndef __RNBSocket_h__ diff --git a/lldb/tools/debugserver/source/SysSignal.cpp b/lldb/tools/debugserver/source/SysSignal.cpp index 69f34ed605c..c2995f362c0 100644 --- a/lldb/tools/debugserver/source/SysSignal.cpp +++ b/lldb/tools/debugserver/source/SysSignal.cpp @@ -15,52 +15,81 @@ #include <signal.h> #include <stddef.h> -const char * -SysSignal::Name(int signal) -{ - switch (signal) - { - case SIGHUP: return "SIGHUP"; // 1 hangup - case SIGINT: return "SIGINT"; // 2 interrupt - case SIGQUIT: return "SIGQUIT"; // 3 quit - case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught) - case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught) - case SIGABRT: return "SIGABRT"; // 6 abort() -#if defined(_POSIX_C_SOURCE) - case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) -#else // !_POSIX_C_SOURCE - case SIGEMT: return "SIGEMT"; // 7 EMT instruction -#endif // !_POSIX_C_SOURCE - case SIGFPE: return "SIGFPE"; // 8 floating point exception - case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored) - case SIGBUS: return "SIGBUS"; // 10 bus error - case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation - case SIGSYS: return "SIGSYS"; // 12 bad argument to system call - case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it - case SIGALRM: return "SIGALRM"; // 14 alarm clock - case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill - case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel - case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty - case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty - case SIGCONT: return "SIGCONT"; // 19 continue a stopped process - case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit - case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read - case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) -#if !defined(_POSIX_C_SOURCE) - case SIGIO: return "SIGIO"; // 23 input/output possible signal +const char *SysSignal::Name(int signal) { + switch (signal) { + case SIGHUP: + return "SIGHUP"; // 1 hangup + case SIGINT: + return "SIGINT"; // 2 interrupt + case SIGQUIT: + return "SIGQUIT"; // 3 quit + case SIGILL: + return "SIGILL"; // 4 illegal instruction (not reset when caught) + case SIGTRAP: + return "SIGTRAP"; // 5 trace trap (not reset when caught) + case SIGABRT: + return "SIGABRT"; // 6 abort() +#if defined(_POSIX_C_SOURCE) + case SIGPOLL: + return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported) +#else // !_POSIX_C_SOURCE + case SIGEMT: + return "SIGEMT"; // 7 EMT instruction +#endif // !_POSIX_C_SOURCE + case SIGFPE: + return "SIGFPE"; // 8 floating point exception + case SIGKILL: + return "SIGKILL"; // 9 kill (cannot be caught or ignored) + case SIGBUS: + return "SIGBUS"; // 10 bus error + case SIGSEGV: + return "SIGSEGV"; // 11 segmentation violation + case SIGSYS: + return "SIGSYS"; // 12 bad argument to system call + case SIGPIPE: + return "SIGPIPE"; // 13 write on a pipe with no one to read it + case SIGALRM: + return "SIGALRM"; // 14 alarm clock + case SIGTERM: + return "SIGTERM"; // 15 software termination signal from kill + case SIGURG: + return "SIGURG"; // 16 urgent condition on IO channel + case SIGSTOP: + return "SIGSTOP"; // 17 sendable stop signal not from tty + case SIGTSTP: + return "SIGTSTP"; // 18 stop signal from tty + case SIGCONT: + return "SIGCONT"; // 19 continue a stopped process + case SIGCHLD: + return "SIGCHLD"; // 20 to parent on child stop or exit + case SIGTTIN: + return "SIGTTIN"; // 21 to readers pgrp upon background tty read + case SIGTTOU: + return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local<OSTOP) +#if !defined(_POSIX_C_SOURCE) + case SIGIO: + return "SIGIO"; // 23 input/output possible signal #endif - case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit - case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit - case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm - case SIGPROF: return "SIGPROF"; // 27 profiling time alarm -#if !defined(_POSIX_C_SOURCE) - case SIGWINCH: return "SIGWINCH"; // 28 window size changes - case SIGINFO: return "SIGINFO"; // 29 information request + case SIGXCPU: + return "SIGXCPU"; // 24 exceeded CPU time limit + case SIGXFSZ: + return "SIGXFSZ"; // 25 exceeded file size limit + case SIGVTALRM: + return "SIGVTALRM"; // 26 virtual time alarm + case SIGPROF: + return "SIGPROF"; // 27 profiling time alarm +#if !defined(_POSIX_C_SOURCE) + case SIGWINCH: + return "SIGWINCH"; // 28 window size changes + case SIGINFO: + return "SIGINFO"; // 29 information request #endif - case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1 - case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2 - default: - break; - } - return NULL; + case SIGUSR1: + return "SIGUSR1"; // 30 user defined signal 1 + case SIGUSR2: + return "SIGUSR2"; // 31 user defined signal 2 + default: + break; + } + return NULL; } diff --git a/lldb/tools/debugserver/source/SysSignal.h b/lldb/tools/debugserver/source/SysSignal.h index 438d137f310..c9827126c18 100644 --- a/lldb/tools/debugserver/source/SysSignal.h +++ b/lldb/tools/debugserver/source/SysSignal.h @@ -14,10 +14,9 @@ #ifndef __SysSignal_h__ #define __SysSignal_h__ -class SysSignal -{ +class SysSignal { public: - static const char *Name(int signal); + static const char *Name(int signal); }; #endif diff --git a/lldb/tools/debugserver/source/TTYState.cpp b/lldb/tools/debugserver/source/TTYState.cpp index 28bc956dc28..5f10050fcdd 100644 --- a/lldb/tools/debugserver/source/TTYState.cpp +++ b/lldb/tools/debugserver/source/TTYState.cpp @@ -13,110 +13,82 @@ #include "TTYState.h" #include <fcntl.h> -#include <unistd.h> #include <sys/signal.h> +#include <unistd.h> -TTYState::TTYState() : - m_fd(-1), - m_tflags(-1), - m_ttystateErr(-1), - m_processGroup(-1) -{ -} +TTYState::TTYState() + : m_fd(-1), m_tflags(-1), m_ttystateErr(-1), m_processGroup(-1) {} -TTYState::~TTYState() -{ -} +TTYState::~TTYState() {} -bool -TTYState::GetTTYState (int fd, bool saveProcessGroup) -{ - if (fd >= 0 && ::isatty (fd)) - { - m_fd = fd; - m_tflags = fcntl (fd, F_GETFL, 0); - m_ttystateErr = tcgetattr (fd, &m_ttystate); - if (saveProcessGroup) - m_processGroup = tcgetpgrp (0); - else - m_processGroup = -1; - } +bool TTYState::GetTTYState(int fd, bool saveProcessGroup) { + if (fd >= 0 && ::isatty(fd)) { + m_fd = fd; + m_tflags = fcntl(fd, F_GETFL, 0); + m_ttystateErr = tcgetattr(fd, &m_ttystate); + if (saveProcessGroup) + m_processGroup = tcgetpgrp(0); else - { - m_fd = -1; - m_tflags = -1; - m_ttystateErr = -1; - m_processGroup = -1; - } - return m_ttystateErr == 0; + m_processGroup = -1; + } else { + m_fd = -1; + m_tflags = -1; + m_ttystateErr = -1; + m_processGroup = -1; + } + return m_ttystateErr == 0; } -bool -TTYState::SetTTYState () const -{ - int result = 0; - if (IsValid()) - { - if (TFlagsValid()) - result = fcntl (m_fd, F_SETFL, m_tflags); - - if (TTYStateValid()) - result = tcsetattr (m_fd, TCSANOW, &m_ttystate); - - if (ProcessGroupValid()) - { - // Save the original signal handler. - void (*saved_sigttou_callback) (int) = NULL; - saved_sigttou_callback = (void (*)(int)) signal (SIGTTOU, SIG_IGN); - // Set the process group - result = tcsetpgrp (m_fd, m_processGroup); - // Restore the original signal handler. - signal (SIGTTOU, saved_sigttou_callback); - } - return true; +bool TTYState::SetTTYState() const { + int result = 0; + if (IsValid()) { + if (TFlagsValid()) + result = fcntl(m_fd, F_SETFL, m_tflags); + + if (TTYStateValid()) + result = tcsetattr(m_fd, TCSANOW, &m_ttystate); + + if (ProcessGroupValid()) { + // Save the original signal handler. + void (*saved_sigttou_callback)(int) = NULL; + saved_sigttou_callback = (void (*)(int))signal(SIGTTOU, SIG_IGN); + // Set the process group + result = tcsetpgrp(m_fd, m_processGroup); + // Restore the original signal handler. + signal(SIGTTOU, saved_sigttou_callback); } - return false; + return true; + } + return false; } +TTYStateSwitcher::TTYStateSwitcher() : m_currentState(~0) {} +TTYStateSwitcher::~TTYStateSwitcher() {} -TTYStateSwitcher::TTYStateSwitcher() : - m_currentState(~0) -{ +bool TTYStateSwitcher::GetState(uint32_t idx, int fd, bool saveProcessGroup) { + if (ValidStateIndex(idx)) + return m_ttystates[idx].GetTTYState(fd, saveProcessGroup); + return false; } -TTYStateSwitcher::~TTYStateSwitcher() -{ -} - -bool -TTYStateSwitcher::GetState(uint32_t idx, int fd, bool saveProcessGroup) -{ - if (ValidStateIndex(idx)) - return m_ttystates[idx].GetTTYState(fd, saveProcessGroup); +bool TTYStateSwitcher::SetState(uint32_t idx) const { + if (!ValidStateIndex(idx)) return false; -} - -bool -TTYStateSwitcher::SetState(uint32_t idx) const -{ - if (!ValidStateIndex(idx)) - return false; - - // See if we already are in this state? - if (ValidStateIndex(m_currentState) && (idx == m_currentState) && m_ttystates[idx].IsValid()) - return true; - // Set the state to match the index passed in and only update the - // current state if there are no errors. - if (m_ttystates[idx].SetTTYState()) - { - m_currentState = idx; - return true; - } - - // We failed to set the state. The tty state was invalid or not - // initialized. - return false; + // See if we already are in this state? + if (ValidStateIndex(m_currentState) && (idx == m_currentState) && + m_ttystates[idx].IsValid()) + return true; + + // Set the state to match the index passed in and only update the + // current state if there are no errors. + if (m_ttystates[idx].SetTTYState()) { + m_currentState = idx; + return true; + } + + // We failed to set the state. The tty state was invalid or not + // initialized. + return false; } - diff --git a/lldb/tools/debugserver/source/TTYState.h b/lldb/tools/debugserver/source/TTYState.h index c01d5125543..ab34015e1a4 100644 --- a/lldb/tools/debugserver/source/TTYState.h +++ b/lldb/tools/debugserver/source/TTYState.h @@ -14,48 +14,46 @@ #ifndef __TTYState_h__ #define __TTYState_h__ -#include <termios.h> #include <stdint.h> +#include <termios.h> -class TTYState -{ +class TTYState { public: - TTYState(); - ~TTYState(); + TTYState(); + ~TTYState(); - bool GetTTYState (int fd, bool saveProcessGroup); - bool SetTTYState () const; + bool GetTTYState(int fd, bool saveProcessGroup); + bool SetTTYState() const; - bool IsValid() const { return FileDescriptorValid() && TFlagsValid() && TTYStateValid(); } - bool FileDescriptorValid() const { return m_fd >= 0; } - bool TFlagsValid() const { return m_tflags != -1; } - bool TTYStateValid() const { return m_ttystateErr == 0; } - bool ProcessGroupValid() const { return m_processGroup != -1; } + bool IsValid() const { + return FileDescriptorValid() && TFlagsValid() && TTYStateValid(); + } + bool FileDescriptorValid() const { return m_fd >= 0; } + bool TFlagsValid() const { return m_tflags != -1; } + bool TTYStateValid() const { return m_ttystateErr == 0; } + bool ProcessGroupValid() const { return m_processGroup != -1; } protected: - int m_fd; // File descriptor - int m_tflags; - int m_ttystateErr; - struct termios m_ttystate; - pid_t m_processGroup; - + int m_fd; // File descriptor + int m_tflags; + int m_ttystateErr; + struct termios m_ttystate; + pid_t m_processGroup; }; - -class TTYStateSwitcher -{ +class TTYStateSwitcher { public: - TTYStateSwitcher(); - ~TTYStateSwitcher(); + TTYStateSwitcher(); + ~TTYStateSwitcher(); - bool GetState(uint32_t idx, int fd, bool saveProcessGroup); - bool SetState(uint32_t idx) const; - uint32_t NumStates() const { return sizeof(m_ttystates)/sizeof(TTYState); } - bool ValidStateIndex(uint32_t idx) const { return idx < NumStates(); } + bool GetState(uint32_t idx, int fd, bool saveProcessGroup); + bool SetState(uint32_t idx) const; + uint32_t NumStates() const { return sizeof(m_ttystates) / sizeof(TTYState); } + bool ValidStateIndex(uint32_t idx) const { return idx < NumStates(); } protected: - mutable uint32_t m_currentState; - TTYState m_ttystates[2]; + mutable uint32_t m_currentState; + TTYState m_ttystates[2]; }; #endif
\ No newline at end of file diff --git a/lldb/tools/debugserver/source/debugserver.cpp b/lldb/tools/debugserver/source/debugserver.cpp index e1ee2c12131..0cb72f4ece4 100644 --- a/lldb/tools/debugserver/source/debugserver.cpp +++ b/lldb/tools/debugserver/source/debugserver.cpp @@ -7,27 +7,28 @@ // //===----------------------------------------------------------------------===// -#include <sys/socket.h> -#include <sys/types.h> +#include <arpa/inet.h> +#include <asl.h> +#include <crt_externs.h> // for _NSGetEnviron() #include <errno.h> #include <getopt.h> -#include <netinet/in.h> -#include <sys/select.h> -#include <sys/sysctl.h> -#include <string> -#include <vector> -#include <asl.h> -#include <arpa/inet.h> #include <netdb.h> #include <netinet/in.h> +#include <netinet/in.h> #include <netinet/tcp.h> -#include <sys/un.h> +#include <string> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/sysctl.h> #include <sys/types.h> -#include <crt_externs.h> // for _NSGetEnviron() +#include <sys/types.h> +#include <sys/un.h> +#include <vector> -#if defined (__APPLE__) +#if defined(__APPLE__) #include <sched.h> -extern "C" int proc_set_wakemon_params(pid_t, int, int); // <libproc_internal.h> SPI +extern "C" int proc_set_wakemon_params(pid_t, int, + int); // <libproc_internal.h> SPI #endif #include "CFString.h" @@ -37,9 +38,9 @@ extern "C" int proc_set_wakemon_params(pid_t, int, int); // <libproc_internal.h> #include "OsLogger.h" #include "PseudoTerminal.h" #include "RNBContext.h" +#include "RNBRemote.h" #include "RNBServices.h" #include "RNBSocket.h" -#include "RNBRemote.h" #include "SysSignal.h" // Global PID in case we get a signal and need to stop the process... @@ -48,23 +49,21 @@ nub_process_t g_pid = INVALID_NUB_PROCESS; //---------------------------------------------------------------------- // Run loop modes which determine which run loop function will be called //---------------------------------------------------------------------- -typedef enum -{ - eRNBRunLoopModeInvalid = 0, - eRNBRunLoopModeGetStartModeFromRemoteProtocol, - eRNBRunLoopModeInferiorAttaching, - eRNBRunLoopModeInferiorLaunching, - eRNBRunLoopModeInferiorExecuting, - eRNBRunLoopModePlatformMode, - eRNBRunLoopModeExit +typedef enum { + eRNBRunLoopModeInvalid = 0, + eRNBRunLoopModeGetStartModeFromRemoteProtocol, + eRNBRunLoopModeInferiorAttaching, + eRNBRunLoopModeInferiorLaunching, + eRNBRunLoopModeInferiorExecuting, + eRNBRunLoopModePlatformMode, + eRNBRunLoopModeExit } RNBRunLoopMode; - //---------------------------------------------------------------------- // Global Variables //---------------------------------------------------------------------- RNBRemoteSP g_remoteSP; -static int g_lockdown_opt = 0; +static int g_lockdown_opt = 0; static int g_applist_opt = 0; static nub_launch_flavor_t g_launch_flavor = eLaunchFlavorDefault; int g_disable_aslr = 0; @@ -72,8 +71,22 @@ int g_disable_aslr = 0; int g_isatty = 0; bool g_detach_on_error = true; -#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) -#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) +#define RNBLogSTDOUT(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stdout, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define RNBLogSTDERR(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) //---------------------------------------------------------------------- // Get our program path and arguments from the remote connection. @@ -81,306 +94,290 @@ bool g_detach_on_error = true; // arguments, wait for the new process to finish launching and hit its // entry point, and then return the run loop mode that should come next. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopGetStartModeFromRemote (RNBRemote* remote) -{ - std::string packet; - - if (remote) - { - RNBContext& ctx = remote->Context(); - uint32_t event_mask = RNBContext::event_read_packet_available | - RNBContext::event_read_thread_exiting; - - // Spin waiting to get the A packet. - while (1) - { - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events); - - if (set_events & RNBContext::event_read_thread_exiting) - { - RNBLogSTDERR ("error: packet read thread exited.\n"); - return eRNBRunLoopModeExit; - } +RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemote *remote) { + std::string packet; + + if (remote) { + RNBContext &ctx = remote->Context(); + uint32_t event_mask = RNBContext::event_read_packet_available | + RNBContext::event_read_thread_exiting; + + // Spin waiting to get the A packet. + while (1) { + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", + __FUNCTION__, event_mask, set_events); + + if (set_events & RNBContext::event_read_thread_exiting) { + RNBLogSTDERR("error: packet read thread exited.\n"); + return eRNBRunLoopModeExit; + } - if (set_events & RNBContext::event_read_packet_available) - { - rnb_err_t err = rnb_err; - RNBRemote::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); - - // check if we tried to attach to a process - if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || type == RNBRemote::vattachorwait) - { - if (err == rnb_success) - { - RNBLogSTDOUT ("Attach succeeded, ready to debug.\n"); - return eRNBRunLoopModeInferiorExecuting; - } - else - { - RNBLogSTDERR ("error: attach failed.\n"); - return eRNBRunLoopModeExit; - } - } - - if (err == rnb_success) - { - // If we got our arguments we are ready to launch using the arguments - // and any environment variables we received. - if (type == RNBRemote::set_argv) - { - return eRNBRunLoopModeInferiorLaunching; - } - } - else if (err == rnb_not_connected) - { - RNBLogSTDERR ("error: connection lost.\n"); - return eRNBRunLoopModeExit; - } - else - { - // a catch all for any other gdb remote packets that failed - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__); - continue; - } - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - } - else - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__); - return eRNBRunLoopModeExit; - } + if (set_events & RNBContext::event_read_packet_available) { + rnb_err_t err = rnb_err; + RNBRemote::PacketEnum type; + + err = remote->HandleReceivedPacket(&type); + + // check if we tried to attach to a process + if (type == RNBRemote::vattach || type == RNBRemote::vattachwait || + type == RNBRemote::vattachorwait) { + if (err == rnb_success) { + RNBLogSTDOUT("Attach succeeded, ready to debug.\n"); + return eRNBRunLoopModeInferiorExecuting; + } else { + RNBLogSTDERR("error: attach failed.\n"); + return eRNBRunLoopModeExit; + } } + + if (err == rnb_success) { + // If we got our arguments we are ready to launch using the arguments + // and any environment variables we received. + if (type == RNBRemote::set_argv) { + return eRNBRunLoopModeInferiorLaunching; + } + } else if (err == rnb_not_connected) { + RNBLogSTDERR("error: connection lost.\n"); + return eRNBRunLoopModeExit; + } else { + // a catch all for any other gdb remote packets that failed + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", + __FUNCTION__); + continue; + } + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + } else { + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s Connection closed before getting \"A\" packet.", + __FUNCTION__); + return eRNBRunLoopModeExit; + } } - return eRNBRunLoopModeExit; + } + return eRNBRunLoopModeExit; } - //---------------------------------------------------------------------- // This run loop mode will wait for the process to launch and hit its // entry point. It will currently ignore all events except for the // process state changed event, where it watches for the process stopped // or crash process state. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopLaunchInferior (RNBRemote *remote, const char *stdin_path, const char *stdout_path, const char *stderr_path, bool no_stdio) -{ - RNBContext& ctx = remote->Context(); +RNBRunLoopMode RNBRunLoopLaunchInferior(RNBRemote *remote, + const char *stdin_path, + const char *stdout_path, + const char *stderr_path, + bool no_stdio) { + RNBContext &ctx = remote->Context(); - // The Process stuff takes a c array, the RNBContext has a vector... - // So make up a c array. + // The Process stuff takes a c array, the RNBContext has a vector... + // So make up a c array. - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, ctx.ArgumentAtIndex(0)); + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Launching '%s'...", __FUNCTION__, + ctx.ArgumentAtIndex(0)); - size_t inferior_argc = ctx.ArgumentCount(); - // Initialize inferior_argv with inferior_argc + 1 NULLs - std::vector<const char *> inferior_argv(inferior_argc + 1, NULL); + size_t inferior_argc = ctx.ArgumentCount(); + // Initialize inferior_argv with inferior_argc + 1 NULLs + std::vector<const char *> inferior_argv(inferior_argc + 1, NULL); - size_t i; - for (i = 0; i < inferior_argc; i++) - inferior_argv[i] = ctx.ArgumentAtIndex(i); + size_t i; + for (i = 0; i < inferior_argc; i++) + inferior_argv[i] = ctx.ArgumentAtIndex(i); - // Pass the environment array the same way: + // Pass the environment array the same way: - size_t inferior_envc = ctx.EnvironmentCount(); - // Initialize inferior_argv with inferior_argc + 1 NULLs - std::vector<const char *> inferior_envp(inferior_envc + 1, NULL); + size_t inferior_envc = ctx.EnvironmentCount(); + // Initialize inferior_argv with inferior_argc + 1 NULLs + std::vector<const char *> inferior_envp(inferior_envc + 1, NULL); - for (i = 0; i < inferior_envc; i++) - inferior_envp[i] = ctx.EnvironmentAtIndex(i); + for (i = 0; i < inferior_envc; i++) + inferior_envp[i] = ctx.EnvironmentAtIndex(i); - // Our launch type hasn't been set to anything concrete, so we need to - // figure our how we are going to launch automatically. + // Our launch type hasn't been set to anything concrete, so we need to + // figure our how we are going to launch automatically. - nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; + nub_launch_flavor_t launch_flavor = g_launch_flavor; + if (launch_flavor == eLaunchFlavorDefault) { + // Our default launch method is posix spawn + launch_flavor = eLaunchFlavorPosixSpawn; #if defined WITH_FBS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorFBS; - } -#elif defined WITH_BKS - // Check if we have an app bundle, if so launch using BackBoard Services. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorBKS; - } -#elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (strstr(inferior_argv[0], ".app")) - { - launch_flavor = eLaunchFlavorSpringBoard; - } -#endif + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorFBS; } - - ctx.SetLaunchFlavor(launch_flavor); - char resolved_path[PATH_MAX]; - - // If we fail to resolve the path to our executable, then just use what we - // were given and hope for the best - if ( !DNBResolveExecutablePath (inferior_argv[0], resolved_path, sizeof(resolved_path)) ) - ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path)); - - char launch_err_str[PATH_MAX]; - launch_err_str[0] = '\0'; - const char * cwd = (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() - : ctx.GetWorkingDirectory()); - const char *process_event = ctx.GetProcessEvent(); - nub_process_t pid = DNBProcessLaunch (resolved_path, - &inferior_argv[0], - &inferior_envp[0], - cwd, - stdin_path, - stdout_path, - stderr_path, - no_stdio, - launch_flavor, - g_disable_aslr, - process_event, - launch_err_str, - sizeof(launch_err_str)); - - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS && strlen (launch_err_str) > 0) - { - DNBLogThreaded ("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, launch_err_str); - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - ctx.LaunchStatus().SetErrorString(launch_err_str); +#elif defined WITH_BKS + // Check if we have an app bundle, if so launch using BackBoard Services. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorBKS; } - else if (pid == INVALID_NUB_PROCESS) - { - DNBLogThreaded ("%s DNBProcessLaunch() failed to launch process, unknown failure", __FUNCTION__); - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - ctx.LaunchStatus().SetErrorString("<unknown failure>"); +#elif defined WITH_SPRINGBOARD + // Check if we have an app bundle, if so launch using SpringBoard. + if (strstr(inferior_argv[0], ".app")) { + launch_flavor = eLaunchFlavorSpringBoard; } - else - { - ctx.LaunchStatus().Clear(); +#endif + } + + ctx.SetLaunchFlavor(launch_flavor); + char resolved_path[PATH_MAX]; + + // If we fail to resolve the path to our executable, then just use what we + // were given and hope for the best + if (!DNBResolveExecutablePath(inferior_argv[0], resolved_path, + sizeof(resolved_path))) + ::strncpy(resolved_path, inferior_argv[0], sizeof(resolved_path)); + + char launch_err_str[PATH_MAX]; + launch_err_str[0] = '\0'; + const char *cwd = + (ctx.GetWorkingDirPath() != NULL ? ctx.GetWorkingDirPath() + : ctx.GetWorkingDirectory()); + const char *process_event = ctx.GetProcessEvent(); + nub_process_t pid = DNBProcessLaunch( + resolved_path, &inferior_argv[0], &inferior_envp[0], cwd, stdin_path, + stdout_path, stderr_path, no_stdio, launch_flavor, g_disable_aslr, + process_event, launch_err_str, sizeof(launch_err_str)); + + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS && strlen(launch_err_str) > 0) { + DNBLogThreaded("%s DNBProcessLaunch() returned error: '%s'", __FUNCTION__, + launch_err_str); + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + ctx.LaunchStatus().SetErrorString(launch_err_str); + } else if (pid == INVALID_NUB_PROCESS) { + DNBLogThreaded( + "%s DNBProcessLaunch() failed to launch process, unknown failure", + __FUNCTION__); + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + ctx.LaunchStatus().SetErrorString("<unknown failure>"); + } else { + ctx.LaunchStatus().Clear(); + } + + if (remote->Comm().IsConnected()) { + // It we are connected already, the next thing gdb will do is ask + // whether the launch succeeded, and if not, whether there is an + // error code. So we need to fetch one packet from gdb before we wait + // on the stop from the target. + + uint32_t event_mask = RNBContext::event_read_packet_available; + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + + if (set_events & RNBContext::event_read_packet_available) { + rnb_err_t err = rnb_err; + RNBRemote::PacketEnum type; + + err = remote->HandleReceivedPacket(&type); + + if (err != rnb_success) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", + __FUNCTION__); + return eRNBRunLoopModeExit; + } + if (type != RNBRemote::query_launch_success) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s Didn't get the expected qLaunchSuccess packet.", + __FUNCTION__); + } } + } + + while (pid != INVALID_NUB_PROCESS) { + // Wait for process to start up and hit entry point + DNBLogThreadedIf(LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE)...", + __FUNCTION__, pid); + nub_event_t set_events = + DNBProcessWaitForEvents(pid, eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged, + true, NULL); + DNBLogThreadedIf(LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, " + "eEventProcessRunningStateChanged | " + "eEventProcessStoppedStateChanged, true, " + "INFINITE) => 0x%8.8x", + __FUNCTION__, pid, set_events); + + if (set_events == 0) { + pid = INVALID_NUB_PROCESS; + g_pid = pid; + } else { + if (set_events & (eEventProcessRunningStateChanged | + eEventProcessStoppedStateChanged)) { + nub_state_t pid_state = DNBProcessGetState(pid); + DNBLogThreadedIf( + LOG_RNB_EVENTS, + "%s process %4.4x state changed (eEventProcessStateChanged): %s", + __FUNCTION__, pid, DNBStateAsString(pid_state)); + + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + case eStateAttaching: + case eStateLaunching: + case eStateSuspended: + break; // Ignore - if (remote->Comm().IsConnected()) - { - // It we are connected already, the next thing gdb will do is ask - // whether the launch succeeded, and if not, whether there is an - // error code. So we need to fetch one packet from gdb before we wait - // on the stop from the target. - - uint32_t event_mask = RNBContext::event_read_packet_available; - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - - if (set_events & RNBContext::event_read_packet_available) - { - rnb_err_t err = rnb_err; - RNBRemote::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); + case eStateRunning: + case eStateStepping: + // Still waiting to stop at entry point... + break; - if (err != rnb_success) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.", __FUNCTION__); - return eRNBRunLoopModeExit; - } - if (type != RNBRemote::query_launch_success) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Didn't get the expected qLaunchSuccess packet.", __FUNCTION__); - } - } - } + case eStateStopped: + case eStateCrashed: + ctx.SetProcessID(pid); + return eRNBRunLoopModeInferiorExecuting; - while (pid != INVALID_NUB_PROCESS) - { - // Wait for process to start up and hit entry point - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE)...", __FUNCTION__, pid); - nub_event_t set_events = DNBProcessWaitForEvents (pid, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, NULL); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s DNBProcessWaitForEvent (%4.4x, eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged, true, INFINITE) => 0x%8.8x", __FUNCTION__, pid, set_events); - - if (set_events == 0) - { - pid = INVALID_NUB_PROCESS; - g_pid = pid; + case eStateDetached: + case eStateExited: + pid = INVALID_NUB_PROCESS; + g_pid = pid; + return eRNBRunLoopModeExit; } - else - { - if (set_events & (eEventProcessRunningStateChanged | eEventProcessStoppedStateChanged)) - { - nub_state_t pid_state = DNBProcessGetState (pid); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s process %4.4x state changed (eEventProcessStateChanged): %s", __FUNCTION__, pid, DNBStateAsString(pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateAttaching: - case eStateLaunching: - case eStateSuspended: - break; // Ignore - - case eStateRunning: - case eStateStepping: - // Still waiting to stop at entry point... - break; - - case eStateStopped: - case eStateCrashed: - ctx.SetProcessID(pid); - return eRNBRunLoopModeInferiorExecuting; - - case eStateDetached: - case eStateExited: - pid = INVALID_NUB_PROCESS; - g_pid = pid; - return eRNBRunLoopModeExit; - } - } + } - DNBProcessResetEvents(pid, set_events); - } + DNBProcessResetEvents(pid, set_events); } + } - return eRNBRunLoopModeExit; + return eRNBRunLoopModeExit; } - //---------------------------------------------------------------------- // This run loop mode will wait for the process to launch and hit its // entry point. It will currently ignore all events except for the // process state changed event, where it watches for the process stopped // or crash process state. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_process_t& pid) -{ - RNBContext& ctx = remote->Context(); - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, attach_pid); - char err_str[1024]; - pid = DNBProcessAttach (attach_pid, NULL, err_str, sizeof(err_str)); - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - return eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - return eRNBRunLoopModeInferiorExecuting; - } +RNBRunLoopMode RNBRunLoopLaunchAttaching(RNBRemote *remote, + nub_process_t attach_pid, + nub_process_t &pid) { + RNBContext &ctx = remote->Context(); + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Attaching to pid %i...", __FUNCTION__, + attach_pid); + char err_str[1024]; + pid = DNBProcessAttach(attach_pid, NULL, err_str, sizeof(err_str)); + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + return eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + return eRNBRunLoopModeInferiorExecuting; + } } //---------------------------------------------------------------------- @@ -390,284 +387,271 @@ RNBRunLoopLaunchAttaching (RNBRemote *remote, nub_process_t attach_pid, nub_proc //---------------------------------------------------------------------- int g_sigint_received = 0; int g_sigpipe_received = 0; -void -signal_handler(int signo) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo)); - - switch (signo) - { - case SIGINT: - g_sigint_received++; - if (g_pid != INVALID_NUB_PROCESS) - { - // Only send a SIGINT once... - if (g_sigint_received == 1) - { - switch (DNBProcessGetState (g_pid)) - { - case eStateRunning: - case eStateStepping: - DNBProcessSignal (g_pid, SIGSTOP); - return; - default: - break; - } - } - } - exit (SIGINT); - break; - - case SIGPIPE: - g_sigpipe_received = 1; - break; +void signal_handler(int signo) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, + SysSignal::Name(signo)); + + switch (signo) { + case SIGINT: + g_sigint_received++; + if (g_pid != INVALID_NUB_PROCESS) { + // Only send a SIGINT once... + if (g_sigint_received == 1) { + switch (DNBProcessGetState(g_pid)) { + case eStateRunning: + case eStateStepping: + DNBProcessSignal(g_pid, SIGSTOP); + return; + default: + break; + } + } } + exit(SIGINT); + break; + + case SIGPIPE: + g_sigpipe_received = 1; + break; + } } // Return the new run loop mode based off of the current process state -RNBRunLoopMode -HandleProcessStateChange (RNBRemote *remote, bool initialize) -{ - RNBContext& ctx = remote->Context(); - nub_process_t pid = ctx.ProcessID(); - - if (pid == INVALID_NUB_PROCESS) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); - return eRNBRunLoopModeExit; - } - nub_state_t pid_state = DNBProcessGetState (pid); - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - // Something bad happened - return eRNBRunLoopModeExit; - break; - - case eStateAttaching: - case eStateLaunching: - return eRNBRunLoopModeInferiorExecuting; +RNBRunLoopMode HandleProcessStateChange(RNBRemote *remote, bool initialize) { + RNBContext &ctx = remote->Context(); + nub_process_t pid = ctx.ProcessID(); - case eStateSuspended: - case eStateCrashed: - case eStateStopped: - // If we stop due to a signal, so clear the fact that we got a SIGINT - // so we can stop ourselves again (but only while our inferior - // process is running..) - g_sigint_received = 0; - if (initialize == false) - { - // Compare the last stop count to our current notion of a stop count - // to make sure we don't notify more than once for a given stop. - nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); - bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); - if (pid_stop_count_changed) - { - remote->FlushSTDIO(); - - if (ctx.GetProcessStopCount() == 1) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); - } - else - { - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); - remote->NotifyThatProcessStopped (); - } - } - else - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %llu (old %llu)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); - } - } - return eRNBRunLoopModeInferiorExecuting; - - case eStateStepping: - case eStateRunning: - return eRNBRunLoopModeInferiorExecuting; + if (pid == INVALID_NUB_PROCESS) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", + __FUNCTION__); + return eRNBRunLoopModeExit; + } + nub_state_t pid_state = DNBProcessGetState(pid); - case eStateExited: - remote->HandlePacket_last_signal(NULL); - case eStateDetached: - return eRNBRunLoopModeExit; + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, + (int)initialize, DNBStateAsString(pid_state)); + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + // Something bad happened + return eRNBRunLoopModeExit; + break; + + case eStateAttaching: + case eStateLaunching: + return eRNBRunLoopModeInferiorExecuting; + + case eStateSuspended: + case eStateCrashed: + case eStateStopped: + // If we stop due to a signal, so clear the fact that we got a SIGINT + // so we can stop ourselves again (but only while our inferior + // process is running..) + g_sigint_received = 0; + if (initialize == false) { + // Compare the last stop count to our current notion of a stop count + // to make sure we don't notify more than once for a given stop. + nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); + bool pid_stop_count_changed = + ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); + if (pid_stop_count_changed) { + remote->FlushSTDIO(); + + if (ctx.GetProcessStopCount() == 1) { + DNBLogThreadedIf( + LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " + "pid_stop_count %llu (old %llu)) Notify??? no, " + "first stop...", + __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), + (uint64_t)ctx.GetProcessStopCount(), + (uint64_t)prev_pid_stop_count); + } else { + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) " + "pid_state = %s pid_stop_count " + "%llu (old %llu)) Notify??? YES!!!", + __FUNCTION__, (int)initialize, + DNBStateAsString(pid_state), + (uint64_t)ctx.GetProcessStopCount(), + (uint64_t)prev_pid_stop_count); + remote->NotifyThatProcessStopped(); + } + } else { + DNBLogThreadedIf( + LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " + "pid_stop_count %llu (old %llu)) Notify??? " + "skipping...", + __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), + (uint64_t)ctx.GetProcessStopCount(), (uint64_t)prev_pid_stop_count); + } } + return eRNBRunLoopModeInferiorExecuting; + + case eStateStepping: + case eStateRunning: + return eRNBRunLoopModeInferiorExecuting; - // Catch all... + case eStateExited: + remote->HandlePacket_last_signal(NULL); + case eStateDetached: return eRNBRunLoopModeExit; + } + + // Catch all... + return eRNBRunLoopModeExit; } // This function handles the case where our inferior program is stopped and // we are waiting for gdb remote protocol packets. When a packet occurs that // makes the inferior run, we need to leave this function with a new state // as the return code. -RNBRunLoopMode -RNBRunLoopInferiorExecuting (RNBRemote *remote) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - RNBContext& ctx = remote->Context(); - - // Init our mode and set 'is_running' based on the current process state - RNBRunLoopMode mode = HandleProcessStateChange (remote, true); - - while (ctx.ProcessID() != INVALID_NUB_PROCESS) - { - - std::string set_events_str; - uint32_t event_mask = ctx.NormalEventBits(); - - if (!ctx.ProcessStateRunning()) - { - // Clear some bits if we are not running so we don't send any async packets - event_mask &= ~RNBContext::event_proc_stdio_available; - event_mask &= ~RNBContext::event_proc_profile_data; - // When we enable async structured data packets over another logical channel, - // this can be relaxed. - event_mask &= ~RNBContext::event_darwin_log_data_available; - } - - // We want to make sure we consume all process state changes and have - // whomever is notifying us to wait for us to reset the event bit before - // continuing. - //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); - - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str)); - - if (set_events) - { - if ((set_events & RNBContext::event_proc_thread_exiting) || - (set_events & RNBContext::event_proc_stdio_available)) - { - remote->FlushSTDIO(); - } - - if (set_events & RNBContext::event_proc_profile_data) - { - remote->SendAsyncProfileData(); - } - - if (set_events & RNBContext::event_darwin_log_data_available) - { - remote->SendAsyncDarwinLogData(); - } - - if (set_events & RNBContext::event_read_packet_available) - { - // handleReceivedPacket will take care of resetting the - // event_read_packet_available events when there are no more... - set_events ^= RNBContext::event_read_packet_available; - - if (ctx.ProcessStateRunning()) - { - if (remote->HandleAsyncPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - else - { - if (remote->HandleReceivedPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - } - - if (set_events & RNBContext::event_proc_state_changed) - { - mode = HandleProcessStateChange (remote, false); - ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); - set_events ^= RNBContext::event_proc_state_changed; - } +RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemote *remote) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + RNBContext &ctx = remote->Context(); + + // Init our mode and set 'is_running' based on the current process state + RNBRunLoopMode mode = HandleProcessStateChange(remote, true); + + while (ctx.ProcessID() != INVALID_NUB_PROCESS) { + + std::string set_events_str; + uint32_t event_mask = ctx.NormalEventBits(); + + if (!ctx.ProcessStateRunning()) { + // Clear some bits if we are not running so we don't send any async + // packets + event_mask &= ~RNBContext::event_proc_stdio_available; + event_mask &= ~RNBContext::event_proc_profile_data; + // When we enable async structured data packets over another logical + // channel, + // this can be relaxed. + event_mask &= ~RNBContext::event_darwin_log_data_available; + } - if (set_events & RNBContext::event_proc_thread_exiting) - { - mode = eRNBRunLoopModeExit; + // We want to make sure we consume all process state changes and have + // whomever is notifying us to wait for us to reset the event bit before + // continuing. + // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); + + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)", + __FUNCTION__, event_mask, set_events, + ctx.EventsAsString(set_events, set_events_str)); + + if (set_events) { + if ((set_events & RNBContext::event_proc_thread_exiting) || + (set_events & RNBContext::event_proc_stdio_available)) { + remote->FlushSTDIO(); + } + + if (set_events & RNBContext::event_proc_profile_data) { + remote->SendAsyncProfileData(); + } + + if (set_events & RNBContext::event_darwin_log_data_available) { + remote->SendAsyncDarwinLogData(); + } + + if (set_events & RNBContext::event_read_packet_available) { + // handleReceivedPacket will take care of resetting the + // event_read_packet_available events when there are no more... + set_events ^= RNBContext::event_read_packet_available; + + if (ctx.ProcessStateRunning()) { + if (remote->HandleAsyncPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } + } else { + if (remote->HandleReceivedPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } + } + } + + if (set_events & RNBContext::event_proc_state_changed) { + mode = HandleProcessStateChange(remote, false); + ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); + set_events ^= RNBContext::event_proc_state_changed; + } + + if (set_events & RNBContext::event_proc_thread_exiting) { + mode = eRNBRunLoopModeExit; + } + + if (set_events & RNBContext::event_read_thread_exiting) { + // Out remote packet receiving thread exited, exit for now. + if (ctx.HasValidProcessID()) { + // TODO: We should add code that will leave the current process + // in its current state and listen for another connection... + if (ctx.ProcessStateRunning()) { + if (ctx.GetDetachOnError()) { + DNBLog("debugserver's event read thread is exiting, detaching " + "from the inferior process."); + DNBProcessDetach(ctx.ProcessID()); + } else { + DNBLog("debugserver's event read thread is exiting, killing the " + "inferior process."); + DNBProcessKill(ctx.ProcessID()); } - - if (set_events & RNBContext::event_read_thread_exiting) - { - // Out remote packet receiving thread exited, exit for now. - if (ctx.HasValidProcessID()) - { - // TODO: We should add code that will leave the current process - // in its current state and listen for another connection... - if (ctx.ProcessStateRunning()) - { - if (ctx.GetDetachOnError()) - { - DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); - DNBProcessDetach (ctx.ProcessID()); - } - else - { - DNBLog ("debugserver's event read thread is exiting, killing the inferior process."); - DNBProcessKill (ctx.ProcessID()); - } - } - else - { - if (ctx.GetDetachOnError()) - { - DNBLog ("debugserver's event read thread is exiting, detaching from the inferior process."); - DNBProcessDetach (ctx.ProcessID()); - } - } - } - mode = eRNBRunLoopModeExit; + } else { + if (ctx.GetDetachOnError()) { + DNBLog("debugserver's event read thread is exiting, detaching " + "from the inferior process."); + DNBProcessDetach(ctx.ProcessID()); } + } } - - // Reset all event bits that weren't reset for now... - if (set_events != 0) - ctx.Events().ResetEvents(set_events); - - if (mode != eRNBRunLoopModeInferiorExecuting) - break; + mode = eRNBRunLoopModeExit; + } } - return mode; -} + // Reset all event bits that weren't reset for now... + if (set_events != 0) + ctx.Events().ResetEvents(set_events); + if (mode != eRNBRunLoopModeInferiorExecuting) + break; + } -RNBRunLoopMode -RNBRunLoopPlatform (RNBRemote *remote) -{ - RNBRunLoopMode mode = eRNBRunLoopModePlatformMode; - RNBContext& ctx = remote->Context(); - - while (mode == eRNBRunLoopModePlatformMode) - { - std::string set_events_str; - const uint32_t event_mask = RNBContext::event_read_packet_available | - RNBContext::event_read_thread_exiting; - - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str)); - - if (set_events) - { - if (set_events & RNBContext::event_read_packet_available) - { - if (remote->HandleReceivedPacket() == rnb_not_connected) - mode = eRNBRunLoopModeExit; - } + return mode; +} - if (set_events & RNBContext::event_read_thread_exiting) - { - mode = eRNBRunLoopModeExit; - } - ctx.Events().ResetEvents(set_events); - } +RNBRunLoopMode RNBRunLoopPlatform(RNBRemote *remote) { + RNBRunLoopMode mode = eRNBRunLoopModePlatformMode; + RNBContext &ctx = remote->Context(); + + while (mode == eRNBRunLoopModePlatformMode) { + std::string set_events_str; + const uint32_t event_mask = RNBContext::event_read_packet_available | + RNBContext::event_read_thread_exiting; + + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)", + __FUNCTION__, event_mask, set_events, + ctx.EventsAsString(set_events, set_events_str)); + + if (set_events) { + if (set_events & RNBContext::event_read_packet_available) { + if (remote->HandleReceivedPacket() == rnb_not_connected) + mode = eRNBRunLoopModeExit; + } + + if (set_events & RNBContext::event_read_thread_exiting) { + mode = eRNBRunLoopModeExit; + } + ctx.Events().ResetEvents(set_events); } - return eRNBRunLoopModeExit; + } + return eRNBRunLoopModeExit; } //---------------------------------------------------------------------- @@ -675,1070 +659,1014 @@ RNBRunLoopPlatform (RNBRemote *remote) // Returns 1 for success 0 for failure. //---------------------------------------------------------------------- -static void -PortWasBoundCallbackUnixSocket (const void *baton, in_port_t port) -{ - //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, port); - - const char *unix_socket_name = (const char *)baton; - - if (unix_socket_name && unix_socket_name[0]) - { - // We were given a unix socket name to use to communicate the port - // that we ended up binding to back to our parent process - struct sockaddr_un saddr_un; - int s = ::socket (AF_UNIX, SOCK_STREAM, 0); - if (s < 0) - { - perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); - exit(1); - } - - saddr_un.sun_family = AF_UNIX; - ::strncpy(saddr_un.sun_path, unix_socket_name, sizeof(saddr_un.sun_path) - 1); - saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; - saddr_un.sun_len = SUN_LEN (&saddr_un); +static void PortWasBoundCallbackUnixSocket(const void *baton, in_port_t port) { + //::printf ("PortWasBoundCallbackUnixSocket (baton = %p, port = %u)\n", baton, + //port); - if (::connect (s, (struct sockaddr *)&saddr_un, static_cast<socklen_t>(SUN_LEN (&saddr_un))) < 0) - { - perror("error: connect (socket, &saddr_un, saddr_un_len)"); - exit(1); - } + const char *unix_socket_name = (const char *)baton; - //::printf ("connect () sucess!!\n"); + if (unix_socket_name && unix_socket_name[0]) { + // We were given a unix socket name to use to communicate the port + // that we ended up binding to back to our parent process + struct sockaddr_un saddr_un; + int s = ::socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) { + perror("error: socket (AF_UNIX, SOCK_STREAM, 0)"); + exit(1); + } + saddr_un.sun_family = AF_UNIX; + ::strncpy(saddr_un.sun_path, unix_socket_name, + sizeof(saddr_un.sun_path) - 1); + saddr_un.sun_path[sizeof(saddr_un.sun_path) - 1] = '\0'; + saddr_un.sun_len = SUN_LEN(&saddr_un); - // We were able to connect to the socket, now write our PID so whomever - // launched us will know this process's ID - RNBLogSTDOUT ("Listening to port %i...\n", port); + if (::connect(s, (struct sockaddr *)&saddr_un, + static_cast<socklen_t>(SUN_LEN(&saddr_un))) < 0) { + perror("error: connect (socket, &saddr_un, saddr_un_len)"); + exit(1); + } - char pid_str[64]; - const int pid_str_len = ::snprintf (pid_str, sizeof(pid_str), "%u", port); - const ssize_t bytes_sent = ::send (s, pid_str, pid_str_len, 0); + //::printf ("connect () sucess!!\n"); - if (pid_str_len != bytes_sent) - { - perror("error: send (s, pid_str, pid_str_len, 0)"); - exit (1); - } + // We were able to connect to the socket, now write our PID so whomever + // launched us will know this process's ID + RNBLogSTDOUT("Listening to port %i...\n", port); - //::printf ("send () sucess!!\n"); + char pid_str[64]; + const int pid_str_len = ::snprintf(pid_str, sizeof(pid_str), "%u", port); + const ssize_t bytes_sent = ::send(s, pid_str, pid_str_len, 0); - // We are done with the socket - close (s); + if (pid_str_len != bytes_sent) { + perror("error: send (s, pid_str, pid_str_len, 0)"); + exit(1); } + + //::printf ("send () sucess!!\n"); + + // We are done with the socket + close(s); + } } -static void -PortWasBoundCallbackNamedPipe (const void *baton, uint16_t port) -{ - const char *named_pipe = (const char *)baton; - if (named_pipe && named_pipe[0]) - { - int fd = ::open(named_pipe, O_WRONLY); - if (fd > -1) - { - char port_str[64]; - const ssize_t port_str_len = ::snprintf (port_str, sizeof(port_str), "%u", port); - // Write the port number as a C string with the NULL terminator - ::write (fd, port_str, port_str_len + 1); - close (fd); - } +static void PortWasBoundCallbackNamedPipe(const void *baton, uint16_t port) { + const char *named_pipe = (const char *)baton; + if (named_pipe && named_pipe[0]) { + int fd = ::open(named_pipe, O_WRONLY); + if (fd > -1) { + char port_str[64]; + const ssize_t port_str_len = + ::snprintf(port_str, sizeof(port_str), "%u", port); + // Write the port number as a C string with the NULL terminator + ::write(fd, port_str, port_str_len + 1); + close(fd); } + } } -static int -ConnectRemote (RNBRemote *remote, - const char *host, - int port, - bool reverse_connect, - const char *named_pipe_path, - const char *unix_socket_name) -{ - if (!remote->Comm().IsConnected()) - { - if (reverse_connect) - { - if (port == 0) - { - DNBLogThreaded("error: invalid port supplied for reverse connection: %i.\n", port); - return 0; - } - if (remote->Comm().Connect(host, port) != rnb_success) - { - DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port); - return 0; - } +static int ConnectRemote(RNBRemote *remote, const char *host, int port, + bool reverse_connect, const char *named_pipe_path, + const char *unix_socket_name) { + if (!remote->Comm().IsConnected()) { + if (reverse_connect) { + if (port == 0) { + DNBLogThreaded( + "error: invalid port supplied for reverse connection: %i.\n", port); + return 0; + } + if (remote->Comm().Connect(host, port) != rnb_success) { + DNBLogThreaded("Failed to reverse connect to %s:%i.\n", host, port); + return 0; + } + } else { + if (port != 0) + RNBLogSTDOUT("Listening to port %i for a connection from %s...\n", port, + host ? host : "127.0.0.1"); + if (unix_socket_name && unix_socket_name[0]) { + if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, + unix_socket_name) != rnb_success) { + RNBLogSTDERR("Failed to get connection from a remote gdb process.\n"); + return 0; } - else - { - if (port != 0) - RNBLogSTDOUT ("Listening to port %i for a connection from %s...\n", port, host ? host : "127.0.0.1"); - if (unix_socket_name && unix_socket_name[0]) - { - if (remote->Comm().Listen(host, port, PortWasBoundCallbackUnixSocket, unix_socket_name) != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - return 0; - } - } - else - { - if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, named_pipe_path) != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - return 0; - } - } + } else { + if (remote->Comm().Listen(host, port, PortWasBoundCallbackNamedPipe, + named_pipe_path) != rnb_success) { + RNBLogSTDERR("Failed to get connection from a remote gdb process.\n"); + return 0; } - remote->StartReadRemoteDataThread(); + } } - return 1; + remote->StartReadRemoteDataThread(); + } + return 1; } //---------------------------------------------------------------------- // ASL Logging callback that can be registered with DNBLogSetLogCallback //---------------------------------------------------------------------- -void -ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args) -{ - if (format == NULL) - return; - static aslmsg g_aslmsg = NULL; - if (g_aslmsg == NULL) - { - g_aslmsg = ::asl_new (ASL_TYPE_MSG); - char asl_key_sender[PATH_MAX]; - snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR); - ::asl_set (g_aslmsg, ASL_KEY_SENDER, asl_key_sender); - } - - int asl_level; - if (flags & DNBLOG_FLAG_FATAL) asl_level = ASL_LEVEL_CRIT; - else if (flags & DNBLOG_FLAG_ERROR) asl_level = ASL_LEVEL_ERR; - else if (flags & DNBLOG_FLAG_WARNING) asl_level = ASL_LEVEL_WARNING; - else if (flags & DNBLOG_FLAG_VERBOSE) asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_INFO; - else asl_level = ASL_LEVEL_WARNING; //ASL_LEVEL_DEBUG; - - ::asl_vlog (NULL, g_aslmsg, asl_level, format, args); +void ASLLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { + if (format == NULL) + return; + static aslmsg g_aslmsg = NULL; + if (g_aslmsg == NULL) { + g_aslmsg = ::asl_new(ASL_TYPE_MSG); + char asl_key_sender[PATH_MAX]; + snprintf(asl_key_sender, sizeof(asl_key_sender), "com.apple.%s-%s", + DEBUGSERVER_PROGRAM_NAME, DEBUGSERVER_VERSION_STR); + ::asl_set(g_aslmsg, ASL_KEY_SENDER, asl_key_sender); + } + + int asl_level; + if (flags & DNBLOG_FLAG_FATAL) + asl_level = ASL_LEVEL_CRIT; + else if (flags & DNBLOG_FLAG_ERROR) + asl_level = ASL_LEVEL_ERR; + else if (flags & DNBLOG_FLAG_WARNING) + asl_level = ASL_LEVEL_WARNING; + else if (flags & DNBLOG_FLAG_VERBOSE) + asl_level = ASL_LEVEL_WARNING; // ASL_LEVEL_INFO; + else + asl_level = ASL_LEVEL_WARNING; // ASL_LEVEL_DEBUG; + + ::asl_vlog(NULL, g_aslmsg, asl_level, format, args); } //---------------------------------------------------------------------- // FILE based Logging callback that can be registered with // DNBLogSetLogCallback //---------------------------------------------------------------------- -void -FileLogCallback(void *baton, uint32_t flags, const char *format, va_list args) -{ - if (baton == NULL || format == NULL) - return; - - ::vfprintf((FILE *)baton, format, args); - ::fprintf((FILE *)baton, "\n"); - ::fflush((FILE *)baton); +void FileLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { + if (baton == NULL || format == NULL) + return; + + ::vfprintf((FILE *)baton, format, args); + ::fprintf((FILE *)baton, "\n"); + ::fflush((FILE *)baton); } - -void -show_usage_and_exit (int exit_code) -{ - RNBLogSTDERR ("Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file [program-name program-arg1 program-arg2 ...]\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s host:port --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); - RNBLogSTDERR (" %s /path/file --attach=<process_name>\n", DEBUGSERVER_PROGRAM_NAME); - exit (exit_code); +void show_usage_and_exit(int exit_code) { + RNBLogSTDERR( + "Usage:\n %s host:port [program-name program-arg1 program-arg2 ...]\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file [program-name program-arg1 program-arg2 ...]\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s host:port --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file --attach=<pid>\n", DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s host:port --attach=<process_name>\n", + DEBUGSERVER_PROGRAM_NAME); + RNBLogSTDERR(" %s /path/file --attach=<process_name>\n", + DEBUGSERVER_PROGRAM_NAME); + exit(exit_code); } - //---------------------------------------------------------------------- // option descriptors for getopt_long_only() //---------------------------------------------------------------------- -static struct option g_long_options[] = -{ - { "attach", required_argument, NULL, 'a' }, - { "arch", required_argument, NULL, 'A' }, - { "debug", no_argument, NULL, 'g' }, - { "kill-on-error", no_argument, NULL, 'K' }, - { "verbose", no_argument, NULL, 'v' }, - { "lockdown", no_argument, &g_lockdown_opt, 1 }, // short option "-k" - { "applist", no_argument, &g_applist_opt, 1 }, // short option "-t" - { "log-file", required_argument, NULL, 'l' }, - { "log-flags", required_argument, NULL, 'f' }, - { "launch", required_argument, NULL, 'x' }, // Valid values are "auto", "posix-spawn", "fork-exec", "springboard" (arm only) - { "waitfor", required_argument, NULL, 'w' }, // Wait for a process whose name starts with ARG - { "waitfor-interval", required_argument, NULL, 'i' }, // Time in usecs to wait between sampling the pid list when waiting for a process by name - { "waitfor-duration", required_argument, NULL, 'd' }, // The time in seconds to wait for a process to show up by name - { "native-regs", no_argument, NULL, 'r' }, // Specify to use the native registers instead of the gdb defaults for the architecture. - { "stdio-path", required_argument, NULL, 's' }, // Set the STDIO path to be used when launching applications (STDIN, STDOUT and STDERR) (only if debugserver launches the process) - { "stdin-path", required_argument, NULL, 'I' }, // Set the STDIN path to be used when launching applications (only if debugserver launches the process) - { "stdout-path", required_argument, NULL, 'O' }, // Set the STDOUT path to be used when launching applications (only if debugserver launches the process) - { "stderr-path", required_argument, NULL, 'E' }, // Set the STDERR path to be used when launching applications (only if debugserver launches the process) - { "no-stdio", no_argument, NULL, 'n' }, // Do not set up any stdio (perhaps the program is a GUI program) (only if debugserver launches the process) - { "setsid", no_argument, NULL, 'S' }, // call setsid() to make debugserver run in its own session - { "disable-aslr", no_argument, NULL, 'D' }, // Use _POSIX_SPAWN_DISABLE_ASLR to avoid shared library randomization - { "working-dir", required_argument, NULL, 'W' }, // The working directory that the inferior process should have (only if debugserver launches the process) - { "platform", required_argument, NULL, 'p' }, // Put this executable into a remote platform mode - { "unix-socket", required_argument, NULL, 'u' }, // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use - { "fd", required_argument, NULL, 'FDSC' }, // A file descriptor was passed to this process when spawned that is already open and ready for communication - { "named-pipe", required_argument, NULL, 'P' }, - { "reverse-connect", no_argument, NULL, 'R' }, - { "env", required_argument, NULL, 'e' }, // When debugserver launches the process, set a single environment entry as specified by the option value ("./debugserver -e FOO=1 -e BAR=2 localhost:1234 -- /bin/ls") - { "forward-env", no_argument, NULL, 'F' }, // When debugserver launches the process, forward debugserver's current environment variables to the child process ("./debugserver -F localhost:1234 -- /bin/ls" - { NULL, 0, NULL, 0 } -}; - +static struct option g_long_options[] = { + {"attach", required_argument, NULL, 'a'}, + {"arch", required_argument, NULL, 'A'}, + {"debug", no_argument, NULL, 'g'}, + {"kill-on-error", no_argument, NULL, 'K'}, + {"verbose", no_argument, NULL, 'v'}, + {"lockdown", no_argument, &g_lockdown_opt, 1}, // short option "-k" + {"applist", no_argument, &g_applist_opt, 1}, // short option "-t" + {"log-file", required_argument, NULL, 'l'}, + {"log-flags", required_argument, NULL, 'f'}, + {"launch", required_argument, NULL, 'x'}, // Valid values are "auto", + // "posix-spawn", "fork-exec", + // "springboard" (arm only) + {"waitfor", required_argument, NULL, + 'w'}, // Wait for a process whose name starts with ARG + {"waitfor-interval", required_argument, NULL, + 'i'}, // Time in usecs to wait between sampling the pid list when waiting + // for a process by name + {"waitfor-duration", required_argument, NULL, + 'd'}, // The time in seconds to wait for a process to show up by name + {"native-regs", no_argument, NULL, 'r'}, // Specify to use the native + // registers instead of the gdb + // defaults for the architecture. + {"stdio-path", required_argument, NULL, + 's'}, // Set the STDIO path to be used when launching applications (STDIN, + // STDOUT and STDERR) (only if debugserver launches the process) + {"stdin-path", required_argument, NULL, + 'I'}, // Set the STDIN path to be used when launching applications (only if + // debugserver launches the process) + {"stdout-path", required_argument, NULL, + 'O'}, // Set the STDOUT path to be used when launching applications (only + // if debugserver launches the process) + {"stderr-path", required_argument, NULL, + 'E'}, // Set the STDERR path to be used when launching applications (only + // if debugserver launches the process) + {"no-stdio", no_argument, NULL, + 'n'}, // Do not set up any stdio (perhaps the program is a GUI program) + // (only if debugserver launches the process) + {"setsid", no_argument, NULL, + 'S'}, // call setsid() to make debugserver run in its own session + {"disable-aslr", no_argument, NULL, 'D'}, // Use _POSIX_SPAWN_DISABLE_ASLR + // to avoid shared library + // randomization + {"working-dir", required_argument, NULL, + 'W'}, // The working directory that the inferior process should have (only + // if debugserver launches the process) + {"platform", required_argument, NULL, + 'p'}, // Put this executable into a remote platform mode + {"unix-socket", required_argument, NULL, + 'u'}, // If we need to handshake with our parent process, an option will be + // passed down that specifies a unix socket name to use + {"fd", required_argument, NULL, + 'FDSC'}, // A file descriptor was passed to this process when spawned that + // is already open and ready for communication + {"named-pipe", required_argument, NULL, 'P'}, + {"reverse-connect", no_argument, NULL, 'R'}, + {"env", required_argument, NULL, + 'e'}, // When debugserver launches the process, set a single environment + // entry as specified by the option value ("./debugserver -e FOO=1 -e + // BAR=2 localhost:1234 -- /bin/ls") + {"forward-env", no_argument, NULL, + 'F'}, // When debugserver launches the process, forward debugserver's + // current environment variables to the child process ("./debugserver + // -F localhost:1234 -- /bin/ls" + {NULL, 0, NULL, 0}}; //---------------------------------------------------------------------- // main //---------------------------------------------------------------------- -int -main (int argc, char *argv[]) -{ - // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we - // don't spawn child processes with this enabled. - unsetenv("DYLD_INSERT_LIBRARIES"); - - const char *argv_sub_zero = argv[0]; // save a copy of argv[0] for error reporting post-launch - -#if defined (__APPLE__) - pthread_setname_np ("main thread"); -#if defined (__arm__) || defined (__arm64__) || defined (__aarch64__) - struct sched_param thread_param; - int thread_sched_policy; - if (pthread_getschedparam(pthread_self(), &thread_sched_policy, &thread_param) == 0) - { - thread_param.sched_priority = 47; - pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); - } - - ::proc_set_wakemon_params (getpid(), 500, 0); // Allow up to 500 wakeups/sec to avoid EXC_RESOURCE for normal use. +int main(int argc, char *argv[]) { + // If debugserver is launched with DYLD_INSERT_LIBRARIES, unset it so we + // don't spawn child processes with this enabled. + unsetenv("DYLD_INSERT_LIBRARIES"); + + const char *argv_sub_zero = + argv[0]; // save a copy of argv[0] for error reporting post-launch + +#if defined(__APPLE__) + pthread_setname_np("main thread"); +#if defined(__arm__) || defined(__arm64__) || defined(__aarch64__) + struct sched_param thread_param; + int thread_sched_policy; + if (pthread_getschedparam(pthread_self(), &thread_sched_policy, + &thread_param) == 0) { + thread_param.sched_priority = 47; + pthread_setschedparam(pthread_self(), thread_sched_policy, &thread_param); + } + + ::proc_set_wakemon_params( + getpid(), 500, + 0); // Allow up to 500 wakeups/sec to avoid EXC_RESOURCE for normal use. #endif #endif - g_isatty = ::isatty (STDIN_FILENO); - - // ::printf ("uid=%u euid=%u gid=%u egid=%u\n", - // getuid(), - // geteuid(), - // getgid(), - // getegid()); - - - // signal (SIGINT, signal_handler); - signal (SIGPIPE, signal_handler); - signal (SIGHUP, signal_handler); - - // We're always sitting in waitpid or kevent waiting on our target process' death, - // we don't need no stinking SIGCHLD's... - - sigset_t sigset; - sigemptyset(&sigset); - sigaddset(&sigset, SIGCHLD); - sigprocmask(SIG_BLOCK, &sigset, NULL); - - g_remoteSP.reset (new RNBRemote ()); - - - RNBRemote *remote = g_remoteSP.get(); - if (remote == NULL) - { - RNBLogSTDERR ("error: failed to create a remote connection class\n"); - return -1; - } - - RNBContext& ctx = remote->Context(); - - int i; - int attach_pid = INVALID_NUB_PROCESS; - - FILE* log_file = NULL; - uint32_t log_flags = 0; - // Parse our options - int ch; - int long_option_index = 0; - int debug = 0; - int communication_fd = -1; - std::string compile_options; - std::string waitfor_pid_name; // Wait for a process that starts with this name - std::string attach_pid_name; - std::string arch_name; - std::string working_dir; // The new working directory to use for the inferior - std::string unix_socket_name; // If we need to handshake with our parent process, an option will be passed down that specifies a unix socket name to use - std::string named_pipe_path; // If we need to handshake with our parent process, an option will be passed down that specifies a named pipe to use - useconds_t waitfor_interval = 1000; // Time in usecs between process lists polls when waiting for a process by name, default 1 msec. - useconds_t waitfor_duration = 0; // Time in seconds to wait for a process by name, 0 means wait forever. - bool no_stdio = false; - bool reverse_connect = false; // Set to true by an option to indicate we should reverse connect to the host:port supplied as the first debugserver argument - -#if !defined (DNBLOG_ENABLED) - compile_options += "(no-logging) "; + g_isatty = ::isatty(STDIN_FILENO); + + // ::printf ("uid=%u euid=%u gid=%u egid=%u\n", + // getuid(), + // geteuid(), + // getgid(), + // getegid()); + + // signal (SIGINT, signal_handler); + signal(SIGPIPE, signal_handler); + signal(SIGHUP, signal_handler); + + // We're always sitting in waitpid or kevent waiting on our target process' + // death, + // we don't need no stinking SIGCHLD's... + + sigset_t sigset; + sigemptyset(&sigset); + sigaddset(&sigset, SIGCHLD); + sigprocmask(SIG_BLOCK, &sigset, NULL); + + g_remoteSP.reset(new RNBRemote()); + + RNBRemote *remote = g_remoteSP.get(); + if (remote == NULL) { + RNBLogSTDERR("error: failed to create a remote connection class\n"); + return -1; + } + + RNBContext &ctx = remote->Context(); + + int i; + int attach_pid = INVALID_NUB_PROCESS; + + FILE *log_file = NULL; + uint32_t log_flags = 0; + // Parse our options + int ch; + int long_option_index = 0; + int debug = 0; + int communication_fd = -1; + std::string compile_options; + std::string waitfor_pid_name; // Wait for a process that starts with this name + std::string attach_pid_name; + std::string arch_name; + std::string working_dir; // The new working directory to use for the inferior + std::string unix_socket_name; // If we need to handshake with our parent + // process, an option will be passed down that + // specifies a unix socket name to use + std::string named_pipe_path; // If we need to handshake with our parent + // process, an option will be passed down that + // specifies a named pipe to use + useconds_t waitfor_interval = 1000; // Time in usecs between process lists + // polls when waiting for a process by + // name, default 1 msec. + useconds_t waitfor_duration = + 0; // Time in seconds to wait for a process by name, 0 means wait forever. + bool no_stdio = false; + bool reverse_connect = false; // Set to true by an option to indicate we + // should reverse connect to the host:port + // supplied as the first debugserver argument + +#if !defined(DNBLOG_ENABLED) + compile_options += "(no-logging) "; #endif - RNBRunLoopMode start_mode = eRNBRunLoopModeExit; - - char short_options[512]; - uint32_t short_options_idx = 0; - - // Handle the two case that don't have short options in g_long_options - short_options[short_options_idx++] = 'k'; - short_options[short_options_idx++] = 't'; - - for (i=0; g_long_options[i].name != NULL; ++i) - { - if (isalpha(g_long_options[i].val)) - { - short_options[short_options_idx++] = g_long_options[i].val; - switch (g_long_options[i].has_arg) - { - default: - case no_argument: - break; - - case optional_argument: - short_options[short_options_idx++] = ':'; - // Fall through to required_argument case below... - case required_argument: - short_options[short_options_idx++] = ':'; - break; - } - } + RNBRunLoopMode start_mode = eRNBRunLoopModeExit; + + char short_options[512]; + uint32_t short_options_idx = 0; + + // Handle the two case that don't have short options in g_long_options + short_options[short_options_idx++] = 'k'; + short_options[short_options_idx++] = 't'; + + for (i = 0; g_long_options[i].name != NULL; ++i) { + if (isalpha(g_long_options[i].val)) { + short_options[short_options_idx++] = g_long_options[i].val; + switch (g_long_options[i].has_arg) { + default: + case no_argument: + break; + + case optional_argument: + short_options[short_options_idx++] = ':'; + // Fall through to required_argument case below... + case required_argument: + short_options[short_options_idx++] = ':'; + break; + } } - // NULL terminate the short option string. - short_options[short_options_idx++] = '\0'; + } + // NULL terminate the short option string. + short_options[short_options_idx++] = '\0'; #if __GLIBC__ - optind = 0; + optind = 0; #else - optreset = 1; - optind = 1; + optreset = 1; + optind = 1; #endif - while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, &long_option_index)) != -1) - { - DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", - ch, (uint8_t)ch, - g_long_options[long_option_index].name, - g_long_options[long_option_index].has_arg ? '=' : ' ', - optarg ? optarg : ""); - switch (ch) - { - case 0: // Any optional that auto set themselves will return 0 - break; - - case 'A': - if (optarg && optarg[0]) - arch_name.assign(optarg); - break; - - case 'a': - if (optarg && optarg[0]) - { - if (isdigit(optarg[0])) - { - char *end = NULL; - attach_pid = static_cast<int>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid pid option '%s'\n", optarg); - exit (4); - } - } - else - { - attach_pid_name = optarg; - } - start_mode = eRNBRunLoopModeInferiorAttaching; - } - break; - - // --waitfor=NAME - case 'w': - if (optarg && optarg[0]) - { - waitfor_pid_name = optarg; - start_mode = eRNBRunLoopModeInferiorAttaching; - } - break; - - // --waitfor-interval=USEC - case 'i': - if (optarg && optarg[0]) - { - char *end = NULL; - waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid waitfor-interval option value '%s'.\n", optarg); - exit (6); - } - } - break; - - // --waitfor-duration=SEC - case 'd': - if (optarg && optarg[0]) - { - char *end = NULL; - waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0)); - if (end == NULL || *end != '\0') - { - RNBLogSTDERR ("error: invalid waitfor-duration option value '%s'.\n", optarg); - exit (7); - } - } - break; - - case 'K': - g_detach_on_error = false; - break; - case 'W': - if (optarg && optarg[0]) - working_dir.assign(optarg); - break; - - case 'x': - if (optarg && optarg[0]) - { - if (strcasecmp(optarg, "auto") == 0) - g_launch_flavor = eLaunchFlavorDefault; - else if (strcasestr(optarg, "posix") == optarg) - g_launch_flavor = eLaunchFlavorPosixSpawn; - else if (strcasestr(optarg, "fork") == optarg) - g_launch_flavor = eLaunchFlavorForkExec; + while ((ch = getopt_long_only(argc, argv, short_options, g_long_options, + &long_option_index)) != -1) { + DNBLogDebug("option: ch == %c (0x%2.2x) --%s%c%s\n", ch, (uint8_t)ch, + g_long_options[long_option_index].name, + g_long_options[long_option_index].has_arg ? '=' : ' ', + optarg ? optarg : ""); + switch (ch) { + case 0: // Any optional that auto set themselves will return 0 + break; + + case 'A': + if (optarg && optarg[0]) + arch_name.assign(optarg); + break; + + case 'a': + if (optarg && optarg[0]) { + if (isdigit(optarg[0])) { + char *end = NULL; + attach_pid = static_cast<int>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid pid option '%s'\n", optarg); + exit(4); + } + } else { + attach_pid_name = optarg; + } + start_mode = eRNBRunLoopModeInferiorAttaching; + } + break; + + // --waitfor=NAME + case 'w': + if (optarg && optarg[0]) { + waitfor_pid_name = optarg; + start_mode = eRNBRunLoopModeInferiorAttaching; + } + break; + + // --waitfor-interval=USEC + case 'i': + if (optarg && optarg[0]) { + char *end = NULL; + waitfor_interval = static_cast<useconds_t>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid waitfor-interval option value '%s'.\n", + optarg); + exit(6); + } + } + break; + + // --waitfor-duration=SEC + case 'd': + if (optarg && optarg[0]) { + char *end = NULL; + waitfor_duration = static_cast<useconds_t>(strtoul(optarg, &end, 0)); + if (end == NULL || *end != '\0') { + RNBLogSTDERR("error: invalid waitfor-duration option value '%s'.\n", + optarg); + exit(7); + } + } + break; + + case 'K': + g_detach_on_error = false; + break; + case 'W': + if (optarg && optarg[0]) + working_dir.assign(optarg); + break; + + case 'x': + if (optarg && optarg[0]) { + if (strcasecmp(optarg, "auto") == 0) + g_launch_flavor = eLaunchFlavorDefault; + else if (strcasestr(optarg, "posix") == optarg) + g_launch_flavor = eLaunchFlavorPosixSpawn; + else if (strcasestr(optarg, "fork") == optarg) + g_launch_flavor = eLaunchFlavorForkExec; #ifdef WITH_SPRINGBOARD - else if (strcasestr(optarg, "spring") == optarg) - g_launch_flavor = eLaunchFlavorSpringBoard; + else if (strcasestr(optarg, "spring") == optarg) + g_launch_flavor = eLaunchFlavorSpringBoard; #endif #ifdef WITH_BKS - else if (strcasestr(optarg, "backboard") == optarg) - g_launch_flavor = eLaunchFlavorBKS; + else if (strcasestr(optarg, "backboard") == optarg) + g_launch_flavor = eLaunchFlavorBKS; #endif #ifdef WITH_FBS - else if (strcasestr(optarg, "frontboard") == optarg) - g_launch_flavor = eLaunchFlavorFBS; + else if (strcasestr(optarg, "frontboard") == optarg) + g_launch_flavor = eLaunchFlavorFBS; #endif - else - { - RNBLogSTDERR ("error: invalid TYPE for the --launch=TYPE (-x TYPE) option: '%s'\n", optarg); - RNBLogSTDERR ("Valid values TYPE are:\n"); - RNBLogSTDERR (" auto Auto-detect the best launch method to use.\n"); - RNBLogSTDERR (" posix Launch the executable using posix_spawn.\n"); - RNBLogSTDERR (" fork Launch the executable using fork and exec.\n"); + else { + RNBLogSTDERR("error: invalid TYPE for the --launch=TYPE (-x TYPE) " + "option: '%s'\n", + optarg); + RNBLogSTDERR("Valid values TYPE are:\n"); + RNBLogSTDERR( + " auto Auto-detect the best launch method to use.\n"); + RNBLogSTDERR( + " posix Launch the executable using posix_spawn.\n"); + RNBLogSTDERR( + " fork Launch the executable using fork and exec.\n"); #ifdef WITH_SPRINGBOARD - RNBLogSTDERR (" spring Launch the executable through Springboard.\n"); + RNBLogSTDERR( + " spring Launch the executable through Springboard.\n"); #endif #ifdef WITH_BKS - RNBLogSTDERR (" backboard Launch the executable through BackBoard Services.\n"); + RNBLogSTDERR(" backboard Launch the executable through BackBoard " + "Services.\n"); #endif #ifdef WITH_FBS - RNBLogSTDERR (" frontboard Launch the executable through FrontBoard Services.\n"); + RNBLogSTDERR(" frontboard Launch the executable through FrontBoard " + "Services.\n"); #endif - exit (5); - } - } - break; - - case 'l': // Set Log File - if (optarg && optarg[0]) - { - if (strcasecmp(optarg, "stdout") == 0) - log_file = stdout; - else if (strcasecmp(optarg, "stderr") == 0) - log_file = stderr; - else - { - log_file = fopen(optarg, "w"); - if (log_file != NULL) - setlinebuf(log_file); - } - - if (log_file == NULL) - { - const char *errno_str = strerror(errno); - RNBLogSTDERR ("Failed to open log file '%s' for writing: errno = %i (%s)", optarg, errno, errno_str ? errno_str : "unknown error"); - } - } - break; - - case 'f': // Log Flags - if (optarg && optarg[0]) - log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0)); - break; - - case 'g': - debug = 1; - DNBLogSetDebug(debug); - break; - - case 't': - g_applist_opt = 1; - break; - - case 'k': - g_lockdown_opt = 1; - break; - - case 'r': - // Do nothing, native regs is the default these days - break; - - case 'R': - reverse_connect = true; - break; - case 'v': - DNBLogSetVerbose(1); - break; - - case 's': - ctx.GetSTDIN().assign(optarg); - ctx.GetSTDOUT().assign(optarg); - ctx.GetSTDERR().assign(optarg); - break; - - case 'I': - ctx.GetSTDIN().assign(optarg); - break; - - case 'O': - ctx.GetSTDOUT().assign(optarg); - break; - - case 'E': - ctx.GetSTDERR().assign(optarg); - break; - - case 'n': - no_stdio = true; - break; - - case 'S': - // Put debugserver into a new session. Terminals group processes - // into sessions and when a special terminal key sequences - // (like control+c) are typed they can cause signals to go out to - // all processes in a session. Using this --setsid (-S) option - // will cause debugserver to run in its own sessions and be free - // from such issues. - // - // This is useful when debugserver is spawned from a command - // line application that uses debugserver to do the debugging, - // yet that application doesn't want debugserver receiving the - // signals sent to the session (i.e. dying when anyone hits ^C). - setsid(); - break; - case 'D': - g_disable_aslr = 1; - break; - - case 'p': - start_mode = eRNBRunLoopModePlatformMode; - break; - - case 'u': - unix_socket_name.assign (optarg); - break; - - case 'P': - named_pipe_path.assign (optarg); - break; - - case 'e': - // Pass a single specified environment variable down to the process that gets launched - remote->Context().PushEnvironment(optarg); - break; - - case 'F': - // Pass the current environment down to the process that gets launched - { - char **host_env = *_NSGetEnviron(); - char *env_entry; - size_t i; - for (i=0; (env_entry = host_env[i]) != NULL; ++i) - remote->Context().PushEnvironment(env_entry); - } - break; - - case 'FDSC': - // File descriptor passed to this process during fork/exec and is already - // open and ready for communication. - communication_fd = atoi(optarg); - break; + exit(5); } + } + break; + + case 'l': // Set Log File + if (optarg && optarg[0]) { + if (strcasecmp(optarg, "stdout") == 0) + log_file = stdout; + else if (strcasecmp(optarg, "stderr") == 0) + log_file = stderr; + else { + log_file = fopen(optarg, "w"); + if (log_file != NULL) + setlinebuf(log_file); + } + + if (log_file == NULL) { + const char *errno_str = strerror(errno); + RNBLogSTDERR( + "Failed to open log file '%s' for writing: errno = %i (%s)", + optarg, errno, errno_str ? errno_str : "unknown error"); + } + } + break; + + case 'f': // Log Flags + if (optarg && optarg[0]) + log_flags = static_cast<uint32_t>(strtoul(optarg, NULL, 0)); + break; + + case 'g': + debug = 1; + DNBLogSetDebug(debug); + break; + + case 't': + g_applist_opt = 1; + break; + + case 'k': + g_lockdown_opt = 1; + break; + + case 'r': + // Do nothing, native regs is the default these days + break; + + case 'R': + reverse_connect = true; + break; + case 'v': + DNBLogSetVerbose(1); + break; + + case 's': + ctx.GetSTDIN().assign(optarg); + ctx.GetSTDOUT().assign(optarg); + ctx.GetSTDERR().assign(optarg); + break; + + case 'I': + ctx.GetSTDIN().assign(optarg); + break; + + case 'O': + ctx.GetSTDOUT().assign(optarg); + break; + + case 'E': + ctx.GetSTDERR().assign(optarg); + break; + + case 'n': + no_stdio = true; + break; + + case 'S': + // Put debugserver into a new session. Terminals group processes + // into sessions and when a special terminal key sequences + // (like control+c) are typed they can cause signals to go out to + // all processes in a session. Using this --setsid (-S) option + // will cause debugserver to run in its own sessions and be free + // from such issues. + // + // This is useful when debugserver is spawned from a command + // line application that uses debugserver to do the debugging, + // yet that application doesn't want debugserver receiving the + // signals sent to the session (i.e. dying when anyone hits ^C). + setsid(); + break; + case 'D': + g_disable_aslr = 1; + break; + + case 'p': + start_mode = eRNBRunLoopModePlatformMode; + break; + + case 'u': + unix_socket_name.assign(optarg); + break; + + case 'P': + named_pipe_path.assign(optarg); + break; + + case 'e': + // Pass a single specified environment variable down to the process that + // gets launched + remote->Context().PushEnvironment(optarg); + break; + + case 'F': + // Pass the current environment down to the process that gets launched + { + char **host_env = *_NSGetEnviron(); + char *env_entry; + size_t i; + for (i = 0; (env_entry = host_env[i]) != NULL; ++i) + remote->Context().PushEnvironment(env_entry); + } + break; + + case 'FDSC': + // File descriptor passed to this process during fork/exec and is already + // open and ready for communication. + communication_fd = atoi(optarg); + break; } + } - if (arch_name.empty()) - { -#if defined (__arm__) - arch_name.assign ("arm"); + if (arch_name.empty()) { +#if defined(__arm__) + arch_name.assign("arm"); #endif + } else { + DNBSetArchitecture(arch_name.c_str()); + } + + // if (arch_name.empty()) + // { + // fprintf(stderr, "error: no architecture was specified\n"); + // exit (8); + // } + // Skip any options we consumed with getopt_long_only + argc -= optind; + argv += optind; + + if (!working_dir.empty()) { + if (remote->Context().SetWorkingDirectory(working_dir.c_str()) == false) { + RNBLogSTDERR("error: working directory doesn't exist '%s'.\n", + working_dir.c_str()); + exit(8); } - else - { - DNBSetArchitecture (arch_name.c_str()); - } + } -// if (arch_name.empty()) -// { -// fprintf(stderr, "error: no architecture was specified\n"); -// exit (8); -// } - // Skip any options we consumed with getopt_long_only - argc -= optind; - argv += optind; - - - if (!working_dir.empty()) - { - if (remote->Context().SetWorkingDirectory (working_dir.c_str()) == false) - { - RNBLogSTDERR ("error: working directory doesn't exist '%s'.\n", working_dir.c_str()); - exit (8); - } - } + remote->Context().SetDetachOnError(g_detach_on_error); - remote->Context().SetDetachOnError(g_detach_on_error); + remote->Initialize(); - remote->Initialize(); + // It is ok for us to set NULL as the logfile (this will disable any logging) - // It is ok for us to set NULL as the logfile (this will disable any logging) + if (log_file != NULL) { + DNBLogSetLogCallback(FileLogCallback, log_file); + // If our log file was set, yet we have no log flags, log everything! + if (log_flags == 0) + log_flags = LOG_ALL | LOG_RNB_ALL; - if (log_file != NULL) - { - DNBLogSetLogCallback(FileLogCallback, log_file); - // If our log file was set, yet we have no log flags, log everything! - if (log_flags == 0) - log_flags = LOG_ALL | LOG_RNB_ALL; + DNBLogSetLogMask(log_flags); + } else { + // Enable DNB logging - DNBLogSetLogMask (log_flags); + // if os_log() support is available, log through that. + auto log_callback = OsLogger::GetLogFunction(); + if (log_callback) { + DNBLogSetLogCallback(log_callback, nullptr); + DNBLog("debugserver will use os_log for internal logging."); + } else { + // Fall back to ASL support. + DNBLogSetLogCallback(ASLLogCallback, NULL); + DNBLog("debugserver will use ASL for internal logging."); } - else - { - // Enable DNB logging - - // if os_log() support is available, log through that. - auto log_callback = OsLogger::GetLogFunction(); - if (log_callback) - { - DNBLogSetLogCallback(log_callback, nullptr); - DNBLog("debugserver will use os_log for internal logging."); - } - else - { - // Fall back to ASL support. - DNBLogSetLogCallback(ASLLogCallback, NULL); - DNBLog("debugserver will use ASL for internal logging."); - } - DNBLogSetLogMask (log_flags); + DNBLogSetLogMask(log_flags); + } - } - - if (DNBLogEnabled()) - { - for (i=0; i<argc; i++) - DNBLogDebug("argv[%i] = %s", i, argv[i]); - } + if (DNBLogEnabled()) { + for (i = 0; i < argc; i++) + DNBLogDebug("argv[%i] = %s", i, argv[i]); + } - // as long as we're dropping remotenub in as a replacement for gdbserver, - // explicitly note that this is not gdbserver. - - RNBLogSTDOUT ("%s-%s %sfor %s.\n", - DEBUGSERVER_PROGRAM_NAME, - DEBUGSERVER_VERSION_STR, - compile_options.c_str(), - RNB_ARCH); - - std::string host; - int port = INT32_MAX; - char str[PATH_MAX]; - str[0] = '\0'; - - if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) - { - // Make sure we at least have port - if (argc < 1) - { - show_usage_and_exit (1); - } - // accept 'localhost:' prefix on port number + // as long as we're dropping remotenub in as a replacement for gdbserver, + // explicitly note that this is not gdbserver. - int items_scanned = ::sscanf (argv[0], "%[^:]:%i", str, &port); - if (items_scanned == 2) - { - host = str; - DNBLogDebug("host = '%s' port = %i", host.c_str(), port); - } - else - { - // No hostname means "localhost" - int items_scanned = ::sscanf (argv[0], "%i", &port); - if (items_scanned == 1) - { - host = "127.0.0.1"; - DNBLogDebug("host = '%s' port = %i", host.c_str(), port); - } - else if (argv[0][0] == '/') - { - port = INT32_MAX; - strncpy(str, argv[0], sizeof(str)); - } - else - { - show_usage_and_exit (2); - } - } + RNBLogSTDOUT("%s-%s %sfor %s.\n", DEBUGSERVER_PROGRAM_NAME, + DEBUGSERVER_VERSION_STR, compile_options.c_str(), RNB_ARCH); - // We just used the 'host:port' or the '/path/file' arg... - argc--; - argv++; + std::string host; + int port = INT32_MAX; + char str[PATH_MAX]; + str[0] = '\0'; + if (g_lockdown_opt == 0 && g_applist_opt == 0 && communication_fd == -1) { + // Make sure we at least have port + if (argc < 1) { + show_usage_and_exit(1); + } + // accept 'localhost:' prefix on port number + + int items_scanned = ::sscanf(argv[0], "%[^:]:%i", str, &port); + if (items_scanned == 2) { + host = str; + DNBLogDebug("host = '%s' port = %i", host.c_str(), port); + } else { + // No hostname means "localhost" + int items_scanned = ::sscanf(argv[0], "%i", &port); + if (items_scanned == 1) { + host = "127.0.0.1"; + DNBLogDebug("host = '%s' port = %i", host.c_str(), port); + } else if (argv[0][0] == '/') { + port = INT32_MAX; + strncpy(str, argv[0], sizeof(str)); + } else { + show_usage_and_exit(2); + } } - // If we know we're waiting to attach, we don't need any of this other info. - if (start_mode != eRNBRunLoopModeInferiorAttaching && - start_mode != eRNBRunLoopModePlatformMode) - { - if (argc == 0 || g_lockdown_opt) - { - if (g_lockdown_opt != 0) - { - // Work around for SIGPIPE crashes due to posix_spawn issue. - // We have to close STDOUT and STDERR, else the first time we - // try and do any, we get SIGPIPE and die as posix_spawn is - // doing bad things with our file descriptors at the moment. - int null = open("/dev/null", O_RDWR); - dup2(null, STDOUT_FILENO); - dup2(null, STDERR_FILENO); - } - else if (g_applist_opt != 0) - { - // List all applications we are able to see - std::string applist_plist; - int err = ListApplications(applist_plist, false, false); - if (err == 0) - { - fputs (applist_plist.c_str(), stdout); - } - else - { - RNBLogSTDERR ("error: ListApplications returned error %i\n", err); - } - // Exit with appropriate error if we were asked to list the applications - // with no other args were given (and we weren't trying to do this over - // lockdown) - return err; - } - - DNBLogDebug("Get args from remote protocol..."); - start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; - } - else - { - start_mode = eRNBRunLoopModeInferiorLaunching; - // Fill in the argv array in the context from the rest of our args. - // Skip the name of this executable and the port number - for (int i = 0; i < argc; i++) - { - DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); - ctx.PushArgument (argv[i]); - } + // We just used the 'host:port' or the '/path/file' arg... + argc--; + argv++; + } + + // If we know we're waiting to attach, we don't need any of this other info. + if (start_mode != eRNBRunLoopModeInferiorAttaching && + start_mode != eRNBRunLoopModePlatformMode) { + if (argc == 0 || g_lockdown_opt) { + if (g_lockdown_opt != 0) { + // Work around for SIGPIPE crashes due to posix_spawn issue. + // We have to close STDOUT and STDERR, else the first time we + // try and do any, we get SIGPIPE and die as posix_spawn is + // doing bad things with our file descriptors at the moment. + int null = open("/dev/null", O_RDWR); + dup2(null, STDOUT_FILENO); + dup2(null, STDERR_FILENO); + } else if (g_applist_opt != 0) { + // List all applications we are able to see + std::string applist_plist; + int err = ListApplications(applist_plist, false, false); + if (err == 0) { + fputs(applist_plist.c_str(), stdout); + } else { + RNBLogSTDERR("error: ListApplications returned error %i\n", err); } + // Exit with appropriate error if we were asked to list the applications + // with no other args were given (and we weren't trying to do this over + // lockdown) + return err; + } + + DNBLogDebug("Get args from remote protocol..."); + start_mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; + } else { + start_mode = eRNBRunLoopModeInferiorLaunching; + // Fill in the argv array in the context from the rest of our args. + // Skip the name of this executable and the port number + for (int i = 0; i < argc; i++) { + DNBLogDebug("inferior_argv[%i] = '%s'", i, argv[i]); + ctx.PushArgument(argv[i]); + } } + } - if (start_mode == eRNBRunLoopModeExit) - return -1; + if (start_mode == eRNBRunLoopModeExit) + return -1; - RNBRunLoopMode mode = start_mode; - char err_str[1024] = {'\0'}; + RNBRunLoopMode mode = start_mode; + char err_str[1024] = {'\0'}; - while (mode != eRNBRunLoopModeExit) - { - switch (mode) - { - case eRNBRunLoopModeGetStartModeFromRemoteProtocol: + while (mode != eRNBRunLoopModeExit) { + switch (mode) { + case eRNBRunLoopModeGetStartModeFromRemoteProtocol: #ifdef WITH_LOCKDOWN - if (g_lockdown_opt) - { - if (!remote->Comm().IsConnected()) - { - if (remote->Comm().ConnectToService () != rnb_success) - { - RNBLogSTDERR ("Failed to get connection from a remote gdb process.\n"); - mode = eRNBRunLoopModeExit; - } - else if (g_applist_opt != 0) - { - // List all applications we are able to see - std::string applist_plist; - if (ListApplications(applist_plist, false, false) == 0) - { - DNBLogDebug("Task list: %s", applist_plist.c_str()); - - remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); - // Issue a read that will never yield any data until the other side - // closes the socket so this process doesn't just exit and cause the - // socket to close prematurely on the other end and cause data loss. - std::string buf; - remote->Comm().Read(buf); - } - remote->Comm().Disconnect(false); - mode = eRNBRunLoopModeExit; - break; - } - else - { - // Start watching for remote packets - remote->StartReadRemoteDataThread(); - } - } - } - else + if (g_lockdown_opt) { + if (!remote->Comm().IsConnected()) { + if (remote->Comm().ConnectToService() != rnb_success) { + RNBLogSTDERR( + "Failed to get connection from a remote gdb process.\n"); + mode = eRNBRunLoopModeExit; + } else if (g_applist_opt != 0) { + // List all applications we are able to see + std::string applist_plist; + if (ListApplications(applist_plist, false, false) == 0) { + DNBLogDebug("Task list: %s", applist_plist.c_str()); + + remote->Comm().Write(applist_plist.c_str(), applist_plist.size()); + // Issue a read that will never yield any data until the other + // side + // closes the socket so this process doesn't just exit and cause + // the + // socket to close prematurely on the other end and cause data + // loss. + std::string buf; + remote->Comm().Read(buf); + } + remote->Comm().Disconnect(false); + mode = eRNBRunLoopModeExit; + break; + } else { + // Start watching for remote packets + remote->StartReadRemoteDataThread(); + } + } + } else #endif - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - { - RNBLogSTDOUT ("Got a connection, waiting for process information for launching or attaching.\n"); - - mode = RNBRunLoopGetStartModeFromRemote (remote); - } - break; - - case eRNBRunLoopModeInferiorAttaching: - if (!waitfor_pid_name.empty()) - { - // Set our end wait time if we are using a waitfor-duration - // option that may have been specified - struct timespec attach_timeout_abstime, *timeout_ptr = NULL; - if (waitfor_duration != 0) - { - DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); - timeout_ptr = &attach_timeout_abstime; - } - nub_launch_flavor_t launch_flavor = g_launch_flavor; - if (launch_flavor == eLaunchFlavorDefault) - { - // Our default launch method is posix spawn - launch_flavor = eLaunchFlavorPosixSpawn; + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) { + RNBLogSTDOUT("Got a connection, waiting for process information for " + "launching or attaching.\n"); + + mode = RNBRunLoopGetStartModeFromRemote(remote); + } + break; + + case eRNBRunLoopModeInferiorAttaching: + if (!waitfor_pid_name.empty()) { + // Set our end wait time if we are using a waitfor-duration + // option that may have been specified + struct timespec attach_timeout_abstime, *timeout_ptr = NULL; + if (waitfor_duration != 0) { + DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, + 0); + timeout_ptr = &attach_timeout_abstime; + } + nub_launch_flavor_t launch_flavor = g_launch_flavor; + if (launch_flavor == eLaunchFlavorDefault) { + // Our default launch method is posix spawn + launch_flavor = eLaunchFlavorPosixSpawn; #if defined WITH_FBS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorFBS; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorFBS; + } #elif defined WITH_BKS - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorBKS; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorBKS; + } #elif defined WITH_SPRINGBOARD - // Check if we have an app bundle, if so launch using SpringBoard. - if (waitfor_pid_name.find (".app") != std::string::npos) - { - launch_flavor = eLaunchFlavorSpringBoard; - } + // Check if we have an app bundle, if so launch using SpringBoard. + if (waitfor_pid_name.find(".app") != std::string::npos) { + launch_flavor = eLaunchFlavorSpringBoard; + } #endif - } - - ctx.SetLaunchFlavor(launch_flavor); - bool ignore_existing = false; - RNBLogSTDOUT ("Waiting to attach to process %s...\n", waitfor_pid_name.c_str()); - nub_process_t pid = DNBProcessAttachWait (waitfor_pid_name.c_str(), launch_flavor, ignore_existing, timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); - g_pid = pid; - - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); - mode = eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - mode = eRNBRunLoopModeInferiorExecuting; - } - } - else if (attach_pid != INVALID_NUB_PROCESS) - { - - RNBLogSTDOUT ("Attaching to process %i...\n", attach_pid); - nub_process_t attached_pid; - mode = RNBRunLoopLaunchAttaching (remote, attach_pid, attached_pid); - if (mode != eRNBRunLoopModeInferiorExecuting) - { - const char *error_str = remote->Context().LaunchStatus().AsString(); - RNBLogSTDERR ("error: failed to attach process %i: %s\n", attach_pid, error_str ? error_str : "unknown error."); - mode = eRNBRunLoopModeExit; - } - } - else if (!attach_pid_name.empty ()) - { - struct timespec attach_timeout_abstime, *timeout_ptr = NULL; - if (waitfor_duration != 0) - { - DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, 0); - timeout_ptr = &attach_timeout_abstime; - } - - RNBLogSTDOUT ("Attaching to process %s...\n", attach_pid_name.c_str()); - nub_process_t pid = DNBProcessAttachByName (attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); - g_pid = pid; - if (pid == INVALID_NUB_PROCESS) - { - ctx.LaunchStatus().SetError(-1, DNBError::Generic); - if (err_str[0]) - ctx.LaunchStatus().SetErrorString(err_str); - RNBLogSTDERR ("error: failed to attach to process named: \"%s\" %s\n", waitfor_pid_name.c_str(), err_str); - mode = eRNBRunLoopModeExit; - } - else - { - ctx.SetProcessID(pid); - mode = eRNBRunLoopModeInferiorExecuting; - } - - } - else - { - RNBLogSTDERR ("error: asked to attach with empty name and invalid PID.\n"); - mode = eRNBRunLoopModeExit; - } - - if (mode != eRNBRunLoopModeExit) - { - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - RNBLogSTDOUT ("Waiting for debugger instructions for process %d.\n", attach_pid); - } - break; - - case eRNBRunLoopModeInferiorLaunching: - { - mode = RNBRunLoopLaunchInferior (remote, - ctx.GetSTDINPath(), - ctx.GetSTDOUTPath(), - ctx.GetSTDERRPath(), - no_stdio); - - if (mode == eRNBRunLoopModeInferiorExecuting) - { - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - { - const char *proc_name = "<unknown>"; - if (ctx.ArgumentCount() > 0) - proc_name = ctx.ArgumentAtIndex(0); - RNBLogSTDOUT ("Got a connection, launched process %s (pid = %d).\n", proc_name, ctx.ProcessID()); - } - } - else - { - const char *error_str = remote->Context().LaunchStatus().AsString(); - RNBLogSTDERR ("error: failed to launch process %s: %s\n", argv_sub_zero, error_str ? error_str : "unknown error."); - } - } - break; - - case eRNBRunLoopModeInferiorExecuting: - mode = RNBRunLoopInferiorExecuting(remote); - break; - - case eRNBRunLoopModePlatformMode: - if (port != INT32_MAX) - { - if (!ConnectRemote (remote, host.c_str(), port, reverse_connect, named_pipe_path.c_str(), unix_socket_name.c_str())) - mode = eRNBRunLoopModeExit; - } - else if (str[0] == '/') - { - if (remote->Comm().OpenFile (str)) - mode = eRNBRunLoopModeExit; - } - else if (communication_fd >= 0) - { - // We were passed a file descriptor to use during fork/exec that is already open - // in our process, so lets just use it! - if (remote->Comm().useFD(communication_fd)) - mode = eRNBRunLoopModeExit; - else - remote->StartReadRemoteDataThread(); - } - - if (mode != eRNBRunLoopModeExit) - mode = RNBRunLoopPlatform (remote); - break; - - default: - mode = eRNBRunLoopModeExit; - case eRNBRunLoopModeExit: - break; } + + ctx.SetLaunchFlavor(launch_flavor); + bool ignore_existing = false; + RNBLogSTDOUT("Waiting to attach to process %s...\n", + waitfor_pid_name.c_str()); + nub_process_t pid = DNBProcessAttachWait( + waitfor_pid_name.c_str(), launch_flavor, ignore_existing, + timeout_ptr, waitfor_interval, err_str, sizeof(err_str)); + g_pid = pid; + + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", + waitfor_pid_name.c_str(), err_str); + mode = eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + mode = eRNBRunLoopModeInferiorExecuting; + } + } else if (attach_pid != INVALID_NUB_PROCESS) { + + RNBLogSTDOUT("Attaching to process %i...\n", attach_pid); + nub_process_t attached_pid; + mode = RNBRunLoopLaunchAttaching(remote, attach_pid, attached_pid); + if (mode != eRNBRunLoopModeInferiorExecuting) { + const char *error_str = remote->Context().LaunchStatus().AsString(); + RNBLogSTDERR("error: failed to attach process %i: %s\n", attach_pid, + error_str ? error_str : "unknown error."); + mode = eRNBRunLoopModeExit; + } + } else if (!attach_pid_name.empty()) { + struct timespec attach_timeout_abstime, *timeout_ptr = NULL; + if (waitfor_duration != 0) { + DNBTimer::OffsetTimeOfDay(&attach_timeout_abstime, waitfor_duration, + 0); + timeout_ptr = &attach_timeout_abstime; + } + + RNBLogSTDOUT("Attaching to process %s...\n", attach_pid_name.c_str()); + nub_process_t pid = DNBProcessAttachByName( + attach_pid_name.c_str(), timeout_ptr, err_str, sizeof(err_str)); + g_pid = pid; + if (pid == INVALID_NUB_PROCESS) { + ctx.LaunchStatus().SetError(-1, DNBError::Generic); + if (err_str[0]) + ctx.LaunchStatus().SetErrorString(err_str); + RNBLogSTDERR("error: failed to attach to process named: \"%s\" %s\n", + waitfor_pid_name.c_str(), err_str); + mode = eRNBRunLoopModeExit; + } else { + ctx.SetProcessID(pid); + mode = eRNBRunLoopModeInferiorExecuting; + } + + } else { + RNBLogSTDERR( + "error: asked to attach with empty name and invalid PID.\n"); + mode = eRNBRunLoopModeExit; + } + + if (mode != eRNBRunLoopModeExit) { + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) + RNBLogSTDOUT("Waiting for debugger instructions for process %d.\n", + attach_pid); + } + break; + + case eRNBRunLoopModeInferiorLaunching: { + mode = RNBRunLoopLaunchInferior(remote, ctx.GetSTDINPath(), + ctx.GetSTDOUTPath(), ctx.GetSTDERRPath(), + no_stdio); + + if (mode == eRNBRunLoopModeInferiorExecuting) { + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) { + const char *proc_name = "<unknown>"; + if (ctx.ArgumentCount() > 0) + proc_name = ctx.ArgumentAtIndex(0); + RNBLogSTDOUT("Got a connection, launched process %s (pid = %d).\n", + proc_name, ctx.ProcessID()); + } + } else { + const char *error_str = remote->Context().LaunchStatus().AsString(); + RNBLogSTDERR("error: failed to launch process %s: %s\n", argv_sub_zero, + error_str ? error_str : "unknown error."); + } + } break; + + case eRNBRunLoopModeInferiorExecuting: + mode = RNBRunLoopInferiorExecuting(remote); + break; + + case eRNBRunLoopModePlatformMode: + if (port != INT32_MAX) { + if (!ConnectRemote(remote, host.c_str(), port, reverse_connect, + named_pipe_path.c_str(), unix_socket_name.c_str())) + mode = eRNBRunLoopModeExit; + } else if (str[0] == '/') { + if (remote->Comm().OpenFile(str)) + mode = eRNBRunLoopModeExit; + } else if (communication_fd >= 0) { + // We were passed a file descriptor to use during fork/exec that is + // already open + // in our process, so lets just use it! + if (remote->Comm().useFD(communication_fd)) + mode = eRNBRunLoopModeExit; + else + remote->StartReadRemoteDataThread(); + } + + if (mode != eRNBRunLoopModeExit) + mode = RNBRunLoopPlatform(remote); + break; + + default: + mode = eRNBRunLoopModeExit; + case eRNBRunLoopModeExit: + break; } + } - remote->StopReadRemoteDataThread (); - remote->Context().SetProcessID(INVALID_NUB_PROCESS); - RNBLogSTDOUT ("Exiting.\n"); + remote->StopReadRemoteDataThread(); + remote->Context().SetProcessID(INVALID_NUB_PROCESS); + RNBLogSTDOUT("Exiting.\n"); - return 0; + return 0; } diff --git a/lldb/tools/debugserver/source/libdebugserver.cpp b/lldb/tools/debugserver/source/libdebugserver.cpp index 63d76eb26ae..0d27cfd89a3 100644 --- a/lldb/tools/debugserver/source/libdebugserver.cpp +++ b/lldb/tools/debugserver/source/libdebugserver.cpp @@ -7,36 +7,34 @@ // //===----------------------------------------------------------------------===// -#include <sys/socket.h> -#include <sys/types.h> #include <errno.h> #include <getopt.h> #include <netinet/in.h> #include <sys/select.h> +#include <sys/socket.h> #include <sys/sysctl.h> +#include <sys/types.h> #include "DNB.h" #include "DNBLog.h" #include "DNBTimer.h" #include "PseudoTerminal.h" #include "RNBContext.h" +#include "RNBRemote.h" #include "RNBServices.h" #include "RNBSocket.h" -#include "RNBRemote.h" #include "SysSignal.h" //---------------------------------------------------------------------- // Run loop modes which determine which run loop function will be called //---------------------------------------------------------------------- -typedef enum -{ - eRNBRunLoopModeInvalid = 0, - eRNBRunLoopModeGetStartModeFromRemoteProtocol, - eRNBRunLoopModeInferiorExecuting, - eRNBRunLoopModeExit +typedef enum { + eRNBRunLoopModeInvalid = 0, + eRNBRunLoopModeGetStartModeFromRemoteProtocol, + eRNBRunLoopModeInferiorExecuting, + eRNBRunLoopModeExit } RNBRunLoopMode; - //---------------------------------------------------------------------- // Global Variables //---------------------------------------------------------------------- @@ -44,9 +42,22 @@ RNBRemoteSP g_remoteSP; int g_disable_aslr = 0; int g_isatty = 0; -#define RNBLogSTDOUT(fmt, ...) do { if (g_isatty) { fprintf(stdout, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) -#define RNBLogSTDERR(fmt, ...) do { if (g_isatty) { fprintf(stderr, fmt, ## __VA_ARGS__); } else { _DNBLog(0, fmt, ## __VA_ARGS__); } } while (0) - +#define RNBLogSTDOUT(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stdout, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#define RNBLogSTDERR(fmt, ...) \ + do { \ + if (g_isatty) { \ + fprintf(stderr, fmt, ##__VA_ARGS__); \ + } else { \ + _DNBLog(0, fmt, ##__VA_ARGS__); \ + } \ + } while (0) //---------------------------------------------------------------------- // Get our program path and arguments from the remote connection. @@ -54,74 +65,65 @@ int g_isatty = 0; // arguments, wait for the new process to finish launching and hit its // entry point, and then return the run loop mode that should come next. //---------------------------------------------------------------------- -RNBRunLoopMode -RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP) -{ - std::string packet; - - if (remoteSP.get() != NULL) - { - RNBRemote* remote = remoteSP.get(); - RNBContext& ctx = remote->Context(); - uint32_t event_mask = RNBContext::event_read_packet_available; - - // Spin waiting to get the A packet. - while (1) - { - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_MAX, "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", __FUNCTION__, event_mask, set_events); - - if (set_events & RNBContext::event_read_packet_available) - { - rnb_err_t err = rnb_err; - RNBRemote::PacketEnum type; - - err = remote->HandleReceivedPacket (&type); - - // check if we tried to attach to a process - if (type == RNBRemote::vattach || type == RNBRemote::vattachwait) - { - if (err == rnb_success) - return eRNBRunLoopModeInferiorExecuting; - else - { - RNBLogSTDERR ("error: attach failed."); - return eRNBRunLoopModeExit; - } - } - - - if (err == rnb_success) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Got success...",__FUNCTION__); - continue; - } - else if (err == rnb_not_connected) - { - RNBLogSTDERR ("error: connection lost."); - return eRNBRunLoopModeExit; - } - else - { - // a catch all for any other gdb remote packets that failed - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Error getting packet.",__FUNCTION__); - continue; - } - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - } - else - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s Connection closed before getting \"A\" packet.", __FUNCTION__); - return eRNBRunLoopModeExit; - } +RNBRunLoopMode RNBRunLoopGetStartModeFromRemote(RNBRemoteSP &remoteSP) { + std::string packet; + + if (remoteSP.get() != NULL) { + RNBRemote *remote = remoteSP.get(); + RNBContext &ctx = remote->Context(); + uint32_t event_mask = RNBContext::event_read_packet_available; + + // Spin waiting to get the A packet. + while (1) { + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_MAX, + "%s ctx.Events().WaitForSetEvents( 0x%08x ) => 0x%08x", + __FUNCTION__, event_mask, set_events); + + if (set_events & RNBContext::event_read_packet_available) { + rnb_err_t err = rnb_err; + RNBRemote::PacketEnum type; + + err = remote->HandleReceivedPacket(&type); + + // check if we tried to attach to a process + if (type == RNBRemote::vattach || type == RNBRemote::vattachwait) { + if (err == rnb_success) + return eRNBRunLoopModeInferiorExecuting; + else { + RNBLogSTDERR("error: attach failed."); + return eRNBRunLoopModeExit; + } + } + + if (err == rnb_success) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Got success...", __FUNCTION__); + continue; + } else if (err == rnb_not_connected) { + RNBLogSTDERR("error: connection lost."); + return eRNBRunLoopModeExit; + } else { + // a catch all for any other gdb remote packets that failed + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s Error getting packet.", + __FUNCTION__); + continue; } + + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + } else { + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s Connection closed before getting \"A\" packet.", + __FUNCTION__); + return eRNBRunLoopModeExit; + } } - return eRNBRunLoopModeExit; + } + return eRNBRunLoopModeExit; } - //---------------------------------------------------------------------- // Watch for signals: // SIGINT: so we can halt our inferior. (disabled for now) @@ -129,269 +131,253 @@ RNBRunLoopGetStartModeFromRemote (RNBRemoteSP &remoteSP) //---------------------------------------------------------------------- nub_process_t g_pid; int g_sigpipe_received = 0; -void -signal_handler(int signo) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, SysSignal::Name(signo)); - - switch (signo) - { - // case SIGINT: - // DNBProcessKill (g_pid, signo); - // break; - - case SIGPIPE: - g_sigpipe_received = 1; - break; - } +void signal_handler(int signo) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (%s)", __FUNCTION__, + SysSignal::Name(signo)); + + switch (signo) { + // case SIGINT: + // DNBProcessKill (g_pid, signo); + // break; + + case SIGPIPE: + g_sigpipe_received = 1; + break; + } } // Return the new run loop mode based off of the current process state -RNBRunLoopMode -HandleProcessStateChange (RNBRemoteSP &remote, bool initialize) -{ - RNBContext& ctx = remote->Context(); - nub_process_t pid = ctx.ProcessID(); - - if (pid == INVALID_NUB_PROCESS) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", __FUNCTION__); - return eRNBRunLoopModeExit; - } - nub_state_t pid_state = DNBProcessGetState (pid); - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state)); - - switch (pid_state) - { - case eStateInvalid: - case eStateUnloaded: - // Something bad happened - return eRNBRunLoopModeExit; - break; - - case eStateAttaching: - case eStateLaunching: - return eRNBRunLoopModeInferiorExecuting; - - case eStateSuspended: - case eStateCrashed: - case eStateStopped: - if (initialize == false) - { - // Compare the last stop count to our current notion of a stop count - // to make sure we don't notify more than once for a given stop. - nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); - bool pid_stop_count_changed = ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); - if (pid_stop_count_changed) - { - remote->FlushSTDIO(); - - if (ctx.GetProcessStopCount() == 1) - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? no, first stop...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); - } - else - { - - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? YES!!!", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); - remote->NotifyThatProcessStopped (); - } - } - else - { - DNBLogThreadedIf (LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s pid_stop_count %zu (old %zu)) Notify??? skipping...", __FUNCTION__, (int)initialize, DNBStateAsString (pid_state), ctx.GetProcessStopCount(), prev_pid_stop_count); - } - } - return eRNBRunLoopModeInferiorExecuting; - - case eStateStepping: - case eStateRunning: - return eRNBRunLoopModeInferiorExecuting; - - case eStateExited: - remote->HandlePacket_last_signal(NULL); - return eRNBRunLoopModeExit; - case eStateDetached: - return eRNBRunLoopModeExit; - +RNBRunLoopMode HandleProcessStateChange(RNBRemoteSP &remote, bool initialize) { + RNBContext &ctx = remote->Context(); + nub_process_t pid = ctx.ProcessID(); + + if (pid == INVALID_NUB_PROCESS) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s error: pid invalid, exiting...", + __FUNCTION__); + return eRNBRunLoopModeExit; + } + nub_state_t pid_state = DNBProcessGetState(pid); + + DNBLogThreadedIf(LOG_RNB_MINIMAL, + "%s (&remote, initialize=%i) pid_state = %s", __FUNCTION__, + (int)initialize, DNBStateAsString(pid_state)); + + switch (pid_state) { + case eStateInvalid: + case eStateUnloaded: + // Something bad happened + return eRNBRunLoopModeExit; + break; + + case eStateAttaching: + case eStateLaunching: + return eRNBRunLoopModeInferiorExecuting; + + case eStateSuspended: + case eStateCrashed: + case eStateStopped: + if (initialize == false) { + // Compare the last stop count to our current notion of a stop count + // to make sure we don't notify more than once for a given stop. + nub_size_t prev_pid_stop_count = ctx.GetProcessStopCount(); + bool pid_stop_count_changed = + ctx.SetProcessStopCount(DNBProcessGetStopCount(pid)); + if (pid_stop_count_changed) { + remote->FlushSTDIO(); + + if (ctx.GetProcessStopCount() == 1) { + DNBLogThreadedIf( + LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " + "pid_stop_count %zu (old %zu)) Notify??? no, " + "first stop...", + __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), + ctx.GetProcessStopCount(), prev_pid_stop_count); + } else { + + DNBLogThreadedIf( + LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) pid_state = %s " + "pid_stop_count %zu (old %zu)) Notify??? YES!!!", + __FUNCTION__, (int)initialize, DNBStateAsString(pid_state), + ctx.GetProcessStopCount(), prev_pid_stop_count); + remote->NotifyThatProcessStopped(); + } + } else { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "%s (&remote, initialize=%i) " + "pid_state = %s pid_stop_count %zu " + "(old %zu)) Notify??? skipping...", + __FUNCTION__, (int)initialize, + DNBStateAsString(pid_state), ctx.GetProcessStopCount(), + prev_pid_stop_count); + } } - - // Catch all... - return eRNBRunLoopModeExit; + return eRNBRunLoopModeInferiorExecuting; + + case eStateStepping: + case eStateRunning: + return eRNBRunLoopModeInferiorExecuting; + + case eStateExited: + remote->HandlePacket_last_signal(NULL); + return eRNBRunLoopModeExit; + case eStateDetached: + return eRNBRunLoopModeExit; + } + + // Catch all... + return eRNBRunLoopModeExit; } // This function handles the case where our inferior program is stopped and // we are waiting for gdb remote protocol packets. When a packet occurs that // makes the inferior run, we need to leave this function with a new state // as the return code. -RNBRunLoopMode -RNBRunLoopInferiorExecuting (RNBRemoteSP &remote) -{ - DNBLogThreadedIf (LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); - RNBContext& ctx = remote->Context(); - - // Init our mode and set 'is_running' based on the current process state - RNBRunLoopMode mode = HandleProcessStateChange (remote, true); - - while (ctx.ProcessID() != INVALID_NUB_PROCESS) - { - - std::string set_events_str; - uint32_t event_mask = ctx.NormalEventBits(); - - if (!ctx.ProcessStateRunning()) - { - // Clear the stdio bits if we are not running so we don't send any async packets - event_mask &= ~RNBContext::event_proc_stdio_available; +RNBRunLoopMode RNBRunLoopInferiorExecuting(RNBRemoteSP &remote) { + DNBLogThreadedIf(LOG_RNB_MINIMAL, "#### %s", __FUNCTION__); + RNBContext &ctx = remote->Context(); + + // Init our mode and set 'is_running' based on the current process state + RNBRunLoopMode mode = HandleProcessStateChange(remote, true); + + while (ctx.ProcessID() != INVALID_NUB_PROCESS) { + + std::string set_events_str; + uint32_t event_mask = ctx.NormalEventBits(); + + if (!ctx.ProcessStateRunning()) { + // Clear the stdio bits if we are not running so we don't send any async + // packets + event_mask &= ~RNBContext::event_proc_stdio_available; + } + + // We want to make sure we consume all process state changes and have + // whomever is notifying us to wait for us to reset the event bit before + // continuing. + // ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); + + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) ...", + __FUNCTION__, event_mask); + nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); + DNBLogThreadedIf(LOG_RNB_EVENTS, + "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)", + __FUNCTION__, event_mask, set_events, + ctx.EventsAsString(set_events, set_events_str)); + + if (set_events) { + if ((set_events & RNBContext::event_proc_thread_exiting) || + (set_events & RNBContext::event_proc_stdio_available)) { + remote->FlushSTDIO(); + } + + if (set_events & RNBContext::event_read_packet_available) { + // handleReceivedPacket will take care of resetting the + // event_read_packet_available events when there are no more... + set_events ^= RNBContext::event_read_packet_available; + + if (ctx.ProcessStateRunning()) { + if (remote->HandleAsyncPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } + } else { + if (remote->HandleReceivedPacket() == rnb_not_connected) { + // TODO: connect again? Exit? + } } - - // We want to make sure we consume all process state changes and have - // whomever is notifying us to wait for us to reset the event bit before - // continuing. - //ctx.Events().SetResetAckMask (RNBContext::event_proc_state_changed); - - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) ...",__FUNCTION__, event_mask); - nub_event_t set_events = ctx.Events().WaitForSetEvents(event_mask); - DNBLogThreadedIf (LOG_RNB_EVENTS, "%s ctx.Events().WaitForSetEvents(0x%08x) => 0x%08x (%s)",__FUNCTION__, event_mask, set_events, ctx.EventsAsString(set_events, set_events_str)); - - if (set_events) - { - if ((set_events & RNBContext::event_proc_thread_exiting) || - (set_events & RNBContext::event_proc_stdio_available)) - { - remote->FlushSTDIO(); - } - - if (set_events & RNBContext::event_read_packet_available) - { - // handleReceivedPacket will take care of resetting the - // event_read_packet_available events when there are no more... - set_events ^= RNBContext::event_read_packet_available; - - if (ctx.ProcessStateRunning()) - { - if (remote->HandleAsyncPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - else - { - if (remote->HandleReceivedPacket() == rnb_not_connected) - { - // TODO: connect again? Exit? - } - } - } - - if (set_events & RNBContext::event_proc_state_changed) - { - mode = HandleProcessStateChange (remote, false); - ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); - set_events ^= RNBContext::event_proc_state_changed; - } - - if (set_events & RNBContext::event_proc_thread_exiting) - { - mode = eRNBRunLoopModeExit; - } - - if (set_events & RNBContext::event_read_thread_exiting) - { - // Out remote packet receiving thread exited, exit for now. - if (ctx.HasValidProcessID()) - { - // TODO: We should add code that will leave the current process - // in its current state and listen for another connection... - if (ctx.ProcessStateRunning()) - { - DNBProcessKill (ctx.ProcessID()); - } - } - mode = eRNBRunLoopModeExit; - } + } + + if (set_events & RNBContext::event_proc_state_changed) { + mode = HandleProcessStateChange(remote, false); + ctx.Events().ResetEvents(RNBContext::event_proc_state_changed); + set_events ^= RNBContext::event_proc_state_changed; + } + + if (set_events & RNBContext::event_proc_thread_exiting) { + mode = eRNBRunLoopModeExit; + } + + if (set_events & RNBContext::event_read_thread_exiting) { + // Out remote packet receiving thread exited, exit for now. + if (ctx.HasValidProcessID()) { + // TODO: We should add code that will leave the current process + // in its current state and listen for another connection... + if (ctx.ProcessStateRunning()) { + DNBProcessKill(ctx.ProcessID()); + } } - - // Reset all event bits that weren't reset for now... - if (set_events != 0) - ctx.Events().ResetEvents(set_events); - - if (mode != eRNBRunLoopModeInferiorExecuting) - break; + mode = eRNBRunLoopModeExit; + } } - - return mode; + + // Reset all event bits that weren't reset for now... + if (set_events != 0) + ctx.Events().ResetEvents(set_events); + + if (mode != eRNBRunLoopModeInferiorExecuting) + break; + } + + return mode; } -void -ASLLogCallback(void *baton, uint32_t flags, const char *format, va_list args) -{ +void ASLLogCallback(void *baton, uint32_t flags, const char *format, + va_list args) { #if 0 vprintf(format, args); #endif } -extern "C" int -debug_server_main(int fd) -{ +extern "C" int debug_server_main(int fd) { #if 1 - g_isatty = 0; + g_isatty = 0; #else - g_isatty = ::isatty (STDIN_FILENO); + g_isatty = ::isatty(STDIN_FILENO); - DNBLogSetDebug(1); - DNBLogSetVerbose(1); - DNBLogSetLogMask(-1); - DNBLogSetLogCallback(ASLLogCallback, NULL); + DNBLogSetDebug(1); + DNBLogSetVerbose(1); + DNBLogSetLogMask(-1); + DNBLogSetLogCallback(ASLLogCallback, NULL); #endif - - signal (SIGPIPE, signal_handler); - - g_remoteSP.reset (new RNBRemote); - - RNBRemote *remote = g_remoteSP.get(); - if (remote == NULL) - { - RNBLogSTDERR ("error: failed to create a remote connection class\n"); - return -1; - } - - - RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; - - while (mode != eRNBRunLoopModeExit) - { - switch (mode) - { - case eRNBRunLoopModeGetStartModeFromRemoteProtocol: - if (g_remoteSP->Comm().useFD(fd) == rnb_success) { - RNBLogSTDOUT("Starting remote data thread.\n"); - g_remoteSP->StartReadRemoteDataThread(); - - RNBLogSTDOUT("Waiting for start mode from remote.\n"); - mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP); - } - else - { - mode = eRNBRunLoopModeExit; - } - break; - - case eRNBRunLoopModeInferiorExecuting: - mode = RNBRunLoopInferiorExecuting(g_remoteSP); - break; - - default: - mode = eRNBRunLoopModeExit; - break; - - case eRNBRunLoopModeExit: - break; - } + + signal(SIGPIPE, signal_handler); + + g_remoteSP.reset(new RNBRemote); + + RNBRemote *remote = g_remoteSP.get(); + if (remote == NULL) { + RNBLogSTDERR("error: failed to create a remote connection class\n"); + return -1; + } + + RNBRunLoopMode mode = eRNBRunLoopModeGetStartModeFromRemoteProtocol; + + while (mode != eRNBRunLoopModeExit) { + switch (mode) { + case eRNBRunLoopModeGetStartModeFromRemoteProtocol: + if (g_remoteSP->Comm().useFD(fd) == rnb_success) { + RNBLogSTDOUT("Starting remote data thread.\n"); + g_remoteSP->StartReadRemoteDataThread(); + + RNBLogSTDOUT("Waiting for start mode from remote.\n"); + mode = RNBRunLoopGetStartModeFromRemote(g_remoteSP); + } else { + mode = eRNBRunLoopModeExit; + } + break; + + case eRNBRunLoopModeInferiorExecuting: + mode = RNBRunLoopInferiorExecuting(g_remoteSP); + break; + + default: + mode = eRNBRunLoopModeExit; + break; + + case eRNBRunLoopModeExit: + break; } - - g_remoteSP->StopReadRemoteDataThread (); - g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS); - - return 0; + } + + g_remoteSP->StopReadRemoteDataThread(); + g_remoteSP->Context().SetProcessID(INVALID_NUB_PROCESS); + + return 0; } |