Skip to content

GDB API [blocks: #4261] #3983

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Mar 19, 2019
Merged

GDB API [blocks: #4261] #3983

merged 17 commits into from
Mar 19, 2019

Conversation

danpoe
Copy link
Contributor

@danpoe danpoe commented Jan 28, 2019

This adds an API to run a program with gdb up to some breakpoint and then query the values of expressions. It is a partial rewrite of @mmuesly's gdb API (part of #2649). It now uses the gdb machine interface instead of the gdb user interface.

  • Each commit message has a non-empty body, explaining why the change was made.
  • Methods or procedures I have added are documented, following the guidelines provided in CODING_STANDARD.md.
  • n/a The feature or user visible behaviour I have added or modified has been documented in the User Guide in doc/cprover-manual/
  • Regression or unit tests are included, or existing tests cover the modified code (in this case I have detailed which ones those are in the commit message).
  • n/a My commit message includes data points confirming performance improvements (if claimed).
  • My PR is restricted to a single feature or bugfix.
  • White-space or formatting changes outside the feature-related changed lines are in commits of their own.

@martin-cs
Copy link
Collaborator

+1 looking back at the original patch set, connecting using the remote protocol was one of the things I requested. Glad to hear this is moving again.

Copy link
Contributor

@smowton smowton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sort of interactive child process management is prone to deadlock whenever gdb might start writing output (for example, an error message) before you're done writing input, and the pipe buffers are small enough that its write op blocks. Therefore usually you should use poll or similar to check for this circumstance and buffer any output it starts producing before your input command is complete.


dprintf(pipe_output[1], "binary name: %s\n", binary);

char *arg[] = {const_cast<char *>("gdb"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? Surely this is a char *const [] as required by execvp and these const casts should go away?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


#include <testing-utils/use_catch.h>

#ifdef __linux__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anything Unix-y I'd have thought? Are you doing anything tricky enough that Cygwin wouldn't support it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, changed to allow various Unices.


/// Termiante the gdb process and close open streams (for reading from and
/// writing to gdb)
void gdb_apit::terminate_gdb_process()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do this in a destructor to raise the chances of cleaning up your child on exception?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@danpoe
Copy link
Contributor Author

danpoe commented Jan 29, 2019

@smowton I'm not sure if that's an issue here. So we only write a command to gdb when we have read the (gdb) prompt. Then we write one command (terminated by a newline). Then gdb only does something and writes output when it has read a complete command. Before writing another command we again wait for the prompt (gdb).

@danpoe danpoe requested review from forejtv and thk123 as code owners January 29, 2019 13:35
@danpoe danpoe force-pushed the feature/gdb-api branch 7 times, most recently from 23642a0 to d5b99d2 Compare February 1, 2019 11:28
@@ -0,0 +1,153 @@
/*******************************************************************\

Module: GDB Machine Interface API unit tests
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really worth having a unit test here? It might be better to just run this in regression/ as an integration test? There isn't a whole lot to the API, and the unit test is fairly close to being a shell script written in C++?

Copy link
Contributor Author

@danpoe danpoe Feb 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The back and forth interaction with gdb is actually quite complicated. I feel like there definitely need to be unit tests to check that the API does this correctly.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, fine with me. I was just wondering whether doing this as a unit test just made things more complicated than necessary.

/// \file
/// Low-level interface to gdb

#ifdef __linux__
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which part of this code is really Linux-specific? If any at all? Even when we might never be able to run a gdb binary on Visual Studio, it's good to know that at least the code compiles and can be re-used/adapted.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, changed to allow various Unices. We need the fork() call from unistd.h.

/// variable `binary`
void gdb_apit::create_gdb_process()
{
PRECONDITION(gdb_state == gdb_statet::NOT_CREATED); std::cout << "GDB Here 0" << std::endl;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this needs some cleanup :-) You might as well use a debug() mstreamt, possibly with a separate debug logger so that you can use, e.g., a stream-based message handler that puts all the debug output on stderr?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes I just added this as I'm debugging some CI issues. This will be removed later.

@danpoe danpoe force-pushed the feature/gdb-api branch 9 times, most recently from 11cfbd2 to 8088eb0 Compare February 1, 2019 16:57
xbauch pushed a commit to xbauch/cbmc that referenced this pull request Mar 4, 2019
xbauch pushed a commit to xbauch/cbmc that referenced this pull request Mar 4, 2019
@chrisr-diffblue chrisr-diffblue self-assigned this Mar 19, 2019
mmuesly and others added 10 commits March 19, 2019 13:42
Applying CBMC on large code bases
requires sometimes to model a test environment.
Running a program until a certain point and let it
crash, allows to analyze the memory state at this point in time.
In continuation, the memory state might be reconstructed as base for
the test environment model.

By using gdb to analyze the core dump, I don't have to take
care of reading and interpreting the core dump myself.
When using the gdb machine interface (option --interpreter=mi), gdb outputs
results (such as that of printing a value) as records which are comma-separated
lists of key=value pairs. This adds a method parse_gdb_output_record() to parse
such records into a std::map.
This switches gdb_apit to use streams to communicate with the gdb subprocess
instead of using pipes/file descriptors directly.
This changes gdb_apit to use the gdb machine interface (mi) instead of the gdb
command line user interface to communicate with gdb.
danpoe and others added 7 commits March 19, 2019 15:52
We require the Unix fork() system call (in unistd.h)
This enables the gdb api unit tests (in memory-analyzer/gdb_api.cpp) and adapts
them to include use_catch.h instead of catch.hpp.
This adds new unit tests for gdb_apit. The tests compile a test file test.c and
then run gdb on it (via gdb_apit).
@danpoe danpoe merged commit 6533631 into diffblue:develop Mar 19, 2019
Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: fa2ed7b).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/104995261

Copy link
Contributor

@allredj allredj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️
Passed Diffblue compatibility checks (cbmc commit: d803bde).
Build URL: https://travis-ci.com/diffblue/test-gen/builds/104996155

@danpoe danpoe deleted the feature/gdb-api branch June 2, 2020 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.