github.com/undoio/delve@v1.9.0/pkg/proc/native/threads_darwin.c (about)

     1  //+build darwin,macnative
     2  
     3  #include "threads_darwin.h"
     4  
     5  int
     6  write_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
     7  	kern_return_t kret;
     8  	vm_region_submap_short_info_data_64_t info;
     9  	mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
    10  	mach_vm_size_t l = len;
    11  	mach_port_t objname;
    12  
    13  	if (len == 1) l = 2;
    14  	kret = mach_vm_region((vm_map_t)task, &(mach_vm_address_t){addr}, (mach_vm_size_t*)&l, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &objname);
    15  	if (kret != KERN_SUCCESS) return -1;
    16  
    17  	// Set permissions to enable writing to this memory location
    18  	kret = mach_vm_protect(task, addr, len, FALSE, VM_PROT_WRITE|VM_PROT_COPY|VM_PROT_READ);
    19  	if (kret != KERN_SUCCESS) return -1;
    20  
    21  	kret = mach_vm_write((vm_map_t)task, addr, (vm_offset_t)d, len);
    22  	if (kret != KERN_SUCCESS) return -1;
    23  
    24  	// Restore virtual memory permissions
    25  	kret = mach_vm_protect(task, addr, len, FALSE, info.protection);
    26  	if (kret != KERN_SUCCESS) return -1;
    27  
    28  	return 0;
    29  }
    30  
    31  int
    32  read_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
    33  	kern_return_t kret;
    34  	pointer_t data;
    35  	mach_msg_type_number_t count;
    36  
    37  	kret = mach_vm_read((vm_map_t)task, addr, len, &data, &count);
    38  	if (kret != KERN_SUCCESS) return -1;
    39  	memcpy(d, (void *)data, len);
    40  
    41  	kret = vm_deallocate(task, data, len);
    42  	if (kret != KERN_SUCCESS) return -1;
    43  
    44  	return count;
    45  }
    46  
    47  kern_return_t
    48  get_registers(mach_port_name_t task, x86_thread_state64_t *state) {
    49  	kern_return_t kret;
    50  	mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
    51  	// TODO(dp) - possible memory leak - vm_deallocate state
    52  	return thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)state, &stateCount);
    53  }
    54  
    55  kern_return_t
    56  get_fpu_registers(mach_port_name_t task, x86_float_state64_t *state) {
    57  	kern_return_t kret;
    58  	mach_msg_type_number_t stateCount = x86_FLOAT_STATE64_COUNT;
    59  	return thread_get_state(task, x86_FLOAT_STATE64, (thread_state_t)state, &stateCount);
    60  }
    61  
    62  kern_return_t
    63  get_identity(mach_port_name_t task, thread_identifier_info_data_t *idinfo) {
    64  	mach_msg_type_number_t idinfoCount = THREAD_IDENTIFIER_INFO_COUNT;
    65  	return thread_info(task, THREAD_IDENTIFIER_INFO, (thread_info_t)idinfo, &idinfoCount);
    66  }
    67  
    68  kern_return_t
    69  set_registers(mach_port_name_t task, x86_thread_state64_t *state) {
    70  	mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
    71  	return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)state, stateCount);
    72  }
    73  
    74  kern_return_t
    75  set_pc(thread_act_t task, uint64_t pc) {
    76  	kern_return_t kret;
    77  	x86_thread_state64_t state;
    78  	mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
    79  
    80  	kret = thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)&state, &stateCount);
    81  	if (kret != KERN_SUCCESS) return kret;
    82  	state.__rip = pc;
    83  
    84  	return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)&state, stateCount);
    85  }
    86  
    87  kern_return_t
    88  single_step(thread_act_t thread) {
    89  	kern_return_t kret;
    90  	x86_thread_state64_t regs;
    91  	mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
    92  
    93  	kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, &count);
    94  	if (kret != KERN_SUCCESS) return kret;
    95  
    96  	// Set trap bit in rflags
    97  	regs.__rflags |= 0x100UL;
    98  
    99  	kret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, count);
   100  	if (kret != KERN_SUCCESS) return kret;
   101  
   102  	return resume_thread(thread);
   103  }
   104  
   105  kern_return_t
   106  resume_thread(thread_act_t thread) {
   107  	kern_return_t kret;
   108  	struct thread_basic_info info;
   109  	unsigned int info_count = THREAD_BASIC_INFO_COUNT;
   110  
   111  	kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
   112  	if (kret != KERN_SUCCESS) return kret;
   113  
   114  	for (int i = 0; i < info.suspend_count; i++) {
   115  		kret = thread_resume(thread);
   116  		if (kret != KERN_SUCCESS) return kret;
   117  	}
   118  	return KERN_SUCCESS;
   119  }
   120  
   121  kern_return_t
   122  clear_trap_flag(thread_act_t thread) {
   123  	kern_return_t kret;
   124  	x86_thread_state64_t regs;
   125  	mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
   126  
   127  	kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, &count);
   128  	if (kret != KERN_SUCCESS) return kret;
   129  
   130  	// Clear trap bit in rflags
   131  	regs.__rflags ^= 0x100UL;
   132  
   133  	return thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&regs, count);
   134  }
   135  
   136  int
   137  thread_blocked(thread_act_t thread) {
   138  	kern_return_t kret;
   139  	struct thread_basic_info info;
   140  	unsigned int info_count = THREAD_BASIC_INFO_COUNT;
   141  
   142  	kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
   143  	if (kret != KERN_SUCCESS) return -1;
   144  
   145  	return info.suspend_count;
   146  }
   147  
   148  int
   149  num_running_threads(task_t task) {
   150  	kern_return_t kret;
   151  	thread_act_array_t list;
   152  	mach_msg_type_number_t count;
   153  	int i, n = 0;
   154  
   155  	kret = task_threads(task, &list, &count);
   156  	if (kret != KERN_SUCCESS) {
   157  		return -kret;
   158  	}
   159  
   160  	for (i = 0; i < count; ++i) {
   161  		thread_act_t thread = list[i];
   162  		struct thread_basic_info info;
   163  		unsigned int info_count = THREAD_BASIC_INFO_COUNT;
   164  
   165  		kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
   166  
   167  		if (kret == KERN_SUCCESS) {
   168  			if (info.suspend_count == 0) {
   169  				++n;
   170  			} else {
   171  			}
   172  		}
   173  	}
   174  
   175  	kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
   176  	if (kret != KERN_SUCCESS) return -kret;
   177  
   178  	return n;
   179  }