darwin-xnu/osfmk/kdp/kdp.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
   3 *
   4 * @APPLE_LICENSE_HEADER_START@
   5 * 
   6 * The contents of this file constitute Original Code as defined in and
   7 * are subject to the Apple Public Source License Version 1.1 (the
   8 * "License").  You may not use this file except in compliance with the
   9 * License.  Please obtain a copy of the License at
  10 * http://www.apple.com/publicsource and read it before using this file.
  11 * 
  12 * This Original Code and all software distributed under the License are
  13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
  17 * License for the specific language governing rights and limitations
  18 * under the License.
  19 * 
  20 * @APPLE_LICENSE_HEADER_END@
  21 */
  22
  23#include <mach/mach_types.h>
  24#include <kern/debug.h>
  25
  26#include <kdp/kdp_internal.h>
  27#include <kdp/kdp_private.h>
  28
  29#include <libsa/types.h>
  30
  31#include <string.h> /* bcopy */
  32
  33int kdp_vm_read( caddr_t, caddr_t, unsigned int);
  34int kdp_vm_write( caddr_t, caddr_t, unsigned int);
  35
  36#define DO_ALIGN        1       /* align all packet data accesses */
  37
  38#define KDP_TEST_HARNESS 0
  39#if KDP_TEST_HARNESS 
  40#define dprintf(x) kprintf x 
  41#else
  42#define dprintf(x)
  43#endif
  44
  45static kdp_dispatch_t
  46    dispatch_table[KDP_HOSTREBOOT - KDP_CONNECT +1] =
  47    {
  48/* 0 */ kdp_connect,
  49/* 1 */ kdp_disconnect,
  50/* 2 */ kdp_hostinfo,
  51/* 3 */ kdp_version,
  52/* 4 */ kdp_maxbytes,
  53/* 5 */ kdp_readmem,
  54/* 6 */ kdp_writemem,
  55/* 7 */ kdp_readregs,
  56/* 8 */ kdp_writeregs,
  57/* 9 */ kdp_unknown,
  58/* A */ kdp_unknown,
  59/* B */ kdp_suspend,
  60/* C */ kdp_resumecpus,
  61/* D */ kdp_unknown,
  62/* E */ kdp_unknown,
  63/* F */ kdp_breakpoint_set,
  64/*10 */ kdp_breakpoint_remove,
  65/*11 */ kdp_regions,
  66/*12 */ kdp_reattach,
  67/*13 */ kdp_reboot
  68    };
  69    
  70kdp_glob_t      kdp;
  71
  72
  73#define MAX_BREAKPOINTS 100
  74#define KDP_MAX_BREAKPOINTS 100
  75
  76#define BREAKPOINT_NOT_FOUND 101
  77#define BREAKPOINT_ALREADY_SET 102
  78
  79#define KDP_VERSION 10
  80
  81typedef struct{
  82  unsigned int address;
  83  unsigned int old_instruction;
  84} kdp_breakpoint_record_t;
  85
  86static kdp_breakpoint_record_t breakpoint_list[MAX_BREAKPOINTS];
  87static unsigned int breakpoints_initialized = 0;
  88
  89int reattach_wait = 0;
  90int noresume_on_disconnect = 0;
  91
  92boolean_t
  93kdp_packet(
  94    unsigned char       *pkt,
  95    int                 *len,
  96    unsigned short      *reply_port
  97)
  98{
  99    static unsigned     aligned_pkt[1538/sizeof(unsigned)+1]; // max ether pkt
 100    kdp_pkt_t           *rd = (kdp_pkt_t *)&aligned_pkt;
 101    int                 plen = *len;
 102    unsigned int        req;
 103    boolean_t           ret;
 104    
 105#if DO_ALIGN
 106    bcopy((char *)pkt, (char *)rd, sizeof(aligned_pkt));
 107#else
 108    rd = (kdp_pkt_t *)pkt;
 109#endif
 110    if (plen < sizeof (rd->hdr) || rd->hdr.len != plen) {
 111        printf("kdp_packet bad len pkt %d hdr %d\n", plen, rd->hdr.len);
 112
 113        return (FALSE);
 114    }
 115    
 116    if (rd->hdr.is_reply) {
 117        printf("kdp_packet reply recvd req %x seq %x\n",
 118            rd->hdr.request, rd->hdr.seq);
 119
 120        return (FALSE);  
 121    }
 122    
 123    req = rd->hdr.request;
 124    if ((req < KDP_CONNECT) || (req > KDP_HOSTREBOOT)) {
 125        printf("kdp_packet bad request %x len %d seq %x key %x\n",
 126            rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
 127
 128        return (FALSE);
 129    }
 130    
 131    ret = ((*dispatch_table[req - KDP_CONNECT])(rd, len, reply_port));
 132#if DO_ALIGN
 133    bcopy((char *)rd, (char *) pkt, *len);
 134#endif
 135    return ret;
 136}
 137
 138static boolean_t
 139kdp_unknown(
 140    kdp_pkt_t           *pkt,
 141    int                 *len,
 142    unsigned short      *reply_port
 143)
 144{
 145    kdp_pkt_t           *rd = (kdp_pkt_t *)pkt;
 146
 147    printf("kdp_unknown request %x len %d seq %x key %x\n",
 148        rd->hdr.request, rd->hdr.len, rd->hdr.seq, rd->hdr.key);
 149
 150    return (FALSE);
 151}
 152
 153static boolean_t
 154kdp_connect(
 155    kdp_pkt_t           *pkt,
 156    int                 *len,
 157    unsigned short      *reply_port
 158)
 159{
 160    kdp_connect_req_t   *rq = &pkt->connect_req;
 161    int                 plen = *len;
 162    kdp_connect_reply_t *rp = &pkt->connect_reply;
 163
 164    if (plen < sizeof (*rq))
 165        return (FALSE);
 166
 167    dprintf(("kdp_connect seq %x greeting %s\n", rq->hdr.seq, rq->greeting));
 168
 169    if (kdp.is_conn) {
 170        if (rq->hdr.seq == kdp.conn_seq)        /* duplicate request */
 171            rp->error = KDPERR_NO_ERROR;
 172        else
 173            rp->error = KDPERR_ALREADY_CONNECTED;
 174    }
 175    else { 
 176        kdp.reply_port = rq->req_reply_port;
 177        kdp.exception_port = rq->exc_note_port;
 178        kdp.is_conn = TRUE;
 179        kdp.conn_seq = rq->hdr.seq;
 180    
 181        rp->error = KDPERR_NO_ERROR;
 182    }
 183
 184    rp->hdr.is_reply = 1;
 185    rp->hdr.len = sizeof (*rp);
 186    
 187    *reply_port = kdp.reply_port;
 188    *len = rp->hdr.len;
 189    
 190    if (current_debugger == KDP_CUR_DB)    
 191        active_debugger=1;
 192
 193    return (TRUE);
 194}
 195
 196static boolean_t
 197kdp_disconnect(
 198    kdp_pkt_t           *pkt,
 199    int                 *len,
 200    unsigned short      *reply_port
 201)
 202{
 203    kdp_disconnect_req_t        *rq = &pkt->disconnect_req;
 204    int                         plen = *len;
 205    kdp_disconnect_reply_t      *rp = &pkt->disconnect_reply;
 206
 207    if (plen < sizeof (*rq))
 208        return (FALSE);
 209        
 210    if (!kdp.is_conn)
 211        return (FALSE);
 212
 213    dprintf(("kdp_disconnect\n"));
 214 
 215    *reply_port = kdp.reply_port;
 216
 217    kdp.reply_port = kdp.exception_port = 0;
 218    kdp.is_halted = kdp.is_conn = FALSE;
 219    kdp.exception_seq = kdp.conn_seq = 0;
 220
 221    if (noresume_on_disconnect == 1) {
 222        reattach_wait = 1;
 223        noresume_on_disconnect = 0;
 224    }
 225
 226    rp->hdr.is_reply = 1;
 227    rp->hdr.len = sizeof (*rp);
 228    
 229    *len = rp->hdr.len;
 230    
 231    if (current_debugger == KDP_CUR_DB)
 232        active_debugger=0;
 233
 234    return (TRUE);
 235}
 236
 237static boolean_t
 238kdp_reattach(
 239    kdp_pkt_t           *pkt,
 240    int                 *len,
 241    unsigned short      *reply_port
 242)
 243{
 244  kdp_reattach_req_t            *rq = &pkt->reattach_req;
 245  kdp_disconnect_reply_t        *rp = &pkt->disconnect_reply;
 246
 247  kdp.is_conn = TRUE;
 248  kdp_disconnect(pkt, len, reply_port);
 249  *reply_port = rq->req_reply_port;
 250  reattach_wait = 1;
 251  return (TRUE);
 252}
 253
 254static boolean_t
 255kdp_hostinfo(
 256    kdp_pkt_t           *pkt,
 257    int                 *len,
 258    unsigned short      *reply_port
 259)
 260{
 261    kdp_hostinfo_req_t  *rq = &pkt->hostinfo_req;
 262    int                 plen = *len;
 263    kdp_hostinfo_reply_t *rp = &pkt->hostinfo_reply;
 264
 265    if (plen < sizeof (*rq))
 266        return (FALSE);
 267
 268    rp->hdr.is_reply = 1;
 269    rp->hdr.len = sizeof (*rp);
 270
 271    kdp_machine_hostinfo(&rp->hostinfo);
 272
 273    *reply_port = kdp.reply_port;
 274    *len = rp->hdr.len;
 275    
 276    return (TRUE);
 277}
 278
 279static boolean_t
 280kdp_suspend(
 281    kdp_pkt_t           *pkt,
 282    int                 *len,
 283    unsigned short      *reply_port
 284)
 285{
 286    kdp_suspend_req_t   *rq = &pkt->suspend_req;
 287    int                 plen = *len;
 288    kdp_suspend_reply_t *rp = &pkt->suspend_reply;
 289
 290    if (plen < sizeof (*rq))
 291        return (FALSE);
 292
 293    rp->hdr.is_reply = 1;
 294    rp->hdr.len = sizeof (*rp);
 295
 296    dprintf(("kdp_suspend\n"));
 297
 298    kdp.is_halted = TRUE;
 299    
 300    *reply_port = kdp.reply_port;
 301    *len = rp->hdr.len;
 302    
 303    return (TRUE);
 304}
 305
 306static boolean_t
 307kdp_resumecpus(
 308    kdp_pkt_t           *pkt,
 309    int                 *len,
 310    unsigned short      *reply_port
 311)
 312{
 313    kdp_resumecpus_req_t        *rq = &pkt->resumecpus_req;
 314    int                 plen = *len;
 315    kdp_resumecpus_reply_t      *rp = &pkt->resumecpus_reply;
 316
 317    if (plen < sizeof (*rq))
 318        return (FALSE);
 319
 320    rp->hdr.is_reply = 1;
 321    rp->hdr.len = sizeof (*rp);
 322
 323    dprintf(("kdp_resumecpus %x\n", rq->cpu_mask));
 324    
 325    kdp.is_halted = FALSE;
 326    
 327    *reply_port = kdp.reply_port;
 328    *len = rp->hdr.len;
 329    
 330    return (TRUE);
 331}
 332
 333static boolean_t
 334kdp_writemem(
 335    kdp_pkt_t           *pkt,
 336    int                 *len,
 337    unsigned short      *reply_port
 338)
 339{
 340    kdp_writemem_req_t  *rq = &pkt->writemem_req;
 341    int                 plen = *len;
 342    kdp_writemem_reply_t *rp = &pkt->writemem_reply;
 343    int                 cnt;
 344
 345    if (plen < sizeof (*rq))
 346        return (FALSE);
 347
 348    if (rq->nbytes > MAX_KDP_DATA_SIZE)
 349        rp->error = KDPERR_BAD_NBYTES;
 350    else {
 351        dprintf(("kdp_writemem addr %x size %d\n", rq->address, rq->nbytes));
 352
 353        cnt = kdp_vm_write((caddr_t)rq->data, (caddr_t)rq->address, rq->nbytes);
 354        rp->error = KDPERR_NO_ERROR;
 355    }
 356
 357    rp->hdr.is_reply = 1;
 358    rp->hdr.len = sizeof (*rp);
 359
 360    *reply_port = kdp.reply_port;
 361    *len = rp->hdr.len;
 362    
 363    return (TRUE);
 364}
 365
 366static boolean_t
 367kdp_readmem(
 368    kdp_pkt_t           *pkt,
 369    int                 *len,
 370    unsigned short      *reply_port
 371)
 372{
 373    kdp_readmem_req_t   *rq = &pkt->readmem_req;
 374    int                 plen = *len;
 375    kdp_readmem_reply_t *rp = &pkt->readmem_reply;
 376    int                 cnt;
 377
 378    if (plen < sizeof (*rq))
 379        return (FALSE);
 380
 381    rp->hdr.is_reply = 1;
 382    rp->hdr.len = sizeof (*rp);
 383
 384    if (rq->nbytes > MAX_KDP_DATA_SIZE)
 385        rp->error = KDPERR_BAD_NBYTES;
 386    else {
 387        unsigned int    n = rq->nbytes;
 388
 389        dprintf(("kdp_readmem addr %x size %d\n", rq->address, rq->nbytes));
 390
 391        cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)rp->data, rq->nbytes);
 392        rp->error = KDPERR_NO_ERROR;
 393
 394        rp->hdr.len += cnt;
 395    }
 396
 397    *reply_port = kdp.reply_port;
 398    *len = rp->hdr.len;
 399    
 400    return (TRUE);
 401}
 402
 403static boolean_t
 404kdp_maxbytes(
 405    kdp_pkt_t           *pkt,
 406    int                 *len,
 407    unsigned short      *reply_port
 408)
 409{
 410    kdp_maxbytes_req_t  *rq = &pkt->maxbytes_req;
 411    int                 plen = *len;
 412    kdp_maxbytes_reply_t *rp = &pkt->maxbytes_reply;
 413
 414    if (plen < sizeof (*rq))
 415        return (FALSE);
 416
 417    rp->hdr.is_reply = 1;
 418    rp->hdr.len = sizeof (*rp);
 419
 420    dprintf(("kdp_maxbytes\n"));
 421
 422    rp->max_bytes = MAX_KDP_DATA_SIZE;
 423
 424    *reply_port = kdp.reply_port;
 425    *len = rp->hdr.len;
 426    
 427    return (TRUE);
 428}
 429
 430static boolean_t
 431kdp_version(
 432    kdp_pkt_t           *pkt,
 433    int                 *len,
 434    unsigned short      *reply_port
 435)
 436{
 437    kdp_version_req_t   *rq = &pkt->version_req;
 438    int                 plen = *len;
 439    kdp_version_reply_t *rp = &pkt->version_reply;
 440    kdp_region_t        *r;     
 441
 442    if (plen < sizeof (*rq))
 443        return (FALSE);
 444
 445    rp->hdr.is_reply = 1;
 446    rp->hdr.len = sizeof (*rp);
 447
 448    dprintf(("kdp_version\n"));
 449
 450    rp->version = KDP_VERSION;
 451#ifdef  __ppc__
 452    if (!(kdp_flag & KDP_BP_DIS))
 453      rp->feature = KDP_FEATURE_BP;
 454    else
 455      rp->feature = 0;
 456#else
 457    rp->feature = 0;
 458#endif
 459
 460    *reply_port = kdp.reply_port;
 461    *len = rp->hdr.len;
 462    
 463    return (TRUE);
 464}
 465
 466static boolean_t
 467kdp_regions(
 468    kdp_pkt_t           *pkt,
 469    int                 *len,
 470    unsigned short      *reply_port
 471)
 472{
 473    kdp_regions_req_t   *rq = &pkt->regions_req;
 474    int                 plen = *len;
 475    kdp_regions_reply_t *rp = &pkt->regions_reply;
 476    kdp_region_t        *r;     
 477
 478    if (plen < sizeof (*rq))
 479        return (FALSE);
 480
 481    rp->hdr.is_reply = 1;
 482    rp->hdr.len = sizeof (*rp);
 483
 484    dprintf(("kdp_regions\n"));
 485
 486    r = rp->regions;
 487    rp->nregions = 0;
 488
 489    (vm_offset_t)r->address = 0;
 490    r->nbytes = 0xffffffff;
 491
 492    r->protection = VM_PROT_ALL; r++; rp->nregions++;
 493    
 494    rp->hdr.len += rp->nregions * sizeof (kdp_region_t);
 495    
 496    *reply_port = kdp.reply_port;
 497    *len = rp->hdr.len;
 498    
 499    return (TRUE);
 500}
 501
 502static boolean_t
 503kdp_writeregs(
 504    kdp_pkt_t           *pkt,
 505    int                 *len,
 506    unsigned short      *reply_port
 507)
 508{
 509    kdp_writeregs_req_t *rq = &pkt->writeregs_req;
 510    int                 plen = *len;
 511    int                 size;
 512    kdp_writeregs_reply_t *rp = &pkt->writeregs_reply;
 513
 514    if (plen < sizeof (*rq))
 515        return (FALSE);
 516    
 517    size = rq->hdr.len - sizeof(kdp_hdr_t) - sizeof(unsigned int);
 518    rp->error = kdp_machine_write_regs(rq->cpu, rq->flavor, rq->data, &size);
 519
 520    rp->hdr.is_reply = 1;
 521    rp->hdr.len = sizeof (*rp);
 522    
 523    *reply_port = kdp.reply_port;
 524    *len = rp->hdr.len;
 525    
 526    return (TRUE);
 527}
 528
 529static boolean_t
 530kdp_readregs(
 531    kdp_pkt_t           *pkt,
 532    int                 *len,
 533    unsigned short      *reply_port
 534)
 535{
 536    kdp_readregs_req_t  *rq = &pkt->readregs_req;
 537    int                 plen = *len;
 538    kdp_readregs_reply_t *rp = &pkt->readregs_reply;
 539    int                 size;
 540
 541    if (plen < sizeof (*rq))
 542        return (FALSE);
 543
 544    rp->hdr.is_reply = 1;
 545    rp->hdr.len = sizeof (*rp);
 546    
 547    rp->error = kdp_machine_read_regs(rq->cpu, rq->flavor, rp->data, &size);
 548    rp->hdr.len += size;
 549    
 550    *reply_port = kdp.reply_port;
 551    *len = rp->hdr.len;
 552    
 553    return (TRUE);
 554}
 555
 556static boolean_t 
 557kdp_breakpoint_set(
 558    kdp_pkt_t           *pkt,
 559    int                 *len,
 560    unsigned short      *reply_port
 561)
 562{
 563  kdp_breakpoint_req_t  *rq = &pkt->breakpoint_req;
 564  kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
 565  int                   plen = *len;
 566  int                   cnt, i;
 567  unsigned int          old_instruction = 0;
 568  unsigned int breakinstr = kdp_ml_get_breakinsn();
 569
 570  if(breakpoints_initialized == 0)
 571    {
 572      for(i=0;(i < MAX_BREAKPOINTS); breakpoint_list[i].address=0, i++);
 573      breakpoints_initialized++;
 574    }
 575  if (plen < sizeof (*rq))
 576    return (FALSE);
 577  cnt = kdp_vm_read((caddr_t)rq->address, (caddr_t)(&old_instruction), sizeof(int));
 578
 579  if (old_instruction==breakinstr)
 580    {
 581      printf("A trap was already set at that address, not setting new breakpoint\n");
 582      rp->error = BREAKPOINT_ALREADY_SET;
 583      
 584      rp->hdr.is_reply = 1;
 585      rp->hdr.len = sizeof (*rp);
 586      *reply_port = kdp.reply_port;
 587      *len = rp->hdr.len;
 588
 589      return (TRUE);
 590    }
 591
 592  for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != 0); i++);
 593
 594  if (i == MAX_BREAKPOINTS)
 595    {
 596      rp->error = KDP_MAX_BREAKPOINTS; 
 597      
 598      rp->hdr.is_reply = 1;
 599      rp->hdr.len = sizeof (*rp);
 600      *reply_port = kdp.reply_port;
 601      *len = rp->hdr.len;
 602
 603      return (TRUE);
 604    }
 605  breakpoint_list[i].address =  rq->address;
 606  breakpoint_list[i].old_instruction = old_instruction;
 607
 608  cnt = kdp_vm_write((caddr_t)&breakinstr, (caddr_t)rq->address, sizeof(&breakinstr));
 609
 610  rp->error = KDPERR_NO_ERROR;
 611  rp->hdr.is_reply = 1;
 612  rp->hdr.len = sizeof (*rp);
 613  *reply_port = kdp.reply_port;
 614  *len = rp->hdr.len;
 615
 616  return (TRUE);
 617}
 618
 619static boolean_t
 620kdp_breakpoint_remove(
 621    kdp_pkt_t           *pkt,
 622    int                 *len,
 623    unsigned short      *reply_port
 624)
 625{
 626  kdp_breakpoint_req_t  *rq = &pkt->breakpoint_req;
 627  kdp_breakpoint_reply_t *rp = &pkt->breakpoint_reply;
 628  int                   plen = *len;
 629  int                   cnt,i;
 630
 631  if (plen < sizeof (*rq))
 632    return (FALSE);
 633
 634  for(i=0;(i < MAX_BREAKPOINTS) && (breakpoint_list[i].address != rq->address); i++);
 635  if (i == MAX_BREAKPOINTS)
 636    {
 637      rp->error = BREAKPOINT_NOT_FOUND; 
 638      rp->hdr.is_reply = 1;
 639      rp->hdr.len = sizeof (*rp);
 640      *reply_port = kdp.reply_port;
 641      *len = rp->hdr.len;
 642
 643      return (TRUE); /* Check if it needs to be FALSE in case of error */
 644    }
 645
 646  breakpoint_list[i].address = 0;
 647  cnt = kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)rq->address, sizeof(int));
 648  rp->error = KDPERR_NO_ERROR;
 649  rp->hdr.is_reply = 1;
 650  rp->hdr.len = sizeof (*rp);
 651  *reply_port = kdp.reply_port;
 652  *len = rp->hdr.len;
 653
 654  return (TRUE);
 655}
 656
 657boolean_t
 658kdp_remove_all_breakpoints()
 659{
 660  int i;
 661  boolean_t breakpoint_found = FALSE;
 662  
 663  if (breakpoints_initialized)
 664    {
 665      for(i=0;i < MAX_BREAKPOINTS; i++)
 666        {
 667          if (breakpoint_list[i].address)
 668            {
 669              kdp_vm_write((caddr_t)&(breakpoint_list[i].old_instruction), (caddr_t)breakpoint_list[i].address, sizeof(int));
 670              breakpoint_found = TRUE;
 671              breakpoint_list[i].address = 0;
 672            }
 673        }
 674      if (breakpoint_found)
 675       printf("kdp_remove_all_breakpoints: found extant breakpoints, removing them.\n");
 676    }
 677  return breakpoint_found;
 678}
 679
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.