29
29
30
30
#include < goto-programs/goto_model.h>
31
31
32
+ #include < util/prefix.h>
32
33
#include < util/string_utils.h>
33
34
35
+ #include < sys/wait.h>
36
+
34
37
// / Create a gdb_apit object
35
38
// /
36
39
// / \param binary the binary to run with gdb
@@ -40,6 +43,31 @@ gdb_apit::gdb_apit(const char *binary, const bool log)
40
43
{
41
44
}
42
45
46
+ // / Terminate the gdb process and close open streams (for reading from and
47
+ // / writing to gdb)
48
+ gdb_apit::~gdb_apit ()
49
+ {
50
+ PRECONDITION (
51
+ gdb_state == gdb_statet::CREATED || gdb_state == gdb_statet::STOPPED ||
52
+ gdb_state == gdb_statet::NOT_CREATED);
53
+
54
+ if (gdb_state == gdb_statet::NOT_CREATED)
55
+ return ;
56
+
57
+ write_to_gdb (" -gdb-exit" );
58
+ // we cannot use most_recent_line_has_tag() here as it checks the last line
59
+ // before the next `(gdb) \n` prompt in the output; however when gdb exits no
60
+ // next prompt is printed
61
+ CHECK_RETURN (has_prefix (read_next_line (), " ^exit" ));
62
+
63
+ gdb_state = gdb_statet::NOT_CREATED;
64
+
65
+ fclose (command_stream);
66
+ fclose (response_stream);
67
+
68
+ wait (NULL );
69
+ }
70
+
43
71
// / Create a new gdb process for analysing the binary indicated by the member
44
72
// / variable `binary`
45
73
void gdb_apit::create_gdb_process ()
@@ -82,10 +110,10 @@ void gdb_apit::create_gdb_process()
82
110
83
111
dprintf (pipe_output[1 ], " binary name: %s\n " , binary);
84
112
85
- char *arg[] = {const_cast <char *>(" gdb" ),
86
- const_cast <char *>(" --interpreter=mi" ),
87
- const_cast <char *>(binary),
88
- NULL };
113
+ char *const arg[] = {const_cast <char *>(" gdb" ),
114
+ const_cast <char *>(" --interpreter=mi" ),
115
+ const_cast <char *>(binary),
116
+ NULL };
89
117
90
118
dprintf (pipe_output[1 ], " Loading gdb...\n " );
91
119
execvp (" gdb" , arg);
@@ -103,68 +131,50 @@ void gdb_apit::create_gdb_process()
103
131
close (pipe_output[1 ]);
104
132
105
133
// get stream for reading the gdb output
106
- input_stream = fdopen (pipe_output[0 ], " r" );
134
+ response_stream = fdopen (pipe_output[0 ], " r" );
107
135
108
136
// get stream for writing to gdb
109
- output_stream = fdopen (pipe_input[1 ], " w" );
137
+ command_stream = fdopen (pipe_input[1 ], " w" );
110
138
111
- CHECK_RETURN (most_recent_line_has_tag (R"( ~"done)" ));
139
+ bool has_done_tag = most_recent_line_has_tag (R"( ~"done)" );
140
+ CHECK_RETURN (has_done_tag);
112
141
113
142
if (log )
114
143
{
115
144
// logs output to `gdb.txt` in the current directory, input is not logged
116
145
// hence we log it to `command_log`
117
146
write_to_gdb (" -gdb-set logging on" );
118
- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
147
+ check_command_accepted ( );
119
148
}
120
149
121
150
write_to_gdb (" -gdb-set max-value-size unlimited" );
122
- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
151
+ check_command_accepted ( );
123
152
}
124
153
}
125
154
126
- // / Terminate the gdb process and close open streams (for reading from and
127
- // / writing to gdb)
128
- void gdb_apit::terminate_gdb_process ()
129
- {
130
- PRECONDITION (
131
- gdb_state == gdb_statet::CREATED || gdb_state == gdb_statet::STOPPED);
132
-
133
- write_to_gdb (" -gdb-exit" );
134
- // we cannot use most_recent_line_has_tag() here as it checks the last line
135
- // before the next `(gdb) \n` prompt in the output; however when gdb exits no
136
- // next prompt is printed
137
- CHECK_RETURN (has_tag (" ^exit" , read_next_line ()));
138
-
139
- gdb_state = gdb_statet::NOT_CREATED;
140
-
141
- fclose (output_stream);
142
- fclose (input_stream);
143
- }
144
-
145
155
void gdb_apit::write_to_gdb (const std::string &command)
146
156
{
147
157
PRECONDITION (!command.empty ());
148
- PRECONDITION (command.back () != ' \n ' );
158
+ PRECONDITION (command.find ( ' \n ' ) == std::string::npos );
149
159
150
160
std::string line (command);
151
161
line += ' \n ' ;
152
162
153
163
if (log )
154
164
{
155
- command_log.push_back (command);
165
+ command_log.push_front (command);
156
166
}
157
167
158
- if (fputs (line.c_str (), output_stream ) == EOF)
168
+ if (fputs (line.c_str (), command_stream ) == EOF)
159
169
{
160
170
throw gdb_interaction_exceptiont (" could not write a command to gdb" );
161
171
}
162
172
163
- fflush (output_stream );
173
+ fflush (command_stream );
164
174
}
165
175
166
176
// / Return the vector of commands that have been written to gdb so far
167
- const std::vector<std::string> &gdb_apit::get_command_log ()
177
+ const gdb_apit::commandst &gdb_apit::get_command_log ()
168
178
{
169
179
PRECONDITION (log );
170
180
return command_log;
@@ -179,17 +189,17 @@ std::string gdb_apit::read_next_line()
179
189
const size_t buf_size = 1024 ;
180
190
char buf[buf_size]; // NOLINT(runtime/arrays)
181
191
182
- const char *c = fgets (buf, buf_size, input_stream );
192
+ const char *c = fgets (buf, buf_size, response_stream );
183
193
184
194
if (c == NULL )
185
195
{
186
- if (ferror (input_stream ))
196
+ if (ferror (response_stream ))
187
197
{
188
198
throw gdb_interaction_exceptiont (" error reading from gdb" );
189
199
}
190
200
191
201
INVARIANT (
192
- feof (input_stream ),
202
+ feof (response_stream ),
193
203
" EOF must have been reached when the error indicator on the stream "
194
204
" is not set and fgets returned NULL" );
195
205
INVARIANT (
@@ -227,7 +237,7 @@ gdb_apit::gdb_output_recordt
227
237
gdb_apit::get_most_recent_record (const std::string &tag, const bool must_exist)
228
238
{
229
239
std::string line = read_most_recent_line ();
230
- const bool b = has_tag (tag, line );
240
+ const bool b = has_prefix (line, tag );
231
241
232
242
if (must_exist)
233
243
{
@@ -243,15 +253,10 @@ gdb_apit::get_most_recent_record(const std::string &tag, const bool must_exist)
243
253
return parse_gdb_output_record (record);
244
254
}
245
255
246
- bool gdb_apit::has_tag (const std::string &tag, const std::string &line)
247
- {
248
- return line.compare (0 , tag.length (), tag) == 0 ;
249
- }
250
-
251
256
bool gdb_apit::most_recent_line_has_tag (const std::string &tag)
252
257
{
253
258
const std::string line = read_most_recent_line ();
254
- return has_tag (tag, line );
259
+ return has_prefix (line, tag );
255
260
}
256
261
257
262
// / Run gdb with the given core file
@@ -265,7 +270,7 @@ void gdb_apit::run_gdb_from_core(const std::string &corefile)
265
270
const std::string command = " core " + corefile;
266
271
267
272
write_to_gdb (command);
268
- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
273
+ check_command_accepted ( );
269
274
270
275
gdb_state = gdb_statet::STOPPED;
271
276
}
@@ -282,7 +287,7 @@ bool gdb_apit::run_gdb_to_breakpoint(const std::string &breakpoint)
282
287
command += " " + breakpoint;
283
288
284
289
write_to_gdb (command);
285
- if (!most_recent_line_has_tag ( " ^done " ))
290
+ if (!was_command_accepted ( ))
286
291
{
287
292
throw gdb_interaction_exceptiont (" could not set breakpoint" );
288
293
}
@@ -315,27 +320,24 @@ bool gdb_apit::run_gdb_to_breakpoint(const std::string &breakpoint)
315
320
" gdb stopped for unhandled reason `" + reason + " `" );
316
321
}
317
322
318
- // not reached
319
- return true ;
323
+ UNREACHABLE;
320
324
}
321
325
322
326
std::string gdb_apit::eval_expr (const std::string &expr)
323
327
{
324
328
write_to_gdb (" -var-create tmp * " + expr);
325
329
326
- if (!most_recent_line_has_tag ( " ^done " ))
330
+ if (!was_command_accepted ( ))
327
331
{
328
332
throw gdb_interaction_exceptiont (
329
- " could not create variable for "
330
- " expression `" +
331
- expr + " `" );
333
+ " could not create variable for expression `" + expr + " `" );
332
334
}
333
335
334
336
write_to_gdb (" -var-evaluate-expression tmp" );
335
337
gdb_output_recordt record = get_most_recent_record (" ^done" , true );
336
338
337
339
write_to_gdb (" -var-delete tmp" );
338
- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
340
+ check_command_accepted ( );
339
341
340
342
const auto it = record.find (" value" );
341
343
CHECK_RETURN (it != record.end ());
@@ -381,8 +383,7 @@ std::string gdb_apit::get_memory(const std::string &expr)
381
383
" ` is not a memory address or has unrecognised format" );
382
384
}
383
385
384
- // not reached
385
- return " " ;
386
+ UNREACHABLE;
386
387
}
387
388
388
389
// / Get value of the given value expression
@@ -432,7 +433,7 @@ gdb_apit::parse_gdb_output_record(const std::string &s)
432
433
433
434
gdb_output_recordt result;
434
435
435
- unsigned depth = 0 ;
436
+ std:: size_t depth = 0 ;
436
437
std::string::size_type start = 0 ;
437
438
438
439
const std::string::size_type n = s.length ();
@@ -488,4 +489,15 @@ gdb_apit::parse_gdb_output_record(const std::string &s)
488
489
return result;
489
490
}
490
491
492
+ bool gdb_apit::was_command_accepted ()
493
+ {
494
+ return most_recent_line_has_tag (" ^done" );
495
+ }
496
+
497
+ void gdb_apit::check_command_accepted ()
498
+ {
499
+ bool was_accepted = was_command_accepted ();
500
+ CHECK_RETURN (was_accepted);
501
+ }
502
+
491
503
#endif
0 commit comments