Skip to content

Commit 7724092

Browse files
committed
Adding initial version of goto-inspect.
This allows to inspect a goto-binary (this means showing the goto-functions, for now at least). The reason this binary is helpful is that different tools (CBMC, goto-instrument, etc) perform instrumentation before showing the goto-functions, and there's a need to be able to inspect certain properties of a goto-binary without doing instrumentation.
1 parent 68af7a4 commit 7724092

18 files changed

+336
-2
lines changed

CMakeLists.txt

+2
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR
158158
"$<TARGET_FILE:goto-cc>"
159159
"$<TARGET_FILE:goto-diff>"
160160
"$<TARGET_FILE:goto-instrument>"
161+
"$<TARGET_FILE:goto-inspect>"
161162
"$<TARGET_FILE:goto-synthesizer>"
162163
"$<TARGET_FILE:janalyzer>"
163164
"$<TARGET_FILE:jbmc>"
@@ -230,6 +231,7 @@ cprover_default_properties(
230231
goto-checker
231232
goto-diff
232233
goto-diff-lib
234+
goto-inspect
233235
goto-harness
234236
goto-instrument
235237
goto-instrument-lib

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
/src/goto-harness/ @martin-cs @chris-ryder @peterschrammel
5454
/src/goto-instrument/ @martin-cs @chris-ryder @peterschrammel @tautschnig @kroening
5555
/src/goto-instrument/contracts/ @tautschnig @feliperodri @remi-delmas-3000
56+
/src/goto-inspect/ @diffblue/diffblue-opensource
5657
/src/goto-synthesizer/ @qinheping @tautschnig @feliperodri @remi-delmas-3000
5758
/src/goto-diff/ @tautschnig @peterschrammel
5859
/src/jsil/ @kroening @tautschnig

doc/man/goto-inspect.1

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.TH GOTO-INSPECT "2" "May 2023" "goto-inspect-5.81.0" "User Commands"
2+
.SH NAME
3+
goto\-inspect \- Inspect goto-binaries.
4+
.SH SYNOPSIS
5+
.TP
6+
.B goto\-inspect [\-?] [\-h] [\-\-help]
7+
show help
8+
.TP
9+
.B goto\-inspect \-\-version
10+
show version and exit
11+
.TP
12+
.B goto\-inspect [options] \fIin\fR
13+
Inspect (show properties, goto-functions, etc of) given goto-binary.
14+
.SH DESCRIPTION
15+
\fBgoto-inspect\fR reads a GOTO binary, and shows goto-functions, properties,
16+
and other attributes associated with the goto-program.
17+
.SH OPTIONS
18+
.SS "User-interface options:"
19+
.TP
20+
\fB\-\-show\-goto\-functions\fR
21+
print the goto-program instructions for the functions contained by the binary.
22+
.SH ENVIRONMENT
23+
All tools honor the TMPDIR environment variable when generating temporary
24+
files and directories.
25+
.SH BUGS
26+
If you encounter a problem please create an issue at
27+
.B https://github.com/diffblue/cbmc/issues
28+
.SH SEE ALSO
29+
.BR cbmc (1),
30+
.BR goto-cc (1)
31+
.BR goto-instrument (1)
32+
.SH COPYRIGHT
33+
2023, Diffblue Ltd.

regression/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_subdirectory(goto-instrument-chc)
4646
add_subdirectory(goto-instrument-json)
4747
add_subdirectory(goto-instrument-wmm-core)
4848
add_subdirectory(goto-instrument-typedef)
49+
add_subdirectory(goto-inspect)
4950
add_subdirectory(smt2_solver)
5051
add_subdirectory(smt2_strings)
5152
add_subdirectory(strings)
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
2+
set(is_windows true)
3+
set(exclude_win_broken_tests -X winbug)
4+
else()
5+
set(is_windows false)
6+
set(exclude_win_broken_tests "")
7+
endif()
8+
9+
add_test_pl_tests(
10+
"${CMAKE_CURRENT_SOURCE_DIR}/chain.sh $<TARGET_FILE:goto-cc> $<TARGET_FILE:goto-inspect> ${is_windows}" ${exclude_win_broken_tests}
11+
)

regression/goto-inspect/chain.sh

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
# A test instruction passed to this `chain.sh` file looks like this:
6+
#
7+
# build/bin/goto-cc build/bin/goto-inspect --show-goto-functions main.c
8+
#
9+
# This allows us to safely assume for now (as long as we're operating
10+
# goto-inspect with one binary and one inspection option, which seems
11+
# to be the case for now) that the option is going to be at $4.
12+
# If this is no longer the case in the future, this script will need
13+
# to be made significantly more sophisticated in terms of handling
14+
# a variable number of options for the goto-inspect binary.
15+
16+
goto_cc_exe=$1
17+
goto_inspect_exe=$2
18+
is_windows=$3
19+
20+
name=${*:$#}
21+
name=${name%.c}
22+
23+
# We need to dispatch to the appropriate platform executable because
24+
# they accept different options.
25+
if [[ "${is_windows}" == "true" ]]; then
26+
$goto_cc_exe "${name}.c" "/Fe${name}.gb"
27+
else
28+
$goto_cc_exe -o "${name}.gb" "${name}.c"
29+
fi
30+
31+
$goto_inspect_exe $4 "${name}.gb"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
int main(int argc, char *argv[])
2+
{
3+
int arr[] = {0, 1, 2, 3, 4};
4+
__CPROVER_assert(arr[0] != 0, "Expected failure: 0 == 0");
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CORE winbug
2+
main.c
3+
" "
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
--
7+
DECL main::1::arr : signedbv\[32\]\[5\]
8+
ASSIGN main::1::arr := \{ 0, 1, 2, 3, 4 \}
9+
ASSERT main::1::arr\[cast\(0, signedbv\[64\]\)\] ≠ 0 // Expected failure: 0 == 0
10+
DEAD main::1::arr
11+
SET RETURN VALUE side_effect statement="nondet" is_nondet_nullable="1"
12+
END_FUNCTION
13+
--
14+
This is testing the behaviour of the goto-inspect binary in case a binary
15+
is present, but no inspection option is present.
16+
17+
This is labelled `winbug` to avoid running on windows because of issues with
18+
the empty string in line 3 (simulating the lack of an option) not working as
19+
it should (it is contrary to the behaviour of unix systems). The behaviour
20+
has been verified manually on a machine as working as expected, but getting
21+
the test to run automatically is a lot more involved, so we're opting to
22+
skipping this on that platform for now.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
main.c
3+
--show-goto-functions
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
main
7+
DECL main::1::arr : signedbv\[32\]\[5\]
8+
ASSIGN main::1::arr := \{ 0, 1, 2, 3, 4 \}
9+
ASSERT main::1::arr\[cast\(0, signedbv\[64\]\)\] ≠ 0 // Expected failure: 0 == 0
10+
DEAD main::1::arr
11+
SET RETURN VALUE side_effect statement="nondet" is_nondet_nullable="1"
12+
END_FUNCTION
13+
--
14+
--

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ add_subdirectory(xmllang)
9898
add_subdirectory(goto-checker)
9999
add_subdirectory(goto-programs)
100100
add_subdirectory(goto-symex)
101+
add_subdirectory(goto-inspect)
101102
add_subdirectory(jsil)
102103
add_subdirectory(json)
103104
add_subdirectory(json-symtab-language)

src/Makefile

+6-2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ DIRS = analyses \
1010
goto-cc \
1111
goto-checker \
1212
goto-diff \
13+
goto-inspect \
1314
goto-instrument \
1415
goto-harness \
1516
goto-programs \
@@ -36,6 +37,7 @@ all: cbmc.dir \
3637
goto-cc.dir \
3738
goto-diff.dir \
3839
goto-instrument.dir \
40+
goto-inspect.dir \
3941
goto-harness.dir \
4042
goto-synthesizer.dir \
4143
symtab2gb.dir \
@@ -82,6 +84,8 @@ goto-harness.dir: util.dir goto-programs.dir langapi.dir linking.dir \
8284
goto-instrument.dir: languages goto-programs.dir pointer-analysis.dir \
8385
goto-symex.dir linking.dir analyses.dir solvers.dir
8486

87+
goto-inspect.dir: util.dir goto-programs.dir languages linking.dir
88+
8589
goto-checker.dir: solvers.dir goto-symex.dir goto-programs.dir
8690

8791
cbmc.dir: languages solvers.dir goto-symex.dir analyses.dir \
@@ -190,8 +194,8 @@ doc :
190194
install: all
191195
for b in \
192196
cbmc crangler \
193-
goto-analyzer goto-cc goto-diff goto-instrument goto-harness goto-synthesizer \
194-
symtab2gb ; do \
197+
goto-analyzer goto-cc goto-diff goto-instrument goto-inspect goto-harness \
198+
goto-synthesizer symtab2gb ; do \
195199
cp $$b/$$b $(PREFIX)/bin/ ; \
196200
cp ../doc/man/$$b.1 $(PREFIX)/doc/man/man1/ ; \
197201
done

src/goto-inspect/CMakeLists.txt

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# For goto-inspect, we are not building a library - only a binary.
2+
3+
file(GLOB_RECURSE sources "*.cpp" "*.h")
4+
5+
add_executable(goto-inspect ${sources})
6+
7+
generic_includes(goto-inspect)
8+
9+
target_link_libraries(goto-inspect
10+
util
11+
goto-programs
12+
)
13+
14+
install(TARGETS goto-inspect DESTINATION ${CMAKE_INSTALL_BINDIR})
15+
16+
# Man page
17+
if(NOT WIN32)
18+
install(
19+
DIRECTORY ${CMAKE_SOURCE_DIR}/doc/man/
20+
DESTINATION ${CMAKE_INSTALL_MANDIR}/man1
21+
FILES_MATCHING PATTERN "goto-harness*")
22+
endif()

src/goto-inspect/Makefile

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
SRC = goto_inspect_main.cpp \
2+
goto_inspect_parse_options.cpp \
3+
# Empty last line
4+
5+
OBJ += ../big-int/big-int$(LIBEXT) \
6+
../linking/linking$(LIBEXT) \
7+
../langapi/langapi$(LIBEXT) \
8+
../goto-programs/goto-programs$(LIBEXT) \
9+
../util/util$(LIBEXT) \
10+
# Empty last line
11+
12+
INCLUDES= -I ..
13+
14+
LIBS =
15+
16+
CLEANFILES = goto-inspect$(EXEEXT) goto-inspect$(LIBEXT)
17+
18+
include ../config.inc
19+
include ../common
20+
21+
all: goto-inspect$(EXEEXT)
22+
23+
###############################################################################
24+
25+
goto-inspect$(EXEEXT): $(OBJ)
26+
$(LINKBIN)
27+
28+
.PHONY: goto-inspect-mac-signed
29+
30+
goto-inspect-mac-signed: goto-inspect$(EXEEXT)
31+
codesign -v -s $(OSX_IDENTITY) goto-inspect$(EXEEXT)
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Author: Fotis Koutoulakis for Diffblue Ltd.
2+
3+
#ifdef _MSC_VER
4+
# include <util/unicode.h>
5+
#endif
6+
7+
#include "goto_inspect_parse_options.h"
8+
9+
#ifdef _MSC_VER
10+
int wmain(int argc, const wchar_t **argv_wide)
11+
{
12+
auto vec = narrow_argv(argc, argv_wide);
13+
auto narrow = to_c_str_array(std::begin(vec), std::end(vec));
14+
auto argv = narrow.data();
15+
#else
16+
int main(int argc, const char **argv)
17+
{
18+
#endif
19+
return goto_inspect_parse_optionst{argc, argv}.main();
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
// Author: Fotis Koutoulakis for Diffblue Ltd.
2+
3+
#include "goto_inspect_parse_options.h"
4+
5+
#include <util/config.h>
6+
#include <util/exception_utils.h>
7+
#include <util/exit_codes.h>
8+
#include <util/version.h>
9+
10+
#include <goto-programs/goto_model.h>
11+
#include <goto-programs/read_goto_binary.h>
12+
#include <goto-programs/show_goto_functions.h>
13+
14+
#include <iostream>
15+
16+
int goto_inspect_parse_optionst::doit()
17+
{
18+
if(cmdline.isset("version"))
19+
{
20+
std::cout << CBMC_VERSION << '\n';
21+
return CPROVER_EXIT_SUCCESS;
22+
}
23+
24+
// Before we do anything else, ensure that a file argument has been given.
25+
if(cmdline.args.size() != 1)
26+
{
27+
help();
28+
throw invalid_command_line_argument_exceptiont{
29+
"failed to supply a goto-binary name or an option for inspection",
30+
"<input goto-binary> <inspection-option>"};
31+
}
32+
33+
// This just sets up the defaults (and would interpret options such as --32).
34+
config.set(cmdline);
35+
36+
// Normally we would register language front-ends here but as goto-inspect
37+
// only works on goto binaries, we don't need to
38+
39+
auto binary_filename = cmdline.args[0];
40+
41+
// Read goto binary into goto-model
42+
auto read_goto_binary_result =
43+
read_goto_binary(binary_filename, ui_message_handler);
44+
if(!read_goto_binary_result.has_value())
45+
{
46+
throw deserialization_exceptiont{
47+
"failed to read goto program from file '" + binary_filename + "'"};
48+
}
49+
auto goto_model = std::move(read_goto_binary_result.value());
50+
51+
// This has to be called after the defaults are set up (as per the
52+
// config.set(cmdline) above) otherwise, e.g. the architecture specification
53+
// will be unknown.
54+
config.set_from_symbol_table(goto_model.symbol_table);
55+
56+
if(cmdline.isset("show-goto-functions"))
57+
{
58+
show_goto_functions(
59+
goto_model, ui_message_handler, cmdline.isset("list-goto-functions"));
60+
return CPROVER_EXIT_SUCCESS;
61+
}
62+
63+
// If an option + binary was provided, the program will have exited
64+
// gracefully through a different branch. If we hit the code below, it
65+
// means that something has gone wrong - it's also possible to fall through
66+
// this case if no optional inspection flag is present in the argument
67+
// vector. This will ensure that the return value in that case is
68+
// semantically meaningful, and provide a return value that also satisfies
69+
// the compiler's requirements based on the signature of `doit()`.
70+
return CPROVER_EXIT_INCORRECT_TASK;
71+
}
72+
73+
void goto_inspect_parse_optionst::help()
74+
{
75+
std::cout << '\n'
76+
<< banner_string("Goto-Inspect", CBMC_VERSION) << '\n'
77+
<< align_center_with_border("Copyright (C) 2023") << '\n'
78+
<< align_center_with_border("Diffblue Ltd.") << '\n'
79+
<< align_center_with_border("[email protected]") << '\n'
80+
<< '\n'
81+
<< "Usage: Purpose:\n"
82+
<< '\n'
83+
<< " goto-inspect [-?] [-h] [--help] show help\n"
84+
<< " goto-inspect --version show version\n"
85+
<< " goto-inspect --show-goto-functions show code for "
86+
"goto-functions present in goto-binary\n"
87+
<< "\n"
88+
<< "<in> goto binary to read from\n";
89+
}
90+
91+
goto_inspect_parse_optionst::goto_inspect_parse_optionst(
92+
int argc,
93+
const char *argv[])
94+
: parse_options_baset{
95+
GOTO_INSPECT_OPTIONS,
96+
argc,
97+
argv,
98+
std::string("GOTO-INSPECT ") + CBMC_VERSION}
99+
{
100+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Author: Fotis Koutoulakis for Diffblue Ltd.
2+
3+
#ifndef CPROVER_GOTO_INSPECT_GOTO_INSPECT_PARSE_OPTIONS_H
4+
#define CPROVER_GOTO_INSPECT_GOTO_INSPECT_PARSE_OPTIONS_H
5+
6+
#include <util/parse_options.h>
7+
8+
// clang-format off
9+
#define GOTO_INSPECT_OPTIONS \
10+
"(version)" \
11+
"(show-goto-functions)" \
12+
// end GOTO_INSPECT_OPTIONS
13+
14+
// clang-format on
15+
16+
struct goto_inspect_parse_optionst : public parse_options_baset
17+
{
18+
int doit() override;
19+
void help() override;
20+
21+
goto_inspect_parse_optionst(int argc, const char *argv[]);
22+
};
23+
24+
#endif // CPROVER_GOTO_INSPECT_GOTO_INSPECT_PARSE_OPTIONS_H

0 commit comments

Comments
 (0)