blob: 4657340d21715b8a0694ffd517ae456d9d6da7b1 [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
njn51d827b2005-05-09 01:02:08 +000047/* See comment above lk_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
njn51d827b2005-05-09 01:02:08 +000075static void lk_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +000076{
77}
78
nethercote7e08f062004-10-20 10:37:00 +000079/* Note: machine instructions are marked by an INCEIP at the end of each one,
njn25e49d8e72002-09-23 09:36:25 +000080 except for the final one in the basic block which ends in an
81 unconditional JMP. Sometimes the final unconditional JMP is preceded by
82 a conditional JMP (Jcc), and thus it isn't reached. Eg:
83
84 <code a>
85 INCEIP ...
86
87 <code b>
88 Jcc ...
89 JMP ... (will not be reached if Jcc succeeds)
90
sewardj9f649aa2004-11-22 20:38:40 +000091 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
njn25e49d8e72002-09-23 09:36:25 +000092 and unconditional JMPs, we'd sometimes miss the final call (when a
nethercote7e08f062004-10-20 10:37:00 +000093 preceding conditional JMP succeeds), underestimating the machine instruction
njn25e49d8e72002-09-23 09:36:25 +000094 count.
95
96 <code a>
sewardj9f649aa2004-11-22 20:38:40 +000097 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +000098 INCEIP ...
99
100 <code b>
101 Jcc ...
sewardj9f649aa2004-11-22 20:38:40 +0000102 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000103 JMP ...
104
105 Instead we add a call before each INCEIP, and also one at the start of the
106 block, but not one at the end, viz:
107
sewardj9f649aa2004-11-22 20:38:40 +0000108 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000109
110 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000111 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000112 INCEIP ...
113
114 <code b>
115 Jcc ...
116 JMP ...
117
118 Which gives us the right answer. And just to avoid two C calls, we fold
119 the basic-block-beginning call in with add_one_BB(). Phew.
120*/
njn51d827b2005-05-09 01:02:08 +0000121static IRBB* lk_instrument(IRBB* bb_in, VexGuestLayout* layout,
122 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000123{
sewardj9f649aa2004-11-22 20:38:40 +0000124 IRDirty* di;
125 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000126 IRBB* bb;
127
128 if (gWordTy != hWordTy) {
129 /* We don't currently support this case. */
130 VG_(tool_panic)("host/guest word size mismatch");
131 }
sewardj9f649aa2004-11-22 20:38:40 +0000132
133 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000134 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000135 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
136 bb->next = dopyIRExpr(bb_in->next);
137 bb->jumpkind = bb_in->jumpkind;
138
139#if 0
140 /* We need to know the entry point for this bb to do this. In any
141 case it's pretty meaningless in the presence of bb chasing since
142 we may enter this function part way through an IRBB. */
143 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
144 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
145 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
146 {
147 addStmtToIRBB(
148 bb,
149 IRStmt_Dirty(
150 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
151 ));
152 }
153#endif
154
155 /* Count this basic block */
156 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
157 addStmtToIRBB( bb, IRStmt_Dirty(di) );
158
159 for (i = 0; i < bb_in->stmts_used; i++) {
160 IRStmt* st = bb_in->stmts[i];
161 if (!st) continue;
162
163 switch (st->tag) {
164 case Ist_Exit:
165 /* Count Jcc */
166 addStmtToIRBB(
167 bb,
168 IRStmt_Dirty(
169 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
170 mkIRExprVec_0() )
171 ));
172 addStmtToIRBB( bb, dopyIRStmt(st) );
173 /* Count non-taken Jcc */
174 addStmtToIRBB(
175 bb,
176 IRStmt_Dirty(
177 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
178 mkIRExprVec_0() )
179 ));
180 break;
181
182 default:
sewardjbd598e12005-01-07 12:10:21 +0000183 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000184 }
185 }
186
187 return bb;
188
189
190#if 0
njn25e49d8e72002-09-23 09:36:25 +0000191 UCodeBlock* cb;
192 Int i;
193 UInstr* u;
194 Char fnname[100];
195
njn810086f2002-11-14 12:42:47 +0000196 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000197
njn25e49d8e72002-09-23 09:36:25 +0000198 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000199 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000200
njn810086f2002-11-14 12:42:47 +0000201 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
202 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000203
204 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000205 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000206 break;
207
208 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000209 /* Count x86 instr */
210 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000211 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000212 break;
213
214 case JMP:
215 if (u->cond != CondAlways) {
216 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000217 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
218 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000219 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000220 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000221 } else {
njn4ba5a792002-09-30 10:23:54 +0000222 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000223 }
224 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000225
njn25e49d8e72002-09-23 09:36:25 +0000226 default:
227 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000228 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
229 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000230 break;
231 }
232 }
233
njn4ba5a792002-09-30 10:23:54 +0000234 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000235 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000236#endif
njn25e49d8e72002-09-23 09:36:25 +0000237}
238
njn51d827b2005-05-09 01:02:08 +0000239static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000240{
241 VG_(message)(Vg_UserMsg,
242 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
243
244 VG_(message)(Vg_UserMsg, "");
245 VG_(message)(Vg_UserMsg, "Executed:");
sewardj9f649aa2004-11-22 20:38:40 +0000246 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
247 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs);
248 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
njn25e49d8e72002-09-23 09:36:25 +0000249
250 VG_(message)(Vg_UserMsg, "");
251 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000252 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
253 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
254 (n_Jccs - n_Jccs_untaken)*100 /
255 (n_Jccs ? n_Jccs : 1));
njn25e49d8e72002-09-23 09:36:25 +0000256
257 VG_(message)(Vg_UserMsg, "");
258 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000259 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10",
260 10 * n_guest_instrs / n_BBs);
261 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
njn25e49d8e72002-09-23 09:36:25 +0000262 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000263 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
264 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000265
njn7d9f94d2003-04-22 21:41:40 +0000266 VG_(message)(Vg_UserMsg, "");
267 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000268}
269
njn51d827b2005-05-09 01:02:08 +0000270static void lk_pre_clo_init(void)
271{
272 VG_(details_name) ("Lackey");
273 VG_(details_version) (NULL);
274 VG_(details_description) ("an example Valgrind tool");
275 VG_(details_copyright_author)(
276 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
277 VG_(details_bug_reports_to) (VG_BUGS_TO);
278 VG_(details_avg_translation_sizeB) ( 175 );
279
280 VG_(basic_tool_funcs) (lk_post_clo_init,
281 lk_instrument,
282 lk_fini);
283}
284
285VG_DETERMINE_INTERFACE_VERSION(lk_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