blob: 3da3339ea43eb78456a9a88efaa82e5eea1b0bfb [file] [log] [blame]
njn25e49d8e72002-09-23 09:36:25 +00001/*--------------------------------------------------------------------*/
2/*--- Simple skin for counting UInstrs, using a C helper. ---*/
njn25cac76cb2002-09-23 11:21:57 +00003/*--- lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +00004/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2002 Nicholas Nethercote
11 njn25@cam.ac.uk
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29*/
30
31#include "vg_skin.h"
32
njn4ba5a792002-09-30 10:23:54 +000033//#define uInstr0 VG_(new_UInstr0)
34//#define uLiteral VG_(set_lit_field)
njn25e49d8e72002-09-23 09:36:25 +000035
36/* Nb: use ULongs because the numbers can get very big */
37static ULong n_dlrr_calls = 0;
38static ULong n_BBs = 0;
39static ULong n_UInstrs = 0;
40static ULong n_x86_instrs = 0;
41static ULong n_Jccs = 0;
42static ULong n_Jccs_untaken = 0;
43
44static void add_one_dlrr_call(void)
45{
46 n_dlrr_calls++;
47}
48
49/* See comment above SK_(instrument) for reason why n_x86_instrs is
50 incremented here. */
51static void add_one_BB(void)
52{
53 n_BBs++;
54 n_x86_instrs++;
55}
56
57static void add_one_UInstr(void)
58{
59 n_UInstrs++;
60}
61
62static void add_one_x86_instr(void)
63{
64 n_x86_instrs++;
65}
66
67static void add_one_Jcc(void)
68{
69 n_Jccs++;
70}
71
72static void add_one_Jcc_untaken(void)
73{
74 n_Jccs_untaken++;
75}
76
77void SK_(pre_clo_init)(VgNeeds* needs, VgTrackEvents* not_used)
78{
79 needs->name = "lackey";
80 needs->description = "a UInstr counter";
81
njn25cac76cb2002-09-23 11:21:57 +000082 VG_(register_compact_helper)((Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +000083 VG_(register_compact_helper)((Addr) & add_one_BB);
84 VG_(register_compact_helper)((Addr) & add_one_x86_instr);
85 VG_(register_compact_helper)((Addr) & add_one_UInstr);
86 VG_(register_compact_helper)((Addr) & add_one_Jcc);
87 VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken);
88}
89
90void SK_(post_clo_init)(void)
91{
92}
93
94/* Note: x86 instructions are marked by an INCEIP at the end of each one,
95 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
106 If we simplemindedly added calls to add_one_x86_instr() before INCEIPs
107 and unconditional JMPs, we'd sometimes miss the final call (when a
108 preceding conditional JMP succeeds), underestimating the x86 instruction
109 count.
110
111 <code a>
112 call add_one_x86_instr()
113 INCEIP ...
114
115 <code b>
116 Jcc ...
117 call add_one_x86_instr()
118 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
123 call add_one_x86_instr()
124
125 <code a>
126 call add_one_x86_instr()
127 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*/
136UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr)
137{
138 UCodeBlock* cb;
139 Int i;
140 UInstr* u;
141 Char fnname[100];
142
njn4ba5a792002-09-30 10:23:54 +0000143 cb = VG_(alloc_UCodeBlock)();
njn25e49d8e72002-09-23 09:36:25 +0000144 cb->nextTemp = cb_in->nextTemp;
145
146 /* Count call to dlrr(), if this BB is dlrr()'s entry point */
147 if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
148 0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
149 {
njn4ba5a792002-09-30 10:23:54 +0000150 VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
njn25e49d8e72002-09-23 09:36:25 +0000151 }
152
153 /* Count basic block */
njn4ba5a792002-09-30 10:23:54 +0000154 VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
njn25e49d8e72002-09-23 09:36:25 +0000155
156 for (i = 0; i < cb_in->used; i++) {
157 u = &cb_in->instrs[i];
158
159 switch (u->opcode) {
160 case NOP: case CALLM_S: case CALLM_E:
161 break;
162
163 case INCEIP:
164 /* Count x86 instr */
njn4ba5a792002-09-30 10:23:54 +0000165 VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
166 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000167 break;
168
169 case JMP:
170 if (u->cond != CondAlways) {
171 /* Count Jcc */
njn4ba5a792002-09-30 10:23:54 +0000172 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
173 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000174 /* Count non-taken Jcc */
njn4ba5a792002-09-30 10:23:54 +0000175 VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
njn25e49d8e72002-09-23 09:36:25 +0000176 } else {
njn4ba5a792002-09-30 10:23:54 +0000177 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000178 }
179 break;
180
181 default:
182 /* Count UInstr */
njn4ba5a792002-09-30 10:23:54 +0000183 VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
184 VG_(copy_UInstr)(cb, u);
njn25e49d8e72002-09-23 09:36:25 +0000185 break;
186 }
187 }
188
njn4ba5a792002-09-30 10:23:54 +0000189 VG_(free_UCodeBlock)(cb_in);
njn25e49d8e72002-09-23 09:36:25 +0000190 return cb;
191}
192
193void SK_(fini)(void)
194{
195 VG_(message)(Vg_UserMsg,
196 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
197
198 VG_(message)(Vg_UserMsg, "");
199 VG_(message)(Vg_UserMsg, "Executed:");
200 VG_(message)(Vg_UserMsg, " BBs: %u", n_BBs);
201 VG_(message)(Vg_UserMsg, " x86 instrs: %u", n_x86_instrs);
202 VG_(message)(Vg_UserMsg, " UInstrs: %u", n_UInstrs);
203
204 VG_(message)(Vg_UserMsg, "");
205 VG_(message)(Vg_UserMsg, "Jccs:");
206 VG_(message)(Vg_UserMsg, " total: %u", n_Jccs);
207 VG_(message)(Vg_UserMsg, " %% taken: %u%%",
208 (n_Jccs - n_Jccs_untaken)*100 / n_Jccs);
209
210 VG_(message)(Vg_UserMsg, "");
211 VG_(message)(Vg_UserMsg, "Ratios:");
212 VG_(message)(Vg_UserMsg, " x86 instrs : BB = %3u : 10",
213 10 * n_x86_instrs / n_BBs);
214 VG_(message)(Vg_UserMsg, " UInstrs : BB = %3u : 10",
215 10 * n_UInstrs / n_BBs);
216 VG_(message)(Vg_UserMsg, " UInstrs : x86_instr = %3u : 10",
217 10 * n_UInstrs / n_x86_instrs);
218
219}
220
221/*--------------------------------------------------------------------*/
njn25cac76cb2002-09-23 11:21:57 +0000222/*--- end lk_main.c ---*/
njn25e49d8e72002-09-23 09:36:25 +0000223/*--------------------------------------------------------------------*/
224