58 const auto maybe_address_string =
get_value(pointer_expr);
78 if(
pipe(pipe_input) == -1)
83 if(
pipe(pipe_output) == -1)
99 close(pipe_output[0]);
101 dup2(pipe_input[0], STDIN_FILENO);
102 dup2(pipe_output[1], STDOUT_FILENO);
103 dup2(pipe_output[1], STDERR_FILENO);
105 dprintf(pipe_output[1],
"binary name: %s\n",
args.front().c_str());
107 std::vector<std::string> exec_cmd;
108 exec_cmd.reserve(
args.size() + 3);
109 exec_cmd.push_back(
"gdb");
110 exec_cmd.push_back(
"--interpreter=mi");
111 exec_cmd.push_back(
"--args");
112 exec_cmd.insert(exec_cmd.end(),
args.begin(),
args.end());
114 char **exec_cmd_ptr =
static_cast<char **
>(
malloc(
115 sizeof(
char *) * (exec_cmd.size() + 1)));
116 exec_cmd_ptr[exec_cmd.size()] = NULL;
118 for(std::size_t i = 0; i < exec_cmd.size(); i++)
120 exec_cmd_ptr[i] =
static_cast<char *
>(
malloc(
121 sizeof(
char) * (exec_cmd[i].length() + 1)));
122 strcpy(exec_cmd_ptr[i], exec_cmd[i].c_str());
125 dprintf(pipe_output[1],
"Loading gdb...\n");
126 execvp(
"gdb", exec_cmd_ptr);
129 int errno_value = errno;
130 dprintf(pipe_output[1],
"Starting gdb failed: %s\n",
strerror(errno_value));
131 dprintf(pipe_output[1],
"(gdb) \n");
137 close(pipe_input[0]);
138 close(pipe_output[1]);
174 std::string line(command);
202 const size_t buf_size = 1024;
216 "EOF must have been reached when the error indicator on the stream "
217 "is not set and fgets returned NULL");
219 result.empty() || result.back() !=
'\n',
220 "when EOF is reached then either no characters were read or the string"
221 " read does not end in a newline");
226 std::string chunk(buf);
227 INVARIANT(!chunk.empty(),
"chunk cannot be empty when EOF was not reached");
230 }
while(result.back() !=
'\n');
244 }
while(line !=
"(gdb) \n");
264 std::string record =
strip_string(line.substr(line.find(
',') + 1));
280 const std::string command =
"core " + corefile;
290 #if defined(__x86_64__)
307 #elif defined(__i386__)
311 write_to_gdb(
"-data-evaluate-expression \"*(unsigned long*)($esp + 4)\"");
313 auto allocated_size =
316 # error malloc calling conventions not know for current platform
328 if(frame_content.find(
"func=\"malloc\"") != std::string::npos)
352 std::string command(
"-break-insert");
353 command +=
" " + breakpoint;
393 const auto it = record.find(
"reason");
396 const std::string &reason = it->second;
398 if(reason ==
"breakpoint-hit")
403 else if(reason ==
"exited-normally")
410 "gdb stopped for unhandled reason `" + reason +
"`");
423 "could not create variable for expression `" + expr +
"`");
432 const auto it = record.find(
"value");
435 const std::string value = it->second;
438 value.back() !=
'"' ||
439 (value.length() >= 2 && value[value.length() - 2] ==
'\\'),
440 "quotes should have been stripped off from value");
441 INVARIANT(value.back() !=
'\n',
"value should not end in a newline");
457 return pointer_valuet{};
464 const bool b = regex_match(value, result, regex);
466 return pointer_valuet{};
468 std::optional<std::string> opt_string;
469 const std::string
string = result[4];
473 const std::size_t len =
string.length();
477 "pointer-string should be: backslash, quotes, .., backslash, quotes");
480 "pointer-string should be: backslash, quotes, .., backslash, quotes");
483 "pointer-string should be: backslash, quotes, .., backslash, quotes");
485 string[len - 2] ==
'\\',
486 "pointer-string should be: backslash, quotes, .., backslash, quotes");
488 string[len - 1] ==
'"',
489 "pointer-string should be: backslash, quotes, .., backslash, quotes");
491 opt_string =
string.substr(2, len - 4);
494 return pointer_valuet(result[1], result[2], result[3], opt_string,
true);
514 std::regex regex(R
"([^ ]+ '([^']+)')");
517 const bool b = regex_match(value, result, regex);
521 return std::string{result[1]};
536 std::size_t depth = 0;
545 if(c ==
'{' || c ==
'[')
549 else if(c ==
'}' || c ==
']')
554 if(depth == 0 && (c ==
',' || i == n - 1))
556 const std::string item =
557 i == n - 1 ? s.substr(start) : s.substr(start, i - start);
565 const std::string key =
strip_string(item.substr(0, j));
568 const char first = value.front();
569 const char last = value.back();
571 INVARIANT(first ==
'"' || first ==
'{' || first ==
'[',
"");
572 INVARIANT(first !=
'"' || last ==
'"',
"");
573 INVARIANT(first !=
'{' || last ==
'}',
"");
574 INVARIANT(first !=
'[' || last ==
']',
"");
579 value = value.substr(1, value.length() - 2);
582 auto r = result.insert(std::make_pair(key, value));
605 return R
"((?:)" + regex + R"()?)";
609 gdb_apit::r_or(const std::string ®ex_left,
const std::string ®ex_right)
611 return R
"((?:)" + regex_left + '|' + regex_right + R
"())";
615 const gdb_output_recordt &record,
616 const std::string &value_name)
618 const auto it = record.find(value_name);
620 const auto value = it->second;
623 value.back() !=
'"' ||
624 (value.length() >= 2 && value[value.length() - 2] ==
'\\'),
625 "quotes should have been stripped off from value");
626 INVARIANT(value.back() !=
'\n',
"value should not end in a newline");
633 const auto it = stopped_record.find(
"reason");
636 if(it->second !=
"breakpoint-hit")
648 std::string value_eq_quotes =
"value=\"";
649 auto value_eq_quotes_size = value_eq_quotes.size();
651 auto starting_pos = record_value.find(value_eq_quotes) + value_eq_quotes_size;
652 auto ending_pos = record_value.find(
'\"', starting_pos);
653 auto value_length = ending_pos - starting_pos;
654 return std::string{record_value, starting_pos, value_length};
static std::string r_opt(const std::string ®ex)
bool was_command_accepted()
void check_command_accepted()
bool run_gdb_to_breakpoint(const std::string &breakpoint)
Run gdb to the given breakpoint.
void collect_malloc_calls()
Intercepts the gdb-analysis at the malloc call-site to add the corresponding information into allocat...
void create_gdb_process()
Create a new gdb process for analysing the binary indicated by the first element in args
std::map< std::string, size_t > allocated_memory
track the allocated size for each malloc call maps hexadecimal address to the number of bytes
const std::string r_hex_addr
void write_to_gdb(const std::string &command)
std::map< std::string, std::string > gdb_output_recordt
void run_gdb_from_core(const std::string &corefile)
Run gdb with the given core file.
const commandst & get_command_log()
Return the vector of commands that have been written to gdb so far.
std::optional< std::string > get_value(const std::string &expr)
Get the memory address pointed to by the given pointer expression.
std::string eval_expr(const std::string &expr)
std::string read_next_line()
const std::string r_string
std::forward_list< std::string > commandst
std::string get_register_value(const gdb_output_recordt &record)
Parse the record produced by listing register value.
gdb_output_recordt get_most_recent_record(const std::string &tag, const bool must_exist=false)
const std::string malloc_name
static std::string r_or(const std::string ®ex_left, const std::string ®ex_right)
std::string get_value_from_record(const gdb_output_recordt &record, const std::string &value_name)
Locate and return the value for a given name.
static gdb_output_recordt parse_gdb_output_record(const std::string &s)
std::vector< std::string > args
pointer_valuet get_memory(const std::string &expr)
Get the value of a pointer associated with expr.
size_t query_malloc_size(const std::string &pointer_expr)
Get the exact allocated size for a pointer pointer_expr.
gdb_apit(const std::vector< std::string > &args, const bool log=false)
Create a gdb_apit object.
std::string read_most_recent_line()
bool most_recent_line_has_tag(const std::string &tag)
~gdb_apit()
Terminate the gdb process and close open streams (for reading from and writing to gdb)
bool hit_malloc_breakpoint(const gdb_output_recordt &stopped_record)
Check if the breakpoint we hit is inside a malloc.
bool has_prefix(const std::string &s, const std::string &prefix)
Low-level interface to gdb.
#define CHECK_RETURN(CONDITION)
#define UNREACHABLE
This should be used to mark dead code.
#define PRECONDITION(CONDITION)
int dprintf(int fd, const char *restrict format,...)
FILE * fdopen(int handle, const char *mode)
int fputs(const char *s, FILE *stream)
char * fgets(char *str, int size, FILE *stream)
void * malloc(__CPROVER_size_t malloc_size)
std::size_t safe_string2size_t(const std::string &str, int base)
char * strcpy(char *dst, const char *src)
char * strerror(int errnum)
std::string strip_string(const std::string &s)
Remove all whitespace characters from either end of a string.
Data associated with the value of a pointer, i.e.