1 /*--------------------------------------------------------------------*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Callgrind, a Valgrind tool for call tracing.
9 Copyright (C) 2002-2017, Josef Weidendorfer (Josef.Weidendorfer@gmx.de)
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of the
14 License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, see <http://www.gnu.org/licenses/>.
24 The GNU General Public License is contained in the file COPYING.
29 /*------------------------------------------------------------*/
30 /*--- Basic block (BB) operations ---*/
31 /*------------------------------------------------------------*/
33 /* BB hash, resizable */
36 void CLG_(init_bb_hash
)(void)
42 bbs
.table
= (BB
**) CLG_MALLOC("cl.bb.ibh.1",
43 bbs
.size
* sizeof(BB
*));
45 for (i
= 0; i
< bbs
.size
; i
++) bbs
.table
[i
] = NULL
;
48 bb_hash
* CLG_(get_bb_hash
)(void)
53 /* The hash stores BBs according to
54 * - ELF object (is 0 for code in anonymous mapping)
55 * - BB base as object file offset
58 UInt
bb_hash_idx(obj_node
* obj
, PtrdiffT offset
, UInt size
)
60 return (((Addr
)obj
) + offset
) % size
;
63 /* double size of bb table */
65 void resize_bb_table(void)
67 Int i
, new_size
, conflicts1
= 0, conflicts2
= 0;
68 BB
**new_table
, *curr
, *next
;
71 new_size
= 2* bbs
.size
+3;
72 new_table
= (BB
**) CLG_MALLOC("cl.bb.rbt.1",
73 new_size
* sizeof(BB
*));
75 for (i
= 0; i
< new_size
; i
++)
78 for (i
= 0; i
< bbs
.size
; i
++) {
79 if (bbs
.table
[i
] == NULL
) continue;
82 while (NULL
!= curr
) {
85 new_idx
= bb_hash_idx(curr
->obj
, curr
->offset
, new_size
);
87 curr
->next
= new_table
[new_idx
];
88 new_table
[new_idx
] = curr
;
102 CLG_DEBUG(0, "Resize BB Hash: %u => %d (entries %u, conflicts %d/%d)\n",
104 bbs
.entries
, conflicts1
, conflicts2
);
107 bbs
.table
= new_table
;
108 CLG_(stat
).bb_hash_resizes
++;
113 * Allocate new BB structure (including space for event type list)
115 * - instr_len, cost_count, instr[]
117 static BB
* new_bb(obj_node
* obj
, PtrdiffT offset
,
118 UInt instr_count
, UInt cjmp_count
, Bool cjmp_inverted
)
123 /* check fill degree of bb hash table and resize if needed (>80%) */
125 if (10 * bbs
.entries
/ bbs
.size
> 8)
128 size
= sizeof(BB
) + instr_count
* sizeof(InstrInfo
)
129 + (cjmp_count
+1) * sizeof(CJmpInfo
);
130 bb
= (BB
*) CLG_MALLOC("cl.bb.nb.1", size
);
131 VG_(memset
)(bb
, 0, size
);
136 bb
->instr_count
= instr_count
;
137 bb
->cjmp_count
= cjmp_count
;
138 bb
->cjmp_inverted
= cjmp_inverted
;
139 bb
->jmp
= (CJmpInfo
*) &(bb
->instr
[instr_count
]);
142 bb
->sect_kind
= VG_(DebugInfo_sect_kind
)(NULL
, offset
+ obj
->offset
);
149 /* insert into BB hash table */
150 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
151 bb
->next
= bbs
.table
[idx
];
154 CLG_(stat
).distinct_bbs
++;
158 VG_(printf
)(" new_bb (instr %u, jmps %u, inv %s) [now %d]: ",
159 instr_count
, cjmp_count
,
160 cjmp_inverted
? "yes":"no",
161 CLG_(stat
).distinct_bbs
);
162 CLG_(print_bb
)(0, bb
);
167 CLG_(get_fn_node
)(bb
);
173 /* get the BB structure for a BB start address */
175 BB
* lookup_bb(obj_node
* obj
, PtrdiffT offset
)
180 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
184 if ((bb
->obj
== obj
) && (bb
->offset
== offset
)) break;
188 CLG_DEBUG(5, " lookup_bb (Obj %s, off %#lx): %p\n",
189 obj
->name
, (UWord
)offset
, bb
);
194 obj_node
* obj_of_address(Addr addr
)
200 DiEpoch ep
= VG_(current_DiEpoch
)();
201 di
= VG_(find_DebugInfo
)(ep
, addr
);
202 obj
= CLG_(get_obj_node
)( di
);
204 /* Update symbol offset in object if remapped */
205 /* FIXME (or at least check this) 2008 Feb 19: 'offset' is
206 only correct for text symbols, not for data symbols */
207 offset
= di
? VG_(DebugInfo_get_text_bias
)(di
):0;
208 if (obj
->offset
!= offset
) {
209 Addr start
= di
? VG_(DebugInfo_get_text_avma
)(di
) : 0;
211 CLG_DEBUG(0, "Mapping changed for '%s': %#lx -> %#lx\n",
212 obj
->name
, obj
->start
, start
);
214 /* Size should be the same, and offset diff == start diff */
215 CLG_ASSERT( obj
->size
== (di
? VG_(DebugInfo_get_text_size
)(di
) : 0) );
216 CLG_ASSERT( obj
->start
- start
== obj
->offset
- offset
);
217 obj
->offset
= offset
;
224 /* Get the BB structure for a BB start address.
225 * If the BB has to be created, the IRBB is needed to
226 * compute the event type list for costs, and seen_before is
227 * set to False. Otherwise, seen_before is set to True.
229 * BBs are never discarded. There are 2 cases where this function
230 * is called from CLG_(instrument)() and a BB already exists:
231 * - The instrumented version was removed from Valgrinds TT cache
232 * - The ELF object of the BB was unmapped and mapped again.
233 * This involves a possibly different address, but is handled by
234 * looking up a BB keyed by (obj_node, file offset).
236 * bbIn==0 is possible for artificial BB without real code.
237 * Such a BB is created when returning to an unknown function.
239 BB
* CLG_(get_bb
)(Addr addr
, IRSB
* bbIn
, /*OUT*/ Bool
*seen_before
)
243 UInt n_instrs
, n_jmps
;
244 Bool cjmp_inverted
= False
;
246 CLG_DEBUG(5, "+ get_bb(BB %#lx)\n", addr
);
248 obj
= obj_of_address(addr
);
249 bb
= lookup_bb(obj
, addr
- obj
->offset
);
253 CLG_(collectBlockInfo
)(bbIn
, &n_instrs
, &n_jmps
, &cjmp_inverted
);
255 *seen_before
= bb
? True
: False
;
257 if (bb
->instr_count
!= n_instrs
) {
258 VG_(message
)(Vg_DebugMsg
,
259 "ERROR: BB Retranslation Mismatch at BB %#lx\n", addr
);
260 VG_(message
)(Vg_DebugMsg
,
261 " new: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
262 obj
->name
, (UWord
)obj
->offset
,
263 addr
- obj
->offset
, n_instrs
);
264 VG_(message
)(Vg_DebugMsg
,
265 " old: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
266 bb
->obj
->name
, (UWord
)bb
->obj
->offset
,
267 (UWord
)bb
->offset
, bb
->instr_count
);
268 CLG_ASSERT(bb
->instr_count
== n_instrs
);
270 CLG_ASSERT(bb
->cjmp_count
== n_jmps
);
271 CLG_(stat
).bb_retranslations
++;
273 CLG_DEBUG(5, "- get_bb(BB %#lx): seen before.\n", addr
);
277 bb
= new_bb(obj
, addr
- obj
->offset
, n_instrs
, n_jmps
, cjmp_inverted
);
279 CLG_DEBUG(5, "- get_bb(BB %#lx)\n", addr
);
284 /* Delete the BB info for the bb with unredirected entry-point
286 void CLG_(delete_bb
)(Addr addr
)
291 obj_node
* obj
= obj_of_address(addr
);
292 PtrdiffT offset
= addr
- obj
->offset
;
294 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
297 /* bb points at the current bb under consideration, and bp is the
301 if ((bb
->obj
== obj
) && (bb
->offset
== offset
)) break;
307 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): NOT FOUND\n",
308 obj
->name
, (UWord
)offset
);
310 /* we didn't find it.
311 * this happens when callgrinds instrumentation mode
312 * was off at BB translation time, ie. no BB was created.
317 /* unlink it from hash table */
320 /* we found the first one in the list. */
321 tl_assert(bb
== bbs
.table
[idx
]);
322 bbs
.table
[idx
] = bb
->next
;
324 tl_assert(bb
!= bbs
.table
[idx
]);
328 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): %p, BBCC head: %p\n",
329 obj
->name
, (UWord
)offset
, bb
, bb
->bbcc_list
);
331 if (bb
->bbcc_list
== 0) {
332 /* can be safely deleted */
334 /* Fill the block up with junk and then free it, so we will
335 hopefully get a segfault if it is used again by mistake. */
337 + bb
->instr_count
* sizeof(InstrInfo
)
338 + (bb
->cjmp_count
+1) * sizeof(CJmpInfo
);
339 VG_(memset
)( bb
, 0xAA, size
);
343 CLG_DEBUG(3, " delete_bb: BB in use, can not free!\n");