• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/debug/wasm/gdb-server/session.h"
6 #include "src/debug/wasm/gdb-server/packet.h"
7 #include "src/debug/wasm/gdb-server/transport.h"
8 
9 namespace v8 {
10 namespace internal {
11 namespace wasm {
12 namespace gdb_server {
13 
Session(TransportBase * transport)14 Session::Session(TransportBase* transport)
15     : io_(transport), connected_(true), ack_enabled_(true) {}
16 
WaitForDebugStubEvent()17 void Session::WaitForDebugStubEvent() { io_->WaitForDebugStubEvent(); }
18 
SignalThreadEvent()19 bool Session::SignalThreadEvent() { return io_->SignalThreadEvent(); }
20 
IsDataAvailable() const21 bool Session::IsDataAvailable() const { return io_->IsDataAvailable(); }
22 
IsConnected() const23 bool Session::IsConnected() const { return connected_; }
24 
Disconnect()25 void Session::Disconnect() {
26   io_->Disconnect();
27   connected_ = false;
28 }
29 
GetChar(char * ch)30 bool Session::GetChar(char* ch) {
31   if (!io_->Read(ch, 1)) {
32     Disconnect();
33     return false;
34   }
35 
36   return true;
37 }
38 
SendPacket(Packet * pkt,bool expect_ack)39 bool Session::SendPacket(Packet* pkt, bool expect_ack) {
40   char ch;
41   do {
42     std::string data = pkt->GetPacketData();
43 
44     TRACE_GDB_REMOTE("TX %s\n", data.size() < 160
45                                     ? data.c_str()
46                                     : (data.substr(0, 160) + "...").c_str());
47     if (!io_->Write(data.data(), static_cast<int32_t>(data.length()))) {
48       return false;
49     }
50 
51     // If ACKs are off, we are done.
52     if (!expect_ack || !ack_enabled_) {
53       break;
54     }
55 
56     // Otherwise, poll for '+'
57     if (!GetChar(&ch)) {
58       return false;
59     }
60 
61     // Retry if we didn't get a '+'
62   } while (ch != '+');
63 
64   return true;
65 }
66 
GetPayload(Packet * pkt,uint8_t * checksum)67 bool Session::GetPayload(Packet* pkt, uint8_t* checksum) {
68   pkt->Clear();
69   *checksum = 0;
70 
71   // Stream in the characters
72   char ch;
73   while (GetChar(&ch)) {
74     if (ch == '#') {
75       // If we see a '#' we must be done with the data.
76       return true;
77     } else if (ch == '$') {
78       // If we see a '$' we must have missed the last cmd, let's retry.
79       TRACE_GDB_REMOTE("RX Missing $, retry.\n");
80       *checksum = 0;
81       pkt->Clear();
82     } else {
83       // Keep a running XSUM.
84       *checksum += ch;
85       pkt->AddRawChar(ch);
86     }
87   }
88   return false;
89 }
90 
GetPacket(Packet * pkt)91 bool Session::GetPacket(Packet* pkt) {
92   while (true) {
93     // Toss characters until we see a start of command
94     char ch;
95     do {
96       if (!GetChar(&ch)) {
97         return false;
98       }
99     } while (ch != '$');
100 
101     uint8_t running_checksum = 0;
102     if (!GetPayload(pkt, &running_checksum)) {
103       return false;
104     }
105 
106     // Get two nibble checksum
107     uint8_t trailing_checksum = 0;
108     char chars[2];
109     if (!GetChar(&chars[0]) || !GetChar(&chars[1]) ||
110         !HexToUInt8(chars, &trailing_checksum)) {
111       return false;
112     }
113 
114     TRACE_GDB_REMOTE("RX $%s#%c%c\n", pkt->GetPayload(), chars[0], chars[1]);
115 
116     pkt->ParseSequence();
117 
118     // If ACKs are off, we are done.
119     if (!ack_enabled_) {
120       return true;
121     }
122 
123     // If the XSUMs don't match, signal bad packet
124     if (trailing_checksum == running_checksum) {
125       char out[3] = {'+', 0, 0};
126 
127       // If we have a sequence number
128       int32_t seq;
129       if (pkt->GetSequence(&seq)) {
130         // Respond with sequence number
131         UInt8ToHex(seq, &out[1]);
132         return io_->Write(out, 3);
133       } else {
134         return io_->Write(out, 1);
135       }
136     } else {
137       // Resend a bad XSUM and look for retransmit
138       TRACE_GDB_REMOTE("RX Bad XSUM, retry\n");
139       io_->Write("-", 1);
140       // retry...
141     }
142   }
143 }
144 
145 }  // namespace gdb_server
146 }  // namespace wasm
147 }  // namespace internal
148 }  // namespace v8
149