linux-old/arch/s390x/kernel/gdb-stub.c
<<
>>
Prefs
   1/*
   2 *  arch/s390/kernel/gdb-stub.c
   3 *
   4 *  S390 version
   5 *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
   6 *    Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
   7 *
   8 *  Originally written by Glenn Engel, Lake Stevens Instrument Division
   9 *
  10 *  Contributed by HP Systems
  11 *
  12 *  Modified for SPARC by Stu Grossman, Cygnus Support.
  13 *
  14 *  Modified for Linux/MIPS (and MIPS in general) by Andreas Busse
  15 *  Send complaints, suggestions etc. to <andy@waldorf-gmbh.de>
  16 *
  17 *  Copyright (C) 1995 Andreas Busse
  18 */
  19
  20/*
  21 *  To enable debugger support, two things need to happen.  One, a
  22 *  call to set_debug_traps() is necessary in order to allow any breakpoints
  23 *  or error conditions to be properly intercepted and reported to gdb.
  24 *  Two, a breakpoint needs to be generated to begin communication.  This
  25 *  is most easily accomplished by a call to breakpoint().  Breakpoint()
  26 *  simulates a breakpoint by executing a BREAK instruction.
  27 *
  28 *
  29 *    The following gdb commands are supported:
  30 *
  31 * command          function                               Return value
  32 *
  33 *    g             return the value of the CPU registers  hex data or ENN
  34 *    G             set the value of the CPU registers     OK or ENN
  35 *
  36 *    mAA..AA,LLLL  Read LLLL bytes at address AA..AA      hex data or ENN
  37 *    MAA..AA,LLLL: Write LLLL bytes at address AA.AA      OK or ENN
  38 *
  39 *    c             Resume at current address              SNN   ( signal NN)
  40 *    cAA..AA       Continue at address AA..AA             SNN
  41 *
  42 *    s             Step one instruction                   SNN
  43 *    sAA..AA       Step one instruction from AA..AA       SNN
  44 *
  45 *    k             kill
  46 *
  47 *    ?             What was the last sigval ?             SNN   (signal NN)
  48 *
  49 *
  50 * All commands and responses are sent with a packet which includes a
  51 * checksum.  A packet consists of
  52 *
  53 * $<packet info>#<checksum>.
  54 *
  55 * where
  56 * <packet info> :: <characters representing the command or response>
  57 * <checksum>    :: < two hex digits computed as modulo 256 sum of <packetinfo>>
  58 *
  59 * When a packet is received, it is first acknowledged with either '+' or '-'.
  60 * '+' indicates a successful transfer.  '-' indicates a failed transfer.
  61 *
  62 * Example:
  63 *
  64 * Host:                  Reply:
  65 * $m0,10#2a               +$00010203040506070809101112131415#42
  66 *
  67 */
  68
  69#include <asm/gdb-stub.h>
  70#include <linux/string.h>
  71#include <linux/kernel.h>
  72#include <linux/signal.h>
  73#include <linux/sched.h>
  74#include <linux/mm.h>
  75#include <asm/pgtable.h>
  76#include <asm/system.h>
  77
  78
  79/*
  80 * external low-level support routines
  81 */
  82
  83extern int putDebugChar(char c);    /* write a single character      */
  84extern char getDebugChar(void);     /* read and return a single char */
  85extern void fltr_set_mem_err(void);
  86extern void trap_low(void);
  87
  88/*
  89 * breakpoint and test functions
  90 */
  91extern void breakpoint(void);
  92extern void breakinst(void);
  93
  94/*
  95 * local prototypes
  96 */
  97
  98static void getpacket(char *buffer);
  99static void putpacket(char *buffer);
 100static int hex(unsigned char ch);
 101static int hexToInt(char **ptr, int *intValue);
 102static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault);
 103
 104
 105/*
 106 * BUFMAX defines the maximum number of characters in inbound/outbound buffers
 107 * at least NUMREGBYTES*2 are needed for register packets
 108 */
 109#define BUFMAX 2048
 110
 111static char input_buffer[BUFMAX];
 112static char output_buffer[BUFMAX];
 113int gdb_stub_initialised = FALSE;       
 114static const char hexchars[]="0123456789abcdef";
 115
 116
 117/*
 118 * Convert ch from a hex digit to an int
 119 */
 120static int hex(unsigned char ch)
 121{
 122        if (ch >= 'a' && ch <= 'f')
 123                return ch-'a'+10;
 124        if (ch >= '0' && ch <= '9')
 125                return ch-'0';
 126        if (ch >= 'A' && ch <= 'F')
 127                return ch-'A'+10;
 128        return -1;
 129}
 130
 131/*
 132 * scan for the sequence $<data>#<checksum>
 133 */
 134static void getpacket(char *buffer)
 135{
 136        unsigned char checksum;
 137        unsigned char xmitcsum;
 138        int i;
 139        int count;
 140        unsigned char ch;
 141
 142        do {
 143                /*
 144                 * wait around for the start character,
 145                 * ignore all other characters
 146                 */
 147                while ((ch = (getDebugChar() & 0x7f)) != '$') ;
 148
 149                checksum = 0;
 150                xmitcsum = -1;
 151                count = 0;
 152        
 153                /*
 154                 * now, read until a # or end of buffer is found
 155                 */
 156                while (count < BUFMAX) {
 157                        ch = getDebugChar() & 0x7f;
 158                        if (ch == '#')
 159                                break;
 160                        checksum = checksum + ch;
 161                        buffer[count] = ch;
 162                        count = count + 1;
 163                }
 164
 165                if (count >= BUFMAX)
 166                        continue;
 167
 168                buffer[count] = 0;
 169
 170                if (ch == '#') {
 171                        xmitcsum = hex(getDebugChar() & 0x7f) << 4;
 172                        xmitcsum |= hex(getDebugChar() & 0x7f);
 173
 174                        if (checksum != xmitcsum)
 175                                putDebugChar('-');      /* failed checksum */
 176                        else {
 177                                putDebugChar('+'); /* successful transfer */
 178
 179                                /*
 180                                 * if a sequence char is present,
 181                                 * reply the sequence ID
 182                                 */
 183                                if (buffer[2] == ':') {
 184                                        putDebugChar(buffer[0]);
 185                                        putDebugChar(buffer[1]);
 186
 187                                        /*
 188                                         * remove sequence chars from buffer
 189                                         */
 190                                        count = strlen(buffer);
 191                                        for (i=3; i <= count; i++)
 192                                                buffer[i-3] = buffer[i];
 193                                }
 194                        }
 195                }
 196        }
 197        while (checksum != xmitcsum);
 198}
 199
 200/*
 201 * send the packet in buffer.
 202 */
 203static void putpacket(char *buffer)
 204{
 205        unsigned char checksum;
 206        int count;
 207        unsigned char ch;
 208
 209        /*
 210         * $<packet info>#<checksum>.
 211         */
 212
 213        do {
 214                putDebugChar('$');
 215                checksum = 0;
 216                count = 0;
 217
 218                while ((ch = buffer[count]) != 0) {
 219                        if (!(putDebugChar(ch)))
 220                                return;
 221                        checksum += ch;
 222                        count += 1;
 223                }
 224
 225                putDebugChar('#');
 226                putDebugChar(hexchars[checksum >> 4]);
 227                putDebugChar(hexchars[checksum & 0xf]);
 228
 229        }
 230        while ((getDebugChar() & 0x7f) != '+');
 231}
 232
 233
 234
 235/*
 236 * Convert the memory pointed to by mem into hex, placing result in buf.
 237 * Return a pointer to the last char put in buf (null), in case of mem fault,
 238 * return 0.
 239 * If MAY_FAULT is non-zero, then we will handle memory faults by returning
 240 * a 0, else treat a fault like any other fault in the stub.
 241 */
 242static unsigned char *mem2hex(char *mem, char *buf, int count, int may_fault)
 243{
 244        unsigned char ch;
 245
 246/*      set_mem_fault_trap(may_fault); */
 247
 248        while (count-- > 0) {
 249                ch = *(mem++);
 250                if (mem_err)
 251                        return 0;
 252                *buf++ = hexchars[ch >> 4];
 253                *buf++ = hexchars[ch & 0xf];
 254        }
 255
 256        *buf = 0;
 257
 258/*      set_mem_fault_trap(0); */
 259
 260        return buf;
 261}
 262
 263/*
 264 * convert the hex array pointed to by buf into binary to be placed in mem
 265 * return a pointer to the character AFTER the last byte written
 266 */
 267static char *hex2mem(char *buf, char *mem, int count, int may_fault)
 268{
 269        int i;
 270        unsigned char ch;
 271
 272/*      set_mem_fault_trap(may_fault); */
 273
 274        for (i=0; i<count; i++)
 275        {
 276                ch = hex(*buf++) << 4;
 277                ch |= hex(*buf++);
 278                *(mem++) = ch;
 279                if (mem_err)
 280                        return 0;
 281        }
 282
 283/*      set_mem_fault_trap(0); */
 284
 285        return mem;
 286}
 287
 288
 289
 290/*
 291 * Set up exception handlers for tracing and breakpoints
 292 */
 293void set_debug_traps(void)
 294{
 295//      unsigned long flags;
 296        unsigned char c;
 297
 298//      save_and_cli(flags);
 299        /*
 300         * In case GDB is started before us, ack any packets
 301         * (presumably "$?#xx") sitting there.
 302         */
 303        while((c = getDebugChar()) != '$');
 304        while((c = getDebugChar()) != '#');
 305        c = getDebugChar(); /* eat first csum byte */
 306        c = getDebugChar(); /* eat second csum byte */
 307        putDebugChar('+'); /* ack it */
 308
 309        gdb_stub_initialised = TRUE;
 310//      restore_flags(flags);
 311}
 312
 313
 314/*
 315 * Trap handler for memory errors.  This just sets mem_err to be non-zero.  It
 316 * assumes that %l1 is non-zero.  This should be safe, as it is doubtful that
 317 * 0 would ever contain code that could mem fault.  This routine will skip
 318 * past the faulting instruction after setting mem_err.
 319 */
 320extern void fltr_set_mem_err(void)
 321{
 322  /* FIXME: Needs to be written... */
 323}
 324
 325
 326/*
 327 * While we find nice hex chars, build an int.
 328 * Return number of chars processed.
 329 */
 330static int hexToInt(char **ptr, int *intValue)
 331{
 332        int numChars = 0;
 333        int hexValue;
 334
 335        *intValue = 0;
 336
 337        while (**ptr)
 338        {
 339                hexValue = hex(**ptr);
 340                if (hexValue < 0)
 341                        break;
 342
 343                *intValue = (*intValue << 4) | hexValue;
 344                numChars ++;
 345
 346                (*ptr)++;
 347        }
 348
 349        return (numChars);
 350}
 351
 352void gdb_stub_get_non_pt_regs(gdb_pt_regs *regs)
 353{
 354        s390_fp_regs *fpregs=&regs->fp_regs;
 355        int has_ieee=save_fp_regs1(fpregs);
 356
 357        if(!has_ieee)
 358        {
 359                fpregs->fpc=0;
 360                fpregs->fprs[1].d=
 361                fpregs->fprs[3].d=
 362                fpregs->fprs[5].d=
 363                fpregs->fprs[7].d=0;
 364                memset(&fpregs->fprs[8].d,0,sizeof(freg_t)*8);
 365        }
 366}
 367
 368void gdb_stub_set_non_pt_regs(gdb_pt_regs *regs)
 369{
 370        restore_fp_regs1(&regs->fp_regs);
 371}
 372
 373void gdb_stub_send_signal(int sigval)
 374{
 375        char *ptr;
 376        ptr = output_buffer;
 377
 378        /*
 379         * Send trap type (converted to signal)
 380         */
 381        *ptr++ = 'S';
 382        *ptr++ = hexchars[sigval >> 4];
 383        *ptr++ = hexchars[sigval & 0xf];
 384        *ptr++ = 0;
 385        putpacket(output_buffer);       /* send it off... */
 386}
 387
 388/*
 389 * This function does all command processing for interfacing to gdb.  It
 390 * returns 1 if you should skip the instruction at the trap address, 0
 391 * otherwise.
 392 */
 393void gdb_stub_handle_exception(gdb_pt_regs *regs,int sigval)
 394{
 395        int trap;                       /* Trap type */
 396        int addr;
 397        int length;
 398        char *ptr;
 399        unsigned long *stack;
 400
 401        
 402        /*
 403         * reply to host that an exception has occurred
 404         */
 405        send_signal(sigval);
 406
 407        /*
 408         * Wait for input from remote GDB
 409         */
 410        while (1) {
 411                output_buffer[0] = 0;
 412                getpacket(input_buffer);
 413
 414                switch (input_buffer[0])
 415                {
 416                case '?':
 417                        send_signal(sigval);
 418                        continue;
 419
 420                case 'd':
 421                        /* toggle debug flag */
 422                        break;
 423
 424                /*
 425                 * Return the value of the CPU registers
 426                 */
 427                case 'g':
 428                        gdb_stub_get_non_pt_regs(regs);
 429                        ptr = output_buffer;
 430                        ptr=  mem2hex((char *)regs,ptr,sizeof(s390_regs_common),FALSE);
 431                        ptr=  mem2hex((char *)&regs->crs[0],ptr,NUM_CRS*CR_SIZE,FALSE);
 432                        ptr = mem2hex((char *)&regs->fp_regs, ptr,sizeof(s390_fp_regs));
 433                        break;
 434          
 435                /*
 436                 * set the value of the CPU registers - return OK
 437                 * FIXME: Needs to be written
 438                 */
 439                case 'G':
 440                        ptr=input_buffer;
 441                        hex2mem (ptr, (char *)regs,sizeof(s390_regs_common), FALSE);
 442                        ptr+=sizeof(s390_regs_common)*2;
 443                        hex2mem (ptr, (char *)regs->crs[0],NUM_CRS*CR_SIZE, FALSE);
 444                        ptr+=NUM_CRS*CR_SIZE*2;
 445                        hex2mem (ptr, (char *)regs->fp_regs,sizeof(s390_fp_regs), FALSE);
 446                        gdb_stub_set_non_pt_regs(regs);
 447                        strcpy(output_buffer,"OK");
 448                break;
 449
 450                /*
 451                 * mAA..AA,LLLL  Read LLLL bytes at address AA..AA
 452                 */
 453                case 'm':
 454                        ptr = &input_buffer[1];
 455
 456                        if (hexToInt(&ptr, &addr)
 457                                && *ptr++ == ','
 458                                && hexToInt(&ptr, &length)) {
 459                                if (mem2hex((char *)addr, output_buffer, length, 1))
 460                                        break;
 461                                strcpy (output_buffer, "E03");
 462                        } else
 463                                strcpy(output_buffer,"E01");
 464                        break;
 465
 466                /*
 467                 * MAA..AA,LLLL: Write LLLL bytes at address AA.AA return OK
 468                 */
 469                case 'M': 
 470                        ptr = &input_buffer[1];
 471
 472                        if (hexToInt(&ptr, &addr)
 473                                && *ptr++ == ','
 474                                && hexToInt(&ptr, &length)
 475                                && *ptr++ == ':') {
 476                                if (hex2mem(ptr, (char *)addr, length, 1))
 477                                        strcpy(output_buffer, "OK");
 478                                else
 479                                        strcpy(output_buffer, "E03");
 480                        }
 481                        else
 482                                strcpy(output_buffer, "E02");
 483                        break;
 484
 485                /*
 486                 * cAA..AA    Continue at address AA..AA(optional)
 487                 */
 488                case 'c':    
 489                        /* try to read optional parameter, pc unchanged if no parm */
 490
 491                        ptr = &input_buffer[1];
 492                        if (hexToInt(&ptr, &addr))
 493                                regs->cp0_epc = addr;
 494          
 495                        /*
 496                         * Need to flush the instruction cache here, as we may
 497                         * have deposited a breakpoint, and the icache probably
 498                         * has no way of knowing that a data ref to some location
 499                         * may have changed something that is in the instruction
 500                         * cache.
 501                         * NB: We flush both caches, just to be sure...
 502                         */
 503
 504                        flush_cache_all();
 505                        return;
 506                        /* NOTREACHED */
 507                        break;
 508
 509
 510                /*
 511                 * kill the program
 512                 */
 513                case 'k' :
 514                        break;          /* do nothing */
 515
 516
 517                /*
 518                 * Reset the whole machine (FIXME: system dependent)
 519                 */
 520                case 'r':
 521                        break;
 522
 523
 524                /*
 525                 * Step to next instruction
 526                 */
 527                case 's':
 528                        /*
 529                         * There is no single step insn in the MIPS ISA, so we
 530                         * use breakpoints and continue, instead.
 531                         */
 532                        single_step(regs);
 533                        flush_cache_all();
 534                        return;
 535                        /* NOTREACHED */
 536
 537                }
 538                break;
 539
 540                }                       /* switch */
 541
 542                /*
 543                 * reply to the request
 544                 */
 545
 546                putpacket(output_buffer);
 547
 548        } /* while */
 549}
 550
 551/*
 552 * This function will generate a breakpoint exception.  It is used at the
 553 * beginning of a program to sync up with a debugger and can be used
 554 * otherwise as a quick means to stop program execution and "break" into
 555 * the debugger.
 556 */
 557void breakpoint(void)
 558{
 559        if (!gdb_stub_initialised)
 560                return;
 561        __asm__ __volatile__(
 562                        ".globl breakinst\n"
 563                        "breakinst:\t.word   %0\n\t"
 564                        :
 565                        : "i" (S390_BREAKPOINT_U16)
 566                                :
 567                                );
 568}
 569
 570
 571
 572
 573
 574
 575
 576
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.