remote_gdb.cc (3082:2b5c51982f78) | remote_gdb.cc (3536:89aa06409e4d) |
---|---|
1/* 2 * Copyright (c) 2002-2005 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; --- 109 unchanged lines hidden (view full) --- 118 119#include <sys/signal.h> 120 121#include <string> 122#include <unistd.h> 123 124#include "arch/vtophys.hh" 125#include "base/intmath.hh" | 1/* 2 * Copyright (c) 2002-2005 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; --- 109 unchanged lines hidden (view full) --- 118 119#include <sys/signal.h> 120 121#include <string> 122#include <unistd.h> 123 124#include "arch/vtophys.hh" 125#include "base/intmath.hh" |
126#include "base/kgdb.h" | |
127#include "base/remote_gdb.hh" 128#include "base/socket.hh" 129#include "base/trace.hh" 130#include "config/full_system.hh" 131#include "cpu/thread_context.hh" 132#include "cpu/static_inst.hh" 133#include "mem/physical.hh" 134#include "mem/port.hh" 135#include "sim/system.hh" 136 137using namespace std; 138using namespace TheISA; 139 140#ifndef NDEBUG | 126#include "base/remote_gdb.hh" 127#include "base/socket.hh" 128#include "base/trace.hh" 129#include "config/full_system.hh" 130#include "cpu/thread_context.hh" 131#include "cpu/static_inst.hh" 132#include "mem/physical.hh" 133#include "mem/port.hh" 134#include "sim/system.hh" 135 136using namespace std; 137using namespace TheISA; 138 139#ifndef NDEBUG |
141vector 142int current_debugger = -1; | 140vector<BaseRemoteGDB *> debuggers; |
143 144void 145debugger() 146{ | 141 142void 143debugger() 144{ |
145 static int current_debugger = -1; |
|
147 if (current_debugger >= 0 && current_debugger < debuggers.size()) { | 146 if (current_debugger >= 0 && current_debugger < debuggers.size()) { |
148 RemoteGDB *gdb = debuggers[current_debugger]; | 147 BaseRemoteGDB *gdb = debuggers[current_debugger]; |
149 if (!gdb->isattached()) 150 gdb->listener->accept(); 151 if (gdb->isattached()) | 148 if (!gdb->isattached()) 149 gdb->listener->accept(); 150 if (gdb->isattached()) |
152 gdb->trap(ALPHA_KENTRY_IF); | 151 gdb->trap(SIGILL); |
153 } 154} 155#endif 156 157/////////////////////////////////////////////////////////// 158// 159// 160// 161 162GDBListener::Event::Event(GDBListener *l, int fd, int e) 163 : PollEvent(fd, e), listener(l) 164{} 165 166void 167GDBListener::Event::process(int revent) 168{ 169 listener->accept(); 170} 171 | 152 } 153} 154#endif 155 156/////////////////////////////////////////////////////////// 157// 158// 159// 160 161GDBListener::Event::Event(GDBListener *l, int fd, int e) 162 : PollEvent(fd, e), listener(l) 163{} 164 165void 166GDBListener::Event::process(int revent) 167{ 168 listener->accept(); 169} 170 |
172GDBListener::GDBListener(RemoteGDB *g, int p) | 171GDBListener::GDBListener(BaseRemoteGDB *g, int p) |
173 : event(NULL), gdb(g), port(p) 174{ 175 assert(!gdb->listener); 176 gdb->listener = this; 177} 178 179GDBListener::~GDBListener() 180{ --- 43 unchanged lines hidden (view full) --- 224 if (sfd != -1) { 225 if (gdb->isattached()) 226 close(sfd); 227 else 228 gdb->attach(sfd); 229 } 230} 231 | 172 : event(NULL), gdb(g), port(p) 173{ 174 assert(!gdb->listener); 175 gdb->listener = this; 176} 177 178GDBListener::~GDBListener() 179{ --- 43 unchanged lines hidden (view full) --- 223 if (sfd != -1) { 224 if (gdb->isattached()) 225 close(sfd); 226 else 227 gdb->attach(sfd); 228 } 229} 230 |
232/////////////////////////////////////////////////////////// 233// 234// 235// 236int digit2i(char); 237char i2digit(int); 238void mem2hex(void *, const void *, int); 239const char *hex2mem(void *, const char *, int); 240Addr hex2i(const char **); 241 242RemoteGDB::Event::Event(RemoteGDB *g, int fd, int e) | 231BaseRemoteGDB::Event::Event(BaseRemoteGDB *g, int fd, int e) |
243 : PollEvent(fd, e), gdb(g) 244{} 245 246void | 232 : PollEvent(fd, e), gdb(g) 233{} 234 235void |
247RemoteGDB::Event::process(int revent) | 236BaseRemoteGDB::Event::process(int revent) |
248{ 249 if (revent & POLLIN) | 237{ 238 if (revent & POLLIN) |
250 gdb->trap(ALPHA_KENTRY_IF); | 239 gdb->trap(SIGILL); |
251 else if (revent & POLLNVAL) 252 gdb->detach(); 253} 254 | 240 else if (revent & POLLNVAL) 241 gdb->detach(); 242} 243 |
255RemoteGDB::RemoteGDB(System *_system, ThreadContext *c) | 244BaseRemoteGDB::BaseRemoteGDB(System *_system, ThreadContext *c, size_t cacheSize) |
256 : event(NULL), listener(NULL), number(-1), fd(-1), 257 active(false), attached(false), | 245 : event(NULL), listener(NULL), number(-1), fd(-1), 246 active(false), attached(false), |
258 system(_system), pmem(_system->physmem), context(c) | 247 system(_system), pmem(_system->physmem), context(c), 248 gdbregs(cacheSize) |
259{ | 249{ |
260 memset(gdbregs, 0, sizeof(gdbregs)); | 250 memset(gdbregs.regs, 0, gdbregs.size); |
261} 262 | 251} 252 |
263RemoteGDB::~RemoteGDB() | 253BaseRemoteGDB::~BaseRemoteGDB() |
264{ 265 if (event) 266 delete event; 267} 268 269string | 254{ 255 if (event) 256 delete event; 257} 258 259string |
270RemoteGDB::name() | 260BaseRemoteGDB::name() |
271{ 272 return system->name() + ".remote_gdb"; 273} 274 275bool | 261{ 262 return system->name() + ".remote_gdb"; 263} 264 265bool |
276RemoteGDB::isattached() | 266BaseRemoteGDB::isattached() |
277{ return attached; } 278 279void | 267{ return attached; } 268 269void |
280RemoteGDB::attach(int f) | 270BaseRemoteGDB::attach(int f) |
281{ 282 fd = f; 283 284 event = new Event(this, fd, POLLIN); 285 pollQueue.schedule(event); 286 287 attached = true; 288 DPRINTFN("remote gdb attached\n"); 289} 290 291void | 271{ 272 fd = f; 273 274 event = new Event(this, fd, POLLIN); 275 pollQueue.schedule(event); 276 277 attached = true; 278 DPRINTFN("remote gdb attached\n"); 279} 280 281void |
292RemoteGDB::detach() | 282BaseRemoteGDB::detach() |
293{ 294 attached = false; 295 close(fd); 296 fd = -1; 297 298 pollQueue.remove(event); 299 DPRINTFN("remote gdb detached\n"); 300} 301 302const char * | 283{ 284 attached = false; 285 close(fd); 286 fd = -1; 287 288 pollQueue.remove(event); 289 DPRINTFN("remote gdb detached\n"); 290} 291 292const char * |
303gdb_command(char cmd) | 293BaseRemoteGDB::gdb_command(char cmd) |
304{ 305 switch (cmd) { | 294{ 295 switch (cmd) { |
306 case KGDB_SIGNAL: return "KGDB_SIGNAL"; 307 case KGDB_SET_BAUD: return "KGDB_SET_BAUD"; 308 case KGDB_SET_BREAK: return "KGDB_SET_BREAK"; 309 case KGDB_CONT: return "KGDB_CONT"; 310 case KGDB_ASYNC_CONT: return "KGDB_ASYNC_CONT"; 311 case KGDB_DEBUG: return "KGDB_DEBUG"; 312 case KGDB_DETACH: return "KGDB_DETACH"; 313 case KGDB_REG_R: return "KGDB_REG_R"; 314 case KGDB_REG_W: return "KGDB_REG_W"; 315 case KGDB_SET_THREAD: return "KGDB_SET_THREAD"; 316 case KGDB_CYCLE_STEP: return "KGDB_CYCLE_STEP"; 317 case KGDB_SIG_CYCLE_STEP: return "KGDB_SIG_CYCLE_STEP"; 318 case KGDB_KILL: return "KGDB_KILL"; 319 case KGDB_MEM_W: return "KGDB_MEM_W"; 320 case KGDB_MEM_R: return "KGDB_MEM_R"; 321 case KGDB_SET_REG: return "KGDB_SET_REG"; 322 case KGDB_READ_REG: return "KGDB_READ_REG"; 323 case KGDB_QUERY_VAR: return "KGDB_QUERY_VAR"; 324 case KGDB_SET_VAR: return "KGDB_SET_VAR"; 325 case KGDB_RESET: return "KGDB_RESET"; 326 case KGDB_STEP: return "KGDB_STEP"; 327 case KGDB_ASYNC_STEP: return "KGDB_ASYNC_STEP"; 328 case KGDB_THREAD_ALIVE: return "KGDB_THREAD_ALIVE"; 329 case KGDB_TARGET_EXIT: return "KGDB_TARGET_EXIT"; 330 case KGDB_BINARY_DLOAD: return "KGDB_BINARY_DLOAD"; 331 case KGDB_CLR_HW_BKPT: return "KGDB_CLR_HW_BKPT"; 332 case KGDB_SET_HW_BKPT: return "KGDB_SET_HW_BKPT"; 333 case KGDB_START: return "KGDB_START"; 334 case KGDB_END: return "KGDB_END"; 335 case KGDB_GOODP: return "KGDB_GOODP"; 336 case KGDB_BADP: return "KGDB_BADP"; | 296 case GDBSignal: return "KGDB_SIGNAL"; 297 case GDBSetBaud: return "KGDB_SET_BAUD"; 298 case GDBSetBreak: return "KGDB_SET_BREAK"; 299 case GDBCont: return "KGDB_CONT"; 300 case GDBAsyncCont: return "KGDB_ASYNC_CONT"; 301 case GDBDebug: return "KGDB_DEBUG"; 302 case GDBDetach: return "KGDB_DETACH"; 303 case GDBRegR: return "KGDB_REG_R"; 304 case GDBRegW: return "KGDB_REG_W"; 305 case GDBSetThread: return "KGDB_SET_THREAD"; 306 case GDBCycleStep: return "KGDB_CYCLE_STEP"; 307 case GDBSigCycleStep: return "KGDB_SIG_CYCLE_STEP"; 308 case GDBKill: return "KGDB_KILL"; 309 case GDBMemW: return "KGDB_MEM_W"; 310 case GDBMemR: return "KGDB_MEM_R"; 311 case GDBSetReg: return "KGDB_SET_REG"; 312 case GDBReadReg: return "KGDB_READ_REG"; 313 case GDBQueryVar: return "KGDB_QUERY_VAR"; 314 case GDBSetVar: return "KGDB_SET_VAR"; 315 case GDBReset: return "KGDB_RESET"; 316 case GDBStep: return "KGDB_STEP"; 317 case GDBAsyncStep: return "KGDB_ASYNC_STEP"; 318 case GDBThreadAlive: return "KGDB_THREAD_ALIVE"; 319 case GDBTargetExit: return "KGDB_TARGET_EXIT"; 320 case GDBBinaryDload: return "KGDB_BINARY_DLOAD"; 321 case GDBClrHwBkpt: return "KGDB_CLR_HW_BKPT"; 322 case GDBSetHwBkpt: return "KGDB_SET_HW_BKPT"; 323 case GDBStart: return "KGDB_START"; 324 case GDBEnd: return "KGDB_END"; 325 case GDBGoodP: return "KGDB_GOODP"; 326 case GDBBadP: return "KGDB_BADP"; |
337 default: return "KGDB_UNKNOWN"; 338 } 339} 340 | 327 default: return "KGDB_UNKNOWN"; 328 } 329} 330 |
341/////////////////////////////////////////////////////////// 342// RemoteGDB::acc 343// 344// Determine if the mapping at va..(va+len) is valid. 345// 346bool 347RemoteGDB::acc(Addr va, size_t len) 348{ 349 Addr last_va; 350 351 va = TheISA::TruncPage(va); 352 last_va = TheISA::RoundPage(va + len); 353 354 do { 355 if (TheISA::IsK0Seg(va)) { 356 if (va < (TheISA::K0SegBase + pmem->size())) { 357 DPRINTF(GDBAcc, "acc: Mapping is valid K0SEG <= " 358 "%#x < K0SEG + size\n", va); 359 return true; 360 } else { 361 DPRINTF(GDBAcc, "acc: Mapping invalid %#x > K0SEG + size\n", 362 va); 363 return false; 364 } 365 } 366 367 /** 368 * This code says that all accesses to palcode (instruction and data) 369 * are valid since there isn't a va->pa mapping because palcode is 370 * accessed physically. At some point this should probably be cleaned up 371 * but there is no easy way to do it. 372 */ 373 374 if (AlphaISA::PcPAL(va) || va < 0x10000) 375 return true; 376 377 Addr ptbr = context->readMiscReg(AlphaISA::IPR_PALtemp20); 378 TheISA::PageTableEntry pte = TheISA::kernel_pte_lookup(context->getPhysPort(), ptbr, va); 379 if (!pte.valid()) { 380 DPRINTF(GDBAcc, "acc: %#x pte is invalid\n", va); 381 return false; 382 } 383 va += TheISA::PageBytes; 384 } while (va < last_va); 385 386 DPRINTF(GDBAcc, "acc: %#x mapping is valid\n", va); 387 return true; 388} 389 390/////////////////////////////////////////////////////////// 391// RemoteGDB::signal 392// 393// Translate a trap number into a Unix-compatible signal number. 394// (GDB only understands Unix signal numbers.) 395// 396int 397RemoteGDB::signal(int type) 398{ 399 switch (type) { 400 case ALPHA_KENTRY_INT: 401 return (SIGTRAP); 402 403 case ALPHA_KENTRY_UNA: 404 return (SIGBUS); 405 406 case ALPHA_KENTRY_ARITH: 407 return (SIGFPE); 408 409 case ALPHA_KENTRY_IF: 410 return (SIGILL); 411 412 case ALPHA_KENTRY_MM: 413 return (SIGSEGV); 414 415 default: 416 panic("unknown signal type"); 417 return 0; 418 } 419} 420 421/////////////////////////////////////////////////////////// 422// RemoteGDB::getregs 423// 424// Translate the kernel debugger register format into 425// the GDB register format. 426void 427RemoteGDB::getregs() 428{ 429 memset(gdbregs, 0, sizeof(gdbregs)); 430 431 gdbregs[KGDB_REG_PC] = context->readPC(); 432 433 // @todo: Currently this is very Alpha specific. 434 if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { 435 for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { 436 gdbregs[i] = context->readIntReg(AlphaISA::reg_redir[i]); 437 } 438 } else { 439 for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { 440 gdbregs[i] = context->readIntReg(i); 441 } 442 } 443 444#ifdef KGDB_FP_REGS 445 for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { 446 gdbregs[i + KGDB_REG_F0] = context->readFloatRegBits(i); 447 } 448#endif 449} 450 451/////////////////////////////////////////////////////////// 452// RemoteGDB::setregs 453// 454// Translate the GDB register format into the kernel 455// debugger register format. 456// 457void 458RemoteGDB::setregs() 459{ 460 // @todo: Currently this is very Alpha specific. 461 if (AlphaISA::PcPAL(gdbregs[KGDB_REG_PC])) { 462 for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { 463 context->setIntReg(AlphaISA::reg_redir[i], gdbregs[i]); 464 } 465 } else { 466 for (int i = 0; i < TheISA::NumIntArchRegs; ++i) { 467 context->setIntReg(i, gdbregs[i]); 468 } 469 } 470 471#ifdef KGDB_FP_REGS 472 for (int i = 0; i < TheISA::NumFloatArchRegs; ++i) { 473 context->setFloatRegBits(i, gdbregs[i + KGDB_REG_F0]); 474 } 475#endif 476 context->setPC(gdbregs[KGDB_REG_PC]); 477} 478 479void 480RemoteGDB::setTempBreakpoint(TempBreakpoint &bkpt, Addr addr) 481{ 482 DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", addr); 483 484 bkpt.address = addr; 485 insertHardBreak(addr, 4); 486} 487 488void 489RemoteGDB::clearTempBreakpoint(TempBreakpoint &bkpt) 490{ 491 DPRINTF(GDBMisc, "setTempBreakpoint: addr=%#x\n", 492 bkpt.address); 493 494 495 removeHardBreak(bkpt.address, 4); 496 bkpt.address = 0; 497} 498 499void 500RemoteGDB::clearSingleStep() 501{ 502 DPRINTF(GDBMisc, "clearSingleStep bt_addr=%#x nt_addr=%#x\n", 503 takenBkpt.address, notTakenBkpt.address); 504 505 if (takenBkpt.address != 0) 506 clearTempBreakpoint(takenBkpt); 507 508 if (notTakenBkpt.address != 0) 509 clearTempBreakpoint(notTakenBkpt); 510} 511 512void 513RemoteGDB::setSingleStep() 514{ 515 Addr pc = context->readPC(); 516 Addr npc, bpc; 517 bool set_bt = false; 518 519 npc = pc + sizeof(MachInst); 520 521 // User was stopped at pc, e.g. the instruction at pc was not 522 // executed. 523 MachInst inst = read<MachInst>(pc); 524 StaticInstPtr si(inst); 525 if (si->hasBranchTarget(pc, context, bpc)) { 526 // Don't bother setting a breakpoint on the taken branch if it 527 // is the same as the next pc 528 if (bpc != npc) 529 set_bt = true; 530 } 531 532 DPRINTF(GDBMisc, "setSingleStep bt_addr=%#x nt_addr=%#x\n", 533 takenBkpt.address, notTakenBkpt.address); 534 535 setTempBreakpoint(notTakenBkpt, npc); 536 537 if (set_bt) 538 setTempBreakpoint(takenBkpt, bpc); 539} 540 | |
541///////////////////////// 542// 543// 544 545uint8_t | 331///////////////////////// 332// 333// 334 335uint8_t |
546RemoteGDB::getbyte() | 336BaseRemoteGDB::getbyte() |
547{ 548 uint8_t b; 549 ::read(fd, &b, 1); 550 return b; 551} 552 553void | 337{ 338 uint8_t b; 339 ::read(fd, &b, 1); 340 return b; 341} 342 343void |
554RemoteGDB::putbyte(uint8_t b) | 344BaseRemoteGDB::putbyte(uint8_t b) |
555{ 556 ::write(fd, &b, 1); 557} 558 559// Send a packet to gdb 560void | 345{ 346 ::write(fd, &b, 1); 347} 348 349// Send a packet to gdb 350void |
561RemoteGDB::send(const char *bp) | 351BaseRemoteGDB::send(const char *bp) |
562{ 563 const char *p; 564 uint8_t csum, c; 565 566 DPRINTF(GDBSend, "send: %s\n", bp); 567 568 do { 569 p = bp; | 352{ 353 const char *p; 354 uint8_t csum, c; 355 356 DPRINTF(GDBSend, "send: %s\n", bp); 357 358 do { 359 p = bp; |
570 putbyte(KGDB_START); | 360 //Start sending a packet 361 putbyte(GDBStart); 362 //Send the contents, and also keep a check sum. |
571 for (csum = 0; (c = *p); p++) { 572 putbyte(c); 573 csum += c; 574 } | 363 for (csum = 0; (c = *p); p++) { 364 putbyte(c); 365 csum += c; 366 } |
575 putbyte(KGDB_END); | 367 //Send the ending character. 368 putbyte(GDBEnd); 369 //Sent the checksum. |
576 putbyte(i2digit(csum >> 4)); 577 putbyte(i2digit(csum)); | 370 putbyte(i2digit(csum >> 4)); 371 putbyte(i2digit(csum)); |
578 } while ((c = getbyte() & 0x7f) == KGDB_BADP); | 372 //Try transmitting over and over again until the other end doesn't send an 373 //error back. 374 } while ((c = getbyte() & 0x7f) == GDBBadP); |
579} 580 581// Receive a packet from gdb 582int | 375} 376 377// Receive a packet from gdb 378int |
583RemoteGDB::recv(char *bp, int maxlen) | 379BaseRemoteGDB::recv(char *bp, int maxlen) |
584{ 585 char *p; 586 int c, csum; 587 int len; 588 589 do { 590 p = bp; 591 csum = len = 0; | 380{ 381 char *p; 382 int c, csum; 383 int len; 384 385 do { 386 p = bp; 387 csum = len = 0; |
592 while ((c = getbyte()) != KGDB_START) | 388 //Find the beginning of a packet 389 while ((c = getbyte()) != GDBStart) |
593 ; 594 | 390 ; 391 |
595 while ((c = getbyte()) != KGDB_END && len < maxlen) { | 392 //Read until you find the end of the data in the packet, and keep 393 //track of the check sum. 394 while ((c = getbyte()) != GDBEnd && len < maxlen) { |
596 c &= 0x7f; 597 csum += c; 598 *p++ = c; 599 len++; 600 } | 395 c &= 0x7f; 396 csum += c; 397 *p++ = c; 398 len++; 399 } |
400 401 //Mask the check sum, and terminate the command string. |
|
601 csum &= 0xff; 602 *p = '\0'; 603 | 402 csum &= 0xff; 403 *p = '\0'; 404 |
405 //If the command was too long, report an error. |
|
604 if (len >= maxlen) { | 406 if (len >= maxlen) { |
605 putbyte(KGDB_BADP); | 407 putbyte(GDBBadP); |
606 continue; 607 } 608 | 408 continue; 409 } 410 |
411 //Bring in the checksum. If the check sum matches, csum will be 0. |
|
609 csum -= digit2i(getbyte()) * 16; 610 csum -= digit2i(getbyte()); 611 | 412 csum -= digit2i(getbyte()) * 16; 413 csum -= digit2i(getbyte()); 414 |
415 //If the check sum was correct |
|
612 if (csum == 0) { | 416 if (csum == 0) { |
613 putbyte(KGDB_GOODP); | 417 //Report that the packet was received correctly 418 putbyte(GDBGoodP); |
614 // Sequence present? 615 if (bp[2] == ':') { 616 putbyte(bp[0]); 617 putbyte(bp[1]); 618 len -= 3; 619 bcopy(bp + 3, bp, len); 620 } 621 break; 622 } | 419 // Sequence present? 420 if (bp[2] == ':') { 421 putbyte(bp[0]); 422 putbyte(bp[1]); 423 len -= 3; 424 bcopy(bp + 3, bp, len); 425 } 426 break; 427 } |
623 putbyte(KGDB_BADP); | 428 //Otherwise, report that there was a mistake. 429 putbyte(GDBBadP); |
624 } while (1); 625 626 DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); 627 628 return (len); 629} 630 631// Read bytes from kernel address space for debugger. 632bool | 430 } while (1); 431 432 DPRINTF(GDBRecv, "recv: %s: %s\n", gdb_command(*bp), bp); 433 434 return (len); 435} 436 437// Read bytes from kernel address space for debugger. 438bool |
633RemoteGDB::read(Addr vaddr, size_t size, char *data) | 439BaseRemoteGDB::read(Addr vaddr, size_t size, char *data) |
634{ 635 static Addr lastaddr = 0; 636 static size_t lastsize = 0; 637 638 if (vaddr < 10) { 639 DPRINTF(GDBRead, "read: reading memory location zero!\n"); 640 vaddr = lastaddr + lastsize; 641 } --- 15 unchanged lines hidden (view full) --- 657 } 658#endif 659 660 return true; 661} 662 663// Write bytes to kernel address space for debugger. 664bool | 440{ 441 static Addr lastaddr = 0; 442 static size_t lastsize = 0; 443 444 if (vaddr < 10) { 445 DPRINTF(GDBRead, "read: reading memory location zero!\n"); 446 vaddr = lastaddr + lastsize; 447 } --- 15 unchanged lines hidden (view full) --- 463 } 464#endif 465 466 return true; 467} 468 469// Write bytes to kernel address space for debugger. 470bool |
665RemoteGDB::write(Addr vaddr, size_t size, const char *data) | 471BaseRemoteGDB::write(Addr vaddr, size_t size, const char *data) |
666{ 667 static Addr lastaddr = 0; 668 static size_t lastsize = 0; 669 670 if (vaddr < 10) { 671 DPRINTF(GDBWrite, "write: writing memory location zero!\n"); 672 vaddr = lastaddr + lastsize; 673 } --- 6 unchanged lines hidden (view full) --- 680 DPRINTFNR(": %s\n", buf); 681 } else 682 DPRINTFNR("\n"); 683 } 684 VirtualPort *vp = context->getVirtPort(context); 685 vp->writeBlob(vaddr, (uint8_t*)data, size); 686 context->delVirtPort(vp); 687 | 472{ 473 static Addr lastaddr = 0; 474 static size_t lastsize = 0; 475 476 if (vaddr < 10) { 477 DPRINTF(GDBWrite, "write: writing memory location zero!\n"); 478 vaddr = lastaddr + lastsize; 479 } --- 6 unchanged lines hidden (view full) --- 486 DPRINTFNR(": %s\n", buf); 487 } else 488 DPRINTFNR("\n"); 489 } 490 VirtualPort *vp = context->getVirtPort(context); 491 vp->writeBlob(vaddr, (uint8_t*)data, size); 492 context->delVirtPort(vp); 493 |
688#ifdef IMB 689 alpha_pal_imb(); 690#endif 691 | |
692 return true; 693} 694 | 494 return true; 495} 496 |
695 696PCEventQueue *RemoteGDB::getPcEventQueue() | 497PCEventQueue *BaseRemoteGDB::getPcEventQueue() |
697{ 698 return &system->pcEventQueue; 699} 700 | 498{ 499 return &system->pcEventQueue; 500} 501 |
701 702RemoteGDB::HardBreakpoint::HardBreakpoint(RemoteGDB *_gdb, Addr pc) | 502BaseRemoteGDB::HardBreakpoint::HardBreakpoint(BaseRemoteGDB *_gdb, Addr pc) |
703 : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), 704 gdb(_gdb), refcount(0) 705{ 706 DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); 707} 708 709void | 503 : PCEvent(_gdb->getPcEventQueue(), "HardBreakpoint Event", pc), 504 gdb(_gdb), refcount(0) 505{ 506 DPRINTF(GDBMisc, "creating hardware breakpoint at %#x\n", evpc); 507} 508 509void |
710RemoteGDB::HardBreakpoint::process(ThreadContext *tc) | 510BaseRemoteGDB::HardBreakpoint::process(ThreadContext *tc) |
711{ 712 DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); 713 714 if (tc == gdb->context) | 511{ 512 DPRINTF(GDBMisc, "handling hardware breakpoint at %#x\n", pc()); 513 514 if (tc == gdb->context) |
715 gdb->trap(ALPHA_KENTRY_INT); | 515 gdb->trap(SIGTRAP); |
716} 717 718bool | 516} 517 518bool |
719RemoteGDB::insertSoftBreak(Addr addr, size_t len) | 519BaseRemoteGDB::insertSoftBreak(Addr addr, size_t len) |
720{ | 520{ |
721 if (len != sizeof(MachInst)) | 521 if (len != sizeof(TheISA::MachInst)) |
722 panic("invalid length\n"); 723 724 return insertHardBreak(addr, len); 725} 726 727bool | 522 panic("invalid length\n"); 523 524 return insertHardBreak(addr, len); 525} 526 527bool |
728RemoteGDB::removeSoftBreak(Addr addr, size_t len) | 528BaseRemoteGDB::removeSoftBreak(Addr addr, size_t len) |
729{ 730 if (len != sizeof(MachInst)) 731 panic("invalid length\n"); 732 733 return removeHardBreak(addr, len); 734} 735 736bool | 529{ 530 if (len != sizeof(MachInst)) 531 panic("invalid length\n"); 532 533 return removeHardBreak(addr, len); 534} 535 536bool |
737RemoteGDB::insertHardBreak(Addr addr, size_t len) | 537BaseRemoteGDB::insertHardBreak(Addr addr, size_t len) |
738{ 739 if (len != sizeof(MachInst)) 740 panic("invalid length\n"); 741 742 DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); 743 744 HardBreakpoint *&bkpt = hardBreakMap[addr]; 745 if (bkpt == 0) 746 bkpt = new HardBreakpoint(this, addr); 747 748 bkpt->refcount++; 749 750 return true; 751} 752 753bool | 538{ 539 if (len != sizeof(MachInst)) 540 panic("invalid length\n"); 541 542 DPRINTF(GDBMisc, "inserting hardware breakpoint at %#x\n", addr); 543 544 HardBreakpoint *&bkpt = hardBreakMap[addr]; 545 if (bkpt == 0) 546 bkpt = new HardBreakpoint(this, addr); 547 548 bkpt->refcount++; 549 550 return true; 551} 552 553bool |
754RemoteGDB::removeHardBreak(Addr addr, size_t len) | 554BaseRemoteGDB::removeHardBreak(Addr addr, size_t len) |
755{ 756 if (len != sizeof(MachInst)) 757 panic("invalid length\n"); 758 759 DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); 760 761 break_iter_t i = hardBreakMap.find(addr); 762 if (i == hardBreakMap.end()) --- 4 unchanged lines hidden (view full) --- 767 delete hbp; 768 hardBreakMap.erase(i); 769 } 770 771 return true; 772} 773 774const char * | 555{ 556 if (len != sizeof(MachInst)) 557 panic("invalid length\n"); 558 559 DPRINTF(GDBMisc, "removing hardware breakpoint at %#x\n", addr); 560 561 break_iter_t i = hardBreakMap.find(addr); 562 if (i == hardBreakMap.end()) --- 4 unchanged lines hidden (view full) --- 567 delete hbp; 568 hardBreakMap.erase(i); 569 } 570 571 return true; 572} 573 574const char * |
775break_type(char c) | 575BaseRemoteGDB::break_type(char c) |
776{ 777 switch(c) { 778 case '0': return "software breakpoint"; 779 case '1': return "hardware breakpoint"; 780 case '2': return "write watchpoint"; 781 case '3': return "read watchpoint"; 782 case '4': return "access watchpoint"; 783 default: return "unknown breakpoint/watchpoint"; 784 } 785} 786 787// This function does all command processing for interfacing to a 788// remote gdb. Note that the error codes are ignored by gdb at 789// present, but might eventually become meaningful. (XXX) It might 790// makes sense to use POSIX errno values, because that is what the 791// gdb/remote.c functions want to return. 792bool | 576{ 577 switch(c) { 578 case '0': return "software breakpoint"; 579 case '1': return "hardware breakpoint"; 580 case '2': return "write watchpoint"; 581 case '3': return "read watchpoint"; 582 case '4': return "access watchpoint"; 583 default: return "unknown breakpoint/watchpoint"; 584 } 585} 586 587// This function does all command processing for interfacing to a 588// remote gdb. Note that the error codes are ignored by gdb at 589// present, but might eventually become meaningful. (XXX) It might 590// makes sense to use POSIX errno values, because that is what the 591// gdb/remote.c functions want to return. 592bool |
793RemoteGDB::trap(int type) | 593BaseRemoteGDB::trap(int type) |
794{ 795 uint64_t val; 796 size_t datalen, len; | 594{ 595 uint64_t val; 596 size_t datalen, len; |
797 char data[KGDB_BUFLEN + 1]; 798 char buffer[sizeof(gdbregs) * 2 + 256]; | 597 char data[GDBPacketBufLen + 1]; 598 char buffer[gdbregs.size * 2 + 256]; |
799 const char *p; 800 char command, subcmd; 801 string var; 802 bool ret; 803 804 if (!attached) 805 return false; 806 --- 11 unchanged lines hidden (view full) --- 818 * listening to us, so just enter the interaction loop. 819 * After the debugger is "active" (connected) it will be 820 * waiting for a "signaled" message from us. 821 */ 822 if (!active) 823 active = true; 824 else 825 // Tell remote host that an exception has occurred. | 599 const char *p; 600 char command, subcmd; 601 string var; 602 bool ret; 603 604 if (!attached) 605 return false; 606 --- 11 unchanged lines hidden (view full) --- 618 * listening to us, so just enter the interaction loop. 619 * After the debugger is "active" (connected) it will be 620 * waiting for a "signaled" message from us. 621 */ 622 if (!active) 623 active = true; 624 else 625 // Tell remote host that an exception has occurred. |
826 snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); | 626 snprintf((char *)buffer, sizeof(buffer), "S%02x", type); |
827 send(buffer); 828 829 // Stick frame regs into our reg cache. 830 getregs(); 831 832 for (;;) { 833 datalen = recv(data, sizeof(data)); 834 data[sizeof(data) - 1] = 0; // Sentinel 835 command = data[0]; 836 subcmd = 0; 837 p = data + 1; 838 switch (command) { 839 | 627 send(buffer); 628 629 // Stick frame regs into our reg cache. 630 getregs(); 631 632 for (;;) { 633 datalen = recv(data, sizeof(data)); 634 data[sizeof(data) - 1] = 0; // Sentinel 635 command = data[0]; 636 subcmd = 0; 637 p = data + 1; 638 switch (command) { 639 |
840 case KGDB_SIGNAL: | 640 case GDBSignal: |
841 // if this command came from a running gdb, answer it -- 842 // the other guy has no way of knowing if we're in or out 843 // of this loop when he issues a "remote-signal". | 641 // if this command came from a running gdb, answer it -- 642 // the other guy has no way of knowing if we're in or out 643 // of this loop when he issues a "remote-signal". |
844 snprintf((char *)buffer, sizeof(buffer), "S%02x", signal(type)); | 644 snprintf((char *)buffer, sizeof(buffer), 645 "S%02x", type); |
845 send(buffer); 846 continue; 847 | 646 send(buffer); 647 continue; 648 |
848 case KGDB_REG_R: 849 if (2 * sizeof(gdbregs) > sizeof(buffer)) | 649 case GDBRegR: 650 if (2 * gdbregs.size > sizeof(buffer)) |
850 panic("buffer too small"); 851 | 651 panic("buffer too small"); 652 |
852 mem2hex(buffer, gdbregs, sizeof(gdbregs)); | 653 mem2hex(buffer, gdbregs.regs, gdbregs.size); |
853 send(buffer); 854 continue; 855 | 654 send(buffer); 655 continue; 656 |
856 case KGDB_REG_W: 857 p = hex2mem(gdbregs, p, sizeof(gdbregs)); | 657 case GDBRegW: 658 p = hex2mem(gdbregs.regs, p, gdbregs.size); |
858 if (p == NULL || *p != '\0') 859 send("E01"); 860 else { 861 setregs(); 862 send("OK"); 863 } 864 continue; 865 866#if 0 | 659 if (p == NULL || *p != '\0') 660 send("E01"); 661 else { 662 setregs(); 663 send("OK"); 664 } 665 continue; 666 667#if 0 |
867 case KGDB_SET_REG: | 668 case GDBSetReg: |
868 val = hex2i(&p); 869 if (*p++ != '=') { 870 send("E01"); 871 continue; 872 } 873 if (val < 0 && val >= KGDB_NUMREGS) { 874 send("E01"); 875 continue; 876 } 877 | 669 val = hex2i(&p); 670 if (*p++ != '=') { 671 send("E01"); 672 continue; 673 } 674 if (val < 0 && val >= KGDB_NUMREGS) { 675 send("E01"); 676 continue; 677 } 678 |
878 gdbregs[val] = hex2i(&p); | 679 gdbregs.regs[val] = hex2i(&p); |
879 setregs(); 880 send("OK"); 881 882 continue; 883#endif 884 | 680 setregs(); 681 send("OK"); 682 683 continue; 684#endif 685 |
885 case KGDB_MEM_R: | 686 case GDBMemR: |
886 val = hex2i(&p); 887 if (*p++ != ',') { 888 send("E02"); 889 continue; 890 } 891 len = hex2i(&p); 892 if (*p != '\0') { 893 send("E03"); --- 15 unchanged lines hidden (view full) --- 909 mem2hex(temp, buffer, len); 910 send(temp); 911 delete [] temp; 912 } else { 913 send("E05"); 914 } 915 continue; 916 | 687 val = hex2i(&p); 688 if (*p++ != ',') { 689 send("E02"); 690 continue; 691 } 692 len = hex2i(&p); 693 if (*p != '\0') { 694 send("E03"); --- 15 unchanged lines hidden (view full) --- 710 mem2hex(temp, buffer, len); 711 send(temp); 712 delete [] temp; 713 } else { 714 send("E05"); 715 } 716 continue; 717 |
917 case KGDB_MEM_W: | 718 case GDBMemW: |
918 val = hex2i(&p); 919 if (*p++ != ',') { 920 send("E06"); 921 continue; 922 } 923 len = hex2i(&p); 924 if (*p++ != ':') { 925 send("E07"); --- 13 unchanged lines hidden (view full) --- 939 continue; 940 } 941 if (write(val, (size_t)len, (char *)buffer)) 942 send("OK"); 943 else 944 send("E0B"); 945 continue; 946 | 719 val = hex2i(&p); 720 if (*p++ != ',') { 721 send("E06"); 722 continue; 723 } 724 len = hex2i(&p); 725 if (*p++ != ':') { 726 send("E07"); --- 13 unchanged lines hidden (view full) --- 740 continue; 741 } 742 if (write(val, (size_t)len, (char *)buffer)) 743 send("OK"); 744 else 745 send("E0B"); 746 continue; 747 |
947 case KGDB_SET_THREAD: | 748 case GDBSetThread: |
948 subcmd = *p++; 949 val = hex2i(&p); 950 if (val == 0) 951 send("OK"); 952 else 953 send("E01"); 954 continue; 955 | 749 subcmd = *p++; 750 val = hex2i(&p); 751 if (val == 0) 752 send("OK"); 753 else 754 send("E01"); 755 continue; 756 |
956 case KGDB_DETACH: 957 case KGDB_KILL: | 757 case GDBDetach: 758 case GDBKill: |
958 active = false; 959 clearSingleStep(); 960 detach(); 961 goto out; 962 | 759 active = false; 760 clearSingleStep(); 761 detach(); 762 goto out; 763 |
963 case KGDB_ASYNC_CONT: | 764 case GDBAsyncCont: |
964 subcmd = hex2i(&p); 965 if (*p++ == ';') { 966 val = hex2i(&p); 967 context->setPC(val); 968 context->setNextPC(val + sizeof(MachInst)); 969 } 970 clearSingleStep(); 971 goto out; 972 | 765 subcmd = hex2i(&p); 766 if (*p++ == ';') { 767 val = hex2i(&p); 768 context->setPC(val); 769 context->setNextPC(val + sizeof(MachInst)); 770 } 771 clearSingleStep(); 772 goto out; 773 |
973 case KGDB_CONT: | 774 case GDBCont: |
974 if (p - data < datalen) { 975 val = hex2i(&p); 976 context->setPC(val); 977 context->setNextPC(val + sizeof(MachInst)); 978 } 979 clearSingleStep(); 980 goto out; 981 | 775 if (p - data < datalen) { 776 val = hex2i(&p); 777 context->setPC(val); 778 context->setNextPC(val + sizeof(MachInst)); 779 } 780 clearSingleStep(); 781 goto out; 782 |
982 case KGDB_ASYNC_STEP: | 783 case GDBAsyncStep: |
983 subcmd = hex2i(&p); 984 if (*p++ == ';') { 985 val = hex2i(&p); 986 context->setPC(val); 987 context->setNextPC(val + sizeof(MachInst)); 988 } 989 setSingleStep(); 990 goto out; 991 | 784 subcmd = hex2i(&p); 785 if (*p++ == ';') { 786 val = hex2i(&p); 787 context->setPC(val); 788 context->setNextPC(val + sizeof(MachInst)); 789 } 790 setSingleStep(); 791 goto out; 792 |
992 case KGDB_STEP: | 793 case GDBStep: |
993 if (p - data < datalen) { 994 val = hex2i(&p); 995 context->setPC(val); 996 context->setNextPC(val + sizeof(MachInst)); 997 } 998 setSingleStep(); 999 goto out; 1000 | 794 if (p - data < datalen) { 795 val = hex2i(&p); 796 context->setPC(val); 797 context->setNextPC(val + sizeof(MachInst)); 798 } 799 setSingleStep(); 800 goto out; 801 |
1001 case KGDB_CLR_HW_BKPT: | 802 case GDBClrHwBkpt: |
1002 subcmd = *p++; 1003 if (*p++ != ',') send("E0D"); 1004 val = hex2i(&p); 1005 if (*p++ != ',') send("E0D"); 1006 len = hex2i(&p); 1007 1008 DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", 1009 break_type(subcmd), val, len); --- 15 unchanged lines hidden (view full) --- 1025 default: // unknown 1026 send(""); 1027 break; 1028 } 1029 1030 send(ret ? "OK" : "E0C"); 1031 continue; 1032 | 803 subcmd = *p++; 804 if (*p++ != ',') send("E0D"); 805 val = hex2i(&p); 806 if (*p++ != ',') send("E0D"); 807 len = hex2i(&p); 808 809 DPRINTF(GDBMisc, "clear %s, addr=%#x, len=%d\n", 810 break_type(subcmd), val, len); --- 15 unchanged lines hidden (view full) --- 826 default: // unknown 827 send(""); 828 break; 829 } 830 831 send(ret ? "OK" : "E0C"); 832 continue; 833 |
1033 case KGDB_SET_HW_BKPT: | 834 case GDBSetHwBkpt: |
1034 subcmd = *p++; 1035 if (*p++ != ',') send("E0D"); 1036 val = hex2i(&p); 1037 if (*p++ != ',') send("E0D"); 1038 len = hex2i(&p); 1039 1040 DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", 1041 break_type(subcmd), val, len); --- 15 unchanged lines hidden (view full) --- 1057 default: // unknown 1058 send(""); 1059 break; 1060 } 1061 1062 send(ret ? "OK" : "E0C"); 1063 continue; 1064 | 835 subcmd = *p++; 836 if (*p++ != ',') send("E0D"); 837 val = hex2i(&p); 838 if (*p++ != ',') send("E0D"); 839 len = hex2i(&p); 840 841 DPRINTF(GDBMisc, "set %s, addr=%#x, len=%d\n", 842 break_type(subcmd), val, len); --- 15 unchanged lines hidden (view full) --- 858 default: // unknown 859 send(""); 860 break; 861 } 862 863 send(ret ? "OK" : "E0C"); 864 continue; 865 |
1065 case KGDB_QUERY_VAR: | 866 case GDBQueryVar: |
1066 var = string(p, datalen - 1); 1067 if (var == "C") 1068 send("QC0"); 1069 else 1070 send(""); 1071 continue; 1072 | 867 var = string(p, datalen - 1); 868 if (var == "C") 869 send("QC0"); 870 else 871 send(""); 872 continue; 873 |
1073 case KGDB_SET_BAUD: 1074 case KGDB_SET_BREAK: 1075 case KGDB_DEBUG: 1076 case KGDB_CYCLE_STEP: 1077 case KGDB_SIG_CYCLE_STEP: 1078 case KGDB_READ_REG: 1079 case KGDB_SET_VAR: 1080 case KGDB_RESET: 1081 case KGDB_THREAD_ALIVE: 1082 case KGDB_TARGET_EXIT: 1083 case KGDB_BINARY_DLOAD: | 874 case GDBSetBaud: 875 case GDBSetBreak: 876 case GDBDebug: 877 case GDBCycleStep: 878 case GDBSigCycleStep: 879 case GDBReadReg: 880 case GDBSetVar: 881 case GDBReset: 882 case GDBThreadAlive: 883 case GDBTargetExit: 884 case GDBBinaryDload: |
1084 // Unsupported command 1085 DPRINTF(GDBMisc, "Unsupported command: %s\n", 1086 gdb_command(command)); 1087 DDUMP(GDBMisc, (uint8_t *)data, datalen); 1088 send(""); 1089 continue; 1090 1091 default: --- 9 unchanged lines hidden (view full) --- 1101 1102 out: 1103 return true; 1104} 1105 1106// Convert a hex digit into an integer. 1107// This returns -1 if the argument passed is no valid hex digit. 1108int | 885 // Unsupported command 886 DPRINTF(GDBMisc, "Unsupported command: %s\n", 887 gdb_command(command)); 888 DDUMP(GDBMisc, (uint8_t *)data, datalen); 889 send(""); 890 continue; 891 892 default: --- 9 unchanged lines hidden (view full) --- 902 903 out: 904 return true; 905} 906 907// Convert a hex digit into an integer. 908// This returns -1 if the argument passed is no valid hex digit. 909int |
1109digit2i(char c) | 910BaseRemoteGDB::digit2i(char c) |
1110{ 1111 if (c >= '0' && c <= '9') 1112 return (c - '0'); 1113 else if (c >= 'a' && c <= 'f') 1114 return (c - 'a' + 10); 1115 else if (c >= 'A' && c <= 'F') 1116 1117 return (c - 'A' + 10); 1118 else 1119 return (-1); 1120} 1121 1122// Convert the low 4 bits of an integer into an hex digit. 1123char | 911{ 912 if (c >= '0' && c <= '9') 913 return (c - '0'); 914 else if (c >= 'a' && c <= 'f') 915 return (c - 'a' + 10); 916 else if (c >= 'A' && c <= 'F') 917 918 return (c - 'A' + 10); 919 else 920 return (-1); 921} 922 923// Convert the low 4 bits of an integer into an hex digit. 924char |
1124i2digit(int n) | 925BaseRemoteGDB::i2digit(int n) |
1125{ 1126 return ("0123456789abcdef"[n & 0x0f]); 1127} 1128 1129// Convert a byte array into an hex string. 1130void | 926{ 927 return ("0123456789abcdef"[n & 0x0f]); 928} 929 930// Convert a byte array into an hex string. 931void |
1131mem2hex(void *vdst, const void *vsrc, int len) | 932BaseRemoteGDB::mem2hex(void *vdst, const void *vsrc, int len) |
1132{ 1133 char *dst = (char *)vdst; 1134 const char *src = (const char *)vsrc; 1135 1136 while (len--) { 1137 *dst++ = i2digit(*src >> 4); 1138 *dst++ = i2digit(*src++); 1139 } 1140 *dst = '\0'; 1141} 1142 1143// Convert an hex string into a byte array. 1144// This returns a pointer to the character following the last valid 1145// hex digit. If the string ends in the middle of a byte, NULL is 1146// returned. 1147const char * | 933{ 934 char *dst = (char *)vdst; 935 const char *src = (const char *)vsrc; 936 937 while (len--) { 938 *dst++ = i2digit(*src >> 4); 939 *dst++ = i2digit(*src++); 940 } 941 *dst = '\0'; 942} 943 944// Convert an hex string into a byte array. 945// This returns a pointer to the character following the last valid 946// hex digit. If the string ends in the middle of a byte, NULL is 947// returned. 948const char * |
1148hex2mem(void *vdst, const char *src, int maxlen) | 949BaseRemoteGDB::hex2mem(void *vdst, const char *src, int maxlen) |
1149{ 1150 char *dst = (char *)vdst; 1151 int msb, lsb; 1152 1153 while (*src && maxlen--) { 1154 msb = digit2i(*src++); 1155 if (msb < 0) 1156 return (src - 1); --- 4 unchanged lines hidden (view full) --- 1161 } 1162 return (src); 1163} 1164 1165// Convert an hex string into an integer. 1166// This returns a pointer to the character following the last valid 1167// hex digit. 1168Addr | 950{ 951 char *dst = (char *)vdst; 952 int msb, lsb; 953 954 while (*src && maxlen--) { 955 msb = digit2i(*src++); 956 if (msb < 0) 957 return (src - 1); --- 4 unchanged lines hidden (view full) --- 962 } 963 return (src); 964} 965 966// Convert an hex string into an integer. 967// This returns a pointer to the character following the last valid 968// hex digit. 969Addr |
1169hex2i(const char **srcp) | 970BaseRemoteGDB::hex2i(const char **srcp) |
1170{ 1171 const char *src = *srcp; 1172 Addr r = 0; 1173 int nibble; 1174 1175 while ((nibble = digit2i(*src)) >= 0) { 1176 r *= 16; 1177 r += nibble; 1178 src++; 1179 } 1180 *srcp = src; 1181 return (r); 1182} 1183 | 971{ 972 const char *src = *srcp; 973 Addr r = 0; 974 int nibble; 975 976 while ((nibble = digit2i(*src)) >= 0) { 977 r *= 16; 978 r += nibble; 979 src++; 980 } 981 *srcp = src; 982 return (r); 983} 984 |