Skip to content

Commit d803bde

Browse files
Petr Bauchdanpoe
Petr Bauch
authored andcommitted
Fix based on comments
1 parent fa2ed7b commit d803bde

File tree

4 files changed

+84
-78
lines changed

4 files changed

+84
-78
lines changed

src/memory-analyzer/gdb_api.cpp

Lines changed: 67 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,11 @@ Author: Malte Mues <[email protected]>
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`
4573
void 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-
145155
void 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
227237
gdb_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-
251256
bool 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

322326
std::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

src/memory-analyzer/gdb_api.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,17 @@ Author: Malte Mues <[email protected]>
2929
#include <unistd.h>
3030

3131
#include <exception>
32+
#include <forward_list>
3233

3334
#include <util/exception_utils.h>
3435

3536
class gdb_apit
3637
{
3738
public:
39+
using commandst = std::forward_list<std::string>;
40+
3841
explicit gdb_apit(const char *binary, const bool log = false);
42+
~gdb_apit();
3943

4044
void create_gdb_process();
4145
void terminate_gdb_process();
@@ -46,22 +50,22 @@ class gdb_apit
4650
std::string get_value(const std::string &expr);
4751
std::string get_memory(const std::string &expr);
4852

49-
const std::vector<std::string> &get_command_log();
53+
const commandst &get_command_log();
5054

5155
protected:
5256
const char *binary;
5357

54-
FILE *input_stream;
55-
FILE *output_stream;
58+
FILE *response_stream;
59+
FILE *command_stream;
5660

5761
const bool log;
58-
std::vector<std::string> command_log;
62+
commandst command_log;
5963

6064
enum class gdb_statet
6165
{
6266
NOT_CREATED,
6367
CREATED,
64-
STOPPED
68+
STOPPED // valid state, reached e.g. after breakpoint was hit
6569
};
6670

6771
gdb_statet gdb_state;
@@ -79,9 +83,9 @@ class gdb_apit
7983
gdb_output_recordt
8084
get_most_recent_record(const std::string &tag, const bool must_exist = false);
8185

82-
static bool has_tag(const std::string &tag, const std::string &line);
83-
8486
bool most_recent_line_has_tag(const std::string &tag);
87+
bool was_command_accepted();
88+
void check_command_accepted();
8589
};
8690

8791
class gdb_interaction_exceptiont : public cprover_exception_baset
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
goto-programs
22
util
3+
sys

unit/memory-analyzer/gdb_api.cpp

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,7 @@ void gdb_api_internals_test()
6060
{
6161
gdb_api_testt gdb_api("test");
6262

63-
gdb_api_testt::gdb_output_recordt gor;
64-
65-
gor = gdb_api.parse_gdb_output_record(
63+
gdb_api_testt::gdb_output_recordt gor = gdb_api.parse_gdb_output_record(
6664
"a = \"1\", b = \"2\", c = {1, 2}, d = [3, 4], e=\"0x0\"");
6765

6866
REQUIRE(gor["a"] == "1");
@@ -77,11 +75,9 @@ void gdb_api_internals_test()
7775
gdb_api_testt gdb_api("test");
7876

7977
FILE *f = fopen("memory-analyzer/input.txt", "r");
80-
gdb_api.input_stream = f;
81-
82-
std::string line;
78+
gdb_api.response_stream = f;
8379

84-
line = gdb_api.read_next_line();
80+
std::string line = gdb_api.read_next_line();
8581
REQUIRE(line == "abc\n");
8682

8783
line = gdb_api.read_next_line();
@@ -98,10 +94,8 @@ void gdb_api_internals_test()
9894
gdb_api.create_gdb_process();
9995

10096
// check input and output streams
101-
REQUIRE(!ferror(gdb_api.input_stream));
102-
REQUIRE(!ferror(gdb_api.output_stream));
103-
104-
gdb_api.terminate_gdb_process();
97+
REQUIRE(!ferror(gdb_api.response_stream));
98+
REQUIRE(!ferror(gdb_api.command_stream));
10599
}
106100
}
107101

@@ -127,8 +121,6 @@ TEST_CASE("gdb api test", "[core][memory-analyzer]")
127121
{
128122
const bool r = gdb_api.run_gdb_to_breakpoint("checkpoint");
129123
REQUIRE(r);
130-
131-
gdb_api.terminate_gdb_process();
132124
}
133125
catch(const gdb_interaction_exceptiont &e)
134126
{
@@ -155,8 +147,6 @@ TEST_CASE("gdb api test", "[core][memory-analyzer]")
155147

156148
std::cerr << "=== gdb log end ===\n";
157149

158-
gdb_api.terminate_gdb_process();
159-
160150
return;
161151
}
162152
}
@@ -203,6 +193,5 @@ TEST_CASE("gdb api test", "[core][memory-analyzer]")
203193
}
204194
}
205195

206-
gdb_api.terminate_gdb_process();
207196
#endif
208197
}

0 commit comments

Comments
 (0)