lk_main.c revision e427a6636de5b2d34c2223821ff5cbf79bad4fad
1/*--------------------------------------------------------------------*/
2/*--- Simple skin for counting UInstrs, using a C helper.          ---*/
3/*---                                                    lk_main.c ---*/
4/*--------------------------------------------------------------------*/
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
33//#define uInstr0   VG_(new_UInstr0)
34//#define uLiteral  VG_(set_lit_field)
35
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   needs->description = "njn25@cam.ac.uk";
82
83   VG_(register_compact_helper)((Addr) & add_one_dlrr_call);
84   VG_(register_compact_helper)((Addr) & add_one_BB);
85   VG_(register_compact_helper)((Addr) & add_one_x86_instr);
86   VG_(register_compact_helper)((Addr) & add_one_UInstr);
87   VG_(register_compact_helper)((Addr) & add_one_Jcc);
88   VG_(register_compact_helper)((Addr) & add_one_Jcc_untaken);
89}
90
91void SK_(post_clo_init)(void)
92{
93}
94
95/* Note: x86 instructions are marked by an INCEIP at the end of each one,
96   except for the final one in the basic block which ends in an
97   unconditional JMP.  Sometimes the final unconditional JMP is preceded by
98   a conditional JMP (Jcc), and thus it isn't reached.  Eg:
99
100      <code a>
101      INCEIP ...
102
103      <code b>
104      Jcc ...
105      JMP ...     (will not be reached if Jcc succeeds)
106
107   If we simplemindedly added calls to add_one_x86_instr() before INCEIPs
108   and unconditional JMPs, we'd sometimes miss the final call (when a
109   preceding conditional JMP succeeds), underestimating the x86 instruction
110   count.
111
112      <code a>
113      call add_one_x86_instr()
114      INCEIP ...
115
116      <code b>
117      Jcc ...
118      call add_one_x86_instr()
119      JMP ...
120
121   Instead we add a call before each INCEIP, and also one at the start of the
122   block, but not one at the end, viz:
123
124      call add_one_x86_instr()
125
126      <code a>
127      call add_one_x86_instr()
128      INCEIP ...
129
130      <code b>
131      Jcc ...
132      JMP ...
133
134   Which gives us the right answer.  And just to avoid two C calls, we fold
135   the basic-block-beginning call in with add_one_BB().  Phew.
136*/
137UCodeBlock* SK_(instrument)(UCodeBlock* cb_in, Addr orig_addr)
138{
139   UCodeBlock* cb;
140   Int         i;
141   UInstr*     u;
142   Char        fnname[100];
143
144   cb = VG_(alloc_UCodeBlock)();
145   cb->nextTemp = cb_in->nextTemp;
146
147   /* Count call to dlrr(), if this BB is dlrr()'s entry point */
148   if (VG_(get_fnname_if_entry)(orig_addr, fnname, 100) &&
149       0 == VG_(strcmp)(fnname, "_dl_runtime_resolve"))
150   {
151      VG_(call_helper_0_0)(cb, (Addr) & add_one_dlrr_call);
152   }
153
154   /* Count basic block */
155   VG_(call_helper_0_0)(cb, (Addr) & add_one_BB);
156
157   for (i = 0; i < cb_in->used; i++) {
158      u = &cb_in->instrs[i];
159
160      switch (u->opcode) {
161         case NOP: case CALLM_S: case CALLM_E:
162            break;
163
164         case INCEIP:
165            /* Count x86 instr */
166            VG_(call_helper_0_0)(cb, (Addr) & add_one_x86_instr);
167            VG_(copy_UInstr)(cb, u);
168            break;
169
170         case JMP:
171            if (u->cond != CondAlways) {
172               /* Count Jcc */
173               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc);
174               VG_(copy_UInstr)(cb, u);
175               /* Count non-taken Jcc */
176               VG_(call_helper_0_0)(cb, (Addr) & add_one_Jcc_untaken);
177            } else {
178               VG_(copy_UInstr)(cb, u);
179            }
180            break;
181
182         default:
183            /* Count UInstr */
184            VG_(call_helper_0_0)(cb, (Addr) & add_one_UInstr);
185            VG_(copy_UInstr)(cb, u);
186            break;
187      }
188   }
189
190   VG_(free_UCodeBlock)(cb_in);
191   return cb;
192}
193
194void SK_(fini)(void)
195{
196    VG_(message)(Vg_UserMsg,
197                 "Counted %d calls to _dl_runtime_resolve()", n_dlrr_calls);
198
199    VG_(message)(Vg_UserMsg, "");
200    VG_(message)(Vg_UserMsg, "Executed:");
201    VG_(message)(Vg_UserMsg, "  BBs:         %u", n_BBs);
202    VG_(message)(Vg_UserMsg, "  x86 instrs:  %u", n_x86_instrs);
203    VG_(message)(Vg_UserMsg, "  UInstrs:     %u", n_UInstrs);
204
205    VG_(message)(Vg_UserMsg, "");
206    VG_(message)(Vg_UserMsg, "Jccs:");
207    VG_(message)(Vg_UserMsg, "  total:       %u", n_Jccs);
208    VG_(message)(Vg_UserMsg, "  %% taken:     %u%%",
209                             (n_Jccs - n_Jccs_untaken)*100 / n_Jccs);
210
211    VG_(message)(Vg_UserMsg, "");
212    VG_(message)(Vg_UserMsg, "Ratios:");
213    VG_(message)(Vg_UserMsg, "  x86 instrs : BB        = %3u : 10",
214                             10 * n_x86_instrs / n_BBs);
215    VG_(message)(Vg_UserMsg, "     UInstrs : BB        = %3u : 10",
216                             10 * n_UInstrs / n_BBs);
217    VG_(message)(Vg_UserMsg, "     UInstrs : x86_instr = %3u : 10",
218                             10 * n_UInstrs / n_x86_instrs);
219
220}
221
222/*--------------------------------------------------------------------*/
223/*--- end                                                lk_main.c ---*/
224/*--------------------------------------------------------------------*/
225
226