X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..b7266188b87f3620ec3f9f717e57194a7dd989fe:/osfmk/kdp/kdp.c diff --git a/osfmk/kdp/kdp.c b/osfmk/kdp/kdp.c index 21a29d47a..df1d6d953 100644 --- a/osfmk/kdp/kdp.c +++ b/osfmk/kdp/kdp.c @@ -29,9 +29,12 @@ #include #include #include +#include #include #include +#include +#include #include @@ -80,11 +83,12 @@ static kdp_dispatch_t /*17 */ kdp_breakpoint64_remove, /*18 */ kdp_kernelversion, /*19 */ kdp_readphysmem64, -/*20 */ kdp_writephysmem64, -/*21 */ kdp_readioport, -/*22 */ kdp_writeioport, -/*23 */ kdp_readmsr64, -/*24 */ kdp_writemsr64, +/*1A */ kdp_writephysmem64, +/*1B */ kdp_readioport, +/*1C */ kdp_writeioport, +/*1D */ kdp_readmsr64, +/*1E */ kdp_writemsr64, +/*1F */ kdp_dumpinfo, }; kdp_glob_t kdp; @@ -95,7 +99,7 @@ kdp_glob_t kdp; * Version 11 of the KDP Protocol adds support for 64-bit wide memory * addresses (read/write and breakpoints) as well as a dedicated * kernelversion request. Version 12 adds read/writing of physical - * memory with 64-bit wide memory addresses. + * memory with 64-bit wide memory addresses. */ #define KDP_VERSION 12 @@ -113,6 +117,7 @@ int noresume_on_disconnect = 0; extern unsigned int return_on_panic; typedef struct thread_snapshot *thread_snapshot_t; +typedef struct task_snapshot *task_snapshot_t; extern int machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p); @@ -141,7 +146,7 @@ kdp_remove_breakpoint_internal( int -kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_options, uint32_t *pbytesTraced); +kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, uint32_t trace_flags, uint32_t dispatch_offset, uint32_t *pbytesTraced); boolean_t kdp_copyin(pmap_t, uint64_t, void *, size_t); extern void bcopy_phys(addr64_t, addr64_t, vm_size_t); @@ -219,31 +224,42 @@ kdp_connect( kdp_connect_req_t *rq = &pkt->connect_req; size_t plen = *len; kdp_connect_reply_t *rp = &pkt->connect_reply; + uint16_t rport, eport; + uint32_t key; + uint8_t seq; if (plen < sizeof (*rq)) return (FALSE); dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting)); + rport = rq->req_reply_port; + eport = rq->exc_note_port; + key = rq->hdr.key; + seq = rq->hdr.seq; if (kdp.is_conn) { - if (rq->hdr.seq == kdp.conn_seq) /* duplicate request */ + if ((seq == kdp.conn_seq) && /* duplicate request */ + (rport == kdp.reply_port) && + (eport == kdp.exception_port) && + (key == kdp.session_key)) rp->error = KDPERR_NO_ERROR; - else + else rp->error = KDPERR_ALREADY_CONNECTED; } else { - kdp.reply_port = rq->req_reply_port; - kdp.exception_port = rq->exc_note_port; - kdp.is_conn = TRUE; - kdp.conn_seq = rq->hdr.seq; - + kdp.reply_port = rport; + kdp.exception_port = eport; + kdp.is_conn = TRUE; + kdp.conn_seq = seq; + kdp.session_key = key; + rp->error = KDPERR_NO_ERROR; } rp->hdr.is_reply = 1; rp->hdr.len = sizeof (*rp); - *reply_port = kdp.reply_port; + *reply_port = rport; *len = rp->hdr.len; if (current_debugger == KDP_CUR_DB) @@ -276,6 +292,7 @@ kdp_disconnect( kdp.reply_port = kdp.exception_port = 0; kdp.is_halted = kdp.is_conn = FALSE; kdp.exception_seq = kdp.conn_seq = 0; + kdp.session_key = 0; if ((panicstr != NULL) && (return_on_panic == 0)) reattach_wait = 1; @@ -1050,7 +1067,7 @@ kdp_copyin(pmap_t p, uint64_t uaddr, void *dest, size_t size) { } int -kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_options, uint32_t *pbytesTraced) +kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, uint32_t trace_flags, uint32_t dispatch_offset, uint32_t *pbytesTraced) { char *tracepos = (char *) tracebuf; char *tracebound = tracepos + tracebuf_size; @@ -1059,49 +1076,105 @@ kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_op task_t task = TASK_NULL; thread_t thread = THREAD_NULL; - int nframes = trace_options; thread_snapshot_t tsnap = NULL; unsigned framesize = 2 * sizeof(vm_offset_t); - boolean_t dispatch_p = ((trace_options & STACKSHOT_GET_DQ) != 0); - uint16_t dispatch_offset = (trace_options & STACKSHOT_DISPATCH_OFFSET_MASK) >> STACKSHOT_DISPATCH_OFFSET_SHIFT; struct task ctask; struct thread cthread; - - if ((nframes <= 0) || nframes > MAX_FRAMES) - nframes = MAX_FRAMES; + + boolean_t dispatch_p = ((trace_flags & STACKSHOT_GET_DQ) != 0); + boolean_t save_loadinfo_p = ((trace_flags & STACKSHOT_SAVE_LOADINFO) != 0); queue_iterate(&tasks, task, task_t, tasks) { + int task_pid = pid_from_task(task); + boolean_t task64 = task_has_64BitAddr(task); + if ((task == NULL) || (ml_nofault_copy((vm_offset_t) task, (vm_offset_t) &ctask, sizeof(struct task)) != sizeof(struct task))) goto error_exit; + /* Trace everything, unless a process was specified */ - if ((pid == -1) || (pid == pid_from_task(task))) + if ((pid == -1) || (pid == task_pid)) { + task_snapshot_t task_snap; + uint32_t uuid_info_count; + mach_vm_address_t uuid_info_addr; + + if (save_loadinfo_p && task_pid > 0) { + // Read the dyld_all_image_infos struct from the task memory to get UUID array count and location + if (task64) { + struct dyld_all_image_infos64 task_image_infos; + if (!kdp_copyin(task->map->pmap, task->all_image_info_addr, &task_image_infos, sizeof(struct dyld_all_image_infos64))) + goto error_exit; + uuid_info_count = (uint32_t)task_image_infos.uuidArrayCount; + uuid_info_addr = task_image_infos.uuidArray; + } else { + struct dyld_all_image_infos task_image_infos; + if (!kdp_copyin(task->map->pmap, task->all_image_info_addr, &task_image_infos, sizeof(struct dyld_all_image_infos))) + goto error_exit; + uuid_info_count = task_image_infos.uuidArrayCount; + uuid_info_addr = task_image_infos.uuidArray; + } + } else { + uuid_info_count = 0; + uuid_info_addr = 0; + } + + if (tracepos + sizeof(struct task_snapshot) > tracebound) { + error = -1; + goto error_exit; + } + + task_snap = (task_snapshot_t) tracepos; + task_snap->snapshot_magic = STACKSHOT_TASK_SNAPSHOT_MAGIC; + task_snap->pid = task_pid; + task_snap->nloadinfos = uuid_info_count; + /* Add the BSD process identifiers */ + if (task_pid != -1) + proc_name_kdp(task, task_snap->p_comm, sizeof(task_snap->p_comm)); + else + task_snap->p_comm[0] = '\0'; + task_snap->ss_flags = 0; + if (task64) + task_snap->ss_flags |= kUser64_p; + + tracepos += sizeof(struct task_snapshot); + + if (task_pid > 0 && uuid_info_count > 0) { + uint32_t uuid_info_size = (uint32_t)(task64 ? sizeof(struct dyld_uuid_info64) : sizeof(struct dyld_uuid_info)); + uint32_t uuid_info_array_size = uuid_info_count * uuid_info_size; + + if (tracepos + uuid_info_array_size > tracebound) { + error = -1; + goto error_exit; + } + + // Copy in the UUID info array + if (!kdp_copyin(task->map->pmap, uuid_info_addr, tracepos, uuid_info_array_size)) + goto error_exit; + + tracepos += uuid_info_array_size; + } + queue_iterate(&task->threads, thread, thread_t, task_threads){ if ((thread == NULL) || (ml_nofault_copy((vm_offset_t) thread, (vm_offset_t) &cthread, sizeof(struct thread)) != sizeof(struct thread))) goto error_exit; + if (((tracepos + 4 * sizeof(struct thread_snapshot)) > tracebound)) { error = -1; goto error_exit; } -/* Populate the thread snapshot header */ + /* Populate the thread snapshot header */ tsnap = (thread_snapshot_t) tracepos; tsnap->thread_id = (uint64_t) (uintptr_t)thread; tsnap->state = thread->state; tsnap->wait_event = thread->wait_event; tsnap->continuation = (uint64_t) (uintptr_t) thread->continuation; -/* Add the BSD process identifiers */ - if ((tsnap->pid = pid_from_task(task)) != -1) - proc_name_kdp(task, tsnap->p_comm, sizeof(tsnap->p_comm)); - else - tsnap->p_comm[0] = '\0'; - tsnap->snapshot_magic = 0xfeedface; + tsnap->snapshot_magic = STACKSHOT_THREAD_SNAPSHOT_MAGIC; tracepos += sizeof(struct thread_snapshot); tsnap->ss_flags = 0; if (dispatch_p && (task != kernel_task) && (task->active) && (task->map)) { uint64_t dqkeyaddr = thread_dispatchqaddr(thread); if (dqkeyaddr != 0) { - boolean_t task64 = task_has_64BitAddr(task); uint64_t dqaddr = 0; if (kdp_copyin(task->map->pmap, dqkeyaddr, &dqaddr, (task64 ? 8 : 4)) && (dqaddr != 0)) { uint64_t dqserialnumaddr = dqaddr + dispatch_offset; @@ -1119,27 +1192,27 @@ kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_op */ if (thread->kernel_stack != 0) { #if defined(__LP64__) - tracebytes = machine_trace_thread64(thread, tracepos, tracebound, nframes, FALSE); + tracebytes = machine_trace_thread64(thread, tracepos, tracebound, MAX_FRAMES, FALSE); tsnap->ss_flags |= kKernel64_p; framesize = 16; #else - tracebytes = machine_trace_thread(thread, tracepos, tracebound, nframes, FALSE); + tracebytes = machine_trace_thread(thread, tracepos, tracebound, MAX_FRAMES, FALSE); framesize = 8; #endif } tsnap->nkern_frames = tracebytes/framesize; tracepos += tracebytes; tracebytes = 0; -/* Trace user stack, if any */ + /* Trace user stack, if any */ if (thread->task->map != kernel_map) { /* 64-bit task? */ if (task_has_64BitAddr(thread->task)) { - tracebytes = machine_trace_thread64(thread, tracepos, tracebound, nframes, TRUE); + tracebytes = machine_trace_thread64(thread, tracepos, tracebound, MAX_FRAMES, TRUE); tsnap->ss_flags |= kUser64_p; framesize = 16; } else { - tracebytes = machine_trace_thread(thread, tracepos, tracebound, nframes, TRUE); + tracebytes = machine_trace_thread(thread, tracepos, tracebound, MAX_FRAMES, TRUE); framesize = 8; } } @@ -1147,6 +1220,7 @@ kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_op tracepos += tracebytes; tracebytes = 0; } + } } error_exit: @@ -1278,3 +1352,36 @@ kdp_writemsr64( return (TRUE); } + +static boolean_t +kdp_dumpinfo( + kdp_pkt_t *pkt, + int *len, + unsigned short *reply_port + ) +{ + kdp_dumpinfo_req_t *rq = &pkt->dumpinfo_req; + kdp_dumpinfo_reply_t *rp = &pkt->dumpinfo_reply; + size_t plen = *len; + + if (plen < sizeof (*rq)) + return (FALSE); + + dprintf(("kdp_dumpinfo file=%s destip=%s routerip=%s\n", rq->name, rq->destip, rq->routerip)); + rp->hdr.is_reply = 1; + rp->hdr.len = sizeof (*rp); + + if ((rq->type & KDP_DUMPINFO_MASK) != KDP_DUMPINFO_GETINFO) { + kdp_set_dump_info(rq->type, rq->name, rq->destip, rq->routerip, + rq->port); + } + + /* gather some stats for reply */ + kdp_get_dump_info(&rp->type, rp->name, rp->destip, rp->routerip, + &rp->port); + + *reply_port = kdp.reply_port; + *len = rp->hdr.len; + + return (TRUE); +}