@@ -29,8 +29,11 @@ Author: Malte Mues <mail.mues@gmail.com>
2929
3030#include < goto-programs/goto_model.h>
3131
32+ #include < util/prefix.h>
3233#include < util/string_utils.h>
3334
35+ #include < sys/wait.h>
36+
3437// / Create a gdb_apit object
3538// /
3639// / \param binary the binary to run with gdb
@@ -40,6 +43,31 @@ gdb_apit::gdb_apit(const char *binary, const bool log)
4043{
4144}
4245
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+
4371// / Create a new gdb process for analysing the binary indicated by the member
4472// / variable `binary`
4573void gdb_apit::create_gdb_process ()
@@ -82,10 +110,10 @@ void gdb_apit::create_gdb_process()
82110
83111 dprintf (pipe_output[1 ], " binary name: %s\n " , binary);
84112
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 };
89117
90118 dprintf (pipe_output[1 ], " Loading gdb...\n " );
91119 execvp (" gdb" , arg);
@@ -103,68 +131,50 @@ void gdb_apit::create_gdb_process()
103131 close (pipe_output[1 ]);
104132
105133 // get stream for reading the gdb output
106- input_stream = fdopen (pipe_output[0 ], " r" );
134+ response_stream = fdopen (pipe_output[0 ], " r" );
107135
108136 // get stream for writing to gdb
109- output_stream = fdopen (pipe_input[1 ], " w" );
137+ command_stream = fdopen (pipe_input[1 ], " w" );
110138
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);
112141
113142 if (log)
114143 {
115144 // logs output to `gdb.txt` in the current directory, input is not logged
116145 // hence we log it to `command_log`
117146 write_to_gdb (" -gdb-set logging on" );
118- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
147+ check_command_accepted ( );
119148 }
120149
121150 write_to_gdb (" -gdb-set max-value-size unlimited" );
122- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
151+ check_command_accepted ( );
123152 }
124153}
125154
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-
145155void gdb_apit::write_to_gdb (const std::string &command)
146156{
147157 PRECONDITION (!command.empty ());
148- PRECONDITION (command.back () != ' \n ' );
158+ PRECONDITION (command.find ( ' \n ' ) == std::string::npos );
149159
150160 std::string line (command);
151161 line += ' \n ' ;
152162
153163 if (log)
154164 {
155- command_log.push_back (command);
165+ command_log.push_front (command);
156166 }
157167
158- if (fputs (line.c_str (), output_stream ) == EOF)
168+ if (fputs (line.c_str (), command_stream ) == EOF)
159169 {
160170 throw gdb_interaction_exceptiont (" could not write a command to gdb" );
161171 }
162172
163- fflush (output_stream );
173+ fflush (command_stream );
164174}
165175
166176// / 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 ()
168178{
169179 PRECONDITION (log);
170180 return command_log;
@@ -179,17 +189,17 @@ std::string gdb_apit::read_next_line()
179189 const size_t buf_size = 1024 ;
180190 char buf[buf_size]; // NOLINT(runtime/arrays)
181191
182- const char *c = fgets (buf, buf_size, input_stream );
192+ const char *c = fgets (buf, buf_size, response_stream );
183193
184194 if (c == NULL )
185195 {
186- if (ferror (input_stream ))
196+ if (ferror (response_stream ))
187197 {
188198 throw gdb_interaction_exceptiont (" error reading from gdb" );
189199 }
190200
191201 INVARIANT (
192- feof (input_stream ),
202+ feof (response_stream ),
193203 " EOF must have been reached when the error indicator on the stream "
194204 " is not set and fgets returned NULL" );
195205 INVARIANT (
@@ -227,7 +237,7 @@ gdb_apit::gdb_output_recordt
227237gdb_apit::get_most_recent_record (const std::string &tag, const bool must_exist)
228238{
229239 std::string line = read_most_recent_line ();
230- const bool b = has_tag (tag, line );
240+ const bool b = has_prefix (line, tag );
231241
232242 if (must_exist)
233243 {
@@ -243,15 +253,10 @@ gdb_apit::get_most_recent_record(const std::string &tag, const bool must_exist)
243253 return parse_gdb_output_record (record);
244254}
245255
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-
251256bool gdb_apit::most_recent_line_has_tag (const std::string &tag)
252257{
253258 const std::string line = read_most_recent_line ();
254- return has_tag (tag, line );
259+ return has_prefix (line, tag );
255260}
256261
257262// / Run gdb with the given core file
@@ -265,7 +270,7 @@ void gdb_apit::run_gdb_from_core(const std::string &corefile)
265270 const std::string command = " core " + corefile;
266271
267272 write_to_gdb (command);
268- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
273+ check_command_accepted ( );
269274
270275 gdb_state = gdb_statet::STOPPED;
271276}
@@ -282,7 +287,7 @@ bool gdb_apit::run_gdb_to_breakpoint(const std::string &breakpoint)
282287 command += " " + breakpoint;
283288
284289 write_to_gdb (command);
285- if (!most_recent_line_has_tag ( " ^done " ))
290+ if (!was_command_accepted ( ))
286291 {
287292 throw gdb_interaction_exceptiont (" could not set breakpoint" );
288293 }
@@ -315,27 +320,24 @@ bool gdb_apit::run_gdb_to_breakpoint(const std::string &breakpoint)
315320 " gdb stopped for unhandled reason `" + reason + " `" );
316321 }
317322
318- // not reached
319- return true ;
323+ UNREACHABLE;
320324}
321325
322326std::string gdb_apit::eval_expr (const std::string &expr)
323327{
324328 write_to_gdb (" -var-create tmp * " + expr);
325329
326- if (!most_recent_line_has_tag ( " ^done " ))
330+ if (!was_command_accepted ( ))
327331 {
328332 throw gdb_interaction_exceptiont (
329- " could not create variable for "
330- " expression `" +
331- expr + " `" );
333+ " could not create variable for expression `" + expr + " `" );
332334 }
333335
334336 write_to_gdb (" -var-evaluate-expression tmp" );
335337 gdb_output_recordt record = get_most_recent_record (" ^done" , true );
336338
337339 write_to_gdb (" -var-delete tmp" );
338- CHECK_RETURN ( most_recent_line_has_tag ( " ^done " ) );
340+ check_command_accepted ( );
339341
340342 const auto it = record.find (" value" );
341343 CHECK_RETURN (it != record.end ());
@@ -381,8 +383,7 @@ std::string gdb_apit::get_memory(const std::string &expr)
381383 " ` is not a memory address or has unrecognised format" );
382384 }
383385
384- // not reached
385- return " " ;
386+ UNREACHABLE;
386387}
387388
388389// / Get value of the given value expression
@@ -432,7 +433,7 @@ gdb_apit::parse_gdb_output_record(const std::string &s)
432433
433434 gdb_output_recordt result;
434435
435- unsigned depth = 0 ;
436+ std:: size_t depth = 0 ;
436437 std::string::size_type start = 0 ;
437438
438439 const std::string::size_type n = s.length ();
@@ -488,4 +489,15 @@ gdb_apit::parse_gdb_output_record(const std::string &s)
488489 return result;
489490}
490491
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+
491503#endif
0 commit comments