X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0c530ab8987f0ae6a1a3d9284f40182b88852816..b0d623f7f2ae71ed96e60569f61f9a9a27016e80:/osfmk/kdp/kdp_udp.c diff --git a/osfmk/kdp/kdp_udp.c b/osfmk/kdp/kdp_udp.c index df1ec3f67..c43049684 100644 --- a/osfmk/kdp/kdp_udp.c +++ b/osfmk/kdp/kdp_udp.c @@ -1,24 +1,31 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ + /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. @@ -34,11 +41,16 @@ #include #include #include +#include #include #include #include +#include #include +#if CONFIG_SERIAL_KDP +#include +#endif #include #include @@ -53,6 +65,10 @@ extern int kdp_getc(void); extern int reattach_wait; +extern int serial_getc(void); +extern void serial_putc(char); +extern int serial_init(void); + static u_short ip_id; /* ip packet ctr, for ids */ /* @(#)udp_usrreq.c 2.2 88/05/23 4.0NFSSRC SMI; from UCB 7.1 6/5/86 */ @@ -71,6 +87,17 @@ static struct { boolean_t input; } pkt, saved_reply; +/* + * Support relatively small request/responses here. + * If kgmacros needs to make a larger request, increase + * this buffer size + */ +static struct { + unsigned char data[128]; + unsigned int len; + boolean_t input; +} manual_pkt; + struct { struct { struct in_addr in; @@ -95,13 +122,13 @@ static const char volatile int kdp_flag = 0; -static kdp_send_t kdp_en_send_pkt = 0; -static kdp_receive_t kdp_en_recv_pkt = 0; +static kdp_send_t kdp_en_send_pkt; +static kdp_receive_t kdp_en_recv_pkt; -static u_long kdp_current_ip_address = 0; +static uint32_t kdp_current_ip_address = 0; static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}}; -static void *kdp_current_ifp = 0; +static void *kdp_current_ifp; static void kdp_handler( void *); @@ -114,7 +141,6 @@ static volatile boolean_t panicd_specified = FALSE; static boolean_t router_specified = FALSE; static unsigned int panicd_port = CORE_REMOTE_PORT; -/* As in bsd/net/ether_if_module.c */ static struct ether_addr etherbroadcastaddr = {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; static struct ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}}; @@ -132,20 +158,17 @@ static unsigned int last_panic_port = CORE_REMOTE_PORT; unsigned int SEGSIZE = 512; -__unused static unsigned int PANIC_PKTSIZE = 518; static char panicd_ip_str[20]; static char router_ip_str[20]; static unsigned int panic_block = 0; -static volatile unsigned int kdp_trigger_core_dump = 0; -static volatile unsigned int flag_kdp_trigger_reboot = 0; +volatile unsigned int kdp_trigger_core_dump = 0; +__private_extern__ volatile unsigned int flag_kdp_trigger_reboot = 0; extern unsigned int not_in_kdp; -extern unsigned long panic_caller; extern unsigned int disableConsoleOutput; -extern int kdp_vm_read( caddr_t, caddr_t, unsigned int); extern void kdp_call(void); extern boolean_t kdp_call_kdb(void); extern int kern_dump(void); @@ -160,6 +183,12 @@ static void kdp_arp_reply(struct ether_arp *); static void kdp_process_arp_reply(struct ether_arp *); static boolean_t kdp_arp_resolve(uint32_t, struct ether_addr *); +static volatile unsigned kdp_reentry_deadline; +#if defined(__LP64__) +uint32_t kdp_crashdump_feature_mask = KDP_FEATURE_LARGE_CRASHDUMPS; +static uint32_t kdp_feature_large_crashdumps; +#endif + static boolean_t gKDPDebug = FALSE; #define KDP_DEBUG(...) if (gKDPDebug) printf(__VA_ARGS__); @@ -172,6 +201,8 @@ static uint32_t stack_snapshot_bufsize; static int stack_snapshot_pid; static uint32_t stack_snapshot_options; +static unsigned int old_debugger; + void kdp_snapshot_preflight(int pid, void * tracebuf, uint32_t tracebuf_size, uint32_t options); @@ -180,7 +211,7 @@ void kdp_snapshot_postflight(void); extern int -kdp_stackshot(int pid, uint32_t tracebuf, uint32_t tracebuf_size, +kdp_stackshot(int pid, void *tracebuf, uint32_t tracebuf_size, unsigned trace_options, uint32_t *pbytesTraced); int @@ -189,51 +220,76 @@ kdp_stack_snapshot_geterror(void); int kdp_stack_snapshot_bytes_traced(void); +static thread_call_t +kdp_timer_call; + +static void +kdp_ml_enter_debugger_wrapper(__unused void *param0, __unused void *param1) { + kdp_ml_enter_debugger(); +} + +static void +kdp_timer_callout_init(void) { + kdp_timer_call = thread_call_allocate(kdp_ml_enter_debugger_wrapper, NULL); +} + + void kdp_register_send_receive( kdp_send_t send, kdp_receive_t receive) { - unsigned int debug=0; - - kdp_en_send_pkt = send; - kdp_en_recv_pkt = receive; + unsigned int debug = 0; debug_log_init(); - PE_parse_boot_arg("debug", &debug); + kdp_timer_callout_init(); + + PE_parse_boot_argn("debug", &debug, sizeof (debug)); +#if defined(__LP64__) + kdp_crashdump_feature_mask = htonl(kdp_crashdump_feature_mask); +#endif + + if (!debug) + return; + + kdp_en_send_pkt = send; + kdp_en_recv_pkt = receive; if (debug & DB_KDP_BP_DIS) kdp_flag |= KDP_BP_DIS; if (debug & DB_KDP_GETC_ENA) kdp_flag |= KDP_GETC_ENA; if (debug & DB_ARP) - kdp_flag |= KDP_ARP; + kdp_flag |= KDP_ARP; if (debug & DB_KERN_DUMP_ON_PANIC) - kdp_flag |= KDP_PANIC_DUMP_ENABLED; + kdp_flag |= KDP_PANIC_DUMP_ENABLED; if (debug & DB_KERN_DUMP_ON_NMI) - kdp_flag |= PANIC_CORE_ON_NMI; - + kdp_flag |= PANIC_CORE_ON_NMI; + if (debug & DB_DBG_POST_CORE) - kdp_flag |= DBG_POST_CORE; - + kdp_flag |= DBG_POST_CORE; + if (debug & DB_PANICLOG_DUMP) - kdp_flag |= PANIC_LOG_DUMP; - - if (PE_parse_boot_arg ("_panicd_ip", panicd_ip_str)) - panicd_specified = TRUE; + kdp_flag |= PANIC_LOG_DUMP; + + if (PE_parse_boot_argn("_panicd_ip", panicd_ip_str, sizeof (panicd_ip_str))) + panicd_specified = TRUE; - if (PE_parse_boot_arg ("_router_ip", router_ip_str)) - router_specified = TRUE; + if ((debug & DB_REBOOT_POST_CORE) && (panicd_specified == TRUE)) + kdp_flag |= REBOOT_POST_CORE; - if (!PE_parse_boot_arg ("panicd_port", &panicd_port)) + if (PE_parse_boot_argn("_router_ip", router_ip_str, sizeof (router_ip_str))) + router_specified = TRUE; + + if (!PE_parse_boot_argn("panicd_port", &panicd_port, sizeof (panicd_port))) panicd_port = CORE_REMOTE_PORT; kdp_flag |= KDP_READY; if (current_debugger == NO_CUR_DB) current_debugger = KDP_CUR_DB; - if (halt_in_debugger) { + if ((kdp_current_ip_address != 0) && halt_in_debugger) { kdp_call(); halt_in_debugger=0; } @@ -260,12 +316,22 @@ kdp_snapshot_preflight(int pid, void * tracebuf, uint32_t tracebuf_size, uint32_ stack_snapshot_bufsize = tracebuf_size; stack_snapshot_options = options; kdp_snapshot++; + /* Mark this debugger as active, since the polled mode driver that + * ordinarily does this may not be enabled (yet), or since KDB may be + * the primary debugger. + */ + old_debugger = current_debugger; + if (old_debugger != KDP_CUR_DB) { + current_debugger = KDP_CUR_DB; + } } void kdp_snapshot_postflight(void) { kdp_snapshot--; + if ((kdp_en_send_pkt == NULL) || (old_debugger == KDB_CUR_DB)) + current_debugger = old_debugger; } int @@ -280,6 +346,14 @@ kdp_stack_snapshot_bytes_traced(void) return stack_snapshot_bytes_traced; } +static void +kdp_schedule_debugger_reentry(unsigned interval) { + uint64_t deadline;; + + clock_interval_to_deadline(interval, 1000 * 1000, &deadline); + thread_call_enter_delayed(kdp_timer_call, deadline); +} + static void enaddr_copy( void *src, @@ -325,7 +399,7 @@ kdp_reply( if (!pkt.input) kdp_panic("kdp_reply"); - pkt.off -= sizeof (struct udpiphdr); + pkt.off -= (unsigned int)sizeof (struct udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); @@ -360,9 +434,9 @@ kdp_reply( bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct udpiphdr); - pkt.off -= sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct ether_header); eh = (struct ether_header *)&pkt.data[pkt.off]; enaddr_copy(eh->ether_shost, &tmp_enaddr); @@ -370,7 +444,7 @@ kdp_reply( enaddr_copy(&tmp_enaddr, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += sizeof (struct ether_header); + pkt.len += (unsigned int)sizeof (struct ether_header); // save reply for possible retransmission bcopy((char *)&pkt, (char *)&saved_reply, sizeof(pkt)); @@ -393,7 +467,7 @@ kdp_send( if (pkt.input) kdp_panic("kdp_send"); - pkt.off -= sizeof (struct udpiphdr); + pkt.off -= (unsigned int)sizeof (struct udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); @@ -427,16 +501,16 @@ kdp_send( bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct udpiphdr); - pkt.off -= sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct ether_header); eh = (struct ether_header *)&pkt.data[pkt.off]; enaddr_copy(&adr.loc.ea, eh->ether_shost); enaddr_copy(&adr.rmt.ea, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += sizeof (struct ether_header); + pkt.len += (unsigned int)sizeof (struct ether_header); (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); } @@ -449,7 +523,7 @@ kdp_set_interface(void *ifp) } void * -kdp_get_interface() +kdp_get_interface(void) { return kdp_current_ifp; } @@ -461,6 +535,10 @@ kdp_set_ip_and_mac_addresses( { kdp_current_ip_address = ipaddr->s_addr; kdp_current_mac_address = *macaddr; + if ((current_debugger == KDP_CUR_DB) && halt_in_debugger) { + kdp_call(); + halt_in_debugger=0; + } } void @@ -479,7 +557,7 @@ kdp_get_mac_addr(void) unsigned int kdp_get_ip_address(void) { - return kdp_current_ip_address; + return (unsigned int)kdp_current_ip_address; } void @@ -494,7 +572,7 @@ kdp_arp_dispatch(void) struct ether_arp aligned_ea, *ea = &aligned_ea; unsigned arp_header_offset; - arp_header_offset = sizeof(struct ether_header) + pkt.off; + arp_header_offset = (unsigned)sizeof(struct ether_header) + pkt.off; memcpy((void *)ea, (void *)&pkt.data[arp_header_offset], sizeof(*ea)); switch(ntohs(ea->arp_op)) { @@ -539,7 +617,7 @@ kdp_arp_reply(struct ether_arp *ea) struct ether_addr my_enaddr; eh = (struct ether_header *)&pkt.data[pkt.off]; - pkt.off += sizeof(struct ether_header); + pkt.off += (unsigned int)sizeof(struct ether_header); if(ntohs(ea->arp_op) != ARPOP_REQUEST) return; @@ -573,7 +651,7 @@ kdp_arp_reply(struct ether_arp *ea) (void)memcpy(eh->ether_shost, &my_enaddr, sizeof(eh->ether_shost)); eh->ether_type = htons(ETHERTYPE_ARP); (void)memcpy(&pkt.data[pkt.off], ea, sizeof(*ea)); - pkt.off -= sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct ether_header); /* pkt.len is still the length we want, ether_header+ether_arp */ (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len); } @@ -621,7 +699,7 @@ kdp_poll(void) if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr))) return; - pkt.off += sizeof (struct ether_header); + pkt.off += (unsigned int)sizeof (struct ether_header); if (ntohs(eh->ether_type) != ETHERTYPE_IP) { return; } @@ -634,7 +712,7 @@ kdp_poll(void) ip = (struct ip *)&pkt.data[pkt.off]; #endif - pkt.off += sizeof (struct udpiphdr); + pkt.off += (unsigned int)sizeof (struct udpiphdr); if (ui->ui_pr != IPPROTO_UDP) { return; } @@ -673,7 +751,7 @@ kdp_poll(void) /* * Calculate kdp packet length. */ - pkt.len = ntohs((u_short)ui->ui_ulen) - sizeof (struct udphdr); + pkt.len = ntohs((u_short)ui->ui_ulen) - (unsigned int)sizeof (struct udphdr); pkt.input = TRUE; } @@ -803,6 +881,23 @@ kdp_handler( goto again; } + /* This is a manual side-channel to the main KDP protocol. + * A client like GDB/kgmacros can manually construct + * a request, set the input flag, issue a dummy KDP request, + * and then manually collect the result + */ + if (manual_pkt.input) { + kdp_hdr_t *manual_hdr = (kdp_hdr_t *)&manual_pkt.data; + unsigned short manual_port_unused = 0; + if (!manual_hdr->is_reply) { + /* process */ + kdp_packet((unsigned char *)&manual_pkt.data, + (int *)&manual_pkt.len, + &manual_port_unused); + } + manual_pkt.input = 0; + } + if (kdp_packet((unsigned char*)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&reply_port)) { @@ -857,6 +952,7 @@ kdp_connection_wait(void) printf("\nWaiting for remote debugger connection.\n"); + if (reattach_wait == 0) { if((kdp_flag & KDP_GETC_ENA) && (0 != kdp_getc())) { @@ -884,7 +980,7 @@ kdp_connection_wait(void) return; case 'r': printf("Rebooting...\n"); - kdp_reboot(); + kdp_machine_reboot(); break; #if MACH_KDB case 'k': @@ -907,7 +1003,7 @@ kdp_connection_wait(void) hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; #endif if (hdr->request == KDP_HOSTREBOOT) { - kdp_reboot(); + kdp_machine_reboot(); /* should not return! */ } if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) && @@ -992,6 +1088,14 @@ kdp_raise_exception( { int index; + /* Was a system trace requested ? */ + if (kdp_snapshot && (!panic_active()) && (panic_caller == 0)) { + stack_snapshot_ret = kdp_stackshot(stack_snapshot_pid, + stack_snapshot_buf, stack_snapshot_bufsize, + stack_snapshot_options, &stack_snapshot_bytes_traced); + return; + } + disable_preemption(); if (saved_state == 0) @@ -1013,29 +1117,24 @@ kdp_raise_exception( * do this. I think the client and the host can get out of sync. */ kdp.saved_state = saved_state; - + kdp.kdp_cpu = cpu_number(); + kdp.kdp_thread = current_thread(); + if (pkt.input) kdp_panic("kdp_raise_exception"); - /* Was a system trace requested ? */ - if (kdp_snapshot && (panicstr == ((char *) 0)) && (panic_caller == 0) && !kdp.is_conn) { - /* XXX This should be reworked to take a pointer to the buffer */ - stack_snapshot_ret = kdp_stackshot(stack_snapshot_pid, - (uint32_t) stack_snapshot_buf, stack_snapshot_bufsize, - stack_snapshot_options, &stack_snapshot_bytes_traced); - goto exit_raise_exception; - } if (((kdp_flag & KDP_PANIC_DUMP_ENABLED) || (kdp_flag & PANIC_LOG_DUMP)) && (panicstr != (char *) 0)) { - kdp_panic_dump(); + if (kdp_flag & REBOOT_POST_CORE) + kdp_machine_reboot(); } else if ((kdp_flag & PANIC_CORE_ON_NMI) && (panicstr == (char *) 0) && !kdp.is_conn) { - disableDebugOuput = disableConsoleOutput = FALSE; + disable_debug_output = disableConsoleOutput = FALSE; kdp_panic_dump(); if (!(kdp_flag & DBG_POST_CORE)) @@ -1072,6 +1171,7 @@ kdp_raise_exception( kdp_flag &= ~PANIC_LOG_DUMP; kdp_flag |= KDP_PANIC_DUMP_ENABLED; kdp_panic_dump(); + kdp_trigger_core_dump = 0; } /* Trigger a reboot if the user has set this flag through the @@ -1080,11 +1180,17 @@ kdp_raise_exception( * available, it should work automatically. */ if (1 == flag_kdp_trigger_reboot) { - kdp_reboot(); + kdp_machine_reboot(); /* If we're still around, reset the flag */ flag_kdp_trigger_reboot = 0; } - + + if (kdp_reentry_deadline) { + kdp_schedule_debugger_reentry(kdp_reentry_deadline); + printf("Debugger re-entry scheduled in %d milliseconds\n", kdp_reentry_deadline); + kdp_reentry_deadline = 0; + } + kdp_sync_cache(); if (reattach_wait == 1) @@ -1112,10 +1218,14 @@ create_panic_header(unsigned int request, const char *corename, struct corehdr *coreh; const char *mode = "octet"; char modelen = strlen(mode); - +#if defined(__LP64__) + size_t fmask_size = sizeof(KDP_FEATURE_MASK_STRING) + sizeof(kdp_crashdump_feature_mask); +#else + size_t fmask_size = 0; +#endif pkt.off = sizeof (struct ether_header); - pkt.len = length + ((request == KDP_WRQ) ? modelen : 0) + - (corename ? strlen(corename): 0) + sizeof(struct corehdr); + pkt.len = (unsigned int)(length + ((request == KDP_WRQ) ? modelen + fmask_size : 0) + + (corename ? strlen(corename): 0) + sizeof(struct corehdr)); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); @@ -1126,7 +1236,7 @@ create_panic_header(unsigned int request, const char *corename, ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_short)pkt.len + sizeof (struct udphdr)); - ui->ui_src.s_addr = kdp_current_ip_address; + ui->ui_src.s_addr = (uint32_t)kdp_current_ip_address; /* Already in network byte order via inet_aton() */ ui->ui_dst.s_addr = panic_server_ip; ui->ui_sport = htons(panicd_port); @@ -1150,44 +1260,47 @@ create_panic_header(unsigned int request, const char *corename, bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif - pkt.len += sizeof (struct udpiphdr); + pkt.len += (unsigned int)sizeof (struct udpiphdr); - pkt.off += sizeof (struct udpiphdr); + pkt.off += (unsigned int)sizeof (struct udpiphdr); coreh = (struct corehdr *) &pkt.data[pkt.off]; coreh->th_opcode = htons((u_short)request); if (request == KDP_WRQ) { - register char *cp; + char *cp; cp = coreh->th_u.tu_rpl; - strcpy (cp, corename); - cp += strlen(corename); + cp += strlcpy (cp, corename, KDP_MAXPACKET); *cp++ = '\0'; - strcpy (cp, mode); - cp+= modelen; + cp += strlcpy (cp, mode, KDP_MAXPACKET - strlen(corename)); *cp++ = '\0'; +#if defined(__LP64__) + cp += strlcpy(cp, KDP_FEATURE_MASK_STRING, sizeof(KDP_FEATURE_MASK_STRING)); + *cp++ = '\0'; /* Redundant */ + bcopy(&kdp_crashdump_feature_mask, cp, sizeof(kdp_crashdump_feature_mask)); +#endif } else { coreh->th_block = htonl((unsigned int) block); } - pkt.off -= sizeof (struct udpiphdr); - pkt.off -= sizeof (struct ether_header); + pkt.off -= (unsigned int)sizeof (struct udpiphdr); + pkt.off -= (unsigned int)sizeof (struct ether_header); eh = (struct ether_header *)&pkt.data[pkt.off]; enaddr_copy(&kdp_current_mac_address, eh->ether_shost); enaddr_copy(&destination_mac, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); - pkt.len += sizeof (struct ether_header); + pkt.len += (unsigned int)sizeof (struct ether_header); return coreh; } int kdp_send_crashdump_data(unsigned int request, char *corename, - unsigned int length, caddr_t txstart) + uint64_t length, caddr_t txstart) { caddr_t txend = txstart + length; int panic_error = 0; @@ -1207,10 +1320,10 @@ int kdp_send_crashdump_data(unsigned int request, char *corename, } txstart += SEGSIZE; if (!(panic_block % 2000)) - printf("."); + kdb_printf_unbuffered("."); } if (txstart < txend) { - kdp_send_crashdump_pkt(request, corename, (txend - txstart), txstart); + kdp_send_crashdump_pkt(request, corename, (unsigned int)(txend - txstart), txstart); } } return 0; @@ -1218,7 +1331,7 @@ int kdp_send_crashdump_data(unsigned int request, char *corename, int kdp_send_crashdump_pkt(unsigned int request, char *corename, - unsigned int length, void *panic_data) + uint64_t length, void *panic_data) { struct corehdr *th = NULL; int poll_count = 2500; @@ -1246,14 +1359,19 @@ TRANSMIT_RETRY: if (tretries > 2) printf("TX retry #%d ", tretries ); - th = create_panic_header(request, corename, length, panic_block); + th = create_panic_header(request, corename, (unsigned)length, panic_block); if (request == KDP_DATA) { - if (!kdp_vm_read((caddr_t) panic_data, (caddr_t) th->th_data, length)) { - memset ((caddr_t) th->th_data, 'X', length); + if (!kdp_machine_vm_read((mach_vm_address_t)(intptr_t)panic_data, (caddr_t) th->th_data, length)) { + memset ((caddr_t) th->th_data, 'X', (size_t)length); } } else if (request == KDP_SEEK) { +#if defined(__LP64__) + if (kdp_feature_large_crashdumps) + *(uint64_t *) th->th_data = OSSwapHostToBigInt64((*(uint64_t *) panic_data)); + else +#endif *(unsigned int *) th->th_data = htonl(*(unsigned int *) panic_data); } @@ -1271,7 +1389,17 @@ RECEIVE_RETRY: pkt.input = FALSE; th = (struct corehdr *) &pkt.data[pkt.off]; - +#if defined(__LP64__) + if (request == KDP_WRQ) { + uint16_t opcode64 = ntohs(th->th_opcode); + uint16_t features64 = (opcode64 & 0xFF00)>>8; + if ((opcode64 & 0xFF) == KDP_ACK) { + kdp_feature_large_crashdumps = features64 & KDP_FEATURE_LARGE_CRASHDUMPS; + printf("Protocol features: 0x%x\n", (uint32_t) features64); + th->th_opcode = htons(KDP_ACK); + } + } +#endif if (ntohs(th->th_opcode) == KDP_ACK && ntohl(th->th_block) == panic_block) { } else @@ -1336,7 +1464,7 @@ strnstr(char *s, const char *find, size_t slen) } while (strncmp(s, find, len) != 0); s--; } - return ((char *)s); + return (s); } extern char version[]; @@ -1353,48 +1481,43 @@ extern char version[]; static int kdp_get_xnu_version(char *versionbuf) { - char *versionpos; char vstr[20]; int retval = -1; char *vptr; - strcpy(vstr, "custom"); - if (version) { - if (kdp_vm_read(version, versionbuf, 95)) { - versionbuf[94] = '\0'; - versionpos = strnstr(versionbuf, "xnu-", 90); - if (versionpos) { - strncpy(vstr, versionpos, sizeof(vstr)); - vstr[sizeof(vstr)-1] = '\0'; - vptr = vstr + 4; /* Begin after "xnu-" */ - while (*vptr && (isdigit(*vptr) || *vptr == '.')) - vptr++; + strlcpy(vstr, "custom", 10); + if (strlcpy(versionbuf, version, 95) < 95) { + versionpos = strnstr(versionbuf, "xnu-", 90); + if (versionpos) { + strncpy(vstr, versionpos, sizeof(vstr)); + vstr[sizeof(vstr)-1] = '\0'; + vptr = vstr + 4; /* Begin after "xnu-" */ + while (*vptr && (isdigit(*vptr) || *vptr == '.')) + vptr++; + *vptr = '\0'; + /* Remove trailing period, if any */ + if (*(--vptr) == '.') *vptr = '\0'; - /* Remove trailing period, if any */ - if (*(--vptr) == '.') - *vptr = '\0'; - retval = 0; - } + retval = 0; } } - strcpy(versionbuf, vstr); + strlcpy(versionbuf, vstr, KDP_MAXPACKET); return retval; } extern char *inet_aton(const char *cp, struct in_addr *pin); -extern int snprintf(char *str, size_t size, const char *format, ...); /* Primary dispatch routine for the system dump */ void -kdp_panic_dump() +kdp_panic_dump(void) { char corename[50]; char coreprefix[10]; int panic_error; uint64_t abstime; - uint32_t current_ip = ntohl(kdp_current_ip_address); + uint32_t current_ip = ntohl((uint32_t)kdp_current_ip_address); if (flag_panic_dump_in_progress) { printf("System dump aborted.\n"); @@ -1480,7 +1603,7 @@ kdp_panic_dump() /* Just the panic log requested */ if ((panicstr != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { printf("Transmitting panic log, please wait: "); - kdp_send_crashdump_data(KDP_DATA, corename, (debug_buf_ptr - debug_buf), debug_buf); + kdp_send_crashdump_data(KDP_DATA, corename, (unsigned int)(debug_buf_ptr - debug_buf), debug_buf); kdp_send_crashdump_pkt (KDP_EOF, NULL, 0, ((void *) 0)); printf("Please file a bug report on this panic, if possible.\n"); goto panic_dump_exit; @@ -1503,3 +1626,112 @@ abort_panic_transfer(void) not_in_kdp = 1; panic_block = 0; } + +#if CONFIG_SERIAL_KDP + +static boolean_t needs_serial_init = TRUE; + +static void +kdp_serial_send(void *rpkt, unsigned int rpkt_len) +{ + if (needs_serial_init) + { + serial_init(); + needs_serial_init = FALSE; + } + + // printf("tx\n"); + kdp_serialize_packet((unsigned char *)rpkt, rpkt_len, serial_putc); +} + +static void +kdp_serial_receive(void *rpkt, unsigned int *rpkt_len, unsigned int timeout) +{ + int readkar; + uint64_t now, deadline; + + if (needs_serial_init) + { + serial_init(); + needs_serial_init = FALSE; + } + + clock_interval_to_deadline(timeout, 1000 * 1000 /* milliseconds */, &deadline); + +// printf("rx\n"); + for(clock_get_uptime(&now); now < deadline; clock_get_uptime(&now)) + { + readkar = serial_getc(); + if(readkar >= 0) + { + unsigned char *packet; + // printf("got char %02x\n", readkar); + if((packet = kdp_unserialize_packet(readkar,rpkt_len))) + { + memcpy(rpkt, packet, *rpkt_len); + return; + } + } + } + *rpkt_len = 0; +} + +static void kdp_serial_callout(__unused void *arg, kdp_event_t event) +{ + /* When we stop KDP, set the bit to re-initialize the console serial port + * the next time we send/receive a KDP packet. We don't do it on + * KDP_EVENT_ENTER directly because it also gets called when we trap to KDP + * for non-external debugging, i.e., stackshot or core dumps. + * + * Set needs_serial_init on exit (and initialization, see above) and not + * enter because enter is sent multiple times and causes excess reinitialization. + */ + + switch (event) + { + case KDP_EVENT_PANICLOG: + case KDP_EVENT_ENTER: + break; + case KDP_EVENT_EXIT: + needs_serial_init = TRUE; + break; + } +} + +#endif /* CONFIG_SERIAL_KDP */ + +void +kdp_init(void) +{ +#if CONFIG_SERIAL_KDP + char kdpname[80]; + struct in_addr ipaddr; + struct ether_addr macaddr; + + +#if CONFIG_EMBEDDED + //serial will be the debugger, unless match name is explicitly provided, and it's not "serial" + if(PE_parse_boot_argn("kdp_match_name", kdpname, sizeof(kdpname)) && strncmp(kdpname, "serial", sizeof(kdpname)) != 0) + return; +#else + // serial must be explicitly requested + if(!PE_parse_boot_argn("kdp_match_name", kdpname, sizeof(kdpname)) || strncmp(kdpname, "serial", sizeof(kdpname)) != 0) + return; +#endif + + kprintf("Intializing serial KDP\n"); + + kdp_register_callout(kdp_serial_callout, NULL); + kdp_register_send_receive(kdp_serial_send, kdp_serial_receive); + + /* fake up an ip and mac for early serial debugging */ + macaddr.ether_addr_octet[0] = 's'; + macaddr.ether_addr_octet[1] = 'e'; + macaddr.ether_addr_octet[2] = 'r'; + macaddr.ether_addr_octet[3] = 'i'; + macaddr.ether_addr_octet[4] = 'a'; + macaddr.ether_addr_octet[5] = 'l'; + ipaddr.s_addr = 0xABADBABE; + kdp_set_ip_and_mac_addresses(&ipaddr, &macaddr); +#endif /* CONFIG_SERIAL_KDP */ +}