/* * Copyright (c) 2000-2019 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_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. 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. * * 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, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1982, 1986, 1993 * The Regents of the University of California. All rights reserved. */ /* * Kernel Debugging Protocol UDP implementation. */ #include #include #include #include #include #include #include #include #if (MACH_KDP && CONFIG_KDP_INTERACTIVE_DEBUGGING) #include #endif #include #include #include #if CONFIG_SERIAL_KDP #include #endif #include #include #include #include /* kernel_map */ #include #include #include /* we just want the link status flags, so undef KERNEL_PRIVATE for this * header file. */ #undef KERNEL_PRIVATE #include #define KERNEL_PRIVATE #include #include #include #include extern unsigned int not_in_kdp; extern int kdp_snapshot; #ifdef CONFIG_KDP_INTERACTIVE_DEBUGGING extern int inet_aton(const char *, struct kdp_in_addr *); /* in libkern */ extern char *inet_ntoa_r(struct kdp_in_addr ina, char *buf, size_t buflen); /* in libkern */ #define DO_ALIGN 1 /* align all packet data accesses */ #define KDP_SERIAL_IPADDR 0xABADBABE /* IP address used for serial KDP */ #define LINK_UP_STATUS (IFM_AVALID | IFM_ACTIVE) extern int kdp_getc(void); extern int reattach_wait; 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 */ /* * UDP protocol implementation. * Per RFC 768, August, 1980. */ #define UDP_TTL 60 /* default time to live for UDP packets */ static u_char udp_ttl = UDP_TTL; static unsigned char exception_seq; struct kdp_ipovly { uint32_t ih_next, ih_prev; /* for protocol sequence q's */ u_char ih_x1; /* (unused) */ u_char ih_pr; /* protocol */ short ih_len; /* protocol length */ struct kdp_in_addr ih_src; /* source internet address */ struct kdp_in_addr ih_dst; /* destination internet address */ }; struct kdp_udphdr { u_short uh_sport; /* source port */ u_short uh_dport; /* destination port */ short uh_ulen; /* udp length */ u_short uh_sum; /* udp checksum */ }; struct kdp_udpiphdr { struct kdp_ipovly ui_i; /* overlaid ip structure */ struct kdp_udphdr ui_u; /* udp header */ }; #define ui_next ui_i.ih_next #define ui_prev ui_i.ih_prev #define ui_x1 ui_i.ih_x1 #define ui_pr ui_i.ih_pr #define ui_len ui_i.ih_len #define ui_src ui_i.ih_src #define ui_dst ui_i.ih_dst #define ui_sport ui_u.uh_sport #define ui_dport ui_u.uh_dport #define ui_ulen ui_u.uh_ulen #define ui_sum ui_u.uh_sum struct kdp_ip { union { uint32_t ip_w; struct { unsigned int #ifdef __LITTLE_ENDIAN__ ip_xhl:4, /* header length */ ip_xv:4, /* version */ ip_xtos:8, /* type of service */ ip_xlen:16; /* total length */ #endif #ifdef __BIG_ENDIAN__ ip_xv:4, /* version */ ip_xhl:4, /* header length */ ip_xtos:8, /* type of service */ ip_xlen:16; /* total length */ #endif } ip_x; } ip_vhltl; u_short ip_id; /* identification */ short ip_off; /* fragment offset field */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct kdp_in_addr ip_src, ip_dst; /* source and dest address */ }; #define ip_v ip_vhltl.ip_x.ip_xv #define ip_hl ip_vhltl.ip_x.ip_xhl #define ip_tos ip_vhltl.ip_x.ip_xtos #define ip_len ip_vhltl.ip_x.ip_xlen #define IPPROTO_UDP 17 #define IPVERSION 4 #define ETHERTYPE_IP 0x0800 /* IP protocol */ /* * Ethernet Address Resolution Protocol. * * See RFC 826 for protocol description. Structure below is adapted * to resolving internet addresses. Field names used correspond to * RFC 826. */ #define ETHERTYPE_ARP 0x0806 /* Addr. resolution protocol */ struct kdp_arphdr { u_short ar_hrd; /* format of hardware address */ #define ARPHRD_ETHER 1 /* ethernet hardware format */ #define ARPHRD_FRELAY 15 /* frame relay hardware format */ u_short ar_pro; /* format of protocol address */ u_char ar_hln; /* length of hardware address */ u_char ar_pln; /* length of protocol address */ u_short ar_op; /* one of: */ #define ARPOP_REQUEST 1 /* request to resolve address */ #define ARPOP_REPLY 2 /* response to previous request */ #define ARPOP_REVREQUEST 3 /* request protocol address given hardware */ #define ARPOP_REVREPLY 4 /* response giving protocol address */ #define ARPOP_INVREQUEST 8 /* request to identify peer */ #define ARPOP_INVREPLY 9 /* response identifying peer */ }; struct kdp_ether_arp { struct kdp_arphdr ea_hdr; /* fixed-size header */ u_char arp_sha[ETHER_ADDR_LEN]; /* sender hardware address */ u_char arp_spa[4]; /* sender protocol address */ u_char arp_tha[ETHER_ADDR_LEN]; /* target hardware address */ u_char arp_tpa[4]; /* target protocol address */ }; #define arp_hrd ea_hdr.ar_hrd #define arp_pro ea_hdr.ar_pro #define arp_hln ea_hdr.ar_hln #define arp_pln ea_hdr.ar_pln #define arp_op ea_hdr.ar_op #define ETHERMTU 1500 #define ETHERHDRSIZE 14 #define ETHERCRC 4 #define KDP_MAXPACKET (ETHERHDRSIZE + ETHERMTU + ETHERCRC) static struct { unsigned char data[KDP_MAXPACKET]; unsigned int off, len; boolean_t input; } pkt, saved_reply; struct kdp_manual_pkt manual_pkt; struct { struct { struct kdp_in_addr in; struct kdp_ether_addr ea; } loc; struct { struct kdp_in_addr in; struct kdp_ether_addr ea; } rmt; } adr; static const char *exception_message[] = { "Unknown", "Memory access", /* EXC_BAD_ACCESS */ "Failed instruction", /* EXC_BAD_INSTRUCTION */ "Arithmetic", /* EXC_ARITHMETIC */ "Emulation", /* EXC_EMULATION */ "Software", /* EXC_SOFTWARE */ "Breakpoint" /* EXC_BREAKPOINT */ }; volatile int kdp_flag = 0; boolean_t kdp_corezip_disabled = 0; kdp_send_t kdp_en_send_pkt; static kdp_receive_t kdp_en_recv_pkt; static kdp_link_t kdp_en_linkstatus; static kdp_mode_t kdp_en_setmode; #if CONFIG_SERIAL_KDP static void kdp_serial_send(void *rpkt, unsigned int rpkt_len); #define KDP_SERIAL_ENABLED() (kdp_en_send_pkt == kdp_serial_send) #else #define KDP_SERIAL_ENABLED() (0) #endif static uint32_t kdp_current_ip_address = 0; static struct kdp_ether_addr kdp_current_mac_address = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; static void *kdp_current_ifp; static void kdp_handler( void *); static uint32_t panic_server_ip = 0; static uint32_t parsed_router_ip = 0; static uint32_t router_ip = 0; static uint32_t target_ip = 0; static boolean_t save_ip_in_nvram = FALSE; static volatile boolean_t panicd_specified = FALSE; static boolean_t router_specified = FALSE; static boolean_t corename_specified = FALSE; static unsigned short panicd_port = CORE_REMOTE_PORT; static struct kdp_ether_addr etherbroadcastaddr = {.ether_addr_octet = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}; static struct kdp_ether_addr router_mac = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; static struct kdp_ether_addr destination_mac = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; static struct kdp_ether_addr temp_mac = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; static struct kdp_ether_addr current_resolved_MAC = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; static boolean_t flag_panic_dump_in_progress = FALSE; static boolean_t flag_router_mac_initialized = FALSE; static boolean_t flag_dont_abort_panic_dump = FALSE; static boolean_t flag_arp_resolved = FALSE; static unsigned int panic_timeout = 100000; static unsigned short last_panic_port = CORE_REMOTE_PORT; #define KDP_THROTTLE_VALUE (10ULL * NSEC_PER_SEC) uint32_t kdp_crashdump_pkt_size = 512; #define KDP_LARGE_CRASHDUMP_PKT_SIZE (1440 - 6 - sizeof(struct kdp_udpiphdr)) static char panicd_ip_str[20]; static char router_ip_str[20]; static char corename_str[100]; static unsigned int panic_block = 0; volatile unsigned int kdp_trigger_core_dump = 0; __private_extern__ volatile unsigned int flag_kdp_trigger_reboot = 0; extern unsigned int disableConsoleOutput; extern void kdp_call(void); void * kdp_get_interface(void); void kdp_set_gateway_mac(void *gatewaymac); void kdp_set_ip_and_mac_addresses(struct kdp_in_addr *ipaddr, struct kdp_ether_addr *); void kdp_set_interface(void *interface, const struct kdp_ether_addr *macaddr); void kdp_disable_arp(void); static void kdp_arp_reply(struct kdp_ether_arp *); static void kdp_process_arp_reply(struct kdp_ether_arp *); static boolean_t kdp_arp_resolve(uint32_t, struct kdp_ether_addr *); static volatile unsigned kdp_reentry_deadline; static uint32_t kdp_crashdump_feature_mask = KDP_FEATURE_LARGE_CRASHDUMPS | KDP_FEATURE_LARGE_PKT_SIZE; uint32_t kdp_feature_large_crashdumps, kdp_feature_large_pkt_size; char kdp_kernelversion_string[256]; static boolean_t gKDPDebug = FALSE; #define KDP_DEBUG(...) if (gKDPDebug) printf(__VA_ARGS__); #define SBLOCKSZ (2048) uint64_t kdp_dump_start_time = 0; uint64_t kdp_min_superblock_dump_time = ~1ULL; uint64_t kdp_max_superblock_dump_time = 0; uint64_t kdp_superblock_dump_time = 0; uint64_t kdp_superblock_dump_start_time = 0; 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); } /* only send/receive data if the link is up */ inline static void wait_for_link(void) { static int first = 0; if (!kdp_en_linkstatus) { return; } while (((*kdp_en_linkstatus)() & LINK_UP_STATUS) != LINK_UP_STATUS) { if (first) { continue; } first = 1; printf("Waiting for link to become available.\n"); kprintf("Waiting for link to become available.\n"); } } inline static void kdp_send_data(void *packet, unsigned int len) { wait_for_link(); (*kdp_en_send_pkt)(packet, len); } inline static void kdp_receive_data(void *packet, unsigned int *len, unsigned int timeout) { wait_for_link(); (*kdp_en_recv_pkt)(packet, len, timeout); } void kdp_register_link(kdp_link_t link, kdp_mode_t mode) { kdp_en_linkstatus = link; kdp_en_setmode = mode; } void kdp_unregister_link(__unused kdp_link_t link, __unused kdp_mode_t mode) { kdp_en_linkstatus = NULL; kdp_en_setmode = NULL; } void kdp_register_send_receive( kdp_send_t send, kdp_receive_t receive) { unsigned int debug = debug_boot_arg; if (kernel_debugging_restricted()) { return; } 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; } if (debug & DB_KERN_DUMP_ON_PANIC) { kdp_flag |= KDP_PANIC_DUMP_ENABLED; } if (debug & DB_KERN_DUMP_ON_NMI) { kdp_flag |= PANIC_CORE_ON_NMI; } if (debug & DB_DBG_POST_CORE) { kdp_flag |= DBG_POST_CORE; } if (debug & DB_PANICLOG_DUMP) { kdp_flag |= PANIC_LOG_DUMP; } kdp_corezip_disabled = (0 != (debug & DB_DISABLE_GZIP_CORE)); if (PE_parse_boot_argn("_panicd_ip", panicd_ip_str, sizeof(panicd_ip_str))) { panicd_specified = TRUE; } if ((debug & DB_REBOOT_POST_CORE) && (panicd_specified == TRUE)) { kdp_flag |= REBOOT_POST_CORE; } 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; } if (PE_parse_boot_argn("_panicd_corename", &corename_str, sizeof(corename_str))) { corename_specified = TRUE; } kdp_flag |= KDP_READY; current_debugger = KDP_CUR_DB; if ((kdp_current_ip_address != 0) && halt_in_debugger) { kdp_call(); halt_in_debugger = 0; } } void kdp_unregister_send_receive( __unused kdp_send_t send, __unused kdp_receive_t receive) { if (current_debugger == KDP_CUR_DB) { current_debugger = NO_CUR_DB; } kdp_flag &= ~KDP_READY; kdp_en_send_pkt = NULL; kdp_en_recv_pkt = NULL; } 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, void *dst ) { bcopy((char *)src, (char *)dst, sizeof(struct kdp_ether_addr)); } static unsigned short ip_sum( unsigned char *c, unsigned int hlen ) { unsigned int high, low, sum; high = low = 0; while (hlen-- > 0) { low += c[1] + c[3]; high += c[0] + c[2]; c += sizeof(int); } sum = (high << 8) + low; sum = (sum >> 16) + (sum & USHRT_MAX); sum = (sum > USHRT_MAX) ? sum - USHRT_MAX : sum; return (unsigned short)sum; } static void kdp_reply( unsigned short reply_port, const boolean_t sideband ) { struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; struct kdp_ip aligned_ip, *ip = &aligned_ip; struct kdp_in_addr tmp_ipaddr; struct kdp_ether_addr tmp_enaddr; struct kdp_ether_header *eh = NULL; if (!pkt.input) { kdp_panic("kdp_reply: no input packet"); } /* Packet size cannot be larger than the static space allocated for it. */ if (pkt.len > KDP_MAXPACKET) { kdp_panic("kdp_send: packet too large (%u > %d)", pkt.len, KDP_MAXPACKET); } pkt.off -= (unsigned int)sizeof(struct kdp_udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_short)pkt.len + sizeof(struct kdp_udphdr)); tmp_ipaddr = ui->ui_src; ui->ui_src = ui->ui_dst; ui->ui_dst = tmp_ipaddr; ui->ui_sport = htons(KDP_REMOTE_PORT); ui->ui_dport = reply_port; ui->ui_ulen = ui->ui_len; ui->ui_sum = 0; #if DO_ALIGN bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif ip->ip_len = htons((ushort_t)(sizeof(struct kdp_udpiphdr) + pkt.len)); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); ip->ip_hl = sizeof(struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); #if DO_ALIGN bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif pkt.len += (unsigned int)sizeof(struct kdp_udpiphdr); pkt.off -= (unsigned int)sizeof(struct kdp_ether_header); eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; enaddr_copy(eh->ether_shost, &tmp_enaddr); enaddr_copy(eh->ether_dhost, eh->ether_shost); enaddr_copy(&tmp_enaddr, eh->ether_dhost); eh->ether_type = htons(ETHERTYPE_IP); pkt.len += (unsigned int)sizeof(struct kdp_ether_header); // save reply for possible retransmission if (!sideband) { bcopy((char *)&pkt, (char *)&saved_reply, sizeof(saved_reply)); } kdp_send_data(&pkt.data[pkt.off], pkt.len); // increment expected sequence number if (!sideband) { exception_seq++; } } static void kdp_send( unsigned short remote_port ) { struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; struct kdp_ip aligned_ip, *ip = &aligned_ip; struct kdp_ether_header *eh; if (pkt.input) { kdp_panic("kdp_send: no input packet"); } /* Packet size cannot be larger than the static space allocated for it. */ if (pkt.len > KDP_MAXPACKET) { kdp_panic("kdp_send: packet too large (%u > %d)", pkt.len, KDP_MAXPACKET); } pkt.off -= (unsigned int)sizeof(struct kdp_udpiphdr); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_short)pkt.len + sizeof(struct kdp_udphdr)); ui->ui_src = adr.loc.in; ui->ui_dst = adr.rmt.in; ui->ui_sport = htons(KDP_REMOTE_PORT); ui->ui_dport = remote_port; ui->ui_ulen = ui->ui_len; ui->ui_sum = 0; #if DO_ALIGN bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif ip->ip_len = htons((ushort_t)(sizeof(struct kdp_udpiphdr) + pkt.len)); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); ip->ip_hl = sizeof(struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); #if DO_ALIGN bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif pkt.len += (unsigned int)sizeof(struct kdp_udpiphdr); pkt.off -= (unsigned int)sizeof(struct kdp_ether_header); eh = (struct kdp_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 += (unsigned int)sizeof(struct kdp_ether_header); kdp_send_data(&pkt.data[pkt.off], pkt.len); } inline static void debugger_if_necessary(void) { if ((current_debugger == KDP_CUR_DB) && halt_in_debugger) { kdp_call(); halt_in_debugger = 0; } } /* We don't interpret this pointer, we just give it to the bsd stack * so it can decide when to set the MAC and IP info. We'll * early initialize the MAC/IP info if we can so that we can use * KDP early in boot. These values may subsequently get over-written * when the interface gets initialized for real. */ void kdp_set_interface(void *ifp, const struct kdp_ether_addr *macaddr) { char kdpstr[80]; struct kdp_in_addr addr = { .s_addr = 0 }; unsigned int len; kdp_current_ifp = ifp; if (PE_parse_boot_argn("kdp_ip_addr", kdpstr, sizeof(kdpstr))) { /* look for a static ip address */ if (inet_aton(kdpstr, &addr) == FALSE) { goto done; } goto config_network; } /* use saved ip address */ save_ip_in_nvram = TRUE; len = sizeof(kdpstr); if (PEReadNVRAMProperty("_kdp_ipstr", kdpstr, &len) == FALSE) { goto done; } kdpstr[len < sizeof(kdpstr) ? len : sizeof(kdpstr) - 1] = '\0'; if (inet_aton(kdpstr, &addr) == FALSE) { goto done; } config_network: kdp_current_ip_address = addr.s_addr; if (macaddr) { kdp_current_mac_address = *macaddr; } /* we can't drop into the debugger at this point because the * link will likely not be up. when getDebuggerLinkStatus() support gets * added to the appropriate network drivers, adding the * following will enable this capability: * debugger_if_necessary(); */ done: return; } void * kdp_get_interface(void) { return kdp_current_ifp; } void kdp_set_ip_and_mac_addresses( struct kdp_in_addr *ipaddr, struct kdp_ether_addr *macaddr) { static uint64_t last_time = (uint64_t) -1; static uint64_t throttle_val = 0; uint64_t cur_time; char addr[16]; if (kdp_current_ip_address == ipaddr->s_addr) { goto done; } /* don't replace if serial debugging is configured */ if (!KDP_SERIAL_ENABLED() || (kdp_current_ip_address != KDP_SERIAL_IPADDR)) { kdp_current_mac_address = *macaddr; kdp_current_ip_address = ipaddr->s_addr; } if (save_ip_in_nvram == FALSE) { goto done; } if (inet_ntoa_r(*ipaddr, addr, sizeof(addr)) == NULL) { goto done; } /* throttle writes if needed */ if (!throttle_val) { nanoseconds_to_absolutetime(KDP_THROTTLE_VALUE, &throttle_val); } cur_time = mach_absolute_time(); if (last_time == (uint64_t) -1 || ((cur_time - last_time) > throttle_val)) { PEWriteNVRAMProperty("_kdp_ipstr", addr, (const unsigned int) strlen(addr)); } last_time = cur_time; done: debugger_if_necessary(); } void kdp_set_gateway_mac(void *gatewaymac) { router_mac = *(struct kdp_ether_addr *)gatewaymac; flag_router_mac_initialized = TRUE; } struct kdp_ether_addr kdp_get_mac_addr(void) { return kdp_current_mac_address; } unsigned int kdp_get_ip_address(void) { return (unsigned int)kdp_current_ip_address; } void kdp_disable_arp(void) { kdp_flag &= ~(DB_ARP); } static void kdp_arp_dispatch(void) { struct kdp_ether_arp aligned_ea, *ea = &aligned_ea; unsigned arp_header_offset; arp_header_offset = (unsigned)sizeof(struct kdp_ether_header) + pkt.off; memcpy((void *)ea, (void *)&pkt.data[arp_header_offset], sizeof(*ea)); switch (ntohs(ea->arp_op)) { case ARPOP_REQUEST: kdp_arp_reply(ea); break; case ARPOP_REPLY: kdp_process_arp_reply(ea); break; default: return; } } static void kdp_process_arp_reply(struct kdp_ether_arp *ea) { /* Are we interested in ARP replies? */ if (flag_arp_resolved == TRUE) { return; } /* Did we receive a reply from the right source? */ if (((struct kdp_in_addr *)(ea->arp_spa))->s_addr != target_ip) { return; } flag_arp_resolved = TRUE; current_resolved_MAC = *(struct kdp_ether_addr *) (ea->arp_sha); return; } /* ARP responses are enabled when the DB_ARP bit of the debug boot arg * is set. */ static void kdp_arp_reply(struct kdp_ether_arp *ea) { struct kdp_ether_header *eh; struct kdp_in_addr isaddr, itaddr, myaddr; struct kdp_ether_addr my_enaddr; eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; pkt.off += (unsigned int)sizeof(struct kdp_ether_header); if (ntohs(ea->arp_op) != ARPOP_REQUEST) { return; } myaddr.s_addr = kdp_get_ip_address(); my_enaddr = kdp_get_mac_addr(); if ((ntohl(myaddr.s_addr) == 0) || ((my_enaddr.ether_addr_octet[0] & 0xff) == 0 && (my_enaddr.ether_addr_octet[1] & 0xff) == 0 && (my_enaddr.ether_addr_octet[2] & 0xff) == 0 && (my_enaddr.ether_addr_octet[3] & 0xff) == 0 && (my_enaddr.ether_addr_octet[4] & 0xff) == 0 && (my_enaddr.ether_addr_octet[5] & 0xff) == 0 )) { return; } (void)memcpy((void *)&isaddr, (void *)ea->arp_spa, sizeof(isaddr)); (void)memcpy((void *)&itaddr, (void *)ea->arp_tpa, sizeof(itaddr)); if (itaddr.s_addr == myaddr.s_addr) { (void)memcpy((void *)ea->arp_tha, (void *)ea->arp_sha, sizeof(ea->arp_sha)); (void)memcpy((void *)ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha)); (void)memcpy((void *)ea->arp_tpa, (void *) ea->arp_spa, sizeof(ea->arp_spa)); (void)memcpy((void *)ea->arp_spa, (void *) &itaddr, sizeof(ea->arp_spa)); ea->arp_op = htons(ARPOP_REPLY); ea->arp_pro = htons(ETHERTYPE_IP); (void)memcpy(eh->ether_dhost, ea->arp_tha, sizeof(eh->ether_dhost)); (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 -= (unsigned int)sizeof(struct kdp_ether_header); /* pkt.len is still the length we want, ether_header+ether_arp */ kdp_send_data(&pkt.data[pkt.off], pkt.len); } } static void kdp_poll(void) { struct kdp_ether_header *eh = NULL; struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; struct kdp_ip aligned_ip, *ip = &aligned_ip; static int msg_printed; if (pkt.input) { kdp_panic("kdp_poll"); } if (!kdp_en_recv_pkt || !kdp_en_send_pkt) { if (msg_printed == 0) { msg_printed = 1; printf("kdp_poll: no debugger device\n"); } return; } pkt.off = pkt.len = 0; kdp_receive_data(pkt.data, &pkt.len, 3 /* ms */); if (pkt.len == 0) { return; } if (pkt.len >= sizeof(struct kdp_ether_header)) { eh = (struct kdp_ether_header *)&pkt.data[pkt.off]; if (kdp_flag & KDP_ARP) { if (ntohs(eh->ether_type) == ETHERTYPE_ARP) { kdp_arp_dispatch(); return; } } } if (pkt.len < (sizeof(struct kdp_ether_header) + sizeof(struct kdp_udpiphdr))) { return; } pkt.off += (unsigned int)sizeof(struct kdp_ether_header); if (ntohs(eh->ether_type) != ETHERTYPE_IP) { return; } #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif pkt.off += (unsigned int)sizeof(struct kdp_udpiphdr); if (ui->ui_pr != IPPROTO_UDP) { return; } if (ip->ip_hl > (sizeof(struct kdp_ip) >> 2)) { return; } if (ntohs(ui->ui_dport) != KDP_REMOTE_PORT) { if (panicd_port == (ntohs(ui->ui_dport)) && flag_panic_dump_in_progress) { last_panic_port = ui->ui_sport; } else { return; } } /* If we receive a kernel debugging packet whilst a * core dump is in progress, abort the transfer and * enter the debugger if not told otherwise. */ else if (flag_panic_dump_in_progress) { if (!flag_dont_abort_panic_dump) { abort_panic_transfer(); } return; } if (!kdp.is_conn && !flag_panic_dump_in_progress) { enaddr_copy(eh->ether_dhost, &adr.loc.ea); adr.loc.in = ui->ui_dst; enaddr_copy(eh->ether_shost, &adr.rmt.ea); adr.rmt.in = ui->ui_src; } /* * Calculate kdp packet length. */ pkt.len = ntohs((u_short)ui->ui_ulen) - (unsigned int)sizeof(struct kdp_udphdr); pkt.input = TRUE; } /* Create and transmit an ARP resolution request for the target IP address. * This is modeled on ether_inet_arp()/RFC 826. */ static void transmit_ARP_request(uint32_t ip_addr) { struct kdp_ether_header *eh = (struct kdp_ether_header *) &pkt.data[0]; struct kdp_ether_arp *ea = (struct kdp_ether_arp *) &pkt.data[sizeof(struct kdp_ether_header)]; KDP_DEBUG("Transmitting ARP request\n"); /* Populate the ether_header */ eh->ether_type = htons(ETHERTYPE_ARP); enaddr_copy(&kdp_current_mac_address, eh->ether_shost); enaddr_copy(ðerbroadcastaddr, eh->ether_dhost); /* Populate the ARP header */ ea->arp_pro = htons(ETHERTYPE_IP); ea->arp_hln = sizeof(ea->arp_sha); ea->arp_pln = sizeof(ea->arp_spa); ea->arp_hrd = htons(ARPHRD_ETHER); ea->arp_op = htons(ARPOP_REQUEST); /* Target fields */ enaddr_copy(ðerbroadcastaddr, ea->arp_tha); memcpy(ea->arp_tpa, (void *) &ip_addr, sizeof(ip_addr)); /* Source fields */ enaddr_copy(&kdp_current_mac_address, ea->arp_sha); memcpy(ea->arp_spa, (void *) &kdp_current_ip_address, sizeof(kdp_current_ip_address)); pkt.off = 0; pkt.len = sizeof(struct kdp_ether_header) + sizeof(struct kdp_ether_arp); /* Transmit */ kdp_send_data(&pkt.data[pkt.off], pkt.len); } static boolean_t kdp_arp_resolve(uint32_t arp_target_ip, struct kdp_ether_addr *resolved_MAC) { int poll_count = 256; /* ~770 ms modulo broadcast/delayed traffic? */ char tretries = 0; #define NUM_ARP_TX_RETRIES 5 target_ip = arp_target_ip; flag_arp_resolved = FALSE; TRANSMIT_RETRY: pkt.off = pkt.len = 0; tretries++; if (tretries >= NUM_ARP_TX_RETRIES) { return FALSE; } KDP_DEBUG("ARP TX attempt #%d \n", tretries); transmit_ARP_request(arp_target_ip); while (!pkt.input && !flag_arp_resolved && flag_panic_dump_in_progress && --poll_count) { kdp_poll(); } if (flag_arp_resolved) { *resolved_MAC = current_resolved_MAC; return TRUE; } if (!flag_panic_dump_in_progress || pkt.input) { /* we received a debugging packet, bail*/ printf("Received a debugger packet,transferring control to debugger\n"); /* Indicate that we should wait in the debugger when we return */ kdp_flag |= DBG_POST_CORE; pkt.input = FALSE; return FALSE; } else { /* We timed out */ if (0 == poll_count) { poll_count = 256; goto TRANSMIT_RETRY; } } return FALSE; } static void kdp_handler( void *saved_state ) { unsigned short reply_port; kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; kdp.saved_state = saved_state; // see comment in kdp_raise_exception do { while (!pkt.input) { kdp_poll(); } #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); #else hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; #endif // ignore replies -- we're not expecting them anyway. if (hdr->is_reply) { goto again; } if (hdr->request == KDP_REATTACH) { exception_seq = hdr->seq; } // check for retransmitted request if (hdr->seq == (exception_seq - 1)) { /* retransmit last reply */ kdp_send_data(&saved_reply.data[saved_reply.off], saved_reply.len); goto again; } else if ((hdr->seq != exception_seq) && (hdr->request != KDP_CONNECT)) { printf("kdp: bad sequence %d (want %d)\n", hdr->seq, exception_seq); 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 */ int packet_length = manual_pkt.len; kdp_packet((unsigned char *)&manual_pkt.data, &packet_length, &manual_port_unused); manual_pkt.len = packet_length; } manual_pkt.input = 0; } if (kdp_packet((unsigned char*)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&reply_port)) { boolean_t sideband = FALSE; /* if it's an already connected error message, * send a sideband reply for that. for successful connects, * make sure the sequence number is correct. */ if (hdr->request == KDP_CONNECT) { kdp_connect_reply_t *rp = (kdp_connect_reply_t *) &pkt.data[pkt.off]; kdp_error_t err = rp->error; if (err == KDPERR_NO_ERROR) { exception_seq = hdr->seq; } else if (err == KDPERR_ALREADY_CONNECTED) { sideband = TRUE; } } kdp_reply(reply_port, sideband); } again: pkt.input = FALSE; } while (kdp.is_halted); } static void kdp_connection_wait(void) { unsigned short reply_port; struct kdp_ether_addr kdp_mac_addr = kdp_get_mac_addr(); unsigned int ip_addr = ntohl(kdp_get_ip_address()); /* * Do both a printf() and a kprintf() of the MAC and IP so that * they will print out on headless machines but not be added to * the panic.log */ if (KDP_SERIAL_ENABLED()) { printf("Using serial KDP.\n"); kprintf("Using serial KDP.\n"); } else { printf("ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", kdp_mac_addr.ether_addr_octet[0] & 0xff, kdp_mac_addr.ether_addr_octet[1] & 0xff, kdp_mac_addr.ether_addr_octet[2] & 0xff, kdp_mac_addr.ether_addr_octet[3] & 0xff, kdp_mac_addr.ether_addr_octet[4] & 0xff, kdp_mac_addr.ether_addr_octet[5] & 0xff); kprintf("ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", kdp_mac_addr.ether_addr_octet[0] & 0xff, kdp_mac_addr.ether_addr_octet[1] & 0xff, kdp_mac_addr.ether_addr_octet[2] & 0xff, kdp_mac_addr.ether_addr_octet[3] & 0xff, kdp_mac_addr.ether_addr_octet[4] & 0xff, kdp_mac_addr.ether_addr_octet[5] & 0xff); printf("ip address: %u.%u.%u.%u\n", (ip_addr & 0xff000000) >> 24, (ip_addr & 0xff0000) >> 16, (ip_addr & 0xff00) >> 8, (ip_addr & 0xff)); kprintf("ip address: %u.%u.%u.%u\n", (ip_addr & 0xff000000) >> 24, (ip_addr & 0xff0000) >> 16, (ip_addr & 0xff00) >> 8, (ip_addr & 0xff)); } printf("\nWaiting for remote debugger connection.\n"); kprintf("\nWaiting for remote debugger connection.\n"); if (reattach_wait == 0) { if ((kdp_flag & KDP_GETC_ENA) && (0 != kdp_getc())) { printf("Options..... Type\n"); printf("------------ ----\n"); printf("continue.... 'c'\n"); printf("reboot...... 'r'\n"); } } else { reattach_wait = 0; } exception_seq = 0; do { kdp_hdr_t aligned_hdr, *hdr = &aligned_hdr; while (!pkt.input) { if (kdp_flag & KDP_GETC_ENA) { switch (kdp_getc()) { case 'c': printf("Continuing...\n"); return; case 'r': printf("Rebooting...\n"); kdp_machine_reboot(); break; default: break; } } kdp_poll(); } #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)hdr, sizeof(*hdr)); #else hdr = (kdp_hdr_t *)&pkt.data[pkt.off]; #endif if (hdr->request == KDP_HOSTREBOOT) { kdp_machine_reboot(); /* should not return! */ } if (((hdr->request == KDP_CONNECT) || (hdr->request == KDP_REATTACH)) && !hdr->is_reply && (hdr->seq == exception_seq)) { if (kdp_packet((unsigned char *)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&reply_port)) { kdp_reply(reply_port, FALSE); } if (hdr->request == KDP_REATTACH) { reattach_wait = 0; hdr->request = KDP_DISCONNECT; exception_seq = 0; } } pkt.input = FALSE; } while (!kdp.is_conn); if (current_debugger == KDP_CUR_DB) { active_debugger = 1; } printf("Connected to remote debugger.\n"); kprintf("Connected to remote debugger.\n"); } static void kdp_send_exception( unsigned int exception, unsigned int code, unsigned int subcode ) { unsigned short remote_port; unsigned int timeout_count = 100; unsigned int poll_timeout; do { pkt.off = sizeof(struct kdp_ether_header) + sizeof(struct kdp_udpiphdr); kdp_exception((unsigned char *)&pkt.data[pkt.off], (int *)&pkt.len, (unsigned short *)&remote_port, (unsigned int)exception, (unsigned int)code, (unsigned int)subcode); kdp_send(remote_port); poll_timeout = 50; while (!pkt.input && poll_timeout) { kdp_poll(); poll_timeout--; } if (pkt.input) { if (!kdp_exception_ack(&pkt.data[pkt.off], pkt.len)) { pkt.input = FALSE; } } pkt.input = FALSE; if (kdp.exception_ack_needed) { kdp_us_spin(250000); } } while (kdp.exception_ack_needed && timeout_count--); if (kdp.exception_ack_needed) { // give up & disconnect printf("kdp: exception ack timeout\n"); if (current_debugger == KDP_CUR_DB) { active_debugger = 0; } kdp_reset(); } } static void kdp_debugger_loop( unsigned int exception, unsigned int code, unsigned int subcode, void *saved_state) { int index; if (saved_state == 0) { printf("kdp_raise_exception with NULL state\n"); } index = exception; if (exception != EXC_BREAKPOINT) { if (exception > EXC_BREAKPOINT || exception < EXC_BAD_ACCESS) { index = 0; } printf("%s exception (%x,%x,%x)\n", exception_message[index], exception, code, subcode); } kdp_sync_cache(); /* XXX WMG it seems that sometimes it doesn't work to let kdp_handler * 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 (kdp_en_setmode) { (*kdp_en_setmode)(TRUE); /* enabling link mode */ } if (pkt.input) { kdp_panic("kdp_raise_exception"); } if (((kdp_flag & KDP_PANIC_DUMP_ENABLED) || (kdp_flag & PANIC_LOG_DUMP)) && panic_active()) { kdp_panic_dump(); if (kdp_flag & REBOOT_POST_CORE && dumped_kernel_core()) { kdp_machine_reboot(); } } else { if ((kdp_flag & PANIC_CORE_ON_NMI) && !panic_active() && !kdp.is_conn) { disableConsoleOutput = FALSE; kdp_panic_dump(); if (kdp_flag & REBOOT_POST_CORE && dumped_kernel_core()) { kdp_machine_reboot(); } if (!(kdp_flag & DBG_POST_CORE)) { goto exit_debugger_loop; } } } again: if (!kdp.is_conn) { kdp_connection_wait(); } else { kdp_send_exception(exception, code, subcode); if (kdp.exception_ack_needed) { kdp.exception_ack_needed = FALSE; kdp_remove_all_breakpoints(); printf("Remote debugger disconnected.\n"); } } if (kdp.is_conn) { kdp.is_halted = TRUE; /* XXX */ kdp_handler(saved_state); if (!kdp.is_conn) { kdp_remove_all_breakpoints(); printf("Remote debugger disconnected.\n"); } } /* Allow triggering a panic core dump when connected to the machine * Continuing after setting kdp_trigger_core_dump should do the * trick. */ if (1 == kdp_trigger_core_dump) { kdp_flag |= KDP_PANIC_DUMP_ENABLED; kdp_panic_dump(); if (kdp_flag & REBOOT_POST_CORE && dumped_kernel_core()) { kdp_machine_reboot(); } kdp_trigger_core_dump = 0; } /* Trigger a reboot if the user has set this flag through the * debugger.Ideally, this would be done through the HOSTREBOOT packet * in the protocol,but that will need gdb support,and when it's * available, it should work automatically. */ if (1 == flag_kdp_trigger_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 %u milliseconds\n", kdp_reentry_deadline); kdp_reentry_deadline = 0; } kdp_sync_cache(); #if defined(__x86_64__) /* We only support returning from KDP on x86 */ if (reattach_wait == 1) #endif { goto again; } exit_debugger_loop: if (kdp_en_setmode) { (*kdp_en_setmode)(FALSE); /* link cleanup */ } } void kdp_reset(void) { 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; pkt.input = manual_pkt.input = FALSE; pkt.len = pkt.off = manual_pkt.len = 0; } static void kdp_setup_packet_size(void) { /* Override default packet size from boot arguments (if present). */ kdp_crashdump_pkt_size = KDP_LARGE_CRASHDUMP_PKT_SIZE; if (PE_parse_boot_argn("kdp_crashdump_pkt_size", &kdp_crashdump_pkt_size, sizeof(kdp_crashdump_pkt_size)) && (kdp_crashdump_pkt_size > KDP_LARGE_CRASHDUMP_PKT_SIZE)) { kdp_crashdump_pkt_size = KDP_LARGE_CRASHDUMP_PKT_SIZE; printf("kdp_crashdump_pkt_size is too large. Reverting to %u\n", kdp_crashdump_pkt_size); } } struct corehdr * create_panic_header(unsigned int request, const char *corename, unsigned length, unsigned int block) { struct kdp_udpiphdr aligned_ui, *ui = &aligned_ui; struct kdp_ip aligned_ip, *ip = &aligned_ip; struct kdp_ether_header *eh; struct corehdr *coreh; const char *mode = "octet"; size_t modelen = strlen(mode) + 1; size_t fmask_size = sizeof(KDP_FEATURE_MASK_STRING) + sizeof(kdp_crashdump_feature_mask); pkt.off = sizeof(struct kdp_ether_header); pkt.len = (unsigned int)(length + ((request == KDP_WRQ) ? modelen + fmask_size : 0) + (corename ? (strlen(corename) + 1): 0) + sizeof(struct corehdr)); #if DO_ALIGN bcopy((char *)&pkt.data[pkt.off], (char *)ui, sizeof(*ui)); #else ui = (struct kdp_udpiphdr *)&pkt.data[pkt.off]; #endif ui->ui_next = ui->ui_prev = 0; ui->ui_x1 = 0; ui->ui_pr = IPPROTO_UDP; ui->ui_len = htons((u_short)pkt.len + sizeof(struct kdp_udphdr)); 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); ui->ui_dport = ((request == KDP_WRQ) ? htons(panicd_port) : last_panic_port); ui->ui_ulen = ui->ui_len; ui->ui_sum = 0; #if DO_ALIGN bcopy((char *)ui, (char *)&pkt.data[pkt.off], sizeof(*ui)); bcopy((char *)&pkt.data[pkt.off], (char *)ip, sizeof(*ip)); #else ip = (struct kdp_ip *)&pkt.data[pkt.off]; #endif ip->ip_len = htons((ushort_t)(sizeof(struct kdp_udpiphdr) + pkt.len)); ip->ip_v = IPVERSION; ip->ip_id = htons(ip_id++); ip->ip_hl = sizeof(struct kdp_ip) >> 2; ip->ip_ttl = udp_ttl; ip->ip_sum = 0; ip->ip_sum = htons(~ip_sum((unsigned char *)ip, ip->ip_hl)); #if DO_ALIGN bcopy((char *)ip, (char *)&pkt.data[pkt.off], sizeof(*ip)); #endif pkt.len += (unsigned int)sizeof(struct kdp_udpiphdr); pkt.off += (unsigned int)sizeof(struct kdp_udpiphdr); coreh = (struct corehdr *) &pkt.data[pkt.off]; coreh->th_opcode = htons((u_short)request); if (request == KDP_WRQ) { char *cp = coreh->th_u.tu_rpl; /* Calculate available string space (remaining space after accounting for mandatory components). */ size_t length_remaining = (sizeof(pkt.data) - pkt.off - offsetof(struct corehdr, th_u) - sizeof(kdp_crashdump_feature_mask) - sizeof(kdp_crashdump_pkt_size)); /* account for the extra NULL characters that have been added historically */ int len = snprintf(cp, length_remaining, "%s%c%s%c%s%c", corename, '\0', mode, '\0', KDP_FEATURE_MASK_STRING, '\0'); if (len < 0) { kdb_printf("Unable to create core header packet.\n"); return NULL; } else if (len >= length_remaining) { kdb_printf("dumpinfo does not fit into KDP packet.\n"); return NULL; } cp += len; /* Append feature flags. The value is already converted with htonl in startup code. */ bcopy(&kdp_crashdump_feature_mask, cp, sizeof(kdp_crashdump_feature_mask)); cp += sizeof(kdp_crashdump_feature_mask); // Make sure we advertise the maximum supported packet size kdp_setup_packet_size(); uint32_t pktsz = htonl(kdp_crashdump_pkt_size); bcopy(&pktsz, cp, sizeof(uint32_t)); } else { coreh->th_block = htonl((unsigned int) block); } pkt.off -= (unsigned int)sizeof(struct kdp_udpiphdr); pkt.off -= (unsigned int)sizeof(struct kdp_ether_header); eh = (struct kdp_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 += (unsigned int)sizeof(struct kdp_ether_header); return coreh; } static int kdp_send_crashdump_seek(char *corename, uint64_t seek_off) { int panic_error; if (kdp_feature_large_crashdumps) { panic_error = kdp_send_crashdump_pkt(KDP_SEEK, corename, sizeof(seek_off), &seek_off); } else { uint32_t off = (uint32_t) seek_off; panic_error = kdp_send_crashdump_pkt(KDP_SEEK, corename, sizeof(off), &off); } if (panic_error < 0) { printf("kdp_send_crashdump_pkt failed with error %d\n", panic_error); return panic_error; } return KERN_SUCCESS; } int kdp_send_crashdump_data(unsigned int request, char *corename, uint64_t length, void * txstart) { int panic_error = 0; while ((length > 0) || !txstart) { uint64_t chunk = MIN(kdp_crashdump_pkt_size, length); panic_error = kdp_send_crashdump_pkt(request, corename, chunk, txstart); if (panic_error < 0) { printf("kdp_send_crashdump_pkt failed with error %d\n", panic_error); return panic_error; } if (!txstart) { break; } txstart = (void *)(((uintptr_t) txstart) + chunk); length -= chunk; } return KERN_SUCCESS; } uint32_t kdp_crashdump_short_pkt; int kdp_send_crashdump_pkt(unsigned int request, char *corename, uint64_t length, void *panic_data) { int poll_count; struct corehdr *th = NULL; char rretries, tretries; if (kdp_dump_start_time == 0) { kdp_dump_start_time = mach_absolute_time(); kdp_superblock_dump_start_time = kdp_dump_start_time; } tretries = rretries = 0; poll_count = KDP_CRASHDUMP_POLL_COUNT; pkt.off = pkt.len = 0; if (request == KDP_WRQ) { /* longer timeout for initial request */ poll_count += 1000; } TRANSMIT_RETRY: tretries++; if (tretries >= 15) { /* The crashdump server is unreachable for some reason. This could be a network * issue or, if we've been especially unfortunate, we've hit Radar 2760413, * which is a long standing problem with the IOKit polled mode network driver * shim which can prevent transmits/receives completely. */ printf("Cannot contact panic server, timing out.\n"); return -3; } if (tretries > 2) { printf("TX retry #%d ", tretries ); } th = create_panic_header(request, corename, (unsigned)length, panic_block); if (th == NULL) { printf("Unable to get panic header.\n"); return -4; } if (request == KDP_DATA) { /* as all packets are kdp_crashdump_pkt_size in length, the last packet * may end up with trailing bits. make sure that those * bits aren't confusing. */ if (length < kdp_crashdump_pkt_size) { kdp_crashdump_short_pkt++; memset(th->th_data + length, 'Y', kdp_crashdump_pkt_size - (uint32_t) length); } if (!kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)panic_data, (caddr_t) th->th_data, length)) { uintptr_t next_page = round_page((uintptr_t)panic_data); memset((caddr_t) th->th_data, 'X', (size_t)length); if ((next_page - ((uintptr_t) panic_data)) < length) { uint64_t resid = length - (next_page - (intptr_t) panic_data); if (!kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)next_page, (caddr_t) th->th_data + (length - resid), resid)) { memset((caddr_t) th->th_data + (length - resid), 'X', (size_t)resid); } } } } else if (request == KDP_SEEK) { if (kdp_feature_large_crashdumps) { *(uint64_t *) th->th_data = OSSwapHostToBigInt64((*(uint64_t *) panic_data)); } else { *(unsigned int *) th->th_data = htonl(*(unsigned int *) panic_data); } } kdp_send_data(&pkt.data[pkt.off], pkt.len); /* Listen for the ACK */ RECEIVE_RETRY: while (!pkt.input && flag_panic_dump_in_progress && poll_count) { kdp_poll(); poll_count--; } if (pkt.input) { pkt.input = FALSE; th = (struct corehdr *) &pkt.data[pkt.off]; 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; if (features64 & KDP_FEATURE_LARGE_PKT_SIZE) { kdp_feature_large_pkt_size = 1; } else { kdp_feature_large_pkt_size = 0; kdp_crashdump_pkt_size = 512; } printf("Protocol features: 0x%x\n", (uint32_t) features64); th->th_opcode = htons(KDP_ACK); } } if (ntohs(th->th_opcode) == KDP_ACK && ntohl(th->th_block) == panic_block) { } else { if (ntohs(th->th_opcode) == KDP_ERROR) { printf("Panic server returned error %u, retrying\n", ntohl(th->th_code)); poll_count = 1000; goto TRANSMIT_RETRY; } else if (ntohl(th->th_block) == (panic_block - 1)) { printf("RX retry "); if (++rretries > 1) { goto TRANSMIT_RETRY; } else { goto RECEIVE_RETRY; } } } } else if (!flag_panic_dump_in_progress) { /* we received a debugging packet, bail*/ printf("Received a debugger packet,transferring control to debugger\n"); /* Configure that if not set ..*/ kdp_flag |= DBG_POST_CORE; return -2; } else { /* We timed out */ if (0 == poll_count) { poll_count = 1000; kdp_us_spin((tretries % 4) * panic_timeout); /* capped linear backoff */ goto TRANSMIT_RETRY; } } if (!(++panic_block % SBLOCKSZ)) { uint64_t ctime; kdb_printf_unbuffered("."); ctime = mach_absolute_time(); kdp_superblock_dump_time = ctime - kdp_superblock_dump_start_time; kdp_superblock_dump_start_time = ctime; if (kdp_superblock_dump_time > kdp_max_superblock_dump_time) { kdp_max_superblock_dump_time = kdp_superblock_dump_time; } if (kdp_superblock_dump_time < kdp_min_superblock_dump_time) { kdp_min_superblock_dump_time = kdp_superblock_dump_time; } } if (request == KDP_EOF) { printf("\nTotal number of packets transmitted: %u\n", panic_block); printf("Avg. superblock transfer abstime 0x%llx\n", ((mach_absolute_time() - kdp_dump_start_time) / panic_block) * SBLOCKSZ); printf("Minimum superblock transfer abstime: 0x%llx\n", kdp_min_superblock_dump_time); printf("Maximum superblock transfer abstime: 0x%llx\n", kdp_max_superblock_dump_time); } return KERN_SUCCESS; } static int isdigit(char c) { return (c > 47) && (c < 58); } /* Horrid hack to extract xnu version if possible - a much cleaner approach * would be to have the integrator run a script which would copy the * xnu version into a string or an int somewhere at project submission * time - makes assumptions about sizeof(version), but will not fail if * it changes, but may be incorrect. */ /* 2006: Incorporated a change from Darwin user P. Lovell to extract * the minor kernel version numbers from the version string. */ static int kdp_get_xnu_version(char *versionbuf) { const char *versionpos; char vstr[20]; int retval = -1; char *vptr; size_t length_remaining = (sizeof(pkt.data) - pkt.off); strlcpy(vstr, "custom", 10); if (kdp_machine_vm_read((mach_vm_address_t)(uintptr_t)version, versionbuf, 128)) { versionbuf[127] = '\0'; versionpos = strnstr(versionbuf, "xnu-", 115); 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'; } retval = 0; } } strlcpy(versionbuf, vstr, length_remaining); return retval; } void kdp_set_dump_info(const uint32_t flags, const char *filename, const char *destipstr, const char *routeripstr, const uint32_t port) { uint32_t cmd; if (destipstr && (destipstr[0] != '\0')) { strlcpy(panicd_ip_str, destipstr, sizeof(panicd_ip_str)); panicd_specified = 1; } if (routeripstr && (routeripstr[0] != '\0')) { strlcpy(router_ip_str, routeripstr, sizeof(router_ip_str)); router_specified = 1; } if (filename && (filename[0] != '\0')) { strlcpy(corename_str, filename, sizeof(corename_str)); corename_specified = TRUE; } else { corename_specified = FALSE; } /* Accept only valid UDP port numbers. */ if (port && port <= USHRT_MAX) { panicd_port = (unsigned short)port; } else { kdb_printf("kdp_set_dump_info: Skipping invalid panicd port %u (using %d)\n", port, panicd_port); } /* on a disconnect, should we stay in KDP or not? */ noresume_on_disconnect = (flags & KDP_DUMPINFO_NORESUME) ? 1 : 0; if ((flags & KDP_DUMPINFO_DUMP) == 0) { return; } /* the rest of the commands can modify kdp_flags */ cmd = flags & KDP_DUMPINFO_MASK; if (cmd == KDP_DUMPINFO_DISABLE) { kdp_flag &= ~KDP_PANIC_DUMP_ENABLED; panicd_specified = 0; kdp_trigger_core_dump = 0; return; } kdp_flag &= ~REBOOT_POST_CORE; if (flags & KDP_DUMPINFO_REBOOT) { kdp_flag |= REBOOT_POST_CORE; } kdp_flag &= ~PANIC_LOG_DUMP; if (cmd == KDP_DUMPINFO_PANICLOG) { kdp_flag |= PANIC_LOG_DUMP; } kdp_flag &= ~SYSTEM_LOG_DUMP; if (cmd == KDP_DUMPINFO_SYSTEMLOG) { kdp_flag |= SYSTEM_LOG_DUMP; } /* trigger a dump */ kdp_flag |= DBG_POST_CORE; flag_dont_abort_panic_dump = (flags & KDP_DUMPINFO_NOINTR) ? TRUE : FALSE; reattach_wait = 1; disableConsoleOutput = 0; kdp_trigger_core_dump = 1; } void kdp_get_dump_info(kdp_dumpinfo_reply_t *rp) { if (panicd_specified) { strlcpy(rp->destip, panicd_ip_str, sizeof(rp->destip)); } else { rp->destip[0] = '\0'; } if (router_specified) { strlcpy(rp->routerip, router_ip_str, sizeof(rp->routerip)); } else { rp->routerip[0] = '\0'; } if (corename_specified) { strlcpy(rp->name, corename_str, sizeof(rp->name)); } else { rp->name[0] = '\0'; } rp->port = panicd_port; rp->type = 0; if (!panicd_specified) { rp->type |= KDP_DUMPINFO_DISABLE; } else if (kdp_flag & PANIC_LOG_DUMP) { rp->type |= KDP_DUMPINFO_PANICLOG; } else { rp->type |= KDP_DUMPINFO_CORE; } if (noresume_on_disconnect) { rp->type |= KDP_DUMPINFO_NORESUME; } } /* Primary dispatch routine for the system dump */ void kdp_panic_dump(void) { char coreprefix[10]; char coresuffix[4]; int panic_error; uint64_t abstime; uint32_t current_ip = ntohl((uint32_t)kdp_current_ip_address); if (flag_panic_dump_in_progress) { kdb_printf("System dump aborted.\n"); goto panic_dump_exit; } printf("Entering system dump routine\n"); if (!kdp_en_recv_pkt || !kdp_en_send_pkt) { kdb_printf("Error: No transport device registered for kernel crashdump\n"); return; } if (!panicd_specified) { kdb_printf("A dump server was not specified in the boot-args, terminating kernel core dump.\n"); goto panic_dump_exit; } flag_panic_dump_in_progress = TRUE; if (pkt.input) { kdp_panic("kdp_panic_dump: unexpected pending input packet"); } kdp_get_xnu_version((char *) &pkt.data[0]); if (!corename_specified) { coresuffix[0] = 0; /* Panic log bit takes precedence over core dump bit */ if ((debugger_panic_str != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { strlcpy(coreprefix, "paniclog", sizeof(coreprefix)); } else if (kdp_flag & SYSTEM_LOG_DUMP) { strlcpy(coreprefix, "systemlog", sizeof(coreprefix)); } else { strlcpy(coreprefix, "core", sizeof(coreprefix)); if (!kdp_corezip_disabled) { strlcpy(coresuffix, ".gz", sizeof(coresuffix)); } } abstime = mach_absolute_time(); pkt.data[20] = '\0'; snprintf(corename_str, sizeof(corename_str), "%s-%s-%u.%u.%u.%u-%x%s", coreprefix, &pkt.data[0], (current_ip & 0xff000000) >> 24, (current_ip & 0xff0000) >> 16, (current_ip & 0xff00) >> 8, (current_ip & 0xff), (unsigned int) (abstime & 0xffffffff), coresuffix); } if (0 == inet_aton(panicd_ip_str, (struct kdp_in_addr *) &panic_server_ip)) { kdb_printf("inet_aton() failed interpreting %s as a panic server IP\n", panicd_ip_str); } else { kdb_printf("Attempting connection to panic server configured at IP %s, port %d\n", panicd_ip_str, panicd_port); } destination_mac = router_mac; if (kdp_arp_resolve(panic_server_ip, &temp_mac)) { kdb_printf("Resolved %s's (or proxy's) link level address\n", panicd_ip_str); destination_mac = temp_mac; } else { if (!flag_panic_dump_in_progress) { goto panic_dump_exit; } if (router_specified) { if (0 == inet_aton(router_ip_str, (struct kdp_in_addr *) &parsed_router_ip)) { kdb_printf("inet_aton() failed interpreting %s as an IP\n", router_ip_str); } else { router_ip = parsed_router_ip; if (kdp_arp_resolve(router_ip, &temp_mac)) { destination_mac = temp_mac; kdb_printf("Routing through specified router IP %s (%u)\n", router_ip_str, router_ip); } } } } if (!flag_panic_dump_in_progress) { goto panic_dump_exit; } kdb_printf("Transmitting packets to link level address: %02x:%02x:%02x:%02x:%02x:%02x\n", destination_mac.ether_addr_octet[0] & 0xff, destination_mac.ether_addr_octet[1] & 0xff, destination_mac.ether_addr_octet[2] & 0xff, destination_mac.ether_addr_octet[3] & 0xff, destination_mac.ether_addr_octet[4] & 0xff, destination_mac.ether_addr_octet[5] & 0xff); kdb_printf("Kernel map size is %llu\n", (unsigned long long) get_vmmap_size(kernel_map)); kdb_printf("Sending write request for %s\n", corename_str); if ((panic_error = kdp_send_crashdump_pkt(KDP_WRQ, corename_str, 0, NULL)) < 0) { kdb_printf("kdp_send_crashdump_pkt failed with error %d\n", panic_error); goto panic_dump_exit; } /* Just the panic log requested */ if ((debugger_panic_str != (char *) 0) && (kdp_flag & PANIC_LOG_DUMP)) { kdb_printf_unbuffered("Transmitting panic log, please wait: "); kdp_send_crashdump_data(KDP_DATA, corename_str, debug_buf_ptr - debug_buf_base, debug_buf_base); 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; } /* maybe we wanted the systemlog */ if (kdp_flag & SYSTEM_LOG_DUMP) { long start_off = msgbufp->msg_bufx; long len; kdb_printf_unbuffered("Transmitting system log, please wait: "); if (start_off >= msgbufp->msg_bufr) { len = msgbufp->msg_size - start_off; kdp_send_crashdump_data(KDP_DATA, corename_str, len, msgbufp->msg_bufc + start_off); /* seek to remove trailing bytes */ kdp_send_crashdump_seek(corename_str, len); start_off = 0; } if (start_off != msgbufp->msg_bufr) { len = msgbufp->msg_bufr - start_off; kdp_send_crashdump_data(KDP_DATA, corename_str, len, msgbufp->msg_bufc + start_off); } kdp_send_crashdump_pkt(KDP_EOF, NULL, 0, ((void *) 0)); goto panic_dump_exit; } /* We want a core dump if we're here */ kern_dump(KERN_DUMP_NET); panic_dump_exit: abort_panic_transfer(); kdp_reset(); return; } void begin_panic_transfer(void) { flag_panic_dump_in_progress = TRUE; } void abort_panic_transfer(void) { flag_panic_dump_in_progress = FALSE; flag_dont_abort_panic_dump = FALSE; 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) { // printf("tx\n"); kdp_serialize_packet((unsigned char *)rpkt, rpkt_len, pal_serial_putc_nocr); } static void kdp_serial_receive(void *rpkt, unsigned int *rpkt_len, unsigned int timeout) { int readkar; uint64_t now, deadline; clock_interval_to_deadline(timeout, 1000 * 1000 /* milliseconds */, &deadline); // printf("rx\n"); for (clock_get_uptime(&now); now < deadline; clock_get_uptime(&now)) { readkar = pal_serial_getc(); if (readkar >= 0) { unsigned char *packet; // printf("got char %02x\n", readkar); if ((packet = kdp_unserialize_packet((unsigned char)readkar, rpkt_len))) { memcpy(rpkt, packet, *rpkt_len); return; } } } *rpkt_len = 0; } static boolean_t kdp_serial_setmode(boolean_t active) { if (active == FALSE) { /* leaving KDP */ return TRUE; } if (!needs_serial_init) { return TRUE; } pal_serial_init(); needs_serial_init = FALSE; return TRUE; } 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) { strlcpy(kdp_kernelversion_string, version, sizeof(kdp_kernelversion_string)); /* Relies on platform layer calling panic_init() before kdp_init() */ assert(startup_phase >= STARTUP_SUB_TUNABLES); if (kernel_uuid_string[0] != '\0') { /* * Update kdp_kernelversion_string with our UUID * generated at link time. */ strlcat(kdp_kernelversion_string, "; UUID=", sizeof(kdp_kernelversion_string)); strlcat(kdp_kernelversion_string, kernel_uuid_string, sizeof(kdp_kernelversion_string)); } debug_log_init(); #if defined(__x86_64__) || defined(__arm64__) if (vm_kernel_slide) { char KASLR_stext[19]; strlcat(kdp_kernelversion_string, "; stext=", sizeof(kdp_kernelversion_string)); snprintf(KASLR_stext, sizeof(KASLR_stext), "%p", (void *) vm_kernel_stext); strlcat(kdp_kernelversion_string, KASLR_stext, sizeof(kdp_kernelversion_string)); } #endif if (debug_boot_arg & DB_REBOOT_POST_CORE) { kdp_flag |= REBOOT_POST_CORE; } #if defined(__x86_64__) kdp_machine_init(); #endif kdp_timer_callout_init(); kdp_crashdump_feature_mask = htonl(kdp_crashdump_feature_mask); // Figure out the initial packet size kdp_setup_packet_size(); kdp_core_init(); #if EXCLAVES_COREDUMP sk_core_init(); #endif /* EXCLAVES_COREDUMP */ #if CONFIG_SERIAL_KDP char kdpname[80]; struct kdp_in_addr ipaddr; struct kdp_ether_addr macaddr; boolean_t kdp_match_name_found = PE_parse_boot_argn("kdp_match_name", kdpname, sizeof(kdpname)); boolean_t kdp_not_serial = kdp_match_name_found ? (strncmp(kdpname, "serial", sizeof(kdpname))) : TRUE; #if defined(__arm64__) //respect any custom debugger boot-args if (kdp_match_name_found && kdp_not_serial) { return; } #else /* defined(__arm64__) */ // serial must be explicitly requested if (!kdp_match_name_found || kdp_not_serial) { return; } #endif /* defined(__arm64__) */ #if defined(__arm64__) if (kdp_not_serial && PE_consistent_debug_enabled() && debug_boot_arg) { return; } else { printf("Serial requested, consistent debug disabled or debug boot arg not present, configuring debugging over serial\n"); } #endif /* defined(__arm64__) */ kprintf("Initializing serial KDP\n"); kdp_register_callout(kdp_serial_callout, NULL); kdp_register_link(NULL, kdp_serial_setmode); 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 = KDP_SERIAL_IPADDR; kdp_set_ip_and_mac_addresses(&ipaddr, &macaddr); #endif /* CONFIG_SERIAL_KDP */ } #else /* CONFIG_KDP_INTERACTIVE_DEBUGGING */ void kdp_init(void) { } #endif /* CONFIG_KDP_INTERACTIVE_DEBUGGING */ #if !(MACH_KDP && CONFIG_KDP_INTERACTIVE_DEBUGGING) static struct kdp_ether_addr kdp_current_mac_address = {.ether_addr_octet = {0, 0, 0, 0, 0, 0}}; /* XXX ugly forward declares to stop warnings */ void *kdp_get_interface(void); void kdp_set_ip_and_mac_addresses(struct kdp_in_addr *, struct kdp_ether_addr *); void kdp_set_gateway_mac(void *); void kdp_set_interface(void *); void kdp_register_send_receive(void *, void *); void kdp_unregister_send_receive(void *, void *); uint32_t kdp_stack_snapshot_bytes_traced(void); void kdp_register_send_receive(__unused void *send, __unused void *receive) { } void kdp_unregister_send_receive(__unused void *send, __unused void *receive) { } void * kdp_get_interface( void) { return (void *)0; } unsigned int kdp_get_ip_address(void ) { return 0; } struct kdp_ether_addr kdp_get_mac_addr(void) { return kdp_current_mac_address; } void kdp_set_ip_and_mac_addresses( __unused struct kdp_in_addr *ipaddr, __unused struct kdp_ether_addr *macaddr) { } void kdp_set_gateway_mac(__unused void *gatewaymac) { } void kdp_set_interface(__unused void *ifp) { } void kdp_register_link(__unused kdp_link_t link, __unused kdp_mode_t mode) { } void kdp_unregister_link(__unused kdp_link_t link, __unused kdp_mode_t mode) { } #endif /* !(MACH_KDP && CONFIG_KDP_INTERACTIVE_DEBUGGING) */ #if !CONFIG_KDP_INTERACTIVE_DEBUGGING extern __attribute__((noreturn)) void panic_spin_forever(void); __attribute__((noreturn)) void kdp_raise_exception( __unused unsigned int exception, __unused unsigned int code, __unused unsigned int subcode, __unused void *saved_state ) #else void kdp_raise_exception( unsigned int exception, unsigned int code, unsigned int subcode, void *saved_state ) #endif { #if defined(__arm64__) assert(!kernel_debugging_restricted()); #endif #if CONFIG_KDP_INTERACTIVE_DEBUGGING kdp_debugger_loop(exception, code, subcode, saved_state); #else /* CONFIG_KDP_INTERACTIVE_DEBUGGING */ assert(current_debugger != KDP_CUR_DB); panic_spin_forever(); #endif /* CONFIG_KDP_INTERACTIVE_DEBUGGING */ }