blob: 92843e05bdfd36bd1019ec7acca33e04be8a7a28 [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
njnc7561b92005-06-19 01:24:32 +000032#include "pub_tool_basics.h"
njn43b9a8a2005-05-10 04:37:01 +000033#include "pub_tool_tooliface.h"
njnf39e9a32005-06-12 02:43:17 +000034#include "pub_tool_libcassert.h"
njn36a20fa2005-06-03 03:08:39 +000035#include "pub_tool_libcprint.h"
njn25e49d8e72002-09-23 09:36:25 +000036
njn25e49d8e72002-09-23 09:36:25 +000037/* Nb: use ULongs because the numbers can get very big */
38static ULong n_dlrr_calls = 0;
39static ULong n_BBs = 0;
40static ULong n_UInstrs = 0;
sewardj9f649aa2004-11-22 20:38:40 +000041static ULong n_guest_instrs = 0;
njn25e49d8e72002-09-23 09:36:25 +000042static ULong n_Jccs = 0;
43static ULong n_Jccs_untaken = 0;
44
njn69f80cf2005-06-11 01:29:23 +000045__attribute__((unused))
njn25e49d8e72002-09-23 09:36:25 +000046static void add_one_dlrr_call(void)
47{
48 n_dlrr_calls++;
49}
50
njn51d827b2005-05-09 01:02:08 +000051/* See comment above lk_instrument for reason why n_machine_instrs is
njn25e49d8e72002-09-23 09:36:25 +000052 incremented here. */
53static void add_one_BB(void)
54{
55 n_BBs++;
sewardj9f649aa2004-11-22 20:38:40 +000056 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000057}
58
njn69f80cf2005-06-11 01:29:23 +000059__attribute__((unused))
njn25e49d8e72002-09-23 09:36:25 +000060static void add_one_UInstr(void)
61{
62 n_UInstrs++;
63}
64
njn69f80cf2005-06-11 01:29:23 +000065__attribute__((unused))
sewardj9f649aa2004-11-22 20:38:40 +000066static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +000067{
sewardj9f649aa2004-11-22 20:38:40 +000068 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000069}
70
71static void add_one_Jcc(void)
72{
73 n_Jccs++;
74}
75
76static void add_one_Jcc_untaken(void)
77{
78 n_Jccs_untaken++;
79}
80
njn51d827b2005-05-09 01:02:08 +000081static void lk_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +000082{
83}
84
nethercote7e08f062004-10-20 10:37:00 +000085/* Note: machine instructions are marked by an INCEIP at the end of each one,
njn25e49d8e72002-09-23 09:36:25 +000086 except for the final one in the basic block which ends in an
87 unconditional JMP. Sometimes the final unconditional JMP is preceded by
88 a conditional JMP (Jcc), and thus it isn't reached. Eg:
89
90 <code a>
91 INCEIP ...
92
93 <code b>
94 Jcc ...
95 JMP ... (will not be reached if Jcc succeeds)
96
sewardj9f649aa2004-11-22 20:38:40 +000097 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
njn25e49d8e72002-09-23 09:36:25 +000098 and unconditional JMPs, we'd sometimes miss the final call (when a
nethercote7e08f062004-10-20 10:37:00 +000099 preceding conditional JMP succeeds), underestimating the machine instruction
njn25e49d8e72002-09-23 09:36:25 +0000100 count.
101
102 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000103 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000104 INCEIP ...
105
106 <code b>
107 Jcc ...
sewardj9f649aa2004-11-22 20:38:40 +0000108 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000109 JMP ...
110
111 Instead we add a call before each INCEIP, and also one at the start of the
112 block, but not one at the end, viz:
113
sewardj9f649aa2004-11-22 20:38:40 +0000114 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000115
116 <code a>
sewardj9f649aa2004-11-22 20:38:40 +0000117 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000118 INCEIP ...
119
120 <code b>
121 Jcc ...
122 JMP ...
123
124 Which gives us the right answer. And just to avoid two C calls, we fold
125 the basic-block-beginning call in with add_one_BB(). Phew.
126*/
njn51d827b2005-05-09 01:02:08 +0000127static IRBB* lk_instrument(IRBB* bb_in, VexGuestLayout* layout,
128 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000129{
sewardj9f649aa2004-11-22 20:38:40 +0000130 IRDirty* di;
131 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000132 IRBB* bb;
133
134 if (gWordTy != hWordTy) {
135 /* We don't currently support this case. */
136 VG_(tool_panic)("host/guest word size mismatch");
137 }
sewardj9f649aa2004-11-22 20:38:40 +0000138
139 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000140 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000141 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
142 bb->next = dopyIRExpr(bb_in->next);
143 bb->jumpkind = bb_in->jumpkind;
144
145#if 0
146 /* We need to know the entry point for this bb to do this. In any
147 case it's pretty meaningless in the presence of bb chasing since
148 we may enter this function part way through an IRBB. */
149 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
150 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
151 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
152 {
153 addStmtToIRBB(
154 bb,
155 IRStmt_Dirty(
156 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
157 ));
158 }
159#endif
160
161 /* Count this basic block */
162 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
163 addStmtToIRBB( bb, IRStmt_Dirty(di) );
164
165 for (i = 0; i < bb_in->stmts_used; i++) {
166 IRStmt* st = bb_in->stmts[i];
167 if (!st) continue;
168
169 switch (st->tag) {
170 case Ist_Exit:
171 /* Count Jcc */
172 addStmtToIRBB(
173 bb,
174 IRStmt_Dirty(
175 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
176 mkIRExprVec_0() )
177 ));
178 addStmtToIRBB( bb, dopyIRStmt(st) );
179 /* Count non-taken Jcc */
180 addStmtToIRBB(
181 bb,
182 IRStmt_Dirty(
183 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
184 mkIRExprVec_0() )
185 ));
186 break;
187
188 default:
sewardjbd598e12005-01-07 12:10:21 +0000189 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000190 }
191 }
192
193 return bb;
194
195
196#if 0
njn25e49d8e72002-09-23 09:36:25 +0000197 UCodeBlock* cb;
198 Int i;
199 UInstr* u;
200 Char fnname[100];
201
njn810086f2002-11-14 12:42:47 +0000202 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000203
njn25e49d8e72002-09-23 09:36:25 +0000204 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000205 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000206
njn810086f2002-11-14 12:42:47 +0000207 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
208 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000209
210 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000211 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000212 break;
213
214 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000215 /* Count x86 instr */
216 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000217 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000218 break;
219
220 case JMP:
221 if (u->cond != CondAlways) {
222 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000223 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
224 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000225 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000226 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000227 } else {
njn4ba5a792002-09-30 10:23:54 +0000228 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000229 }
230 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000231
njn25e49d8e72002-09-23 09:36:25 +0000232 default:
233 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000234 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
235 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000236 break;
237 }
238 }
239
njn4ba5a792002-09-30 10:23:54 +0000240 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000241 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000242#endif
njn25e49d8e72002-09-23 09:36:25 +0000243}
244
njn51d827b2005-05-09 01:02:08 +0000245static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000246{
247 VG_(message)(Vg_UserMsg,
248 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
249
250 VG_(message)(Vg_UserMsg, "");
251 VG_(message)(Vg_UserMsg, "Executed:");
sewardj9f649aa2004-11-22 20:38:40 +0000252 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
253 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs);
254 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
njn25e49d8e72002-09-23 09:36:25 +0000255
256 VG_(message)(Vg_UserMsg, "");
257 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000258 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
259 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
260 (n_Jccs - n_Jccs_untaken)*100 /
261 (n_Jccs ? n_Jccs : 1));
njn25e49d8e72002-09-23 09:36:25 +0000262
263 VG_(message)(Vg_UserMsg, "");
264 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000265 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10",
266 10 * n_guest_instrs / n_BBs);
267 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
njn25e49d8e72002-09-23 09:36:25 +0000268 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000269 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
270 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000271
njn7d9f94d2003-04-22 21:41:40 +0000272 VG_(message)(Vg_UserMsg, "");
273 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000274}
275
njn51d827b2005-05-09 01:02:08 +0000276static void lk_pre_clo_init(void)
277{
278 VG_(details_name) ("Lackey");
279 VG_(details_version) (NULL);
280 VG_(details_description) ("an example Valgrind tool");
281 VG_(details_copyright_author)(
282 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
283 VG_(details_bug_reports_to) (VG_BUGS_TO);
284 VG_(details_avg_translation_sizeB) ( 175 );
285
286 VG_(basic_tool_funcs) (lk_post_clo_init,
287 lk_instrument,
288 lk_fini);
289}
290
sewardj45f4e7c2005-09-27 19:20:21 +0000291VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000292
njn25e49d8e72002-09-23 09:36:25 +0000293/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000294/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000295/*--------------------------------------------------------------------*/
296