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 <stdio.h>
9 : #include <stdlib.h>
10 : #include <string.h>
11 :
12 : #include <string>
13 : #include <sstream>
14 : #include <vector>
15 :
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/test.h"
19 :
20 : using gdb_rsp::Session;
21 : using gdb_rsp::Packet;
22 :
23 : // Transport simulation class, this stores data and a r/w index
24 : // to simulate one direction of a pipe, or a pipe to self.
25 : class SharedVector {
26 : public:
27 1 : SharedVector() : rd(0), wr(0) {}
28 :
29 : public:
30 : std::vector<char> data;
31 : volatile uint32_t rd;
32 : volatile uint32_t wr;
33 : };
34 :
35 : // Simulates a transport (such as a socket), the reports "ready"
36 : // when polled, but fails on TX/RX.
37 : class DCSocketTransport : public port::ITransport {
38 : public:
39 1 : virtual bool Read(void *ptr, int32_t len) {
40 : (void) ptr;
41 : (void) len;
42 1 : return false;
43 1 : }
44 :
45 0 : virtual bool Write(const void *ptr, int32_t len) {
46 : (void) ptr;
47 : (void) len;
48 0 : return false;
49 0 : }
50 :
51 0 : virtual bool IsDataAvailable() {
52 0 : return true;
53 0 : }
54 :
55 : virtual void WaitForDebugStubEvent(struct NaClApp *nap,
56 0 : bool ignore_gdb) {
57 : UNREFERENCED_PARAMETER(nap);
58 : UNREFERENCED_PARAMETER(ignore_gdb);
59 0 : }
60 :
61 1 : virtual void Disconnect() {}
62 : };
63 :
64 :
65 : // Simulate a transport transmitting data Q'd in TX and verifying that
66 : // inbound data matches expected "golden" string.
67 : class GoldenTransport : public DCSocketTransport {
68 : public:
69 1 : GoldenTransport(const char *rx, const char *tx, int cnt) {
70 1 : rx_ = rx;
71 1 : tx_ = tx;
72 1 : cnt_ = cnt;
73 1 : txCnt_ = 0;
74 1 : rxCnt_ = 0;
75 1 : errs_ = 0;
76 1 : disconnected_ = false;
77 1 : }
78 :
79 1 : virtual bool Read(void *ptr, int32_t len) {
80 1 : if (disconnected_) return false;
81 1 : memcpy(ptr, &rx_[rxCnt_], len);
82 1 : rxCnt_ += len;
83 1 : if (static_cast<int>(strlen(rx_)) < rxCnt_) {
84 0 : printf("End of RX\n");
85 0 : errs_++;
86 : }
87 1 : return true;
88 1 : }
89 :
90 : // Read from this link, return a negative value if there is an error
91 1 : virtual bool Write(const void *ptr, int32_t len) {
92 1 : const char *str = reinterpret_cast<const char *>(ptr);
93 1 : if (disconnected_) return false;
94 1 : if (strncmp(str, &tx_[txCnt_], len) != 0) {
95 0 : printf("TX mismatch in %s vs %s.\n", str, &tx_[txCnt_]);
96 0 : errs_++;
97 : }
98 1 : txCnt_ += len;
99 1 : return true;
100 1 : }
101 :
102 0 : virtual bool IsDataAvailable() {
103 0 : if (disconnected_) return true;
104 :
105 0 : return rxCnt_ < static_cast<int>(strlen(rx_));
106 0 : }
107 :
108 1 : virtual void Disconnect() {
109 1 : disconnected_ = true;
110 1 : }
111 :
112 1 : int errs() { return errs_; }
113 :
114 :
115 : protected:
116 : const char *rx_;
117 : const char *tx_;
118 : int cnt_;
119 : int rxCnt_;
120 : int txCnt_;
121 : int errs_;
122 : bool disconnected_;
123 : };
124 :
125 :
126 : class TestTransport : public DCSocketTransport {
127 : public:
128 1 : TestTransport(SharedVector *rvec, SharedVector *wvec) {
129 1 : rvector_ = rvec;
130 1 : wvector_ = wvec;
131 1 : disconnected_ = false;
132 1 : }
133 :
134 1 : virtual bool Read(void *ptr, int32_t len) {
135 1 : if (disconnected_) return false;
136 :
137 1 : int max = rvector_->wr - rvector_->rd;
138 1 : if (max > len) {
139 1 : max = len;
140 1 : } else {
141 1 : return false;
142 : }
143 :
144 1 : if (max > 0) {
145 1 : char *src = &rvector_->data[rvector_->rd];
146 1 : memcpy(ptr, src, max);
147 : }
148 1 : rvector_->rd += max;
149 1 : return true;
150 1 : }
151 :
152 1 : virtual bool Write(const void *ptr, int32_t len) {
153 1 : if (disconnected_) return false;
154 :
155 1 : wvector_->data.resize(wvector_->wr + len);
156 1 : memcpy(&wvector_->data[wvector_->wr], ptr, len);
157 1 : wvector_->wr += len;
158 1 : return true;
159 1 : }
160 :
161 0 : virtual bool IsDataAvailable() {
162 0 : if (disconnected_) return true;
163 :
164 0 : return rvector_->rd < rvector_->wr;
165 0 : }
166 :
167 1 : virtual void Disconnect() {
168 1 : disconnected_ = true;
169 1 : }
170 :
171 : protected:
172 : SharedVector *rvector_;
173 : SharedVector *wvector_;
174 : bool disconnected_;
175 : };
176 :
177 :
178 1 : int TestSession() {
179 1 : int errs = 0;
180 1 : Packet pktOut;
181 1 : Packet pktIn;
182 1 : SharedVector vec;
183 :
184 : // Create a "loopback" session by using the same
185 : // FIFO for ingress and egress.
186 1 : Session cli(new TestTransport(&vec, &vec));
187 1 : Session srv(new TestTransport(&vec, &vec));
188 :
189 : // Check, Set,Clear,Get flags.
190 1 : cli.ClearFlags(static_cast<uint32_t>(-1));
191 1 : cli.SetFlags(Session::IGNORE_ACK | Session::DEBUG_RECV);
192 1 : if (cli.GetFlags() != (Session::IGNORE_ACK + Session::DEBUG_RECV)) {
193 0 : printf("SetFlag failed.\n");
194 0 : errs++;
195 : }
196 1 : cli.ClearFlags(Session::IGNORE_ACK | Session::DEBUG_SEND);
197 1 : if (cli.GetFlags() != Session::DEBUG_RECV) {
198 0 : printf("ClearFlag failed.\n");
199 0 : errs++;
200 : }
201 :
202 : // Check Send Packet of known value.
203 1 : const char *str = "1234";
204 :
205 1 : pktOut.AddString(str);
206 1 : cli.SendPacketOnly(&pktOut);
207 1 : srv.GetPacket(&pktIn);
208 1 : std::string out;
209 1 : pktIn.GetString(&out);
210 1 : if (out != str) {
211 0 : printf("Send Only failed.\n");
212 0 : errs++;
213 : }
214 :
215 : // Check send against golden transactions
216 1 : const char tx[] = { "$1234#ca+" };
217 1 : const char rx[] = { "+$OK#9a" };
218 1 : GoldenTransport gold(rx, tx, 2);
219 1 : Session uni(&gold);
220 :
221 1 : pktOut.Clear();
222 1 : pktOut.AddString(str);
223 1 : if (!uni.SendPacket(&pktOut)) {
224 0 : printf("Send failed.\n");
225 0 : errs++;
226 : }
227 1 : if (!uni.GetPacket(&pktIn)) {
228 0 : printf("Get failed.\n");
229 0 : errs++;
230 : }
231 1 : pktIn.GetString(&out);
232 1 : if (out != "OK") {
233 0 : printf("Send/Get failed.\n");
234 0 : errs++;
235 : }
236 :
237 : // Check that a closed Transport reports to session
238 1 : if (!uni.Connected()) {
239 0 : printf("Expecting uni to be connected.\n");
240 0 : errs++;
241 : }
242 1 : gold.Disconnect();
243 1 : uni.GetPacket(&pktIn);
244 1 : if (uni.Connected()) {
245 0 : printf("Expecting uni to be disconnected.\n");
246 0 : errs++;
247 : }
248 :
249 : // Check that a failed read/write reports DC
250 1 : DCSocketTransport dctrans;
251 1 : Session dctest(&dctrans);
252 1 : if (!dctest.Connected()) {
253 0 : printf("Expecting dctest to be connected.\n");
254 0 : errs++;
255 : }
256 1 : dctest.GetPacket(&pktIn);
257 1 : if (dctest.Connected()) {
258 0 : printf("Expecting dctest to be disconnected.\n");
259 0 : errs++;
260 : }
261 :
262 1 : errs += gold.errs();
263 1 : return errs;
264 1 : }
265 :
|