1 /*--------------------------------------------------------------------*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Callgrind, a Valgrind tool for call tracing.
9 Copyright (C) 2002-2015, 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, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 The GNU General Public License is contained in the file COPYING.
31 /*------------------------------------------------------------*/
32 /*--- Basic block (BB) operations ---*/
33 /*------------------------------------------------------------*/
35 /* BB hash, resizable */
38 void CLG_(init_bb_hash
)()
44 bbs
.table
= (BB
**) CLG_MALLOC("cl.bb.ibh.1",
45 bbs
.size
* sizeof(BB
*));
47 for (i
= 0; i
< bbs
.size
; i
++) bbs
.table
[i
] = NULL
;
50 bb_hash
* CLG_(get_bb_hash
)()
55 /* The hash stores BBs according to
56 * - ELF object (is 0 for code in anonymous mapping)
57 * - BB base as object file offset
60 UInt
bb_hash_idx(obj_node
* obj
, PtrdiffT offset
, UInt size
)
62 return (((Addr
)obj
) + offset
) % size
;
65 /* double size of bb table */
67 void resize_bb_table(void)
69 Int i
, new_size
, conflicts1
= 0, conflicts2
= 0;
70 BB
**new_table
, *curr
, *next
;
73 new_size
= 2* bbs
.size
+3;
74 new_table
= (BB
**) CLG_MALLOC("cl.bb.rbt.1",
75 new_size
* sizeof(BB
*));
77 for (i
= 0; i
< new_size
; i
++)
80 for (i
= 0; i
< bbs
.size
; i
++) {
81 if (bbs
.table
[i
] == NULL
) continue;
84 while (NULL
!= curr
) {
87 new_idx
= bb_hash_idx(curr
->obj
, curr
->offset
, new_size
);
89 curr
->next
= new_table
[new_idx
];
90 new_table
[new_idx
] = curr
;
101 VG_(free
)(bbs
.table
);
104 CLG_DEBUG(0, "Resize BB Hash: %u => %d (entries %u, conflicts %d/%d)\n",
106 bbs
.entries
, conflicts1
, conflicts2
);
109 bbs
.table
= new_table
;
110 CLG_(stat
).bb_hash_resizes
++;
115 * Allocate new BB structure (including space for event type list)
117 * - instr_len, cost_count, instr[]
119 static BB
* new_bb(obj_node
* obj
, PtrdiffT offset
,
120 UInt instr_count
, UInt cjmp_count
, Bool cjmp_inverted
)
125 /* check fill degree of bb hash table and resize if needed (>80%) */
127 if (10 * bbs
.entries
/ bbs
.size
> 8)
130 size
= sizeof(BB
) + instr_count
* sizeof(InstrInfo
)
131 + (cjmp_count
+1) * sizeof(CJmpInfo
);
132 bb
= (BB
*) CLG_MALLOC("cl.bb.nb.1", size
);
133 VG_(memset
)(bb
, 0, size
);
138 bb
->instr_count
= instr_count
;
139 bb
->cjmp_count
= cjmp_count
;
140 bb
->cjmp_inverted
= cjmp_inverted
;
141 bb
->jmp
= (CJmpInfo
*) &(bb
->instr
[instr_count
]);
144 bb
->sect_kind
= VG_(DebugInfo_sect_kind
)(NULL
, offset
+ obj
->offset
);
151 /* insert into BB hash table */
152 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
153 bb
->next
= bbs
.table
[idx
];
156 CLG_(stat
).distinct_bbs
++;
160 VG_(printf
)(" new_bb (instr %u, jmps %u, inv %s) [now %d]: ",
161 instr_count
, cjmp_count
,
162 cjmp_inverted
? "yes":"no",
163 CLG_(stat
).distinct_bbs
);
164 CLG_(print_bb
)(0, bb
);
169 CLG_(get_fn_node
)(bb
);
175 /* get the BB structure for a BB start address */
177 BB
* lookup_bb(obj_node
* obj
, PtrdiffT offset
)
182 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
186 if ((bb
->obj
== obj
) && (bb
->offset
== offset
)) break;
190 CLG_DEBUG(5, " lookup_bb (Obj %s, off %#lx): %p\n",
191 obj
->name
, (UWord
)offset
, bb
);
196 obj_node
* obj_of_address(Addr addr
)
202 di
= VG_(find_DebugInfo
)(addr
);
203 obj
= CLG_(get_obj_node
)( di
);
205 /* Update symbol offset in object if remapped */
206 /* FIXME (or at least check this) 2008 Feb 19: 'offset' is
207 only correct for text symbols, not for data symbols */
208 offset
= di
? VG_(DebugInfo_get_text_bias
)(di
):0;
209 if (obj
->offset
!= offset
) {
210 Addr start
= di
? VG_(DebugInfo_get_text_avma
)(di
) : 0;
212 CLG_DEBUG(0, "Mapping changed for '%s': %#lx -> %#lx\n",
213 obj
->name
, obj
->start
, start
);
215 /* Size should be the same, and offset diff == start diff */
216 CLG_ASSERT( obj
->size
== (di
? VG_(DebugInfo_get_text_size
)(di
) : 0) );
217 CLG_ASSERT( obj
->start
- start
== obj
->offset
- offset
);
218 obj
->offset
= offset
;
225 /* Get the BB structure for a BB start address.
226 * If the BB has to be created, the IRBB is needed to
227 * compute the event type list for costs, and seen_before is
228 * set to False. Otherwise, seen_before is set to True.
230 * BBs are never discarded. There are 2 cases where this function
231 * is called from CLG_(instrument)() and a BB already exists:
232 * - The instrumented version was removed from Valgrinds TT cache
233 * - The ELF object of the BB was unmapped and mapped again.
234 * This involves a possibly different address, but is handled by
235 * looking up a BB keyed by (obj_node, file offset).
237 * bbIn==0 is possible for artificial BB without real code.
238 * Such a BB is created when returning to an unknown function.
240 BB
* CLG_(get_bb
)(Addr addr
, IRSB
* bbIn
, /*OUT*/ Bool
*seen_before
)
244 UInt n_instrs
, n_jmps
;
245 Bool cjmp_inverted
= False
;
247 CLG_DEBUG(5, "+ get_bb(BB %#lx)\n", addr
);
249 obj
= obj_of_address(addr
);
250 bb
= lookup_bb(obj
, addr
- obj
->offset
);
254 CLG_(collectBlockInfo
)(bbIn
, &n_instrs
, &n_jmps
, &cjmp_inverted
);
256 *seen_before
= bb
? True
: False
;
258 if (bb
->instr_count
!= n_instrs
) {
259 VG_(message
)(Vg_DebugMsg
,
260 "ERROR: BB Retranslation Mismatch at BB %#lx\n", addr
);
261 VG_(message
)(Vg_DebugMsg
,
262 " new: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
263 obj
->name
, (UWord
)obj
->offset
,
264 addr
- obj
->offset
, n_instrs
);
265 VG_(message
)(Vg_DebugMsg
,
266 " old: Obj %s, Off %#lx, BBOff %#lx, Instrs %u\n",
267 bb
->obj
->name
, (UWord
)bb
->obj
->offset
,
268 (UWord
)bb
->offset
, bb
->instr_count
);
269 CLG_ASSERT(bb
->instr_count
== n_instrs
);
271 CLG_ASSERT(bb
->cjmp_count
== n_jmps
);
272 CLG_(stat
).bb_retranslations
++;
274 CLG_DEBUG(5, "- get_bb(BB %#lx): seen before.\n", addr
);
278 bb
= new_bb(obj
, addr
- obj
->offset
, n_instrs
, n_jmps
, cjmp_inverted
);
280 CLG_DEBUG(5, "- get_bb(BB %#lx)\n", addr
);
285 /* Delete the BB info for the bb with unredirected entry-point
287 void CLG_(delete_bb
)(Addr addr
)
292 obj_node
* obj
= obj_of_address(addr
);
293 PtrdiffT offset
= addr
- obj
->offset
;
295 idx
= bb_hash_idx(obj
, offset
, bbs
.size
);
298 /* bb points at the current bb under consideration, and bp is the
302 if ((bb
->obj
== obj
) && (bb
->offset
== offset
)) break;
308 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): NOT FOUND\n",
309 obj
->name
, (UWord
)offset
);
311 /* we didn't find it.
312 * this happens when callgrinds instrumentation mode
313 * was off at BB translation time, ie. no BB was created.
318 /* unlink it from hash table */
321 /* we found the first one in the list. */
322 tl_assert(bb
== bbs
.table
[idx
]);
323 bbs
.table
[idx
] = bb
->next
;
325 tl_assert(bb
!= bbs
.table
[idx
]);
329 CLG_DEBUG(3, " delete_bb (Obj %s, off %#lx): %p, BBCC head: %p\n",
330 obj
->name
, (UWord
)offset
, bb
, bb
->bbcc_list
);
332 if (bb
->bbcc_list
== 0) {
333 /* can be safely deleted */
335 /* Fill the block up with junk and then free it, so we will
336 hopefully get a segfault if it is used again by mistake. */
338 + bb
->instr_count
* sizeof(InstrInfo
)
339 + (bb
->cjmp_count
+1) * sizeof(CJmpInfo
);
340 VG_(memset
)( bb
, 0xAA, size
);
344 CLG_DEBUG(3, " delete_bb: BB in use, can not free!\n");