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