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 : Session::Session(ITransport *transport)
27 : : io_(transport),
28 : flags_(0),
29 : seq_(0),
30 1 : connected_(true) {
31 1 : }
32 :
33 1 : Session::~Session() {
34 1 : }
35 :
36 1 : void Session::SetFlags(uint32_t flags) {
37 1 : flags_ |= flags;
38 1 : }
39 :
40 1 : void Session::ClearFlags(uint32_t flags) {
41 1 : flags_ &= ~flags;
42 1 : }
43 :
44 1 : uint32_t Session::GetFlags() {
45 1 : return flags_;
46 1 : }
47 :
48 0 : bool Session::IsDataAvailable() {
49 0 : return io_->IsDataAvailable();
50 0 : }
51 :
52 1 : bool Session::Connected() {
53 1 : return connected_;
54 1 : }
55 :
56 1 : void Session::Disconnect() {
57 1 : io_->Disconnect();
58 1 : connected_ = false;
59 1 : }
60 :
61 1 : bool Session::GetChar(char *ch) {
62 1 : if (!io_->Read(ch, 1)) {
63 1 : Disconnect();
64 1 : return false;
65 : }
66 :
67 1 : return true;
68 1 : }
69 :
70 :
71 1 : bool Session::SendPacket(Packet *pkt) {
72 : char ch;
73 :
74 : do {
75 1 : if (!SendPacketOnly(pkt)) return false;
76 :
77 : // If ACKs are off, we are done.
78 1 : if (GetFlags() & IGNORE_ACK) break;
79 :
80 : // Otherwise, poll for '+'
81 1 : if (!GetChar(&ch)) return false;
82 :
83 : // Retry if we didn't get a '+'
84 1 : } while (ch != '+');
85 :
86 1 : return true;
87 1 : }
88 :
89 :
90 1 : bool Session::SendPacketOnly(Packet *pkt) {
91 : const char *ptr;
92 : char ch;
93 1 : std::stringstream outstr;
94 :
95 1 : char run_xsum = 0;
96 : int32_t seq;
97 :
98 1 : ptr = pkt->GetPayload();
99 1 : size_t size = pkt->GetPayloadSize();
100 :
101 1 : if (!pkt->GetSequence(&seq) && (GetFlags() & USE_SEQ)) {
102 0 : pkt->SetSequence(seq_++);
103 : }
104 :
105 : // Signal start of response
106 1 : outstr << '$';
107 :
108 : // If there is a sequence, send as two nibble 8bit value + ':'
109 1 : 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 1 : for (size_t offs = 0; offs < size; ++offs) {
125 1 : ch = ptr[offs];
126 1 : outstr << ch;
127 1 : run_xsum += ch;
128 1 : }
129 :
130 1 : if (GetFlags() & DEBUG_SEND) {
131 0 : NaClLog(1, "TX %s\n", outstr.str().c_str());
132 : }
133 :
134 : // Send XSUM as two nible 8bit value preceeded by '#'
135 1 : outstr << '#';
136 1 : IntToNibble((run_xsum >> 4) & 0xF, &ch);
137 1 : outstr << ch;
138 1 : IntToNibble(run_xsum & 0xF, &ch);
139 1 : outstr << ch;
140 :
141 : return io_->Write(outstr.str().data(),
142 1 : static_cast<int32_t>(outstr.str().length()));
143 1 : }
144 :
145 : // Attempt to receive a packet
146 1 : bool Session::GetPacket(Packet *pkt) {
147 : char run_xsum, fin_xsum, ch;
148 1 : std::string in;
149 :
150 : // Toss characters until we see a start of command
151 : do {
152 1 : if (!GetChar(&ch)) return false;
153 1 : in += ch;
154 1 : } while (ch != '$');
155 :
156 : retry:
157 : // Clear the stream
158 1 : pkt->Clear();
159 :
160 : // Prepare XSUM calc
161 1 : run_xsum = 0;
162 1 : fin_xsum = 0;
163 :
164 : // Stream in the characters
165 1 : while (1) {
166 1 : if (!GetChar(&ch)) return false;
167 :
168 : // If we see a '#' we must be done with the data
169 1 : if (ch == '#') break;
170 :
171 1 : in += ch;
172 :
173 : // If we see a '$' we must have missed the last cmd
174 1 : if (ch == '$') {
175 0 : NaClLog(LOG_INFO, "RX Missing $, retry.\n");
176 0 : goto retry;
177 : }
178 : // Keep a running XSUM
179 1 : run_xsum += ch;
180 1 : pkt->AddRawChar(ch);
181 1 : }
182 :
183 :
184 : // Get two Nibble XSUM
185 1 : if (!GetChar(&ch)) return false;
186 :
187 : int val;
188 1 : NibbleToInt(ch, & val);
189 1 : fin_xsum = val << 4;
190 :
191 1 : if (!GetChar(&ch)) return false;
192 1 : NibbleToInt(ch, &val);
193 1 : fin_xsum |= val;
194 :
195 1 : if (GetFlags() & DEBUG_RECV) NaClLog(1, "RX %s\n", in.c_str());
196 :
197 1 : pkt->ParseSequence();
198 :
199 : // If ACKs are off, we are done.
200 1 : if (GetFlags() & IGNORE_ACK) return true;
201 :
202 : // If the XSUMs don't match, signal bad packet
203 1 : if (fin_xsum == run_xsum) {
204 1 : char out[3] = { '+', 0, 0 };
205 : int32_t seq;
206 :
207 : // If we have a sequence number
208 1 : 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 1 : 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 : return true;
224 1 : }
225 :
226 : } // End of namespace gdb_rsp
227 :
|