diff options
Diffstat (limited to 'gcc/doc/analyzer.texi')
-rw-r--r-- | gcc/doc/analyzer.texi | 175 |
1 files changed, 147 insertions, 28 deletions
diff --git a/gcc/doc/analyzer.texi b/gcc/doc/analyzer.texi index b53096e..1403473 100644 --- a/gcc/doc/analyzer.texi +++ b/gcc/doc/analyzer.texi @@ -259,56 +259,175 @@ memory, with a @code{store} recording a binding between @code{region} instances, to @code{svalue} instances. The bindings are organized into clusters, where regions accessible via well-defined pointer arithmetic are in the same cluster. The representation is graph-like because values -can be pointers to regions. It also stores a constraint_manager, +can be pointers to regions. It also stores a @code{constraint_manager}, capturing relationships between the values. Because each node in the @code{exploded_graph} has a @code{region_model}, and each of the latter is graph-like, the @code{exploded_graph} is in some ways a graph of graphs. -Here's an example of printing a @code{program_state}, showing the -@code{region_model} within it, along with state for the @code{malloc} -state machine. +There are several ``dump'' functions for use when debugging the analyzer. + +Consider this example C code: + +@smallexample +void * +calls_malloc (size_t n) +@{ + void *result = malloc (1024); + return result; /* HERE */ +@} + +void test (size_t n) +@{ + void *ptr = calls_malloc (n * 4); + /* etc. */ +@} +@end smallexample + +and the state at the point @code{/* HERE */} for the interprocedural +analysis case where @code{calls_malloc} returns back to @code{test}. + +Here's an example of printing a @code{program_state} at @code{/* HERE */}, +showing the @code{region_model} within it, along with state for the +@code{malloc} state machine. @smallexample -(gdb) call debug (*this) +(gdb) break region_model::on_return +[..snip...] +(gdb) run +[..snip...] +(gdb) up +[..snip...] +(gdb) call state->dump() +State +├─ Region Model +│ ├─ Current Frame: frame: ‘calls_malloc’@@2 +│ ├─ Store +│ │ ├─ m_called_unknown_fn: false +│ │ ├─ frame: ‘test’@@1 +│ │ │ ╰─ _1: (INIT_VAL(n_2(D))*(size_t)4) +│ │ ╰─ frame: ‘calls_malloc’@@2 +│ │ ├─ result_4: &HEAP_ALLOCATED_REGION(27) +│ │ ╰─ _5: &HEAP_ALLOCATED_REGION(27) +│ ╰─ Dynamic Extents +│ ╰─ HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4) +╰─ ‘malloc’ state machine + ╰─ 0x468cb40: &HEAP_ALLOCATED_REGION(27): unchecked (@{free@}) (‘result_4’) +@end smallexample + +Within the store, there are bindings clusters for the SSA names for the +various local variables within frames for @code{test} and +@code{calls_malloc}. For example, + +@itemize @bullet +@item +within @code{test} the whole cluster for @code{_1} is bound +to a @code{binop_svalue} representing @code{n * 4}, and +@item +within @code{test} the whole cluster for @code{result_4} is bound to a +@code{region_svalue} pointing at @code{HEAP_ALLOCATED_REGION(12)}. +@end itemize + +Additionally, this latter pointer has the @code{unchecked} state for the +@code{malloc} state machine indicating it hasn't yet been checked against +@code{NULL} since the allocation call. + +We also see that the state has captured the size of the heap-allocated +region (``Dynamic Extents''). + +This visualization can also be seen within the output of +@option{-fdump-analyzer-exploded-nodes-2} and +@option{-fdump-analyzer-exploded-nodes-3}. + +As well as the above visualizations of states, there are tree-like +visualizations for instances of @code{svalue} and @code{region}, showing +their IDs and how they are constructed from simpler symbols: + +@smallexample +(gdb) break region_model::set_dynamic_extents +[..snip...] +(gdb) run +[..snip...] +(gdb) up +[..snip...] +(gdb) call size_in_bytes->dump() +(17): ‘long unsigned int’: binop_svalue(mult_expr: ‘*’) +├─ (15): ‘size_t’: initial_svalue +│ ╰─ m_reg: (12): ‘size_t’: decl_region(‘n_2(D)’) +│ ╰─ parent: (9): frame_region(‘test’, index: 0, depth: 1) +│ ╰─ parent: (1): stack region +│ ╰─ parent: (0): root region +╰─ (16): ‘size_t’: constant_svalue (‘4’) +@end smallexample + +i.e. that @code{size_in_bytes} is a @code{binop_svalue} expressing +the result of multiplying + +@itemize @bullet +@item +the initial value of the @code{PARM_DECL} @code{n_2(D)} for the +parameter @code{n} within the frame for @code{test} by +@item +the constant value @code{4}. +@end itemize + +The above visualizations rely on the @code{text_art::widget} framework, +which performs significant work to lay out the output, so there is also +an earlier, simpler, form of dumping available. For states there is: + +@smallexample +(gdb) call state->dump(eg.m_ext_state, true) rmodel: -stack depth: 1 +stack depth: 2 + frame (index 1): frame: ‘calls_malloc’@@2 frame (index 0): frame: ‘test’@@1 clusters within frame: ‘test’@@1 - cluster for: ptr_3: &HEAP_ALLOCATED_REGION(12) + cluster for: _1: (INIT_VAL(n_2(D))*(size_t)4) +clusters within frame: ‘calls_malloc’@@2 + cluster for: result_4: &HEAP_ALLOCATED_REGION(27) + cluster for: _5: &HEAP_ALLOCATED_REGION(27) m_called_unknown_fn: FALSE constraint_manager: equiv classes: constraints: +dynamic_extents: + HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4) malloc: - 0x2e89590: &HEAP_ALLOCATED_REGION(12): unchecked ('ptr_3') + 0x468cb40: &HEAP_ALLOCATED_REGION(27): unchecked (@{free@}) (‘result_4’) @end smallexample -This is the state at the point of returning from @code{calls_malloc} back -to @code{test} in the following: +or for @code{region_model} just: @smallexample -void * -calls_malloc (void) -@{ - void *result = malloc (1024); - return result; -@} - -void test (void) -@{ - void *ptr = calls_malloc (); - /* etc. */ -@} +(gdb) call state->m_region_model->debug() +stack depth: 2 + frame (index 1): frame: ‘calls_malloc’@@2 + frame (index 0): frame: ‘test’@@1 +clusters within frame: ‘test’@@1 + cluster for: _1: (INIT_VAL(n_2(D))*(size_t)4) +clusters within frame: ‘calls_malloc’@@2 + cluster for: result_4: &HEAP_ALLOCATED_REGION(27) + cluster for: _5: &HEAP_ALLOCATED_REGION(27) +m_called_unknown_fn: FALSE +constraint_manager: + equiv classes: + constraints: +dynamic_extents: + HEAP_ALLOCATED_REGION(27): (INIT_VAL(n_2(D))*(size_t)4) @end smallexample -Within the store, there is the cluster for @code{ptr_3} within the frame -for @code{test}, where the whole cluster is bound to a pointer value, -pointing at @code{HEAP_ALLOCATED_REGION(12)}. Additionally, this pointer -has the @code{unchecked} state for the @code{malloc} state machine -indicating it hasn't yet been checked against NULL since the allocation -call. +and for instances of @code{svalue} and @code{region} there is this +older dump implementation, which takes a @code{bool simple} flag +controlling the verbosity of the dump: + +@smallexample +(gdb) call size_in_bytes->dump(true) +(INIT_VAL(n_2(D))*(size_t)4) + +(gdb) call size_in_bytes->dump(false) +binop_svalue (mult_expr, initial_svalue(‘size_t’, decl_region(frame_region(‘test’, index: 0, depth: 1), ‘size_t’, ‘n_2(D)’)), constant_svalue(‘size_t’, 4)) +@end smallexample @subsection Analyzer Paths |