blob: dbeabb8cf60419fe071a1da3ce9dffce8a693d38 [file] [log] [blame]
njnc9539842002-10-02 13:26:35 +00001
njn25e49d8e72002-09-23 09:36:25 +00002/*--------------------------------------------------------------------*/
nethercote137bc552003-11-14 17:47:54 +00003/*--- Simple tool for counting UInstrs, using a C helper. ---*/
njn25cac76cb2002-09-23 11:21:57 +00004/*--- lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00005/*--------------------------------------------------------------------*/
6
7/*
nethercote137bc552003-11-14 17:47:54 +00008 This file is part of Lackey, an example Valgrind tool that does
njnc9539842002-10-02 13:26:35 +00009 some simple program measurement.
njn25e49d8e72002-09-23 09:36:25 +000010
njn53612422005-03-12 16:22:54 +000011 Copyright (C) 2002-2005 Nicholas Nethercote
njn2bc10122005-05-08 02:10:27 +000012 njn@valgrind.org
njn25e49d8e72002-09-23 09:36:25 +000013
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file COPYING.
30*/
31
nethercote46063202004-09-02 08:51:43 +000032#include "tool.h"
njn25e49d8e72002-09-23 09:36:25 +000033
njn25e49d8e72002-09-23 09:36:25 +000034/* Nb: use ULongs because the numbers can get very big */
35static ULong n_dlrr_calls = 0;
36static ULong n_BBs = 0;
37static ULong n_UInstrs = 0;
sewardj9f649aa2004-11-22 20:38:40 +000038static ULong n_guest_instrs = 0;
njn25e49d8e72002-09-23 09:36:25 +000039static ULong n_Jccs = 0;
40static ULong n_Jccs_untaken = 0;
41
42static void add_one_dlrr_call(void)
43{
44 n_dlrr_calls++;
45}
46
njn26f02512004-11-22 18:33:15 +000047/* See comment above TL_(instrument) for reason why n_machine_instrs is
njn25e49d8e72002-09-23 09:36:25 +000048 incremented here. */
49static void add_one_BB(void)
50{
51 n_BBs++;
sewardj9f649aa2004-11-22 20:38:40 +000052 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000053}
54
55static void add_one_UInstr(void)
56{
57 n_UInstrs++;
58}
59
sewardj9f649aa2004-11-22 20:38:40 +000060static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +000061{
sewardj9f649aa2004-11-22 20:38:40 +000062 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000063}
64
65static void add_one_Jcc(void)
66{
67 n_Jccs++;
68}
69
70static void add_one_Jcc_untaken(void)
71{
72 n_Jccs_untaken++;
73}
74
njn26f02512004-11-22 18:33:15 +000075void TL_(pre_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +000076{
njn810086f2002-11-14 12:42:47 +000077 VG_(details_name) ("Lackey");
78 VG_(details_version) (NULL);
nethercote137bc552003-11-14 17:47:54 +000079 VG_(details_description) ("an example Valgrind tool");
njn810086f2002-11-14 12:42:47 +000080 VG_(details_copyright_author)(
njn53612422005-03-12 16:22:54 +000081 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
nethercote421281e2003-11-20 16:20:55 +000082 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardjc0d8f682002-11-30 00:49:43 +000083 VG_(details_avg_translation_sizeB) ( 175 );
njn8a97c6d2005-03-31 04:37:24 +000084
85 VG_(basic_tool_funcs) (TL_(post_clo_init),
86 TL_(instrument),
87 TL_(fini));
njn25e49d8e72002-09-23 09:36:25 +000088}
89
njn26f02512004-11-22 18:33:15 +000090void TL_(post_clo_init)(void)
njn25e49d8e72002-09-23 09:36:25 +000091{
92}
93
nethercote7e08f062004-10-20 10:37:00 +000094/* Note: machine instructions are marked by an INCEIP at the end of each one,
njn25e49d8e72002-09-23 09:36:25 +000095 except for the final one in the basic block which ends in an
96 unconditional JMP. Sometimes the final unconditional JMP is preceded by
97 a conditional JMP (Jcc), and thus it isn't reached. Eg:
98
99 <code a>
100 INCEIP ...
101
102 <code b>
103 Jcc ...
104 JMP ... (will not be reached if Jcc succeeds)
105
sewardj9f649aa2004-11-22 20:38:40 +0000106 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
njn25e49d8e72002-09-23 09:36:25 +0000107 and unconditional JMPs, we'd sometimes miss the final call (when a
nethercote7e08f062004-10-20 10:37:00 +0000108 preceding conditional JMP succeeds), underestimating the machine instruction
njn25e49d8e72002-09-23 09:36:25 +0000109 count.
110
111 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000112 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000113 INCEIP ...
114
115 <code b>
116 Jcc ...
sewardj9f649aa2004-11-22 20:38:40 +0000117 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000118 JMP ...
119
120 Instead we add a call before each INCEIP, and also one at the start of the
121 block, but not one at the end, viz:
122
sewardj9f649aa2004-11-22 20:38:40 +0000123 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000124
125 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000126 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000127 INCEIP ...
128
129 <code b>
130 Jcc ...
131 JMP ...
132
133 Which gives us the right answer. And just to avoid two C calls, we fold
134 the basic-block-beginning call in with add_one_BB(). Phew.
135*/
sewardjd54babf2005-03-21 00:55:49 +0000136IRBB* TL_(instrument)(IRBB* bb_in, VexGuestLayout* layout,
137 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000138{
sewardj9f649aa2004-11-22 20:38:40 +0000139 IRDirty* di;
140 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000141 IRBB* bb;
142
143 if (gWordTy != hWordTy) {
144 /* We don't currently support this case. */
145 VG_(tool_panic)("host/guest word size mismatch");
146 }
sewardj9f649aa2004-11-22 20:38:40 +0000147
148 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000149 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000150 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
151 bb->next = dopyIRExpr(bb_in->next);
152 bb->jumpkind = bb_in->jumpkind;
153
154#if 0
155 /* We need to know the entry point for this bb to do this. In any
156 case it's pretty meaningless in the presence of bb chasing since
157 we may enter this function part way through an IRBB. */
158 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
159 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
160 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
161 {
162 addStmtToIRBB(
163 bb,
164 IRStmt_Dirty(
165 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
166 ));
167 }
168#endif
169
170 /* Count this basic block */
171 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
172 addStmtToIRBB( bb, IRStmt_Dirty(di) );
173
174 for (i = 0; i < bb_in->stmts_used; i++) {
175 IRStmt* st = bb_in->stmts[i];
176 if (!st) continue;
177
178 switch (st->tag) {
179 case Ist_Exit:
180 /* Count Jcc */
181 addStmtToIRBB(
182 bb,
183 IRStmt_Dirty(
184 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
185 mkIRExprVec_0() )
186 ));
187 addStmtToIRBB( bb, dopyIRStmt(st) );
188 /* Count non-taken Jcc */
189 addStmtToIRBB(
190 bb,
191 IRStmt_Dirty(
192 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
193 mkIRExprVec_0() )
194 ));
195 break;
196
197 default:
sewardjbd598e12005-01-07 12:10:21 +0000198 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000199 }
200 }
201
202 return bb;
203
204
205#if 0
njn25e49d8e72002-09-23 09:36:25 +0000206 UCodeBlock* cb;
207 Int i;
208 UInstr* u;
209 Char fnname[100];
210
njn810086f2002-11-14 12:42:47 +0000211 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000212
njn25e49d8e72002-09-23 09:36:25 +0000213 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000214 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000215
njn810086f2002-11-14 12:42:47 +0000216 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
217 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000218
219 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000220 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000221 break;
222
223 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000224 /* Count x86 instr */
225 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000226 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000227 break;
228
229 case JMP:
230 if (u->cond != CondAlways) {
231 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000232 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
233 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000234 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000235 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000236 } else {
njn4ba5a792002-09-30 10:23:54 +0000237 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000238 }
239 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000240
njn25e49d8e72002-09-23 09:36:25 +0000241 default:
242 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000243 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
244 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000245 break;
246 }
247 }
248
njn4ba5a792002-09-30 10:23:54 +0000249 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000250 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000251#endif
njn25e49d8e72002-09-23 09:36:25 +0000252}
253
njn26f02512004-11-22 18:33:15 +0000254void TL_(fini)(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000255{
256 VG_(message)(Vg_UserMsg,
257 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
258
259 VG_(message)(Vg_UserMsg, "");
260 VG_(message)(Vg_UserMsg, "Executed:");
sewardj9f649aa2004-11-22 20:38:40 +0000261 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
262 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs);
263 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
njn25e49d8e72002-09-23 09:36:25 +0000264
265 VG_(message)(Vg_UserMsg, "");
266 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000267 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
268 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
269 (n_Jccs - n_Jccs_untaken)*100 /
270 (n_Jccs ? n_Jccs : 1));
njn25e49d8e72002-09-23 09:36:25 +0000271
272 VG_(message)(Vg_UserMsg, "");
273 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000274 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10",
275 10 * n_guest_instrs / n_BBs);
276 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
njn25e49d8e72002-09-23 09:36:25 +0000277 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000278 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
279 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000280
njn7d9f94d2003-04-22 21:41:40 +0000281 VG_(message)(Vg_UserMsg, "");
282 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000283}
284
njn26f02512004-11-22 18:33:15 +0000285VG_DETERMINE_INTERFACE_VERSION(TL_(pre_clo_init), 0)
fitzhardinge98abfc72003-12-16 02:05:15 +0000286
njn25e49d8e72002-09-23 09:36:25 +0000287/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000288/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000289/*--------------------------------------------------------------------*/
290