1 : /*
2 : * Copyright 2010 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be found in the LICENSE file.
5 : */
6 :
7 : #include <assert.h>
8 : #include <string.h>
9 : #include <stdio.h>
10 : #include <stdlib.h>
11 :
12 : #include <string>
13 : #include <sstream>
14 :
15 : #include "native_client/src/trusted/gdb_rsp/abi.h"
16 : #include "native_client/src/trusted/gdb_rsp/session.h"
17 : #include "native_client/src/trusted/gdb_rsp/session_mock.h"
18 : #include "native_client/src/trusted/port/platform.h"
19 : #include "native_client/src/trusted/port/thread.h"
20 : #include "native_client/src/trusted/port/transport.h"
21 :
22 : #ifdef WIN32
23 : #define snprintf _snprintf
24 : #endif
25 :
26 : namespace gdb_rsp {
27 :
28 2 : SessionMock::SessionMock(bool target) : Session() {
29 2 : target_ = target;
30 2 : cur_ = 0;
31 :
32 4 : Session::Init(new TransportMock);
33 2 : SetFlags(IGNORE_ACK);
34 2 : }
35 :
36 2 : SessionMock::~SessionMock() {
37 44 : for (size_t a = 0; a < actions_.size(); a++)
38 42 : delete actions_[a];
39 :
40 2 : delete static_cast<TransportMock*>(io_);
41 2 : }
42 :
43 20 : bool SessionMock::SendPacketOnly(gdb_rsp::Packet *packet) {
44 20 : if (PeekAction() == SEND) {
45 20 : Action *pact = GetAction();
46 20 : const char *str = packet->GetPayload();
47 :
48 20 : if (GetFlags() & DEBUG_SEND) port::IPlatform::LogInfo("TX %s\n", str);
49 :
50 : // Check if we match
51 20 : if (pact->str_ == str) return true;
52 :
53 : port::IPlatform::LogInfo("Mismatch:\n\tSENDING: %s\n\tEXPECT: %s\n",
54 0 : str, pact->str_.data());
55 : }
56 0 : return false;
57 : }
58 :
59 22 : bool SessionMock::GetPacket(gdb_rsp::Packet *packet) {
60 22 : if (PeekAction() == RECV) {
61 20 : Action *pact = GetAction();
62 20 : packet->Clear();
63 20 : packet->AddString(pact->str_.data());
64 20 : if (GetFlags() & DEBUG_RECV) {
65 0 : port::IPlatform::LogInfo("RX %s\n", pact->str_.data());
66 : }
67 20 : return true;
68 : }
69 2 : return false;
70 : }
71 :
72 0 : bool SessionMock::DataAvailable() {
73 0 : return PeekAction() == RECV;
74 : }
75 :
76 44 : SessionMock::ActionType SessionMock::PeekAction() {
77 44 : if (cur_ < actions_.size()) {
78 43 : Action* pact = actions_[cur_];
79 43 : ActionType at = pact->type_;
80 43 : if (DISCONNECT == at) {
81 3 : connected_ = false;
82 : }
83 43 : return at;
84 : }
85 1 : return TIMEOUT;
86 : }
87 :
88 41 : SessionMock::Action* SessionMock::GetAction() {
89 41 : if (cur_ < actions_.size()) return actions_[cur_++];
90 0 : return NULL;
91 : }
92 :
93 42 : void SessionMock::AddAction(ActionType act, const char *str) {
94 42 : Action *pact = new Action;
95 :
96 42 : pact->type_ = act;
97 42 : pact->str_ = str;
98 42 : actions_.push_back(pact);
99 42 : }
100 :
101 19 : void SessionMock::AddTransaction(const char *snd, const char *rcv) {
102 19 : if (target_) {
103 : // If we are a target, we get a command, then respond
104 7 : AddAction(RECV, snd);
105 7 : AddAction(SEND, rcv);
106 : } else {
107 : // If we are a host, we send a command, and expect a reply
108 12 : AddAction(SEND, snd);
109 12 : AddAction(RECV, rcv);
110 : }
111 19 : }
112 :
113 2 : void AddMockInit(SessionMock* ses) {
114 2 : const gdb_rsp::Abi* abi = gdb_rsp::Abi::Get();
115 :
116 : // Setup supported query
117 : ses->AddTransaction(
118 : "qSupported",
119 2 : "PacketSize=7cf;qXfer:libraries:read+;qXfer:features:read+");
120 :
121 : // Setup arch query
122 2 : std::string str = "l<target><architecture>";
123 4 : str += abi->GetName();
124 2 : str += "</architecture></target>";
125 : ses->AddTransaction(
126 : "qXfer:features:read:target.xml:0,7cf",
127 2 : str.data());
128 2 : }
129 :
130 3 : void AddMockUpdate(SessionMock* ses, uint8_t sig) {
131 3 : const gdb_rsp::Abi* abi = gdb_rsp::Abi::Get();
132 :
133 : // Setup thread query
134 : ses->AddTransaction(
135 : "qfThreadInfo",
136 3 : "m1234");
137 : ses->AddTransaction(
138 : "qsThreadInfo",
139 3 : "l");
140 : ses->AddTransaction(
141 : "Hg1234",
142 3 : "OK");
143 :
144 : // Setup Register Query
145 3 : std::string str = "";
146 6 : port::IThread *thread = port::IThread::Acquire(0x1234, true);
147 51 : for (uint32_t a = 0; a < abi->GetRegisterCount(); a++) {
148 : char tmp[8];
149 48 : const Abi::RegDef* def = abi->GetRegisterDef(a);
150 48 : uint64_t val = static_cast<uint64_t>(a);
151 48 : uint8_t *pval = reinterpret_cast<uint8_t*>(&val);
152 :
153 : // Create a hex version of the register number of
154 : // the specified zero padded to the correct size
155 240 : for (uint32_t b = 0; b < def->bytes_; b++) {
156 192 : snprintf(tmp, sizeof(tmp), "%02x", pval[b]);
157 192 : str += tmp;
158 : }
159 :
160 48 : thread->SetRegister(a, &val, def->bytes_);
161 : }
162 3 : ses->AddTransaction("g", str.data());
163 :
164 : char tmp[8];
165 3 : snprintf(tmp, sizeof(tmp), "S%02x", sig);
166 3 : ses->AddTransaction("?", tmp);
167 3 : }
168 :
169 : // GetGoldenSessionMock
170 : //
171 : // The function bellow generates a mock session and preloads it
172 : // with expected inputs and outputs for a common connection case.
173 : // For GDB, that's:
174 : // 1) qSupported - Querry for supported features
175 : // 2) qXfer:features:read:target.xml:0,7cf - Query for target arch.
176 : // 3) qfThreadInfo/qsThreadInfo - Query for active threads
177 : // 4) Hg1234 - Set current register context to retreived thread id
178 : // 5) g - Get current thread registers
179 : // 6) disconnect
180 2 : SessionMock *GetGoldenSessionMock(bool target, bool debug) {
181 2 : SessionMock *ses = new SessionMock(target);
182 :
183 2 : if (debug) ses->SetFlags(Session::DEBUG_RECV | Session::DEBUG_SEND);
184 :
185 2 : AddMockInit(ses);
186 2 : AddMockUpdate(ses, 5);
187 :
188 2 : ses->AddAction(SessionMock::DISCONNECT, "");
189 2 : return ses;
190 : }
191 :
192 : } // namespace gdb_rsp
|