src/Sim/System/EmulationDebugSystem/DebugStub/DebugStub.cpp

説明を見る。
00001 // 
00002 // Copyright (c) 2005-2008 Kenichi Watanabe.
00003 // Copyright (c) 2005-2008 Yasuhiro Watari.
00004 // Copyright (c) 2005-2008 Hironori Ichibayashi.
00005 // Copyright (c) 2008-2009 Kazuo Horio.
00006 // Copyright (c) 2009-2013 Naruki Kurata.
00007 // Copyright (c) 2005-2013 Ryota Shioya.
00008 // Copyright (c) 2005-2013 Masahiro Goshima.
00009 // 
00010 // This software is provided 'as-is', without any express or implied
00011 // warranty. In no event will the authors be held liable for any damages
00012 // arising from the use of this software.
00013 // 
00014 // Permission is granted to anyone to use this software for any purpose,
00015 // including commercial applications, and to alter it and redistribute it
00016 // freely, subject to the following restrictions:
00017 // 
00018 // 1. The origin of this software must not be misrepresented; you must not
00019 // claim that you wrote the original software. If you use this software
00020 // in a product, an acknowledgment in the product documentation would be
00021 // appreciated but is not required.
00022 // 
00023 // 2. Altered source versions must be plainly marked as such, and must not be
00024 // misrepresented as being the original software.
00025 // 
00026 // 3. This notice may not be removed or altered from any source
00027 // distribution.
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 // #define GDB_DEBUG
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 // Communicating functions
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 ('?'): // Indicate the reason the target halted
00119         break;
00120     case ('q'): // General query
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'): // Set thread
00131         m_packet.command = m_streamBuffer.at(1);
00132         m_packet.params.push_back(m_streamBuffer.substr(2));
00133         break;
00134     case ('g'): // Read general registers
00135         break;
00136     case ('G'): // Write general registers
00137         m_packet.command = m_streamBuffer.substr(1);
00138         break;
00139     case ('p'): // Read the value of specified register
00140         m_packet.command = m_streamBuffer.substr(1);
00141         break;
00142     case ('P'): // Write specified register
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'): // Read memory
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'): // Write memory
00153     case ('M'): // Write memory
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'): // Resume
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'): // Insert breakpoint
00174     case ('z'): // Remove breakpoint
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 ('?'): // Indicate the reason the target halted
00200         SendPacket("T05thread:00;");
00201         break;
00202     case ('q'): // General query
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'): // Set thread
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'): // Read general registers
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); // TODO: 32bit register
00272         }
00273         SendPacket(readstr);
00274         break;
00275     case ('G'): // Write general registers
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'): // Read the value of specified register
00288         SendPacket(U64ToHexStr(GetRegister((int)HexStrToU64(m_packet.command)), 8)); // TODO: 32bit register
00289         break;
00290     case ('P'): // Write specified register
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'): // Read memory
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'): // Write memory
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'): // Write memory
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'): // Resume
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'): // Continue
00390         m_stopExec = false;
00391         break;
00392     case ('s'): // Step
00393         m_stopExec = false;
00394         m_stopCount = 1;
00395         break;
00396     case ('t'): // Terminate?
00397         m_stopExec = true;
00398         SendPacket("");
00399         break;
00400     case ('k'): // Kill
00401         THROW_RUNTIME_ERROR("Terminated via gdb.");
00402         break;
00403     case ('Z'): // Insert breakpoint
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'): // Remove breakpoint
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++){ // try 3 times and then give up
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 { // Wait for commands from gdb in this loop
00504         if(m_stopCount > 0){ // step exec
00505             if(m_stopCount == 1){
00506                 m_stopExec = true;
00507                 SendPacket("S05");
00508             }
00509             m_stopCount--;
00510         }
00511         if(!m_stopExec){ // Software Breakpoint
00512             if (m_breakpoint.find(m_context->architectureStateList[m_pid].pc.address) != m_breakpoint.end()) // Z0
00513             {
00514                 m_stopExec = true;
00515                 SendPacket("S05");
00516             }
00517             else if (op->GetOpInfo()->GetOpClass().IsLoad()) // Z3, Z4
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()) // Z2, Z4
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 // Utility functions
00568 //
00569 
00570 u64 DebugStub::GetRegister( int regNum )
00571 {
00572     // TODO: set correct PC on every ISA
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     // TODO: set correct PC on every ISA
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         // '#', '$' and '}' are escaped by '}'.
00630         // The original character is XORed with 0x20.
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 }

Onikiri2に対してTue Jun 18 14:34:26 2013に生成されました。  doxygen 1.4.7