blob: 9c1d29ebc540a9ff5efb171f1916ac539a544958 [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*/
sewardj4ba057c2005-10-18 12:04:18 +0000127static
128IRBB* lk_instrument( IRBB* bb_in, VexGuestLayout* layout,
129 Addr64 orig_addr_noredir, VexGuestExtents* vge,
130 IRType gWordTy, IRType hWordTy )
njn25e49d8e72002-09-23 09:36:25 +0000131{
sewardj9f649aa2004-11-22 20:38:40 +0000132 IRDirty* di;
133 Int i;
sewardjd54babf2005-03-21 00:55:49 +0000134 IRBB* bb;
135
136 if (gWordTy != hWordTy) {
137 /* We don't currently support this case. */
138 VG_(tool_panic)("host/guest word size mismatch");
139 }
sewardj9f649aa2004-11-22 20:38:40 +0000140
141 /* Set up BB */
sewardjd54babf2005-03-21 00:55:49 +0000142 bb = emptyIRBB();
sewardj9f649aa2004-11-22 20:38:40 +0000143 bb->tyenv = dopyIRTypeEnv(bb_in->tyenv);
144 bb->next = dopyIRExpr(bb_in->next);
145 bb->jumpkind = bb_in->jumpkind;
146
147#if 0
148 /* We need to know the entry point for this bb to do this. In any
149 case it's pretty meaningless in the presence of bb chasing since
150 we may enter this function part way through an IRBB. */
151 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
152 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
153 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
154 {
155 addStmtToIRBB(
156 bb,
157 IRStmt_Dirty(
158 unsafeIRDirty_0_N( "add_one_dlrr_call", mkIRExprVec_0() )
159 ));
160 }
161#endif
162
163 /* Count this basic block */
164 di = unsafeIRDirty_0_N( 0, "add_one_BB", &add_one_BB, mkIRExprVec_0() );
165 addStmtToIRBB( bb, IRStmt_Dirty(di) );
166
167 for (i = 0; i < bb_in->stmts_used; i++) {
168 IRStmt* st = bb_in->stmts[i];
169 if (!st) continue;
170
171 switch (st->tag) {
172 case Ist_Exit:
173 /* Count Jcc */
174 addStmtToIRBB(
175 bb,
176 IRStmt_Dirty(
177 unsafeIRDirty_0_N( 0, "add_one_Jcc", &add_one_Jcc,
178 mkIRExprVec_0() )
179 ));
180 addStmtToIRBB( bb, dopyIRStmt(st) );
181 /* Count non-taken Jcc */
182 addStmtToIRBB(
183 bb,
184 IRStmt_Dirty(
185 unsafeIRDirty_0_N( 0, "add_one_Jcc_untaken", &add_one_Jcc_untaken,
186 mkIRExprVec_0() )
187 ));
188 break;
189
190 default:
sewardjbd598e12005-01-07 12:10:21 +0000191 addStmtToIRBB( bb, st );
sewardj9f649aa2004-11-22 20:38:40 +0000192 }
193 }
194
195 return bb;
196
197
198#if 0
njn25e49d8e72002-09-23 09:36:25 +0000199 UCodeBlock* cb;
200 Int i;
201 UInstr* u;
202 Char fnname[100];
203
njn810086f2002-11-14 12:42:47 +0000204 cb = VG_(setup_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000205
njn25e49d8e72002-09-23 09:36:25 +0000206 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000207 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000208
njn810086f2002-11-14 12:42:47 +0000209 for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
210 u = VG_(get_instr)(cb_in, i);
njn25e49d8e72002-09-23 09:36:25 +0000211
212 switch (u->opcode) {
sewardj7a5ebcf2002-11-13 22:42:13 +0000213 case NOP: case LOCK: case CALLM_S: case CALLM_E:
njn25e49d8e72002-09-23 09:36:25 +0000214 break;
215
216 case INCEIP:
sewardj9f649aa2004-11-22 20:38:40 +0000217 /* Count x86 instr */
218 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
njn4ba5a792002-09-30 10:23:54 +0000219 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000220 break;
221
222 case JMP:
223 if (u->cond != CondAlways) {
224 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000225 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
226 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000227 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000228 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000229 } else {
njn4ba5a792002-09-30 10:23:54 +0000230 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000231 }
232 break;
sewardj3d7c9c82003-03-26 21:08:13 +0000233
njn25e49d8e72002-09-23 09:36:25 +0000234 default:
235 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000236 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
237 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000238 break;
239 }
240 }
241
njn4ba5a792002-09-30 10:23:54 +0000242 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000243 return cb;
sewardj9f649aa2004-11-22 20:38:40 +0000244#endif
njn25e49d8e72002-09-23 09:36:25 +0000245}
246
njn51d827b2005-05-09 01:02:08 +0000247static void lk_fini(Int exitcode)
njn25e49d8e72002-09-23 09:36:25 +0000248{
249 VG_(message)(Vg_UserMsg,
250 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
251
252 VG_(message)(Vg_UserMsg, "");
253 VG_(message)(Vg_UserMsg, "Executed:");
sewardj9f649aa2004-11-22 20:38:40 +0000254 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
255 VG_(message)(Vg_UserMsg, " guest instrs: %u", n_guest_instrs);
256 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
njn25e49d8e72002-09-23 09:36:25 +0000257
258 VG_(message)(Vg_UserMsg, "");
259 VG_(message)(Vg_UserMsg, "Jccs:");
sewardj9f649aa2004-11-22 20:38:40 +0000260 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
261 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
262 (n_Jccs - n_Jccs_untaken)*100 /
263 (n_Jccs ? n_Jccs : 1));
njn25e49d8e72002-09-23 09:36:25 +0000264
265 VG_(message)(Vg_UserMsg, "");
266 VG_(message)(Vg_UserMsg, "Ratios:");
sewardj9f649aa2004-11-22 20:38:40 +0000267 VG_(message)(Vg_UserMsg, " guest instrs : BB = %3u : 10",
268 10 * n_guest_instrs / n_BBs);
269 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
njn25e49d8e72002-09-23 09:36:25 +0000270 10 * n_UInstrs / n_BBs);
sewardj9f649aa2004-11-22 20:38:40 +0000271 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
272 10 * n_UInstrs / n_guest_instrs);
njn25e49d8e72002-09-23 09:36:25 +0000273
njn7d9f94d2003-04-22 21:41:40 +0000274 VG_(message)(Vg_UserMsg, "");
275 VG_(message)(Vg_UserMsg, "Exit code: %d", exitcode);
njn25e49d8e72002-09-23 09:36:25 +0000276}
277
njn51d827b2005-05-09 01:02:08 +0000278static void lk_pre_clo_init(void)
279{
280 VG_(details_name) ("Lackey");
281 VG_(details_version) (NULL);
282 VG_(details_description) ("an example Valgrind tool");
283 VG_(details_copyright_author)(
284 "Copyright (C) 2002-2005, and GNU GPL'd, by Nicholas Nethercote.");
285 VG_(details_bug_reports_to) (VG_BUGS_TO);
286 VG_(details_avg_translation_sizeB) ( 175 );
287
288 VG_(basic_tool_funcs) (lk_post_clo_init,
289 lk_instrument,
290 lk_fini);
291}
292
sewardj45f4e7c2005-09-27 19:20:21 +0000293VG_DETERMINE_INTERFACE_VERSION(lk_pre_clo_init)
fitzhardinge98abfc72003-12-16 02:05:15 +0000294
njn25e49d8e72002-09-23 09:36:25 +0000295/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000296/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000297/*--------------------------------------------------------------------*/
298