remote_gdb.cc revision 72
1/*
2 * Copyright (c) 2003 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/*
30 * Copyright (c) 1990, 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * This software was developed by the Computer Systems Engineering group
34 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
35 * contributed to Berkeley.
36 *
37 * All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 *	This product includes software developed by the University of
40 *	California, Lawrence Berkeley Laboratories.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 *    notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 *    notice, this list of conditions and the following disclaimer in the
49 *    documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 *    must display the following acknowledgement:
52 *	This product includes software developed by the University of
53 *	California, Berkeley and its contributors.
54 * 4. Neither the name of the University nor the names of its contributors
55 *    may be used to endorse or promote products derived from this software
56 *    without specific prior written permission.
57 *
58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68 * SUCH DAMAGE.
69 *
70 *	@(#)kgdb_stub.c	8.4 (Berkeley) 1/12/94
71 */
72
73/*-
74 * Copyright (c) 2001 The NetBSD Foundation, Inc.
75 * All rights reserved.
76 *
77 * This code is derived from software contributed to The NetBSD Foundation
78 * by Jason R. Thorpe.
79 *
80 * Redistribution and use in source and binary forms, with or without
81 * modification, are permitted provided that the following conditions
82 * are met:
83 * 1. Redistributions of source code must retain the above copyright
84 *    notice, this list of conditions and the following disclaimer.
85 * 2. Redistributions in binary form must reproduce the above copyright
86 *    notice, this list of conditions and the following disclaimer in the
87 *    documentation and/or other materials provided with the distribution.
88 * 3. All advertising materials mentioning features or use of this software
89 *    must display the following acknowledgement:
90 *	This product includes software developed by the NetBSD
91 *	Foundation, Inc. and its contributors.
92 * 4. Neither the name of The NetBSD Foundation nor the names of its
93 *    contributors may be used to endorse or promote products derived
94 *    from this software without specific prior written permission.
95 *
96 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
97 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
98 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
99 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
100 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
101 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
102 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
103 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
104 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
105 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
106 * POSSIBILITY OF SUCH DAMAGE.
107 */
108
109/*
110 * $NetBSD: kgdb_stub.c,v 1.8 2001/07/07 22:58:00 wdk Exp $
111 *
112 * Taken from NetBSD
113 *
114 * "Stub" to allow remote cpu to debug over a serial line using gdb.
115 */
116
117#include <sys/signal.h>
118
119#include <unistd.h>
120
121#include <cstdio>
122#include <string>
123
124#include "cpu/exec_context.hh"
125#include "base/intmath.hh"
126#include "base/kgdb.h"
127
128#include "mem/functional_mem/physical_memory.hh"
129#include "base/remote_gdb.hh"
130#include "base/socket.hh"
131#include "base/trace.hh"
132#include "targetarch/vtophys.hh"
133#include "sim/system.hh"
134#include "cpu/static_inst.hh"
135
136using namespace std;
137
138#ifdef DEBUG
139RemoteGDB *theDebugger = NULL;
140
141void
142debugger()
143{
144    if (theDebugger)
145        theDebugger->trap(ALPHA_KENTRY_IF);
146}
147#endif
148
149///////////////////////////////////////////////////////////
150//
151//
152//
153
154GDBListener::Event::Event(GDBListener *l, int fd, int e)
155    : PollEvent(fd, e), listener(l)
156{}
157
158void
159GDBListener::Event::process(int revent)
160{
161    listener->accept();
162}
163
164GDBListener::GDBListener(RemoteGDB *g, int p)
165    : event(NULL), gdb(g), port(p)
166{}
167
168GDBListener::~GDBListener()
169{
170    if (event)
171        delete event;
172}
173
174void
175GDBListener::listen()
176{
177    while (!listener.listen(port, true)) {
178        DPRINTF(RGDB, "GDBListener(listen): Can't bind port %d\n", port);
179        port++;
180    }
181
182    cerr << "Listening for remote gdb connection on port " << port << endl;
183    event = new Event(this, listener.getfd(), POLLIN);
184    pollQueue.schedule(event);
185}
186
187void
188GDBListener::accept()
189{
190    if (!listener.islistening())
191        panic("GDBListener(accept): cannot accept a connection if we're not listening!");
192
193    int sfd = listener.accept(true);
194
195    if (sfd != -1) {
196        if (gdb->isattached())
197            close(sfd);
198        else
199            gdb->attach(sfd);
200    }
201}
202
203///////////////////////////////////////////////////////////
204//
205//
206//
207int digit2i(char);
208char i2digit(int);
209void mem2hex(void *, const void *, int);
210const char *hex2mem(void *, const char *, int);
211Addr hex2i(const char **);
212
213RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e)
214    : PollEvent(fd, e), gdb(g)
215{}
216
217void
218RemoteGDB::Event::process(int revent)
219{ gdb->trap(ALPHA_KENTRY_IF); }
220
221RemoteGDB::RemoteGDB(System *_system, ExecContext *c)
222    : event(NULL), fd(-1), active(false), attached(false),
223      system(_system), pmem(_system->physmem), context(c)
224{
225#ifdef DEBUG
226    theDebugger = this;
227#endif
228    memset(gdbregs, 0, sizeof(gdbregs));
229}
230
231RemoteGDB::~RemoteGDB()
232{
233    if (event)
234        delete event;
235}
236
237bool
238RemoteGDB::isattached()
239{ return attached; }
240
241void
242RemoteGDB::attach(int f)
243{
244    fd = f;
245
246    event = new Event(this, fd, POLLIN);
247    pollQueue.schedule(event);
248
249    attached = true;
250    DPRINTFN("remote gdb attached\n");
251}
252
253void
254RemoteGDB::detach()
255{
256    attached = false;
257    close(fd);
258    fd = -1;
259
260    pollQueue.remove(event);
261    DPRINTFN("remote gdb detached\n");
262}
263
264const char *
265gdb_command(char cmd)
266{
267    switch (cmd) {
268      case KGDB_SIGNAL: return "KGDB_SIGNAL";
269      case KGDB_SET_BAUD: return "KGDB_SET_BAUD";
270      case KGDB_SET_BREAK: return "KGDB_SET_BREAK";
271      case KGDB_CONT: return "KGDB_CONT";
272      case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT";
273      case KGDB_DEBUG: return "KGDB_DEBUG";
274      case KGDB_DETACH: return "KGDB_DETACH";
275      case KGDB_REG_R: return "KGDB_REG_R";
276      case KGDB_REG_W: return "KGDB_REG_W";
277      case KGDB_SET_THREAD: return "KGDB_SET_THREAD";
278      case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP";
279      case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP";
280      case KGDB_KILL: return "KGDB_KILL";
281      case KGDB_MEM_W: return "KGDB_MEM_W";
282      case KGDB_MEM_R: return "KGDB_MEM_R";
283      case KGDB_SET_REG: return "KGDB_SET_REG";
284      case KGDB_READ_REG: return "KGDB_READ_REG";
285      case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR";
286      case KGDB_SET_VAR: return "KGDB_SET_VAR";
287      case KGDB_RESET: return "KGDB_RESET";
288      case KGDB_STEP: return "KGDB_STEP";
289      case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP";
290      case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE";
291      case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT";
292      case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD";
293      case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT";
294      case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT";
295      case KGDB_START: return "KGDB_START";
296      case KGDB_END: return "KGDB_END";
297      case KGDB_GOODP: return "KGDB_GOODP";
298      case KGDB_BADP: return "KGDB_BADP";
299      default: return "KGDB_UNKNOWN";
300    }
301}
302
303///////////////////////////////////////////////////////////
304// RemoteGDB::acc
305//
306//	Determine if the mapping at va..(va+len) is valid.
307//
308bool
309RemoteGDB::acc(Addr va, size_t len)
310{
311    Addr last_va;
312    Addr pte;
313
314    va = alpha_trunc_page(va);
315    last_va = alpha_round_page(va + len);
316
317    do  {
318        if (va < ALPHA_K0SEG_BASE) {
319            DPRINTF(RGDB, "RGDB(acc):   Mapping is invalid %#x < K0SEG\n", va);
320            return false;
321        }
322
323        if (va < ALPHA_K1SEG_BASE) {
324            if (va < (ALPHA_K0SEG_BASE + pmem->getSize())) {
325                DPRINTF(RGDB, "RGDB(acc):   Mapping is valid  K0SEG <= "
326                        "%#x < K0SEG + size\n", va);
327                return true;
328            } else {
329                DPRINTF(RGDB, "RGDB(acc):   Mapping is invalid %#x < K0SEG\n",
330                        va);
331                return false;
332            }
333        }
334
335        Addr ptbr = context->regs.ipr[AlphaISA::IPR_PALtemp20];
336        pte = kernel_pte_lookup(pmem, ptbr, va);
337        if (!pte || !entry_valid(pmem->phys_read_qword(pte))) {
338            DPRINTF(RGDB, "RGDB(acc):   %#x pte is invalid\n", va);
339            return false;
340        }
341        va += ALPHA_PGBYTES;
342    } while (va < last_va);
343
344    DPRINTF(RGDB, "RGDB(acc):   %#x mapping is valid\n", va);
345    return true;
346}
347
348///////////////////////////////////////////////////////////
349// RemoteGDB::signal
350//
351//	Translate a trap number into a Unix-compatible signal number.
352//	(GDB only understands Unix signal numbers.)
353//
354int
355RemoteGDB::signal(int type)
356{
357    switch (type) {
358      case ALPHA_KENTRY_UNA:
359        return (SIGBUS);
360
361      case ALPHA_KENTRY_ARITH:
362        return (SIGFPE);
363
364      case ALPHA_KENTRY_IF:
365        return (SIGILL);
366
367      case ALPHA_KENTRY_MM:
368        return (SIGSEGV);
369
370      default:
371        panic("unknown signal type");
372        return 0;
373    }
374}
375
376///////////////////////////////////////////////////////////
377// RemoteGDB::getregs
378//
379//	Translate the kernel debugger register format into
380//	the GDB register format.
381void
382RemoteGDB::getregs()
383{
384    memset(gdbregs, 0, sizeof(gdbregs));
385    memcpy(&gdbregs[KGDB_REG_V0], context->regs.intRegFile, 32 * sizeof(uint64_t));
386#ifdef KGDB_FP_REGS
387    memcpy(&gdbregs[KGDB_REG_F0], context->regs.floatRegFile.q,
388           32 * sizeof(uint64_t));
389#endif
390    gdbregs[KGDB_REG_PC] = context->regs.pc;
391}
392
393///////////////////////////////////////////////////////////
394// RemoteGDB::setregs
395//
396//	Translate the GDB register format into the kernel
397//	debugger register format.
398//
399void
400RemoteGDB::setregs()
401{
402    memcpy(context->regs.intRegFile, &gdbregs[KGDB_REG_V0], 32 * sizeof(uint64_t));
403#ifdef KGDB_FP_REGS
404    memcpy(context->regs.floatRegFile.q, &gdbregs[KGDB_REG_F0],
405           32 * sizeof(uint64_t));
406#endif
407    context->regs.pc = gdbregs[KGDB_REG_PC];
408}
409
410void
411RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr)
412{
413    DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n", addr);
414
415    bkpt.address = addr;
416    insertHardBreak(addr, 4);
417}
418
419void
420RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt)
421{
422    DPRINTF(RGDB, "RGDB(setTempBreakpoint): addr=%#x\n",
423            bkpt.address);
424
425
426    removeHardBreak(bkpt.address, 4);
427    bkpt.address = 0;
428}
429
430void
431RemoteGDB::clearSingleStep()
432{
433    DPRINTF(RGDB, "clearSingleStep bt_addr=%#x nt_addr=%#x\n",
434            takenBkpt.address, notTakenBkpt.address);
435
436    if (takenBkpt.address != 0)
437        clearTempBreakpoint(takenBkpt);
438
439    if (notTakenBkpt.address != 0)
440        clearTempBreakpoint(notTakenBkpt);
441}
442
443void
444RemoteGDB::setSingleStep()
445{
446    Addr pc = context->regs.pc;
447    Addr npc, bpc;
448    bool set_bt = false;
449
450    npc = pc + sizeof(MachInst);
451
452    // User was stopped at pc, e.g. the instruction at pc was not
453    // executed.
454    MachInst inst = read<MachInst>(pc);
455    StaticInstPtr<TheISA> si(inst);
456    if (si->hasBranchTarget(pc, context, bpc)) {
457        // Don't bother setting a breakpoint on the taken branch if it
458        // is the same as the next pc
459        if (bpc != npc)
460            set_bt = true;
461    }
462
463    DPRINTF(RGDB, "setSingleStep bt_addr=%#x nt_addr=%#x\n",
464            takenBkpt.address, notTakenBkpt.address);
465
466    setTempBreakpoint(notTakenBkpt, npc);
467
468    if (set_bt)
469        setTempBreakpoint(takenBkpt, bpc);
470}
471
472/////////////////////////
473//
474//
475
476uint8_t
477RemoteGDB::getbyte()
478{
479    uint8_t b;
480    ::read(fd, &b, 1);
481    return b;
482}
483
484void
485RemoteGDB::putbyte(uint8_t b)
486{
487    ::write(fd, &b, 1);
488}
489
490// Send a packet to gdb
491void
492RemoteGDB::send(const char *bp)
493{
494    const char *p;
495    uint8_t csum, c;
496
497//    DPRINTF(RGDB, "RGDB(send):  %s\n", bp);
498
499    do {
500        p = bp;
501        putbyte(KGDB_START);
502        for (csum = 0; (c = *p); p++) {
503            putbyte(c);
504            csum += c;
505        }
506        putbyte(KGDB_END);
507        putbyte(i2digit(csum >> 4));
508        putbyte(i2digit(csum));
509    } while ((c = getbyte() & 0x7f) == KGDB_BADP);
510}
511
512// Receive a packet from gdb
513int
514RemoteGDB::recv(char *bp, int maxlen)
515{
516    char *p;
517    int c, csum;
518    int len;
519
520    do {
521        p = bp;
522        csum = len = 0;
523        while ((c = getbyte()) != KGDB_START)
524            ;
525
526        while ((c = getbyte()) != KGDB_END && len < maxlen) {
527            c &= 0x7f;
528            csum += c;
529            *p++ = c;
530            len++;
531        }
532        csum &= 0xff;
533        *p = '\0';
534
535        if (len >= maxlen) {
536            putbyte(KGDB_BADP);
537            continue;
538        }
539
540        csum -= digit2i(getbyte()) * 16;
541        csum -= digit2i(getbyte());
542
543        if (csum == 0) {
544            putbyte(KGDB_GOODP);
545            // Sequence present?
546            if (bp[2] == ':') {
547                putbyte(bp[0]);
548                putbyte(bp[1]);
549                len -= 3;
550                bcopy(bp + 3, bp, len);
551            }
552            break;
553        }
554        putbyte(KGDB_BADP);
555    } while (1);
556
557//    DPRINTF(RGDB, "RGDB(recv):  %s: %s\n", gdb_command(*bp), bp);
558
559    return (len);
560}
561
562// Read bytes from kernel address space for debugger.
563bool
564RemoteGDB::read(Addr vaddr, size_t size, char *data)
565{
566    static Addr lastaddr = 0;
567    static size_t lastsize = 0;
568
569    uint8_t *maddr;
570
571    if (vaddr < 10) {
572      DPRINTF(RGDB, "\nRGDB(read):  reading memory location zero!\n");
573      vaddr = lastaddr + lastsize;
574    }
575
576    DPRINTF(RGDB, "RGDB(read):  addr=%#x, size=%d", vaddr, size);
577#if TRACING_ON
578    char *d = data;
579    size_t s = size;
580#endif
581
582    lastaddr = vaddr;
583    lastsize = size;
584
585    size_t count = min((Addr)size,
586                       VMPageSize - (vaddr & (VMPageSize - 1)));
587
588    maddr = vtomem(context, vaddr, count);
589    memcpy(data, maddr, count);
590
591    vaddr += count;
592    data += count;
593    size -= count;
594
595    while (size >= VMPageSize) {
596        maddr = vtomem(context, vaddr, count);
597        memcpy(data, maddr, VMPageSize);
598
599        vaddr += VMPageSize;
600        data += VMPageSize;
601        size -= VMPageSize;
602    }
603
604    if (size > 0) {
605        maddr = vtomem(context, vaddr, count);
606        memcpy(data, maddr, size);
607    }
608
609#if TRACING_ON
610    if (DTRACE(RGDB)) {
611      char buf[1024];
612      mem2hex(buf, d, s);
613      cprintf(": %s\n", buf);
614    }
615#endif
616
617    return true;
618}
619
620// Write bytes to kernel address space for debugger.
621bool
622RemoteGDB::write(Addr vaddr, size_t size, const char *data)
623{
624    static Addr lastaddr = 0;
625    static size_t lastsize = 0;
626
627    uint8_t *maddr;
628
629    if (vaddr < 10) {
630      DPRINTF(RGDB, "RGDB(write): writing memory location zero!\n");
631      vaddr = lastaddr + lastsize;
632    }
633
634    if (DTRACE(RGDB)) {
635      char buf[1024];
636      mem2hex(buf, data, size);
637      cprintf("RGDB(write): addr=%#x, size=%d: %s\n", vaddr, size, buf);
638    }
639
640    lastaddr = vaddr;
641    lastsize = size;
642
643    size_t count = min((Addr)size,
644                       VMPageSize - (vaddr & (VMPageSize - 1)));
645
646    maddr = vtomem(context, vaddr, count);
647    memcpy(maddr, data, count);
648
649    vaddr += count;
650    data += count;
651    size -= count;
652
653    while (size >= VMPageSize) {
654        maddr = vtomem(context, vaddr, count);
655        memcpy(maddr, data, VMPageSize);
656
657        vaddr += VMPageSize;
658        data += VMPageSize;
659        size -= VMPageSize;
660    }
661
662    if (size > 0) {
663        maddr = vtomem(context, vaddr, count);
664        memcpy(maddr, data, size);
665    }
666
667#ifdef IMB
668    alpha_pal_imb();
669#endif
670
671    return true;
672}
673
674
675PCEventQueue *RemoteGDB::getPcEventQueue()
676{
677    return &system->pcEventQueue;
678}
679
680
681RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc)
682    : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc),
683      gdb(_gdb), refcount(0)
684{
685    DPRINTF(RGDB, "creating hardware breakpoint at %#x\n", evpc);
686    schedule();
687}
688
689void
690RemoteGDB::HardBreakpoint::process(ExecContext *xc)
691{
692    DPRINTF(RGDB, "handling hardware breakpoint at %#x\n", pc());
693
694    if (xc == gdb->context)
695        gdb->trap(ALPHA_KENTRY_IF);
696}
697
698bool
699RemoteGDB::insertSoftBreak(Addr addr, size_t len)
700{
701    if (len != sizeof(MachInst))
702        panic("invalid length\n");
703
704    return insertHardBreak(addr, len);
705}
706
707bool
708RemoteGDB::removeSoftBreak(Addr addr, size_t len)
709{
710    if (len != sizeof(MachInst))
711        panic("invalid length\n");
712
713    return removeHardBreak(addr, len);
714}
715
716bool
717RemoteGDB::insertHardBreak(Addr addr, size_t len)
718{
719    if (len != sizeof(MachInst))
720        panic("invalid length\n");
721
722    DPRINTF(RGDB, "inserting hardware breakpoint at %#x\n", addr);
723
724    HardBreakpoint *&bkpt = hardBreakMap[addr];
725    if (bkpt == 0)
726        bkpt = new HardBreakpoint(this, addr);
727
728    bkpt->refcount++;
729
730    return true;
731
732#if 0
733    break_iter_t i = hardBreakMap.find(addr);
734    if (i == hardBreakMap.end()) {
735        HardBreakpoint *bkpt = new HardBreakpoint(this, addr);
736        hardBreakMap[addr] = bkpt;
737        i = hardBreakMap.insert(make_pair(addr, bkpt));
738        if (i == hardBreakMap.end())
739            return false;
740    }
741
742    (*i).second->refcount++;
743#endif
744}
745
746bool
747RemoteGDB::removeHardBreak(Addr addr, size_t len)
748{
749    if (len != sizeof(MachInst))
750        panic("invalid length\n");
751
752    DPRINTF(RGDB, "removing hardware breakpoint at %#x\n", addr);
753
754    break_iter_t i = hardBreakMap.find(addr);
755    if (i == hardBreakMap.end())
756        return false;
757
758    HardBreakpoint *hbp = (*i).second;
759    if (--hbp->refcount == 0) {
760        delete hbp;
761        hardBreakMap.erase(i);
762    }
763
764    return true;
765}
766
767const char *
768break_type(char c)
769{
770    switch(c) {
771      case '0': return "software breakpoint";
772      case '1': return "hardware breakpoint";
773      case '2': return "write watchpoint";
774      case '3': return "read watchpoint";
775      case '4': return "access watchpoint";
776      default: return "unknown breakpoint/watchpoint";
777    }
778}
779
780// This function does all command processing for interfacing to a
781// remote gdb.  Note that the error codes are ignored by gdb at
782// present, but might eventually become meaningful. (XXX) It might
783// makes sense to use POSIX errno values, because that is what the
784// gdb/remote.c functions want to return.
785bool
786RemoteGDB::trap(int type)
787{
788    uint64_t val;
789    size_t datalen, len;
790    char data[KGDB_BUFLEN + 1];
791    char buffer[sizeof(gdbregs) * 2 + 256];
792    char temp[KGDB_BUFLEN];
793    const char *p;
794    char command, subcmd;
795    string var;
796    bool ret;
797
798    if (!attached)
799        return false;
800
801    DPRINTF(RGDB, "RGDB(trap): PC=%#x NPC=%#x\n",
802            context->regs.pc, context->regs.npc);
803
804    clearSingleStep();
805
806    /*
807     * The first entry to this function is normally through
808     * a breakpoint trap in kgdb_connect(), in which case we
809     * must advance past the breakpoint because gdb will not.
810     *
811     * On the first entry here, we expect that gdb is not yet
812     * listening to us, so just enter the interaction loop.
813     * After the debugger is "active" (connected) it will be
814     * waiting for a "signaled" message from us.
815     */
816    if (!active) {
817        if (!IS_BREAKPOINT_TRAP(type, 0)) {
818            // No debugger active -- let trap handle this.
819            return false;
820        }
821        active = true;
822    } else {
823        // Tell remote host that an exception has occurred.
824        sprintf((char *)buffer, "S%02x", signal(type));
825        send(buffer);
826    }
827
828    // Stick frame regs into our reg cache.
829    getregs();
830
831    for (;;) {
832        datalen = recv(data, sizeof(data));
833        data[sizeof(data) - 1] = 0; // Sentinel
834        command = data[0];
835        subcmd = 0;
836        p = data + 1;
837        switch (command) {
838
839          case KGDB_SIGNAL:
840            // if this command came from a running gdb, answer it --
841            // the other guy has no way of knowing if we're in or out
842            // of this loop when he issues a "remote-signal".
843            sprintf((char *)buffer, "S%02x", signal(type));
844            send(buffer);
845            continue;
846
847          case KGDB_REG_R:
848            if (2 * sizeof(gdbregs) > sizeof(buffer))
849                panic("buffer too small");
850
851            mem2hex(buffer, gdbregs, sizeof(gdbregs));
852            send(buffer);
853            continue;
854
855          case KGDB_REG_W:
856            p = hex2mem(gdbregs, p, sizeof(gdbregs));
857            if (p == NULL || *p != '\0')
858                send("E01");
859            else {
860                setregs();
861                send("OK");
862            }
863            continue;
864
865#if 0
866          case KGDB_SET_REG:
867            val = hex2i(&p);
868            if (*p++ != '=') {
869                send("E01");
870                continue;
871            }
872            if (val < 0 && val >= KGDB_NUMREGS) {
873                send("E01");
874                continue;
875            }
876
877            gdbregs[val] = hex2i(&p);
878            setregs();
879            send("OK");
880
881            continue;
882#endif
883
884          case KGDB_MEM_R:
885            val = hex2i(&p);
886            if (*p++ != ',') {
887                send("E02");
888                continue;
889            }
890            len = hex2i(&p);
891            if (*p != '\0') {
892                send("E03");
893                continue;
894            }
895            if (len > sizeof(buffer)) {
896                send("E04");
897                continue;
898            }
899            if (!acc(val, len)) {
900                send("E05");
901                continue;
902            }
903
904            if (read(val, (size_t)len, (char *)buffer)) {
905              mem2hex(temp, buffer, len);
906              send(temp);
907            } else {
908              send("E05");
909            }
910            continue;
911
912          case KGDB_MEM_W:
913            val = hex2i(&p);
914            if (*p++ != ',') {
915                send("E06");
916                continue;
917            }
918            len = hex2i(&p);
919            if (*p++ != ':') {
920                send("E07");
921                continue;
922            }
923            if (len > datalen - (p - data)) {
924                send("E08");
925                continue;
926            }
927            p = hex2mem(buffer, p, sizeof(buffer));
928            if (p == NULL) {
929                send("E09");
930                continue;
931            }
932            if (!acc(val, len)) {
933                send("E0A");
934                continue;
935            }
936            if (write(val, (size_t)len, (char *)buffer))
937              send("OK");
938            else
939              send("E0B");
940            continue;
941
942          case KGDB_SET_THREAD:
943            subcmd = *p++;
944            val = hex2i(&p);
945            if (val == 0)
946                send("OK");
947            else
948                send("E01");
949            continue;
950
951          case KGDB_DETACH:
952          case KGDB_KILL:
953            active = false;
954            clearSingleStep();
955            detach();
956            goto out;
957
958          case KGDB_ASYNC_CONT:
959            subcmd = hex2i(&p);
960            if (*p++ == ';') {
961                val = hex2i(&p);
962                context->regs.pc = val;
963                context->regs.npc = val + sizeof(MachInst);
964            }
965            clearSingleStep();
966            goto out;
967
968          case KGDB_CONT:
969            if (p - data < datalen) {
970                val = hex2i(&p);
971                context->regs.pc = val;
972                context->regs.npc = val + sizeof(MachInst);
973            }
974            clearSingleStep();
975            goto out;
976
977          case KGDB_ASYNC_STEP:
978            subcmd = hex2i(&p);
979            if (*p++ == ';') {
980                val = hex2i(&p);
981                context->regs.pc = val;
982                context->regs.npc = val + sizeof(MachInst);
983            }
984            setSingleStep();
985            goto out;
986
987          case KGDB_STEP:
988            if (p - data < datalen) {
989                val = hex2i(&p);
990                context->regs.pc = val;
991                context->regs.npc = val + sizeof(MachInst);
992            }
993            setSingleStep();
994            goto out;
995
996          case KGDB_CLR_HW_BKPT:
997            subcmd = *p++;
998            if (*p++ != ',') send("E0D");
999            val = hex2i(&p);
1000            if (*p++ != ',') send("E0D");
1001            len = hex2i(&p);
1002
1003            DPRINTF(RGDB, "kgdb: clear %s, addr=%#x, len=%d\n",
1004                    break_type(subcmd), val, len);
1005
1006            ret = false;
1007
1008            switch (subcmd) {
1009              case '0': // software breakpoint
1010                ret = removeSoftBreak(val, len);
1011                break;
1012
1013              case '1': // hardware breakpoint
1014                ret = removeHardBreak(val, len);
1015                break;
1016
1017              case '2': // write watchpoint
1018              case '3': // read watchpoint
1019              case '4': // access watchpoint
1020              default: // unknown
1021                send("");
1022                break;
1023            }
1024
1025            send(ret ? "OK" : "E0C");
1026            continue;
1027
1028          case KGDB_SET_HW_BKPT:
1029            subcmd = *p++;
1030            if (*p++ != ',') send("E0D");
1031            val = hex2i(&p);
1032            if (*p++ != ',') send("E0D");
1033            len = hex2i(&p);
1034
1035            DPRINTF(RGDB, "kgdb: set %s, addr=%#x, len=%d\n",
1036                    break_type(subcmd), val, len);
1037
1038            ret = false;
1039
1040            switch (subcmd) {
1041              case '0': // software breakpoint
1042                ret = insertSoftBreak(val, len);
1043                break;
1044
1045              case '1': // hardware breakpoint
1046                ret = insertHardBreak(val, len);
1047                break;
1048
1049              case '2': // write watchpoint
1050              case '3': // read watchpoint
1051              case '4': // access watchpoint
1052              default: // unknown
1053                send("");
1054                break;
1055            }
1056
1057            send(ret ? "OK" : "E0C");
1058            continue;
1059
1060          case KGDB_QUERY_VAR:
1061            var = string(p, datalen - 1);
1062            if (var == "C")
1063                send("QC0");
1064            else
1065                send("");
1066            continue;
1067
1068          case KGDB_SET_BAUD:
1069          case KGDB_SET_BREAK:
1070          case KGDB_DEBUG:
1071          case KGDB_CYCLE_STEP:
1072          case KGDB_SIG_CYCLE_STEP:
1073          case KGDB_READ_REG:
1074          case KGDB_SET_VAR:
1075          case KGDB_RESET:
1076          case KGDB_THREAD_ALIVE:
1077          case KGDB_TARGET_EXIT:
1078          case KGDB_BINARY_DLOAD:
1079            // Unsupported command
1080            DPRINTF(RGDB, "kgdb: Unsupported command: %s\n",
1081                    gdb_command(command));
1082            DDUMP(RGDB, (uint8_t *)data, datalen);
1083            send("");
1084            continue;
1085
1086          default:
1087            // Unknown command.
1088            DPRINTF(RGDB, "kgdb: Unknown command: %c(%#x)\n",
1089                    command, command);
1090            send("");
1091            continue;
1092
1093
1094        }
1095    }
1096
1097  out:
1098    return true;
1099}
1100
1101// Convert a hex digit into an integer.
1102// This returns -1 if the argument passed is no valid hex digit.
1103int
1104digit2i(char c)
1105{
1106    if (c >= '0' && c <= '9')
1107        return (c - '0');
1108    else if (c >= 'a' && c <= 'f')
1109        return (c - 'a' + 10);
1110    else if (c >= 'A' && c <= 'F')
1111
1112        return (c - 'A' + 10);
1113    else
1114        return (-1);
1115}
1116
1117// Convert the low 4 bits of an integer into an hex digit.
1118char
1119i2digit(int n)
1120{
1121    return ("0123456789abcdef"[n & 0x0f]);
1122}
1123
1124// Convert a byte array into an hex string.
1125void
1126mem2hex(void *vdst, const void *vsrc, int len)
1127{
1128    char *dst = (char *)vdst;
1129    const char *src = (const char *)vsrc;
1130
1131    while (len--) {
1132        *dst++ = i2digit(*src >> 4);
1133        *dst++ = i2digit(*src++);
1134    }
1135    *dst = '\0';
1136}
1137
1138// Convert an hex string into a byte array.
1139// This returns a pointer to the character following the last valid
1140// hex digit. If the string ends in the middle of a byte, NULL is
1141// returned.
1142const char *
1143hex2mem(void *vdst, const char *src, int maxlen)
1144{
1145    char *dst = (char *)vdst;
1146    int msb, lsb;
1147
1148    while (*src && maxlen--) {
1149        msb = digit2i(*src++);
1150        if (msb < 0)
1151            return (src - 1);
1152        lsb = digit2i(*src++);
1153        if (lsb < 0)
1154            return (NULL);
1155        *dst++ = (msb << 4) | lsb;
1156    }
1157    return (src);
1158}
1159
1160// Convert an hex string into an integer.
1161// This returns a pointer to the character following the last valid
1162// hex digit.
1163Addr
1164hex2i(const char **srcp)
1165{
1166    const char *src = *srcp;
1167    Addr r = 0;
1168    int nibble;
1169
1170    while ((nibble = digit2i(*src)) >= 0) {
1171        r *= 16;
1172        r += nibble;
1173        src++;
1174    }
1175    *srcp = src;
1176    return (r);
1177}
1178
1179