1 | //===-- StringExtractorGDBRemote.cpp --------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "lldb/Utility/StringExtractorGDBRemote.h" |
10 | |
11 | #include <cctype> |
12 | #include <cstring> |
13 | #include <optional> |
14 | |
15 | constexpr lldb::pid_t StringExtractorGDBRemote::; |
16 | constexpr lldb::tid_t StringExtractorGDBRemote::; |
17 | |
18 | StringExtractorGDBRemote::ResponseType |
19 | StringExtractorGDBRemote::() const { |
20 | if (m_packet.empty()) |
21 | return eUnsupported; |
22 | |
23 | switch (m_packet[0]) { |
24 | case 'E': |
25 | if (isxdigit(m_packet[1]) && isxdigit(m_packet[2])) { |
26 | if (m_packet.size() == 3) |
27 | return eError; |
28 | llvm::StringRef packet_ref(m_packet); |
29 | if (packet_ref[3] == ';') { |
30 | auto err_string = packet_ref.substr(Start: 4); |
31 | for (auto e : err_string) |
32 | if (!isxdigit(e)) |
33 | return eResponse; |
34 | return eError; |
35 | } |
36 | } |
37 | break; |
38 | |
39 | case 'O': |
40 | if (m_packet.size() == 2 && m_packet[1] == 'K') |
41 | return eOK; |
42 | break; |
43 | |
44 | case '+': |
45 | if (m_packet.size() == 1) |
46 | return eAck; |
47 | break; |
48 | |
49 | case '-': |
50 | if (m_packet.size() == 1) |
51 | return eNack; |
52 | break; |
53 | } |
54 | return eResponse; |
55 | } |
56 | |
57 | StringExtractorGDBRemote::ServerPacketType |
58 | StringExtractorGDBRemote::() const { |
59 | #define PACKET_MATCHES(s) \ |
60 | ((packet_size == (sizeof(s) - 1)) && (strcmp((packet_cstr), (s)) == 0)) |
61 | #define PACKET_STARTS_WITH(s) \ |
62 | ((packet_size >= (sizeof(s) - 1)) && \ |
63 | ::strncmp(packet_cstr, s, (sizeof(s) - 1)) == 0) |
64 | |
65 | // Empty is not a supported packet... |
66 | if (m_packet.empty()) |
67 | return eServerPacketType_invalid; |
68 | |
69 | const size_t packet_size = m_packet.size(); |
70 | const char *packet_cstr = m_packet.c_str(); |
71 | switch (m_packet[0]) { |
72 | |
73 | case '%': |
74 | return eServerPacketType_notify; |
75 | |
76 | case '\x03': |
77 | if (packet_size == 1) |
78 | return eServerPacketType_interrupt; |
79 | break; |
80 | |
81 | case '-': |
82 | if (packet_size == 1) |
83 | return eServerPacketType_nack; |
84 | break; |
85 | |
86 | case '+': |
87 | if (packet_size == 1) |
88 | return eServerPacketType_ack; |
89 | break; |
90 | |
91 | case 'A': |
92 | return eServerPacketType_A; |
93 | |
94 | case 'Q': |
95 | |
96 | switch (packet_cstr[1]) { |
97 | case 'E': |
98 | if (PACKET_STARTS_WITH("QEnvironment:" )) |
99 | return eServerPacketType_QEnvironment; |
100 | if (PACKET_STARTS_WITH("QEnvironmentHexEncoded:" )) |
101 | return eServerPacketType_QEnvironmentHexEncoded; |
102 | if (PACKET_STARTS_WITH("QEnableErrorStrings" )) |
103 | return eServerPacketType_QEnableErrorStrings; |
104 | break; |
105 | |
106 | case 'P': |
107 | if (PACKET_STARTS_WITH("QPassSignals:" )) |
108 | return eServerPacketType_QPassSignals; |
109 | break; |
110 | |
111 | case 'S': |
112 | if (PACKET_MATCHES("QStartNoAckMode" )) |
113 | return eServerPacketType_QStartNoAckMode; |
114 | if (PACKET_STARTS_WITH("QSaveRegisterState" )) |
115 | return eServerPacketType_QSaveRegisterState; |
116 | if (PACKET_STARTS_WITH("QSetDisableASLR:" )) |
117 | return eServerPacketType_QSetDisableASLR; |
118 | if (PACKET_STARTS_WITH("QSetDetachOnError:" )) |
119 | return eServerPacketType_QSetDetachOnError; |
120 | if (PACKET_STARTS_WITH("QSetSTDIN:" )) |
121 | return eServerPacketType_QSetSTDIN; |
122 | if (PACKET_STARTS_WITH("QSetSTDOUT:" )) |
123 | return eServerPacketType_QSetSTDOUT; |
124 | if (PACKET_STARTS_WITH("QSetSTDERR:" )) |
125 | return eServerPacketType_QSetSTDERR; |
126 | if (PACKET_STARTS_WITH("QSetWorkingDir:" )) |
127 | return eServerPacketType_QSetWorkingDir; |
128 | if (PACKET_STARTS_WITH("QSetLogging:" )) |
129 | return eServerPacketType_QSetLogging; |
130 | if (PACKET_STARTS_WITH("QSetIgnoredExceptions" )) |
131 | return eServerPacketType_QSetIgnoredExceptions; |
132 | if (PACKET_STARTS_WITH("QSetMaxPacketSize:" )) |
133 | return eServerPacketType_QSetMaxPacketSize; |
134 | if (PACKET_STARTS_WITH("QSetMaxPayloadSize:" )) |
135 | return eServerPacketType_QSetMaxPayloadSize; |
136 | if (PACKET_STARTS_WITH("QSetEnableAsyncProfiling;" )) |
137 | return eServerPacketType_QSetEnableAsyncProfiling; |
138 | if (PACKET_STARTS_WITH("QSyncThreadState:" )) |
139 | return eServerPacketType_QSyncThreadState; |
140 | break; |
141 | |
142 | case 'L': |
143 | if (PACKET_STARTS_WITH("QLaunchArch:" )) |
144 | return eServerPacketType_QLaunchArch; |
145 | if (PACKET_MATCHES("QListThreadsInStopReply" )) |
146 | return eServerPacketType_QListThreadsInStopReply; |
147 | break; |
148 | |
149 | case 'M': |
150 | if (PACKET_STARTS_WITH("QMemTags" )) |
151 | return eServerPacketType_QMemTags; |
152 | break; |
153 | |
154 | case 'N': |
155 | if (PACKET_STARTS_WITH("QNonStop:" )) |
156 | return eServerPacketType_QNonStop; |
157 | break; |
158 | |
159 | case 'R': |
160 | if (PACKET_STARTS_WITH("QRestoreRegisterState:" )) |
161 | return eServerPacketType_QRestoreRegisterState; |
162 | break; |
163 | |
164 | case 'T': |
165 | if (PACKET_MATCHES("QThreadSuffixSupported" )) |
166 | return eServerPacketType_QThreadSuffixSupported; |
167 | break; |
168 | } |
169 | break; |
170 | |
171 | case 'q': |
172 | switch (packet_cstr[1]) { |
173 | case 's': |
174 | if (PACKET_MATCHES("qsProcessInfo" )) |
175 | return eServerPacketType_qsProcessInfo; |
176 | if (PACKET_MATCHES("qsThreadInfo" )) |
177 | return eServerPacketType_qsThreadInfo; |
178 | break; |
179 | |
180 | case 'f': |
181 | if (PACKET_STARTS_WITH("qfProcessInfo" )) |
182 | return eServerPacketType_qfProcessInfo; |
183 | if (PACKET_STARTS_WITH("qfThreadInfo" )) |
184 | return eServerPacketType_qfThreadInfo; |
185 | break; |
186 | |
187 | case 'C': |
188 | if (packet_size == 2) |
189 | return eServerPacketType_qC; |
190 | break; |
191 | |
192 | case 'E': |
193 | if (PACKET_STARTS_WITH("qEcho:" )) |
194 | return eServerPacketType_qEcho; |
195 | break; |
196 | |
197 | case 'F': |
198 | if (PACKET_STARTS_WITH("qFileLoadAddress:" )) |
199 | return eServerPacketType_qFileLoadAddress; |
200 | break; |
201 | |
202 | case 'G': |
203 | if (PACKET_STARTS_WITH("qGroupName:" )) |
204 | return eServerPacketType_qGroupName; |
205 | if (PACKET_MATCHES("qGetWorkingDir" )) |
206 | return eServerPacketType_qGetWorkingDir; |
207 | if (PACKET_MATCHES("qGetPid" )) |
208 | return eServerPacketType_qGetPid; |
209 | if (PACKET_STARTS_WITH("qGetProfileData;" )) |
210 | return eServerPacketType_qGetProfileData; |
211 | if (PACKET_MATCHES("qGDBServerVersion" )) |
212 | return eServerPacketType_qGDBServerVersion; |
213 | break; |
214 | |
215 | case 'H': |
216 | if (PACKET_MATCHES("qHostInfo" )) |
217 | return eServerPacketType_qHostInfo; |
218 | break; |
219 | |
220 | case 'K': |
221 | if (PACKET_STARTS_WITH("qKillSpawnedProcess" )) |
222 | return eServerPacketType_qKillSpawnedProcess; |
223 | break; |
224 | |
225 | case 'L': |
226 | if (PACKET_STARTS_WITH("qLaunchGDBServer" )) |
227 | return eServerPacketType_qLaunchGDBServer; |
228 | if (PACKET_MATCHES("qLaunchSuccess" )) |
229 | return eServerPacketType_qLaunchSuccess; |
230 | break; |
231 | |
232 | case 'M': |
233 | if (PACKET_STARTS_WITH("qMemoryRegionInfo:" )) |
234 | return eServerPacketType_qMemoryRegionInfo; |
235 | if (PACKET_MATCHES("qMemoryRegionInfo" )) |
236 | return eServerPacketType_qMemoryRegionInfoSupported; |
237 | if (PACKET_STARTS_WITH("qModuleInfo:" )) |
238 | return eServerPacketType_qModuleInfo; |
239 | if (PACKET_STARTS_WITH("qMemTags:" )) |
240 | return eServerPacketType_qMemTags; |
241 | break; |
242 | |
243 | case 'P': |
244 | if (PACKET_STARTS_WITH("qProcessInfoPID:" )) |
245 | return eServerPacketType_qProcessInfoPID; |
246 | if (PACKET_STARTS_WITH("qPlatform_shell:" )) |
247 | return eServerPacketType_qPlatform_shell; |
248 | if (PACKET_STARTS_WITH("qPlatform_mkdir:" )) |
249 | return eServerPacketType_qPlatform_mkdir; |
250 | if (PACKET_STARTS_WITH("qPlatform_chmod:" )) |
251 | return eServerPacketType_qPlatform_chmod; |
252 | if (PACKET_MATCHES("qProcessInfo" )) |
253 | return eServerPacketType_qProcessInfo; |
254 | if (PACKET_STARTS_WITH("qPathComplete:" )) |
255 | return eServerPacketType_qPathComplete; |
256 | break; |
257 | |
258 | case 'Q': |
259 | if (PACKET_MATCHES("qQueryGDBServer" )) |
260 | return eServerPacketType_qQueryGDBServer; |
261 | break; |
262 | |
263 | case 'R': |
264 | if (PACKET_STARTS_WITH("qRcmd," )) |
265 | return eServerPacketType_qRcmd; |
266 | if (PACKET_STARTS_WITH("qRegisterInfo" )) |
267 | return eServerPacketType_qRegisterInfo; |
268 | break; |
269 | |
270 | case 'S': |
271 | if (PACKET_STARTS_WITH("qSaveCore" )) |
272 | return eServerPacketType_qLLDBSaveCore; |
273 | if (PACKET_STARTS_WITH("qSpeedTest:" )) |
274 | return eServerPacketType_qSpeedTest; |
275 | if (PACKET_MATCHES("qShlibInfoAddr" )) |
276 | return eServerPacketType_qShlibInfoAddr; |
277 | if (PACKET_MATCHES("qStepPacketSupported" )) |
278 | return eServerPacketType_qStepPacketSupported; |
279 | if (PACKET_STARTS_WITH("qSupported" )) |
280 | return eServerPacketType_qSupported; |
281 | if (PACKET_MATCHES("qSyncThreadStateSupported" )) |
282 | return eServerPacketType_qSyncThreadStateSupported; |
283 | break; |
284 | |
285 | case 'T': |
286 | if (PACKET_STARTS_WITH("qThreadExtraInfo," )) |
287 | return eServerPacketType_qThreadExtraInfo; |
288 | if (PACKET_STARTS_WITH("qThreadStopInfo" )) |
289 | return eServerPacketType_qThreadStopInfo; |
290 | break; |
291 | |
292 | case 'U': |
293 | if (PACKET_STARTS_WITH("qUserName:" )) |
294 | return eServerPacketType_qUserName; |
295 | break; |
296 | |
297 | case 'V': |
298 | if (PACKET_MATCHES("qVAttachOrWaitSupported" )) |
299 | return eServerPacketType_qVAttachOrWaitSupported; |
300 | break; |
301 | |
302 | case 'W': |
303 | if (PACKET_STARTS_WITH("qWatchpointSupportInfo:" )) |
304 | return eServerPacketType_qWatchpointSupportInfo; |
305 | if (PACKET_MATCHES("qWatchpointSupportInfo" )) |
306 | return eServerPacketType_qWatchpointSupportInfoSupported; |
307 | break; |
308 | |
309 | case 'X': |
310 | if (PACKET_STARTS_WITH("qXfer:" )) |
311 | return eServerPacketType_qXfer; |
312 | break; |
313 | } |
314 | break; |
315 | |
316 | case 'j': |
317 | if (PACKET_STARTS_WITH("jModulesInfo:" )) |
318 | return eServerPacketType_jModulesInfo; |
319 | if (PACKET_MATCHES("jSignalsInfo" )) |
320 | return eServerPacketType_jSignalsInfo; |
321 | if (PACKET_MATCHES("jThreadsInfo" )) |
322 | return eServerPacketType_jThreadsInfo; |
323 | |
324 | if (PACKET_MATCHES("jLLDBTraceSupported" )) |
325 | return eServerPacketType_jLLDBTraceSupported; |
326 | if (PACKET_STARTS_WITH("jLLDBTraceStop:" )) |
327 | return eServerPacketType_jLLDBTraceStop; |
328 | if (PACKET_STARTS_WITH("jLLDBTraceStart:" )) |
329 | return eServerPacketType_jLLDBTraceStart; |
330 | if (PACKET_STARTS_WITH("jLLDBTraceGetState:" )) |
331 | return eServerPacketType_jLLDBTraceGetState; |
332 | if (PACKET_STARTS_WITH("jLLDBTraceGetBinaryData:" )) |
333 | return eServerPacketType_jLLDBTraceGetBinaryData; |
334 | break; |
335 | |
336 | case 'v': |
337 | if (PACKET_STARTS_WITH("vFile:" )) { |
338 | if (PACKET_STARTS_WITH("vFile:open:" )) |
339 | return eServerPacketType_vFile_open; |
340 | else if (PACKET_STARTS_WITH("vFile:close:" )) |
341 | return eServerPacketType_vFile_close; |
342 | else if (PACKET_STARTS_WITH("vFile:pread" )) |
343 | return eServerPacketType_vFile_pread; |
344 | else if (PACKET_STARTS_WITH("vFile:pwrite" )) |
345 | return eServerPacketType_vFile_pwrite; |
346 | else if (PACKET_STARTS_WITH("vFile:size" )) |
347 | return eServerPacketType_vFile_size; |
348 | else if (PACKET_STARTS_WITH("vFile:exists" )) |
349 | return eServerPacketType_vFile_exists; |
350 | else if (PACKET_STARTS_WITH("vFile:fstat" )) |
351 | return eServerPacketType_vFile_fstat; |
352 | else if (PACKET_STARTS_WITH("vFile:stat" )) |
353 | return eServerPacketType_vFile_stat; |
354 | else if (PACKET_STARTS_WITH("vFile:mode" )) |
355 | return eServerPacketType_vFile_mode; |
356 | else if (PACKET_STARTS_WITH("vFile:MD5" )) |
357 | return eServerPacketType_vFile_md5; |
358 | else if (PACKET_STARTS_WITH("vFile:symlink" )) |
359 | return eServerPacketType_vFile_symlink; |
360 | else if (PACKET_STARTS_WITH("vFile:unlink" )) |
361 | return eServerPacketType_vFile_unlink; |
362 | |
363 | } else { |
364 | if (PACKET_STARTS_WITH("vAttach;" )) |
365 | return eServerPacketType_vAttach; |
366 | if (PACKET_STARTS_WITH("vAttachWait;" )) |
367 | return eServerPacketType_vAttachWait; |
368 | if (PACKET_STARTS_WITH("vAttachOrWait;" )) |
369 | return eServerPacketType_vAttachOrWait; |
370 | if (PACKET_STARTS_WITH("vAttachName;" )) |
371 | return eServerPacketType_vAttachName; |
372 | if (PACKET_STARTS_WITH("vCont;" )) |
373 | return eServerPacketType_vCont; |
374 | if (PACKET_MATCHES("vCont?" )) |
375 | return eServerPacketType_vCont_actions; |
376 | if (PACKET_STARTS_WITH("vKill;" )) |
377 | return eServerPacketType_vKill; |
378 | if (PACKET_STARTS_WITH("vRun;" )) |
379 | return eServerPacketType_vRun; |
380 | if (PACKET_MATCHES("vStopped" )) |
381 | return eServerPacketType_vStopped; |
382 | if (PACKET_MATCHES("vCtrlC" )) |
383 | return eServerPacketType_vCtrlC; |
384 | if (PACKET_MATCHES("vStdio" )) |
385 | return eServerPacketType_vStdio; |
386 | break; |
387 | |
388 | } |
389 | break; |
390 | case '_': |
391 | switch (packet_cstr[1]) { |
392 | case 'M': |
393 | return eServerPacketType__M; |
394 | |
395 | case 'm': |
396 | return eServerPacketType__m; |
397 | } |
398 | break; |
399 | |
400 | case '?': |
401 | if (packet_size == 1) |
402 | return eServerPacketType_stop_reason; |
403 | break; |
404 | |
405 | case 'c': |
406 | return eServerPacketType_c; |
407 | |
408 | case 'C': |
409 | return eServerPacketType_C; |
410 | |
411 | case 'D': |
412 | return eServerPacketType_D; |
413 | |
414 | case 'g': |
415 | return eServerPacketType_g; |
416 | |
417 | case 'G': |
418 | return eServerPacketType_G; |
419 | |
420 | case 'H': |
421 | return eServerPacketType_H; |
422 | |
423 | case 'I': |
424 | return eServerPacketType_I; |
425 | |
426 | case 'k': |
427 | if (packet_size == 1) |
428 | return eServerPacketType_k; |
429 | break; |
430 | |
431 | case 'm': |
432 | return eServerPacketType_m; |
433 | |
434 | case 'M': |
435 | return eServerPacketType_M; |
436 | |
437 | case 'p': |
438 | return eServerPacketType_p; |
439 | |
440 | case 'P': |
441 | return eServerPacketType_P; |
442 | |
443 | case 's': |
444 | if (packet_size == 1) |
445 | return eServerPacketType_s; |
446 | break; |
447 | |
448 | case 'S': |
449 | return eServerPacketType_S; |
450 | |
451 | case 'x': |
452 | return eServerPacketType_x; |
453 | |
454 | case 'X': |
455 | return eServerPacketType_X; |
456 | |
457 | case 'T': |
458 | return eServerPacketType_T; |
459 | |
460 | case 'z': |
461 | if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') |
462 | return eServerPacketType_z; |
463 | break; |
464 | |
465 | case 'Z': |
466 | if (packet_cstr[1] >= '0' && packet_cstr[1] <= '4') |
467 | return eServerPacketType_Z; |
468 | break; |
469 | } |
470 | return eServerPacketType_unimplemented; |
471 | } |
472 | |
473 | bool StringExtractorGDBRemote::() const { |
474 | return GetResponseType() == eOK; |
475 | } |
476 | |
477 | bool StringExtractorGDBRemote::() const { |
478 | return GetResponseType() == eUnsupported; |
479 | } |
480 | |
481 | bool StringExtractorGDBRemote::() const { |
482 | return GetResponseType() == eResponse; |
483 | } |
484 | |
485 | bool StringExtractorGDBRemote::() const { |
486 | return GetResponseType() == eError && isxdigit(m_packet[1]) && |
487 | isxdigit(m_packet[2]); |
488 | } |
489 | |
490 | uint8_t StringExtractorGDBRemote::() { |
491 | if (GetResponseType() == eError) { |
492 | SetFilePos(1); |
493 | return GetHexU8(fail_value: 255); |
494 | } |
495 | return 0; |
496 | } |
497 | |
498 | lldb_private::Status StringExtractorGDBRemote::() { |
499 | lldb_private::Status error; |
500 | if (GetResponseType() == eError) { |
501 | SetFilePos(1); |
502 | uint8_t errc = GetHexU8(fail_value: 255); |
503 | error.SetError(err: errc, type: lldb::eErrorTypeGeneric); |
504 | |
505 | error.SetErrorStringWithFormat("Error %u" , errc); |
506 | std::string error_messg; |
507 | if (GetChar() == ';') { |
508 | GetHexByteString(str&: error_messg); |
509 | error.SetErrorString(error_messg); |
510 | } |
511 | } |
512 | return error; |
513 | } |
514 | |
515 | size_t StringExtractorGDBRemote::(std::string &str) { |
516 | // Just get the data bytes in the string as |
517 | // GDBRemoteCommunication::CheckForPacket() already removes any 0x7d escaped |
518 | // characters. If any 0x7d characters are left in the packet, then they are |
519 | // supposed to be there... |
520 | str.clear(); |
521 | const size_t bytes_left = GetBytesLeft(); |
522 | if (bytes_left > 0) { |
523 | str.assign(str: m_packet, pos: m_index, n: bytes_left); |
524 | m_index += bytes_left; |
525 | } |
526 | return str.size(); |
527 | } |
528 | |
529 | static bool |
530 | (void *, |
531 | const StringExtractorGDBRemote &response) { |
532 | switch (response.GetResponseType()) { |
533 | case StringExtractorGDBRemote::eOK: |
534 | case StringExtractorGDBRemote::eError: |
535 | case StringExtractorGDBRemote::eUnsupported: |
536 | return true; |
537 | |
538 | case StringExtractorGDBRemote::eAck: |
539 | case StringExtractorGDBRemote::eNack: |
540 | case StringExtractorGDBRemote::eResponse: |
541 | break; |
542 | } |
543 | return false; |
544 | } |
545 | |
546 | static bool (void *, |
547 | const StringExtractorGDBRemote &response) { |
548 | switch (response.GetResponseType()) { |
549 | case StringExtractorGDBRemote::eUnsupported: |
550 | case StringExtractorGDBRemote::eError: |
551 | return true; // Accept unsupported or EXX as valid responses |
552 | |
553 | case StringExtractorGDBRemote::eOK: |
554 | case StringExtractorGDBRemote::eAck: |
555 | case StringExtractorGDBRemote::eNack: |
556 | break; |
557 | |
558 | case StringExtractorGDBRemote::eResponse: |
559 | // JSON that is returned in from JSON query packets is currently always |
560 | // either a dictionary which starts with a '{', or an array which starts |
561 | // with a '['. This is a quick validator to just make sure the response |
562 | // could be valid JSON without having to validate all of the |
563 | // JSON content. |
564 | switch (response.GetStringRef()[0]) { |
565 | case '{': |
566 | return true; |
567 | case '[': |
568 | return true; |
569 | default: |
570 | break; |
571 | } |
572 | break; |
573 | } |
574 | return false; |
575 | } |
576 | |
577 | static bool |
578 | (void *, |
579 | const StringExtractorGDBRemote &response) { |
580 | switch (response.GetResponseType()) { |
581 | case StringExtractorGDBRemote::eUnsupported: |
582 | case StringExtractorGDBRemote::eError: |
583 | return true; // Accept unsupported or EXX as valid responses |
584 | |
585 | case StringExtractorGDBRemote::eOK: |
586 | case StringExtractorGDBRemote::eAck: |
587 | case StringExtractorGDBRemote::eNack: |
588 | break; |
589 | |
590 | case StringExtractorGDBRemote::eResponse: { |
591 | uint32_t valid_count = 0; |
592 | for (const char ch : response.GetStringRef()) { |
593 | if (!isxdigit(ch)) { |
594 | return false; |
595 | } |
596 | if (++valid_count >= 16) |
597 | break; // Don't validate all the characters in case the packet is very |
598 | // large |
599 | } |
600 | return true; |
601 | } break; |
602 | } |
603 | return false; |
604 | } |
605 | |
606 | void StringExtractorGDBRemote::( |
607 | const StringExtractorGDBRemote &rhs) { |
608 | m_validator = rhs.m_validator; |
609 | m_validator_baton = rhs.m_validator_baton; |
610 | } |
611 | |
612 | void StringExtractorGDBRemote::( |
613 | ResponseValidatorCallback callback, void *baton) { |
614 | m_validator = callback; |
615 | m_validator_baton = baton; |
616 | } |
617 | |
618 | void StringExtractorGDBRemote::() { |
619 | m_validator = OKErrorNotSupportedResponseValidator; |
620 | m_validator_baton = nullptr; |
621 | } |
622 | |
623 | void StringExtractorGDBRemote::() { |
624 | m_validator = ASCIIHexBytesResponseValidator; |
625 | m_validator_baton = nullptr; |
626 | } |
627 | |
628 | void StringExtractorGDBRemote::() { |
629 | m_validator = JSONResponseValidator; |
630 | m_validator_baton = nullptr; |
631 | } |
632 | |
633 | bool StringExtractorGDBRemote::() const { |
634 | // If we have a validator callback, try to validate the callback |
635 | if (m_validator) |
636 | return m_validator(m_validator_baton, *this); |
637 | else |
638 | return true; // No validator, so response is valid |
639 | } |
640 | |
641 | std::optional<std::pair<lldb::pid_t, lldb::tid_t>> |
642 | StringExtractorGDBRemote::(lldb::pid_t default_pid) { |
643 | llvm::StringRef view = llvm::StringRef(m_packet).substr(Start: m_index); |
644 | size_t initial_length = view.size(); |
645 | lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; |
646 | lldb::tid_t tid; |
647 | |
648 | if (view.consume_front(Prefix: "p" )) { |
649 | // process identifier |
650 | if (view.consume_front(Prefix: "-1" )) { |
651 | // -1 is a special case |
652 | pid = AllProcesses; |
653 | } else if (view.consumeInteger(Radix: 16, Result&: pid) || pid == 0) { |
654 | // not a valid hex integer OR unsupported pid 0 |
655 | m_index = UINT64_MAX; |
656 | return std::nullopt; |
657 | } |
658 | |
659 | // "." must follow if we expect TID too; otherwise, we assume -1 |
660 | if (!view.consume_front(Prefix: "." )) { |
661 | // update m_index |
662 | m_index += initial_length - view.size(); |
663 | |
664 | return {{pid, AllThreads}}; |
665 | } |
666 | } |
667 | |
668 | // thread identifier |
669 | if (view.consume_front(Prefix: "-1" )) { |
670 | // -1 is a special case |
671 | tid = AllThreads; |
672 | } else if (view.consumeInteger(Radix: 16, Result&: tid) || tid == 0 || pid == AllProcesses) { |
673 | // not a valid hex integer OR tid 0 OR pid -1 + a specific tid |
674 | m_index = UINT64_MAX; |
675 | return std::nullopt; |
676 | } |
677 | |
678 | // update m_index |
679 | m_index += initial_length - view.size(); |
680 | |
681 | return {{pid != LLDB_INVALID_PROCESS_ID ? pid : default_pid, tid}}; |
682 | } |
683 | |