1 : /*
2 : * Copyright (c) 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include <assert.h>
8 : #include <string.h>
9 : #include <stdlib.h>
10 :
11 : #include <string>
12 : #include <sstream>
13 :
14 : #include "native_client/src/shared/platform/nacl_log.h"
15 : #include "native_client/src/trusted/debug_stub/packet.h"
16 : #include "native_client/src/trusted/debug_stub/platform.h"
17 : #include "native_client/src/trusted/debug_stub/session.h"
18 : #include "native_client/src/trusted/debug_stub/transport.h"
19 : #include "native_client/src/trusted/debug_stub/util.h"
20 :
21 : using port::IPlatform;
22 : using port::ITransport;
23 :
24 : namespace gdb_rsp {
25 :
26 35 : Session::Session(ITransport *transport)
27 : : io_(transport),
28 : flags_(0),
29 : seq_(0),
30 35 : connected_(true) {
31 35 : }
32 :
33 19 : Session::~Session() {
34 19 : }
35 :
36 32 : void Session::SetFlags(uint32_t flags) {
37 32 : flags_ |= flags;
38 32 : }
39 :
40 2 : void Session::ClearFlags(uint32_t flags) {
41 2 : flags_ &= ~flags;
42 2 : }
43 :
44 4456 : uint32_t Session::GetFlags() {
45 4456 : return flags_;
46 : }
47 :
48 1 : bool Session::IsDataAvailable() {
49 1 : return io_->IsDataAvailable();
50 : }
51 :
52 11254 : bool Session::Connected() {
53 11254 : return connected_;
54 : }
55 :
56 33 : void Session::Disconnect() {
57 33 : io_->Disconnect();
58 33 : connected_ = false;
59 33 : }
60 :
61 16110 : bool Session::GetChar(char *ch) {
62 16110 : if (!io_->Read(ch, 1)) {
63 31 : Disconnect();
64 31 : return false;
65 : }
66 :
67 16079 : return true;
68 : }
69 :
70 :
71 838 : bool Session::SendPacket(Packet *pkt) {
72 : char ch;
73 :
74 823 : do {
75 838 : if (!SendPacketOnly(pkt)) return false;
76 :
77 : // If ACKs are off, we are done.
78 838 : if (GetFlags() & IGNORE_ACK) break;
79 :
80 : // Otherwise, poll for '+'
81 838 : if (!GetChar(&ch)) return false;
82 :
83 : // Retry if we didn't get a '+'
84 : } while (ch != '+');
85 :
86 823 : return true;
87 : }
88 :
89 :
90 905 : bool Session::SendPacketOnly(Packet *pkt) {
91 : const char *ptr;
92 : char ch;
93 905 : std::stringstream outstr;
94 :
95 905 : char run_xsum = 0;
96 : int32_t seq;
97 :
98 905 : ptr = pkt->GetPayload();
99 905 : size_t size = pkt->GetPayloadSize();
100 :
101 905 : if (!pkt->GetSequence(&seq) && (GetFlags() & USE_SEQ)) {
102 0 : pkt->SetSequence(seq_++);
103 : }
104 :
105 : // Signal start of response
106 905 : outstr << '$';
107 :
108 : // If there is a sequence, send as two nibble 8bit value + ':'
109 905 : if (pkt->GetSequence(&seq)) {
110 0 : IntToNibble((seq & 0xFF) >> 4, &ch);
111 0 : outstr << ch;
112 0 : run_xsum += ch;
113 :
114 0 : IntToNibble(seq & 0xF, &ch);
115 0 : outstr << ch;
116 0 : run_xsum += ch;
117 :
118 0 : ch = ':';
119 0 : outstr << ch;
120 0 : run_xsum += ch;
121 : }
122 :
123 : // Send the main payload
124 230730 : for (size_t offs = 0; offs < size; ++offs) {
125 229825 : ch = ptr[offs];
126 229825 : outstr << ch;
127 229825 : run_xsum += ch;
128 : }
129 :
130 905 : if (GetFlags() & DEBUG_SEND) {
131 903 : NaClLog(1, "TX %s\n", outstr.str().c_str());
132 : }
133 :
134 : // Send XSUM as two nible 8bit value preceeded by '#'
135 905 : outstr << '#';
136 905 : IntToNibble((run_xsum >> 4) & 0xF, &ch);
137 905 : outstr << ch;
138 905 : IntToNibble(run_xsum & 0xF, &ch);
139 905 : outstr << ch;
140 :
141 1810 : return io_->Write(outstr.str().data(),
142 2715 : static_cast<int32_t>(outstr.str().length()));
143 : }
144 :
145 : // Attempt to receive a packet
146 919 : bool Session::GetPacket(Packet *pkt) {
147 : char run_xsum, fin_xsum, ch;
148 919 : std::string in;
149 :
150 : // Toss characters until we see a start of command
151 998 : do {
152 1013 : if (!GetChar(&ch)) return false;
153 998 : in += ch;
154 : } while (ch != '$');
155 :
156 : retry:
157 : // Clear the stream
158 904 : pkt->Clear();
159 :
160 : // Prepare XSUM calc
161 904 : run_xsum = 0;
162 904 : fin_xsum = 0;
163 :
164 : // Stream in the characters
165 11547 : while (1) {
166 12451 : if (!GetChar(&ch)) return false;
167 :
168 : // If we see a '#' we must be done with the data
169 12451 : if (ch == '#') break;
170 :
171 11547 : in += ch;
172 :
173 : // If we see a '$' we must have missed the last cmd
174 11547 : if (ch == '$') {
175 0 : NaClLog(LOG_INFO, "RX Missing $, retry.\n");
176 0 : goto retry;
177 : }
178 : // Keep a running XSUM
179 11547 : run_xsum += ch;
180 11547 : pkt->AddRawChar(ch);
181 : }
182 :
183 :
184 : // Get two Nibble XSUM
185 904 : if (!GetChar(&ch)) return false;
186 :
187 : int val;
188 904 : NibbleToInt(ch, & val);
189 904 : fin_xsum = val << 4;
190 :
191 904 : if (!GetChar(&ch)) return false;
192 903 : NibbleToInt(ch, &val);
193 903 : fin_xsum |= val;
194 :
195 903 : if (GetFlags() & DEBUG_RECV) NaClLog(1, "RX %s\n", in.c_str());
196 :
197 903 : pkt->ParseSequence();
198 :
199 : // If ACKs are off, we are done.
200 903 : if (GetFlags() & IGNORE_ACK) return true;
201 :
202 : // If the XSUMs don't match, signal bad packet
203 903 : if (fin_xsum == run_xsum) {
204 903 : char out[3] = { '+', 0, 0 };
205 : int32_t seq;
206 :
207 : // If we have a sequence number
208 903 : if (pkt->GetSequence(&seq)) {
209 : // Respond with Sequence number
210 0 : IntToNibble(seq >> 4, &out[1]);
211 0 : IntToNibble(seq & 0xF, &out[2]);
212 0 : return io_->Write(out, 3);
213 : }
214 903 : return io_->Write(out, 1);
215 : } else {
216 : // Resend a bad XSUM and look for retransmit
217 0 : io_->Write("-", 1);
218 :
219 0 : NaClLog(LOG_INFO, "RX Bad XSUM, retry\n");
220 0 : goto retry;
221 : }
222 :
223 919 : return true;
224 : }
225 :
226 : } // End of namespace gdb_rsp
227 :
|