func registers(thread *Thread) (Registers, error) { var state C.x86_thread_state64_t var identity C.thread_identifier_info_data_t kret := C.get_registers(C.mach_port_name_t(thread.os.thread_act), &state) if kret != C.KERN_SUCCESS { return nil, fmt.Errorf("could not get registers") } kret = C.get_identity(C.mach_port_name_t(thread.os.thread_act), &identity) if kret != C.KERN_SUCCESS { return nil, fmt.Errorf("could not get thread identity informations") } /* thread_identifier_info::thread_handle contains the base of the thread-specific data area, which on x86 and x86_64 is the thread’s base address of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c thread_info_internal() gets the value from machine_thread::cthread_self, which is the same value used to set the %gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c act_machine_switch_pcb(). -- comment copied from chromium's crashpad https://chromium.googlesource.com/crashpad/crashpad/+/master/snapshot/mac/process_reader.cc */ regs := &Regs{ rax: uint64(state.__rax), rbx: uint64(state.__rbx), rcx: uint64(state.__rcx), rdx: uint64(state.__rdx), rdi: uint64(state.__rdi), rsi: uint64(state.__rsi), rbp: uint64(state.__rbp), rsp: uint64(state.__rsp), r8: uint64(state.__r8), r9: uint64(state.__r9), r10: uint64(state.__r10), r11: uint64(state.__r11), r12: uint64(state.__r12), r13: uint64(state.__r13), r14: uint64(state.__r14), r15: uint64(state.__r15), rip: uint64(state.__rip), rflags: uint64(state.__rflags), cs: uint64(state.__cs), fs: uint64(state.__fs), gs: uint64(state.__gs), gs_base: uint64(identity.thread_handle), } return regs, nil }
func (thread *Thread) restoreRegisters() error { kret := C.set_registers(C.mach_port_name_t(thread.os.thread_act), &thread.os.registers) if kret != C.KERN_SUCCESS { return fmt.Errorf("could not save register contents") } return nil }
func registers(thread *Thread) (Registers, error) { var state C.x86_thread_state64_t kret := C.get_registers(C.mach_port_name_t(thread.os.thread_act), &state) if kret != C.KERN_SUCCESS { return nil, fmt.Errorf("could not get registers") } regs := &Regs{ rax: uint64(state.__rax), rbx: uint64(state.__rbx), rcx: uint64(state.__rcx), rdx: uint64(state.__rdx), rdi: uint64(state.__rdi), rsi: uint64(state.__rsi), rbp: uint64(state.__rbp), rsp: uint64(state.__rsp), r8: uint64(state.__r8), r9: uint64(state.__r9), r10: uint64(state.__r10), r11: uint64(state.__r11), r12: uint64(state.__r12), r13: uint64(state.__r13), r14: uint64(state.__r14), r15: uint64(state.__r15), rip: uint64(state.__rip), rflags: uint64(state.__rflags), cs: uint64(state.__cs), fs: uint64(state.__fs), gs: uint64(state.__gs), } return regs, nil }
func (thread *Thread) saveRegisters() (Registers, error) { kret := C.get_registers(C.mach_port_name_t(thread.os.thread_act), &thread.os.registers) if kret != C.KERN_SUCCESS { return nil, fmt.Errorf("could not save register contents") } return &Regs{rip: uint64(thread.os.registers.__rip), rsp: uint64(thread.os.registers.__rsp)}, nil }
func (c *ProcessStat) Collect(collectAttributes bool) { h := c.Processes for _, v := range h { v.dead = true } var pDefaultSet C.processor_set_name_t var pDefaultSetControl C.processor_set_t var tasks C.task_array_t var taskCount C.mach_msg_type_number_t if C.processor_set_default(c.hport, &pDefaultSet) != C.KERN_SUCCESS { return } // get privileged port to get information about all tasks if C.host_processor_set_priv(C.host_priv_t(c.hport), pDefaultSet, &pDefaultSetControl) != C.KERN_SUCCESS { return } if C.processor_set_tasks(pDefaultSetControl, &tasks, &taskCount) != C.KERN_SUCCESS { return } // convert tasks to a Go slice hdr := reflect.SliceHeader{ Data: uintptr(unsafe.Pointer(tasks)), Len: int(taskCount), Cap: int(taskCount), } goTaskList := *(*[]C.task_name_t)(unsafe.Pointer(&hdr)) // mach_msg_type_number_t - type natural_t = uint32_t var i uint32 for i = 0; i < uint32(taskCount); i++ { taskId := goTaskList[i] var pid C.int // var tinfo C.task_info_data_t var count C.mach_msg_type_number_t var taskBasicInfo C.mach_task_basic_info_data_t var taskAbsoluteInfo C.task_absolutetime_info_data_t if (C.pid_for_task(C.mach_port_name_t(taskId), &pid) != C.KERN_SUCCESS) || (pid < 0) { continue } count = C.MACH_TASK_BASIC_INFO_COUNT kr := C.task_info(taskId, C.MACH_TASK_BASIC_INFO, (C.task_info_t)(unsafe.Pointer(&taskBasicInfo)), &count) if kr != C.KERN_SUCCESS { continue } spid := fmt.Sprintf("%v", pid) pidstat, ok := h[spid] if !ok { pidstat = NewPerProcessStat(c.m, spid) h[spid] = pidstat } if collectAttributes || !ok { pidstat.CollectAttributes(pid) } pidstat.Metrics.VirtualSize.Set(float64(taskBasicInfo.virtual_size)) pidstat.Metrics.ResidentSize.Set(float64(taskBasicInfo.resident_size)) pidstat.Metrics.ResidentSizeMax.Set(float64(taskBasicInfo.resident_size_max)) count = C.TASK_ABSOLUTETIME_INFO_COUNT kr = C.task_info(taskId, C.TASK_ABSOLUTETIME_INFO, (C.task_info_t)(unsafe.Pointer(&taskAbsoluteInfo)), &count) if kr != C.KERN_SUCCESS { continue } pidstat.Metrics.UserTime.Set( uint64(C.absolute_to_nano(taskAbsoluteInfo.total_user))) pidstat.Metrics.SystemTime.Set( uint64(C.absolute_to_nano(taskAbsoluteInfo.total_system))) pidstat.dead = false } // remove dead processes for k, v := range h { if v.dead { delete(h, k) } } }