blob: 80a987b63a5407752c6b308c28fbf6390872f2ee [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"
njn43b9a8a2005-05-10 04:37:01 +000033#include "pub_tool_tooliface.h"
njn25e49d8e72002-09-23 09:36:25 +000034
njn25e49d8e72002-09-23 09:36:25 +000035/* Nb: use ULongs because the numbers can get very big */
36static ULong n_dlrr_calls = 0;
37static ULong n_BBs = 0;
38static ULong n_UInstrs = 0;
sewardj9f649aa2004-11-22 20:38:40 +000039static ULong n_guest_instrs = 0;
njn25e49d8e72002-09-23 09:36:25 +000040static ULong n_Jccs = 0;
41static ULong n_Jccs_untaken = 0;
42
43static void add_one_dlrr_call(void)
44{
45 n_dlrr_calls++;
46}
47
njn51d827b2005-05-09 01:02:08 +000048/* See comment above lk_instrument for reason why n_machine_instrs is
njn25e49d8e72002-09-23 09:36:25 +000049 incremented here. */
50static void add_one_BB(void)
51{
52 n_BBs++;
sewardj9f649aa2004-11-22 20:38:40 +000053 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000054}
55
56static void add_one_UInstr(void)
57{
58 n_UInstrs++;
59}
60
sewardj9f649aa2004-11-22 20:38:40 +000061static void add_one_guest_instr(void)
njn25e49d8e72002-09-23 09:36:25 +000062{
sewardj9f649aa2004-11-22 20:38:40 +000063 n_guest_instrs++;
njn25e49d8e72002-09-23 09:36:25 +000064}
65
66static void add_one_Jcc(void)
67{
68 n_Jccs++;
69}
70
71static void add_one_Jcc_untaken(void)
72{
73 n_Jccs_untaken++;
74}
75
njn51d827b2005-05-09 01:02:08 +000076static void lk_post_clo_init(void)
njn25e49d8e72002-09-23 09:36:25 +000077{
78}
79
nethercote7e08f062004-10-20 10:37:00 +000080/* Note: machine instructions are marked by an INCEIP at the end of each one,
njn25e49d8e72002-09-23 09:36:25 +000081 except for the final one in the basic block which ends in an
82 unconditional JMP. Sometimes the final unconditional JMP is preceded by
83 a conditional JMP (Jcc), and thus it isn't reached. Eg:
84
85 <code a>
86 INCEIP ...
87
88 <code b>
89 Jcc ...
90 JMP ... (will not be reached if Jcc succeeds)
91
sewardj9f649aa2004-11-22 20:38:40 +000092 If we simplemindedly added calls to add_one_guest_instr() before INCEIPs
njn25e49d8e72002-09-23 09:36:25 +000093 and unconditional JMPs, we'd sometimes miss the final call (when a
nethercote7e08f062004-10-20 10:37:00 +000094 preceding conditional JMP succeeds), underestimating the machine instruction
njn25e49d8e72002-09-23 09:36:25 +000095 count.
96
97 <code a>
sewardj9f649aa2004-11-22 20:38:40 +000098 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +000099 INCEIP ...
100
101 <code b>
102 Jcc ...
sewardj9f649aa2004-11-22 20:38:40 +0000103 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000104 JMP ...
105
106 Instead we add a call before each INCEIP, and also one at the start of the
107 block, but not one at the end, viz:
108
sewardj9f649aa2004-11-22 20:38:40 +0000109 call add_one_guest_instr()
njn25e49d8e72002-09-23 09:36:25 +0000110
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 ...
117 JMP ...
118
119 Which gives us the right answer. And just to avoid two C calls, we fold
120 the basic-block-beginning call in with add_one_BB(). Phew.
121*/
njn51d827b2005-05-09 01:02:08 +0000122static IRBB* lk_instrument(IRBB* bb_in, VexGuestLayout* layout,
123 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000124{
sewardj9f649aa2004-11-22 20:38:40 +0000125 IRDirty* di;
126 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000127 IRBB* bb;
128
129 if (gWordTy != hWordTy) {
130 /* We don't currently support this case. */
131 VG_(tool_panic)("host/guest word size mismatch");
132 }
sewardj9f649aa2004-11-22 20:38:40 +0000133
134 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000135 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000136 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
137 bb->next = dopyIRExpr(bb_in->next);
138 bb->jumpkind = bb_in->jumpkind;
139
140#if 0
141 /* We need to know the entry point for this bb to do this. In any
142 case it's pretty meaningless in the presence of bb chasing since
143 we may enter this function part way through an IRBB. */
144 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
145 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
146 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
147 {
148 addStmtToIRBB(
149 bb,
150 IRStmt_Dirty(
151 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
152 ));
153 }
154#endif
155
156 /* Count this basic block */
157 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
158 addStmtToIRBB( bb, IRStmt_Dirty(di) );
159
160 for (i = 0; i < bb_in->stmts_used; i++) {
161 IRStmt* st = bb_in->stmts[i];
162 if (!st) continue;
163
164 switch (st->tag) {
165 case Ist_Exit:
166 /* Count Jcc */
167 addStmtToIRBB(
168 bb,
169 IRStmt_Dirty(
170 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
171 mkIRExprVec_0() )
172 ));
173 addStmtToIRBB( bb, dopyIRStmt(st) );
174 /* Count non-taken Jcc */
175 addStmtToIRBB(
176 bb,
177 IRStmt_Dirty(
178 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
179 mkIRExprVec_0() )
180 ));
181 break;
182
183 default:
sewardjbd598e12005-01-07 12:10:21 +0000184 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000185 }
186 }
187
188 return bb;
189
190
191#if 0
njn25e49d8e72002-09-23 09:36:25 +0000192 UCodeBlock* cb;
193 Int i;
194 UInstr* u;
195 Char fnname[100];
196
njn810086f2002-11-14 12:42:47 +0000197 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000198
njn25e49d8e72002-09-23 09:36:25 +0000199 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000200 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000201
njn810086f2002-11-14 12:42:47 +0000202 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
203 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000204
205 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000206 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000207 break;
208
209 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000210 /* Count x86 instr */
211 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000212 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000213 break;
214
215 case JMP:
216 if (u->cond != CondAlways) {
217 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000218 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
219 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000220 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000221 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000222 } else {
njn4ba5a792002-09-30 10:23:54 +0000223 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000224 }
225 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000226
njn25e49d8e72002-09-23 09:36:25 +0000227 default:
228 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000229 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
230 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000231 break;
232 }
233 }
234
njn4ba5a792002-09-30 10:23:54 +0000235 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000236 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000237#endif
njn25e49d8e72002-09-23 09:36:25 +0000238}
239
njn51d827b2005-05-09 01:02:08 +0000240static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000241{
242 VG_(message)(Vg_UserMsg,
243 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
244
245 VG_(message)(Vg_UserMsg, "");
246 VG_(message)(Vg_UserMsg, "Executed:");
sewardj9f649aa2004-11-22 20:38:40 +0000247 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
248 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs);
249 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
njn25e49d8e72002-09-23 09:36:25 +0000250
251 VG_(message)(Vg_UserMsg, "");
252 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000253 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
254 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
255 (n_Jccs - n_Jccs_untaken)*100 /
256 (n_Jccs ? n_Jccs : 1));
njn25e49d8e72002-09-23 09:36:25 +0000257
258 VG_(message)(Vg_UserMsg, "");
259 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000260 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10",
261 10 * n_guest_instrs / n_BBs);
262 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
njn25e49d8e72002-09-23 09:36:25 +0000263 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000264 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
265 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000266
njn7d9f94d2003-04-22 21:41:40 +0000267 VG_(message)(Vg_UserMsg, "");
268 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000269}
270
njn51d827b2005-05-09 01:02:08 +0000271static void lk_pre_clo_init(void)
272{
273 VG_(details_name) ("Lackey");
274 VG_(details_version) (NULL);
275 VG_(details_description) ("an example Valgrind tool");
276 VG_(details_copyright_author)(
277 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
278 VG_(details_bug_reports_to) (VG_BUGS_TO);
279 VG_(details_avg_translation_sizeB) ( 175 );
280
281 VG_(basic_tool_funcs) (lk_post_clo_init,
282 lk_instrument,
283 lk_fini);
284}
285
286VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init, 0)
fitzhardinge98abfc72003-12-16 02:05:15 +0000287
njn25e49d8e72002-09-23 09:36:25 +0000288/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000289/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000290/*--------------------------------------------------------------------*/
291