00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <pch.h>
00033 #include "DebugStub.h"
00034
00035 using namespace Onikiri;
00036 using namespace std;
00037 using namespace boost::asio;
00038 using ip::tcp;
00039
00040
00041
00042 DebugStub::DebugStub(SystemBase::SystemContext* context, int pid) :
00043 m_acc(m_ioService, tcp::endpoint(tcp::v4(), (unsigned short)context->debugParam.debugPort))
00044 {
00045 ASSERT(context->targetArchitecture == "AlphaLinux", "GDB Debug mode is currently available on AlphaLinux only.");
00046 ASSERT(context->threads.GetSize() == 1, "Multithread GDB Debugging is not supported.");
00047
00048 m_context = context;
00049 m_pid = pid;
00050 m_stopExec = true;
00051 m_stopCount = 0;
00052 g_env.PrintInternal("Waiting for host GDB access...");
00053 m_acc.accept(*m_iostream.rdbuf());
00054 g_env.PrintInternal(" connected.\n");
00055 while(m_stopExec) {
00056 if( GetStartChar() ){
00057 if( !GetStream() ) return;
00058 ParsePacket();
00059 ExecDebug();
00060 }
00061 }
00062 }
00063
00064 DebugStub::~DebugStub()
00065 {
00066 SendPacket("W00");
00067 }
00068
00069
00070
00071
00072
00073 bool DebugStub::GetStartChar()
00074 {
00075 char ch;
00076 while(m_iostream.rdbuf()->available()){
00077 m_iostream.get(ch);
00078 if(ch == '$') return true;
00079 }
00080 return false;
00081 }
00082
00083 bool DebugStub::GetStream()
00084 {
00085 char ch;
00086 int checksum = 0;
00087 int sum = 0;
00088 stringstream ss;
00089 m_streamBuffer.clear();
00090 while (m_iostream.get(ch)) {
00091 if(ch == '#') break;
00092 sum += ch;
00093 m_streamBuffer += ch;
00094 }
00095 m_iostream.get(ch);
00096 ss << ch;
00097 m_iostream.get(ch);
00098 ss << ch;
00099 ss >> hex >> checksum;
00100 #ifdef GDB_DEBUG
00101 cout << "received:\"" << m_streamBuffer << "\"" << endl;
00102 #endif
00103 if( (sum&0xff) == checksum ) {
00104 m_iostream << '+';
00105 return true;
00106 }
00107 else {
00108 m_iostream << '-';
00109 return false;
00110 }
00111 }
00112
00113 void DebugStub::ParsePacket()
00114 {
00115 size_t pos;
00116 m_packet.clear();
00117 switch(m_packet.letter = m_streamBuffer.at(0)){
00118 case ('?'):
00119 break;
00120 case ('q'):
00121 pos = m_streamBuffer.find(':');
00122 m_packet.command = m_streamBuffer.substr(1,pos-1);
00123 while(pos != m_streamBuffer.npos){
00124 size_t nextpos;
00125 nextpos = m_streamBuffer.find(';',pos+1);
00126 m_packet.params.push_back(m_streamBuffer.substr(pos+1,nextpos-pos-1));
00127 pos = nextpos;
00128 }
00129 break;
00130 case ('H'):
00131 m_packet.command = m_streamBuffer.at(1);
00132 m_packet.params.push_back(m_streamBuffer.substr(2));
00133 break;
00134 case ('g'):
00135 break;
00136 case ('G'):
00137 m_packet.command = m_streamBuffer.substr(1);
00138 break;
00139 case ('p'):
00140 m_packet.command = m_streamBuffer.substr(1);
00141 break;
00142 case ('P'):
00143 pos = m_streamBuffer.find('=');
00144 m_packet.command = m_streamBuffer.substr(1,pos-1);
00145 m_packet.params.push_back(m_streamBuffer.substr(pos+1));
00146 break;
00147 case ('m'):
00148 pos = m_streamBuffer.find(',');
00149 m_packet.command = m_streamBuffer.substr(1,pos-1);
00150 m_packet.params.push_back(m_streamBuffer.substr(pos+1));
00151 break;
00152 case ('X'):
00153 case ('M'):
00154 pos = m_streamBuffer.find(',');
00155 m_packet.command = m_streamBuffer.substr(1,pos-1);
00156 while(pos != m_streamBuffer.npos){
00157 size_t nextpos;
00158 nextpos = m_streamBuffer.find(':',pos+1);
00159 m_packet.params.push_back(m_streamBuffer.substr(pos+1,nextpos-pos-1));
00160 pos = nextpos;
00161 }
00162 break;
00163 case ('v'):
00164 pos = m_streamBuffer.find(';');
00165 m_packet.command = m_streamBuffer.substr(1,pos-1);
00166 while(pos != m_streamBuffer.npos){
00167 size_t nextpos;
00168 nextpos = m_streamBuffer.find(';',pos+1);
00169 m_packet.params.push_back(m_streamBuffer.substr(pos+1,nextpos-pos-1));
00170 pos = nextpos;
00171 }
00172 break;
00173 case ('Z'):
00174 case ('z'):
00175 pos = m_streamBuffer.find(',');
00176 m_packet.command = m_streamBuffer.substr(1,pos-1);
00177 while(pos != m_streamBuffer.npos){
00178 size_t nextpos;
00179 nextpos = m_streamBuffer.find(',',pos+1);
00180 m_packet.params.push_back(m_streamBuffer.substr(pos+1,nextpos-pos-1));
00181 pos = nextpos;
00182 }
00183 break;
00184 default:
00185 break;
00186 }
00187
00188 }
00189
00190 void DebugStub::ExecDebug()
00191 {
00192 size_t readnum = 0;
00193 string readstr = "";
00194 u64 addr;
00195 u64 value = 0;
00196 MemAccess access;
00197 bool validAccess = true;
00198 switch(m_packet.letter){
00199 case ('?'):
00200 SendPacket("T05thread:00;");
00201 break;
00202 case ('q'):
00203 if( m_packet.command == "Supported" ){
00204 if( m_packet.params.at(0) == "qRelocInsn+" ){
00205 SendPacket("PacketSize=1000");
00206 }
00207 else{
00208 SendPacket("");
00209 }
00210 }
00211 else if ( m_packet.command == "fThreadInfo" ){
00212 SendPacket("m0");
00213 }
00214 else if ( m_packet.command == "sThreadInfo" ){
00215 SendPacket("l");
00216 }
00217 else if ( m_packet.command == "C")
00218 {
00219 SendPacket("QC1");
00220 }
00221 else if ( m_packet.command == "Attached")
00222 {
00223 SendPacket("");
00224 }
00225 else if ( m_packet.command == "TStatus")
00226 {
00227 SendPacket("");
00228 }
00229 else if ( m_packet.command == "TfV")
00230 {
00231 SendPacket( U64ToHexStr(0, 8) + ":" + U64ToHexStr(0, 8));
00232 }
00233 else if ( m_packet.command == "TsV")
00234 {
00235 SendPacket("l");
00236 }
00237 else if ( m_packet.command == "TfP")
00238 {
00239 SendPacket("l");
00240 }
00241 else if ( m_packet.command == "Offsets")
00242 {
00243 SendPacket("Text=0000000000000000;Data=0000000000000000;Bss=0000000000000000");
00244 }
00245 else if ( m_packet.command == "Symbol")
00246 {
00247 SendPacket("");
00248 }
00249 else
00250 {
00251 SendPacket("");
00252 }
00253 break;
00254 case ('H'):
00255 if ( m_packet.command == "g" && m_packet.params.at(0) == "0" ){
00256 SendPacket("OK");
00257 }
00258 else if ( m_packet.command == "g" && m_packet.params.at(0) == "1" ){
00259 SendPacket("E22");
00260 }
00261 else if ( m_packet.command == "c" && m_packet.params.at(0) == "-1" ){
00262 SendPacket("OK");
00263 }
00264 else{
00265 SendPacket("");
00266 }
00267 break;
00268 case ('g'):
00269 readnum = m_context->architectureStateList.at(m_pid).registerValue.capacity();
00270 for(size_t i = 0; i < readnum; i++){
00271 readstr += U64ToHexStr(GetRegister((int)i), 8);
00272 }
00273 SendPacket(readstr);
00274 break;
00275 case ('G'):
00276 readnum = m_context->architectureStateList.at(m_pid).registerValue.capacity();
00277 for(size_t i = 0; i < readnum; i++){
00278 u64 value = 0;
00279 for (int j=0; j < 8; j++)
00280 {
00281 value += HexStrToU64(m_packet.command.substr(16*i+(j<<1),2)) << (j*8);
00282 }
00283 SetRegister((int)i,value);
00284 }
00285 SendPacket("OK");
00286 break;
00287 case ('p'):
00288 SendPacket(U64ToHexStr(GetRegister((int)HexStrToU64(m_packet.command)), 8));
00289 break;
00290 case ('P'):
00291 for (int i=0; i < 8; i++)
00292 {
00293 value += HexStrToU64(m_packet.params.at(0).substr(i<<1,2)) << (i*8);
00294 }
00295 SetRegister((int)HexStrToU64(m_packet.command), value);
00296 SendPacket("OK");
00297 break;
00298 case ('m'):
00299 readnum = (int)HexStrToU64(m_packet.params.at(0));
00300 addr = HexStrToU64(m_packet.command);
00301 while(readnum){
00302 size_t readSize = (readnum > 8) ? 8 : readnum;
00303 access.address = Addr(m_pid, 0, addr);
00304 access.size = (int)readSize;
00305 readstr += U64ToHexStr(GetMemory(&access), (int)readSize);
00306 readnum -= readSize;
00307 addr += readSize;
00308 if (access.result != MemAccess::MAR_SUCCESS)
00309 {
00310 validAccess = false;
00311 break;
00312 }
00313 }
00314 if (validAccess){
00315 SendPacket(readstr);
00316 } else {
00317 SendPacket("E14");
00318 }
00319 break;
00320 case ('X'):
00321 readnum = (int)HexStrToU64(m_packet.params.at(0));
00322 addr = HexStrToU64(m_packet.command);
00323 for(size_t i = 0; readnum != 0;){
00324 size_t readSize = (readnum > 8) ? 8 : readnum;
00325 access.address = Addr(m_pid, 0, addr);
00326 access.size = (int)readSize;
00327 access.value = ParseBinary(m_packet.params.at(1).substr(i,readSize));
00328 SetMemory(&access);
00329 readnum -= readSize;
00330 addr += readSize;
00331 i += readSize;
00332 if (access.result != MemAccess::MAR_SUCCESS)
00333 {
00334 validAccess = false;
00335 break;
00336 }
00337 }
00338 if (validAccess){
00339 SendPacket("OK");
00340 } else {
00341 SendPacket("E14");
00342 }
00343 break;
00344 case ('M'):
00345 readnum = (int)HexStrToU64(m_packet.params.at(0));
00346 addr = HexStrToU64(m_packet.command);
00347 while(readnum){
00348 size_t readSize = (readnum > 8) ? 8 : readnum;
00349 u64 value = 0;
00350 for (size_t i=0; i < readSize; i++)
00351 {
00352 value += HexStrToU64(m_packet.params.at(1).substr(i<<1,2)) << (i*8);
00353 }
00354 access.address = Addr(m_pid, 0, addr);
00355 access.size = (int)readSize;
00356 access.value = value;
00357 SetMemory(&access);
00358 readnum -= readSize;
00359 addr += readSize;
00360 if (access.result != MemAccess::MAR_SUCCESS)
00361 {
00362 validAccess = false;
00363 break;
00364 }
00365 }
00366 if (validAccess){
00367 SendPacket("OK");
00368 } else {
00369 SendPacket("E14");
00370 }
00371 break;
00372 case ('v'):
00373 if(m_packet.command == "Cont?"){
00374 SendPacket("vCont;c;C;s;S");
00375 }
00376 else if (m_packet.command == "Cont"){
00377 if (m_packet.params.at(0) == "c"){
00378 m_stopExec = false;
00379 }
00380 else if (m_packet.params.at(0) == "s:0"){
00381 m_stopExec = false;
00382 m_stopCount = 1;
00383 }
00384 }
00385 else if (m_packet.command == "Kill"){
00386 THROW_RUNTIME_ERROR("Terminated via gdb.");
00387 }
00388 break;
00389 case ('c'):
00390 m_stopExec = false;
00391 break;
00392 case ('s'):
00393 m_stopExec = false;
00394 m_stopCount = 1;
00395 break;
00396 case ('t'):
00397 m_stopExec = true;
00398 SendPacket("");
00399 break;
00400 case ('k'):
00401 THROW_RUNTIME_ERROR("Terminated via gdb.");
00402 break;
00403 case ('Z'):
00404 if(m_packet.command == "0"){
00405 m_breakpoint.insert(pointpair(HexStrToU64(m_packet.params.at(0)),(int)HexStrToU64(m_packet.params.at(1))));
00406 SendPacket("OK");
00407 }
00408 else {
00409 WatchList* watchList;
00410 if (m_packet.command == "2") {
00411 watchList = &m_watchWrite;
00412 }
00413 else if (m_packet.command == "3") {
00414 watchList = &m_watchRead;
00415 }
00416 else if (m_packet.command == "4") {
00417 watchList = &m_watchAccess;
00418 }
00419 else{
00420 SendPacket("");
00421 break;
00422 }
00423 watchList->push_back(pointpair(HexStrToU64(m_packet.params.at(0)),(int)HexStrToU64(m_packet.params.at(1))));
00424 SendPacket("OK");
00425 }
00426 break;
00427 case ('z'):
00428 if(m_packet.command == "0"){
00429 Pointmap::iterator i = m_breakpoint.find(HexStrToU64(m_packet.params.at(0)));
00430 if (i != m_breakpoint.end() && i->second == (int)HexStrToU64(m_packet.params.at(1)))
00431 {
00432 m_breakpoint.erase(i);
00433 }
00434 SendPacket("OK");
00435 }
00436 else {
00437 WatchList* watchList;
00438 if (m_packet.command == "2")
00439 {
00440 watchList = &m_watchWrite;
00441 }
00442 else if (m_packet.command == "3")
00443 {
00444 watchList = &m_watchRead;
00445 }
00446 else if (m_packet.command == "4"){
00447 watchList = &m_watchAccess;
00448 }
00449 else{
00450 SendPacket("");
00451 break;
00452 }
00453
00454 for (WatchList::iterator i = watchList->begin(); i != watchList->end();)
00455 {
00456 if (i->first == HexStrToU64(m_packet.params.at(0)) &&
00457 i->second == (int)HexStrToU64(m_packet.params.at(1)))
00458 {
00459 i =watchList->erase(i);
00460 }
00461 else{
00462 i++;
00463 }
00464 }
00465 SendPacket("OK");
00466 }
00467 break;
00468 default:
00469 SendPacket("");
00470 break;
00471 }
00472
00473 }
00474
00475 void DebugStub::SendPacket(string packet)
00476 {
00477 for(int i=0; i < 3; i++){
00478 int sum = 0;
00479 stringstream ss;
00480 for(unsigned int i = 0; i < packet.size(); i++){
00481 sum += packet.at(i);
00482 }
00483 ss << setw(2) << setfill('0') << hex << (sum & 0xff);
00484 #ifdef GDB_DEBUG
00485 cout << "sent:\"" << packet << "\"" << endl;
00486 #endif
00487 m_iostream << "$" << packet << "#" << ss.str();
00488
00489 char ch;
00490 bool thru = false;
00491 do{
00492 m_iostream.get(ch);
00493 if(ch == '$') thru = true;
00494 if(ch == '#' && thru) thru = false;
00495 } while ((ch != '+' && ch != '-') || thru);
00496 if(ch == '+') break;
00497 }
00498
00499 }
00500
00501 void DebugStub::OnExec(EmulationDebugOp* op)
00502 {
00503 do {
00504 if(m_stopCount > 0){
00505 if(m_stopCount == 1){
00506 m_stopExec = true;
00507 SendPacket("S05");
00508 }
00509 m_stopCount--;
00510 }
00511 if(!m_stopExec){
00512 if (m_breakpoint.find(m_context->architectureStateList[m_pid].pc.address) != m_breakpoint.end())
00513 {
00514 m_stopExec = true;
00515 SendPacket("S05");
00516 }
00517 else if (op->GetOpInfo()->GetOpClass().IsLoad())
00518 {
00519 MemAccess access = op->GetMemAccess();
00520 for (WatchList::iterator i = m_watchRead.begin(); i != m_watchRead.end(); i++)
00521 {
00522 if (IsAddressOverlap(access,*i))
00523 {
00524 m_stopExec = true;
00525 SendPacket("S05");
00526 }
00527 }
00528 for (WatchList::iterator i = m_watchAccess.begin(); i != m_watchAccess.end(); i++)
00529 {
00530 if (IsAddressOverlap(access,*i))
00531 {
00532 m_stopExec = true;
00533 SendPacket("S05");
00534 }
00535 }
00536 }
00537 else if (op->GetOpInfo()->GetOpClass().IsStore())
00538 {
00539 MemAccess access = op->GetMemAccess();
00540 for (WatchList::iterator i = m_watchWrite.begin(); i != m_watchWrite.end(); i++)
00541 {
00542 if (IsAddressOverlap(access,*i))
00543 {
00544 m_stopExec = true;
00545 SendPacket("S05");
00546 }
00547 }
00548 for (WatchList::iterator i = m_watchAccess.begin(); i != m_watchAccess.end(); i++)
00549 {
00550 if (IsAddressOverlap(access,*i))
00551 {
00552 m_stopExec = true;
00553 SendPacket("S05");
00554 }
00555 }
00556 }
00557 }
00558 if( GetStartChar() ){
00559 if( !GetStream() ) return;
00560 ParsePacket();
00561 ExecDebug();
00562 }
00563 }while(m_stopExec);
00564 }
00565
00566
00567
00568
00569
00570 u64 DebugStub::GetRegister( int regNum )
00571 {
00572
00573 if (regNum == 0x42)
00574 {
00575 return 0;
00576 }
00577 return (regNum != 0x40) ? m_context->architectureStateList[m_pid].registerValue[regNum] : m_context->architectureStateList[m_pid].pc.address;
00578 }
00579
00580 void DebugStub::SetRegister( int regNum, u64 value )
00581 {
00582
00583 if(regNum != 0x40){
00584 m_context->architectureStateList[m_pid].registerValue[regNum] = value;
00585 }
00586 else {
00587 m_context->architectureStateList[m_pid].pc.address = value;
00588 }
00589 }
00590
00591 u64 DebugStub::GetMemory( MemAccess* access )
00592 {
00593 m_context->emulator->GetMemImage()->Read(access);
00594 return access->value;
00595 }
00596
00597 void DebugStub::SetMemory( MemAccess* access )
00598 {
00599 m_context->emulator->GetMemImage()->Write(access);
00600 return;
00601 }
00602
00603 u64 DebugStub::HexStrToU64(string str)
00604 {
00605 stringstream ss;
00606 u64 retVal;
00607
00608 ss << str;
00609 ss >> hex >> retVal;
00610 return retVal;
00611 }
00612
00613 string DebugStub::U64ToHexStr( u64 val, int num )
00614 {
00615 stringstream ss;
00616 for(int i = 0; i < num; i++){
00617 ss << setw(2) << setfill('0') << hex << (val & 0xff);
00618 val >>= 8;
00619 }
00620 return ss.str();
00621 }
00622
00623 u64 DebugStub::ParseBinary(string binStr)
00624 {
00625 u64 value = 0;
00626 int numByte = 0;
00627 for (unsigned int i = 0; i < binStr.length(); i++)
00628 {
00629
00630
00631 if (binStr[i] == '}')
00632 {
00633 i++;
00634 value += ((unsigned char)binStr[i]^0x20) << (numByte*8);
00635 }
00636 else
00637 {
00638 value += (unsigned char)binStr[i] << (numByte*8);
00639 }
00640 numByte++;
00641 }
00642 return value;
00643 }
00644
00645 bool DebugStub::IsAddressOverlap(MemAccess access, pointpair watchpoint)
00646 {
00647 return ((access.address.address <= watchpoint.first) &&
00648 (watchpoint.first < access.address.address+access.size)) ||
00649 ((watchpoint.first <= access.address.address) &&
00650 (access.address.address < watchpoint.first+watchpoint.second));
00651 }