Skip to content

Commit faf7f43

Browse files
author
Thomas Kiley
authored
Merge pull request #5381 from thk123/trace-loop-heads
Add loop heads to the XML and JSON trace output
2 parents 818afcc + 657c1a6 commit faf7f43

12 files changed

+233
-21
lines changed

doc/assets/xml_spec.md

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,18 @@ Function Return (element name: `function_return`)
389389
</xs:element>
390390
```
391391

392-
All Other Steps (element name: `location-only`)
392+
All Other Steps (element name: `location-only` and `loop-head`)
393+
394+
A step that indicates where in the source program we are.
395+
396+
A `location-only` step is emitted if the source location exists and
397+
differs from the previous one.
398+
399+
A `loop-head` step is emitted if the location relates to the start of a loop,
400+
even if the previous step is also the same start of the loop (to ensure
401+
that it is printed out for each loop iteration)
402+
393403

394-
Only included if the source location exists and differs from the
395-
previous one.\
396404
**Attributes**:
397405

398406
- `hidden`: boolean attribute
@@ -411,6 +419,9 @@ previous one.\
411419
<location-only hidden="false" step_nr="19" thread="0">
412420
<location .. />
413421
</location-only>
422+
<loop-head hidden="false" step_nr="19" thread="0">
423+
<location .. />
424+
</loop-head>
414425
```
415426

416427
**XSD**:
@@ -424,6 +435,15 @@ previous one.\
424435
<xs:attributeGroup ref="traceStepAttrs">
425436
</xs:complexType>
426437
</xs:element>
438+
439+
<xs:element name="loop-head">
440+
<xs:complexType>
441+
<xs:all>
442+
<xs:element name="location" minOccurs="0"></xs:element>
443+
</xs:all>
444+
<xs:attributeGroup ref="traceStepAttrs">
445+
</xs:complexType>
446+
</xs:element>
427447
```
428448

429449
Full Trace XSD
@@ -440,6 +460,7 @@ Full Trace XSD
440460
<xs:element ref="input"></xs:element>
441461
<xs:element ref="output"></xs:element>
442462
<xs:element ref="location-only"></xs:element>
463+
<xs:element ref="loop-head"></xs:element>
443464
</xs:choice>
444465
</xs:complexType>
445466
</xs:element>

doc/assets/xml_spec.tex

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,10 +373,18 @@ \subsection{Trace Steps in XML}
373373
374374
375375
\begin{center}
376-
{\Large All Other Steps} (element name: \texttt{location-only})
376+
{\Large All Other Steps} (element name: \texttt{location-only} and
377+
\texttt{loop-head})
377378
\end{center}
378379
379-
\noindent Only included if the source location exists and differs from the previous one.\\
380+
\noindent A step that indicates where in the source program we are.
381+
382+
A \texttt{location-only} step is emitted if the source location exists and
383+
differs from the previous one.
384+
385+
A \texttt{loop-head} step is emitted if the location relates to the start of a loop,
386+
even if the previous step is also the same start of the loop (to ensure
387+
that it is printed out for each loop iteration) \\
380388
381389
\noindent\textbf{Attributes}:
382390
\begin{itemize}
@@ -395,6 +403,9 @@ \subsection{Trace Steps in XML}
395403
<location-only hidden="false" step_nr="19" thread="0">
396404
<location .. />
397405
</location-only>
406+
<loop-head hidden="false" step_nr="19" thread="0">
407+
<location .. />
408+
</loop-head>
398409
\end{minted}
399410
400411
\noindent\textbf{XSD}:
@@ -407,6 +418,14 @@ \subsection{Trace Steps in XML}
407418
<xs:attributeGroup ref="traceStepAttrs">
408419
</xs:complexType>
409420
</xs:element>
421+
<xs:element name="loop-head">
422+
<xs:complexType>
423+
<xs:all>
424+
<xs:element name="location" minOccurs="0"></xs:element>
425+
</xs:all>
426+
<xs:attributeGroup ref="traceStepAttrs">
427+
</xs:complexType>
428+
</xs:element>
410429
\end{minted}
411430
412431
\subsection{Full Trace XSD}
@@ -422,6 +441,7 @@ \subsection{Full Trace XSD}
422441
<xs:element ref="input"></xs:element>
423442
<xs:element ref="output"></xs:element>
424443
<xs:element ref="location-only"></xs:element>
444+
<xs:element ref="loop-head"></xs:element>
425445
</xs:choice>
426446
</xs:complexType>
427447
</xs:element>

doc/assets/xml_spec.xsd

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@
138138
</xs:complexType>
139139
</xs:element>
140140

141+
<xs:element name="loop-head">
142+
<xs:complexType>
143+
<xs:all>
144+
<xs:element ref="location" minOccurs="0"/>
145+
</xs:all>
146+
<xs:attributeGroup ref="traceStepAttrs"/>
147+
</xs:complexType>
148+
</xs:element>
149+
141150
<xs:element name="goto_trace">
142151
<xs:complexType>
143152
<xs:choice minOccurs="0" maxOccurs="unbounded">
@@ -148,6 +157,7 @@
148157
<xs:element ref="input"></xs:element>
149158
<xs:element ref="output"></xs:element>
150159
<xs:element ref="location-only"></xs:element>
160+
<xs:element ref="loop-head"></xs:element>
151161
</xs:choice>
152162
</xs:complexType>
153163
</xs:element>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
CORE
2+
test.c
3+
--unwind 6 test.c --trace --json-ui --partial-loops --slice-formula
4+
activate-multi-line-match
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
\s*\{\n\s* .*\n\s* "sourceLocation": \{\n\s* .*,\n\s* .*,\n\s* "line": "5",\n\s* .*\n\s* \},\n\s* "stepType": "loop-head",\n\s* .*\n\s*\},\n\s*\{\n\s* .*\n\s* "sourceLocation": \{\n\s* .*,\n\s* .*,\n\s* "line": "5",\n\s* .*\n\s* \},\n\s* "stepType": "loop-head",\n\s* .*\n\s*\},
8+
--
9+
--
10+
Ensure even with sliced formulas, we get a location only step for
11+
each iteration of the loop (called loop-heads) when using partial loops.
12+
13+
This test is checking the following json:(deleting the new lines after each \n to obtain
14+
monster regex above).
15+
16+
\s*\{\n
17+
\s* .*\n
18+
\s* "sourceLocation": \{\n
19+
\s* .*,\n
20+
\s* .*,\n
21+
\s* "line": "5",\n
22+
\s* .*\n
23+
\s* \},\n
24+
\s* "stepType": "loop-head",\n
25+
\s* .*\n
26+
\s*\},\n
27+
\s*\{\n
28+
\s* .*\n
29+
\s* "sourceLocation": \{\n
30+
\s* .*,\n
31+
\s* .*,\n
32+
\s* "line": "5",\n
33+
\s* .*\n
34+
\s* \},\n
35+
\s* "stepType": "loop-head",\n
36+
\s* .*\n
37+
\s*\},
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
CORE
2+
test.c
3+
--unwind 6 test.c --trace --xml-ui --partial-loops --slice-formula
4+
activate-multi-line-match
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
\s*<loop-head .*>\n\s* <location .* line="5" .*/>\n\s*</loop-head>\n\s*<loop-head .*>\n\s* <location .* line="5".*/>\n\s*</loop-head>\n
8+
--
9+
--
10+
Ensure even with sliced formulas, we get a location only step for
11+
each iteration of the loop (called loop-heads) when using partial loops.
12+
13+
This test is checking the following XML:(deleting the new lines
14+
after each \n to obtain the monster regex above).
15+
16+
\s*<loop-head .*>
17+
\s* <location .* line="5" .*/>
18+
\s*</loop-head>
19+
\s*<loop-head .*>
20+
\s* <location .* line="5".*/>
21+
\s*</loop-head>
22+

regression/cbmc/loophead-trace/test.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
void main(void)
2+
{
3+
int i = 0;
4+
5+
while(1)
6+
{
7+
i = 1;
8+
}
9+
10+
// invalid assertion
11+
assert(i == 0);
12+
}

src/goto-programs/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ SRC = adjust_float_expressions.cpp \
6464
slice_global_inits.cpp \
6565
string_abstraction.cpp \
6666
string_instrumentation.cpp \
67+
structured_trace_util.cpp \
6768
system_library_symbols.cpp \
6869
validate_goto_model.cpp \
6970
vcd_goto_trace.cpp \

src/goto-programs/json_goto_trace.cpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -276,22 +276,15 @@ void convert_return(
276276
json_call_return["sourceLocation"] = location;
277277
}
278278

279-
/// Convert all other types of steps not already handled
280-
/// by the other conversion functions.
281-
/// \param [out] json_location_only: The JSON object that
282-
/// will contain the information about the step
283-
/// after this function has run.
284-
/// \param conversion_dependencies: A structure
285-
/// that contains information the conversion function
286-
/// needs.
287279
void convert_default(
288280
json_objectt &json_location_only,
289-
const conversion_dependenciest &conversion_dependencies)
281+
const conversion_dependenciest &conversion_dependencies,
282+
const default_step_kindt &step_kind)
290283
{
291284
const goto_trace_stept &step = conversion_dependencies.step;
292285
const jsont &location = conversion_dependencies.location;
293286

294-
json_location_only["stepType"] = json_stringt("location-only");
287+
json_location_only["stepType"] = json_stringt(default_step_name(step_kind));
295288
json_location_only["hidden"] = jsont::json_boolean(step.hidden);
296289
json_location_only["thread"] = json_numbert(std::to_string(step.thread_nr));
297290
json_location_only["sourceLocation"] = location;

src/goto-programs/json_goto_trace.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ Date: November 2005
1515
#define CPROVER_GOTO_PROGRAMS_JSON_GOTO_TRACE_H
1616

1717
#include "goto_trace.h"
18+
#include "structured_trace_util.h"
1819

20+
#include <algorithm>
1921
#include <util/invariant.h>
2022
#include <util/json.h>
2123
#include <util/json_irep.h>
@@ -97,9 +99,12 @@ void convert_return(
9799
/// \param conversion_dependencies: A structure
98100
/// that contains information the conversion function
99101
/// needs.
102+
/// \param step_kind: The kind of default step we are printing.
103+
/// See \ref default_step_kind
100104
void convert_default(
101105
json_objectt &json_location_only,
102-
const conversion_dependenciest &conversion_dependencies);
106+
const conversion_dependenciest &conversion_dependencies,
107+
const default_step_kindt &step_kind);
103108

104109
/// Templated version of the conversion method.
105110
/// Works by dispatching to the more specialised
@@ -186,10 +191,14 @@ void convert(
186191
case goto_trace_stept::typet::SHARED_WRITE:
187192
case goto_trace_stept::typet::CONSTRAINT:
188193
case goto_trace_stept::typet::NONE:
189-
if(source_location != previous_source_location)
194+
const auto default_step_kind = ::default_step_kind(*step.pc);
195+
if(
196+
source_location != previous_source_location ||
197+
default_step_kind == default_step_kindt::LOOP_HEAD)
190198
{
191199
json_objectt &json_location_only = dest_array.push_back().make_object();
192-
convert_default(json_location_only, conversion_dependencies);
200+
convert_default(
201+
json_location_only, conversion_dependencies, default_step_kind);
193202
}
194203
}
195204

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*******************************************************************\
2+
3+
Author: Diffblue
4+
5+
\*******************************************************************/
6+
7+
/// \file
8+
/// Utilities for printing location info steps in the trace in a format
9+
/// agnostic way
10+
11+
#include "structured_trace_util.h"
12+
#include <algorithm>
13+
14+
default_step_kindt
15+
default_step_kind(const goto_programt::instructiont &instruction)
16+
{
17+
const bool is_loophead = std::any_of(
18+
instruction.incoming_edges.begin(),
19+
instruction.incoming_edges.end(),
20+
[](goto_programt::targett t) { return t->is_backwards_goto(); });
21+
22+
return is_loophead ? default_step_kindt::LOOP_HEAD
23+
: default_step_kindt::LOCATION_ONLY;
24+
}
25+
std::string default_step_name(const default_step_kindt &step_type)
26+
{
27+
switch(step_type)
28+
{
29+
case default_step_kindt::LOCATION_ONLY:
30+
return "location-only";
31+
case default_step_kindt::LOOP_HEAD:
32+
return "loop-head";
33+
}
34+
UNREACHABLE;
35+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/*******************************************************************\
2+
3+
Author: Diffblue
4+
5+
\*******************************************************************/
6+
7+
/// \file
8+
/// Utilities for printing location info steps in the trace in a format
9+
/// agnostic way
10+
11+
#ifndef CPROVER_GOTO_PROGRAMS_STRUCTURED_TRACE_UTIL_H
12+
#define CPROVER_GOTO_PROGRAMS_STRUCTURED_TRACE_UTIL_H
13+
14+
#include "goto_program.h"
15+
#include <string>
16+
17+
/// There are two kinds of step for location markers - location-only and
18+
/// loop-head (for locations associated with the first step of a loop).
19+
enum class default_step_kindt
20+
{
21+
LOCATION_ONLY,
22+
LOOP_HEAD
23+
};
24+
25+
/// Identify for a given instruction whether it is a loophead or just a location
26+
///
27+
/// Loopheads are determined by whether there is backwards jump to them. This
28+
/// matches the loop detection used for loop IDs
29+
/// \param instruction: The instruction to inspect.
30+
/// \return LOOP_HEAD if this is a loop head, otherwise LOCATION_ONLY
31+
default_step_kindt
32+
default_step_kind(const goto_programt::instructiont &instruction);
33+
34+
/// Turns a \ref default_step_kindt into a string that can be used in the trace
35+
/// \param step_type: The kind of step, deduced from \ref default_step_kind
36+
/// \return Either "loop-head" or "location-only"
37+
std::string default_step_name(const default_step_kindt &step_type);
38+
39+
#endif // CPROVER_GOTO_PROGRAMS_STRUCTURED_TRACE_UTIL_H

0 commit comments

Comments
 (0)