1 /** 2 * @file daemon/opd_trans.c 3 * Processing the sample buffer 4 * 5 * @remark Copyright 2002 OProfile authors 6 * @remark Read the file COPYING 7 * 8 * @author John Levon 9 * @author Philippe Elie 10 * Modified by Aravind Menon for Xen 11 * These modifications are: 12 * Copyright (C) 2005 Hewlett-Packard Co. 13 * 14 * Modified by Maynard Johnson <maynardj (at) us.ibm.com> 15 * These modifications are: 16 * (C) Copyright IBM Corporation 2007 17 */ 18 19 #include "opd_trans.h" 20 #include "opd_kernel.h" 21 #include "opd_sfile.h" 22 #include "opd_anon.h" 23 #include "opd_stats.h" 24 #include "opd_printf.h" 25 #include "opd_interface.h" 26 27 #include <limits.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <stdint.h> 31 #include <stdio.h> 32 #include <errno.h> 33 34 extern size_t kernel_pointer_size; 35 36 37 void clear_trans_last(struct transient * trans) 38 { 39 trans->last = NULL; 40 trans->last_anon = NULL; 41 } 42 43 44 void clear_trans_current(struct transient * trans) 45 { 46 trans->current = NULL; 47 trans->anon = NULL; 48 } 49 50 51 uint64_t pop_buffer_value(struct transient * trans) 52 { 53 uint64_t val; 54 55 if (!trans->remaining) { 56 fprintf(stderr, "BUG: popping empty buffer !\n"); 57 abort(); 58 } 59 60 if (kernel_pointer_size == 4) { 61 uint32_t const * lbuf = (void const *)trans->buffer; 62 val = *lbuf; 63 } else { 64 uint64_t const * lbuf = (void const *)trans->buffer; 65 val = *lbuf; 66 } 67 68 trans->remaining--; 69 trans->buffer += kernel_pointer_size; 70 return val; 71 } 72 73 74 int enough_remaining(struct transient * trans, size_t size) 75 { 76 if (trans->remaining >= size) 77 return 1; 78 79 verbprintf(vmisc, "Dangling ESCAPE_CODE.\n"); 80 opd_stats[OPD_DANGLING_CODE]++; 81 return 0; 82 } 83 84 85 static void opd_put_sample(struct transient * trans, unsigned long long pc) 86 { 87 unsigned long long event; 88 89 if (!enough_remaining(trans, 1)) { 90 trans->remaining = 0; 91 return; 92 } 93 94 event = pop_buffer_value(trans); 95 96 if (trans->tracing != TRACING_ON) 97 trans->event = event; 98 99 trans->pc = pc; 100 101 /* sfile can change at each sample for kernel */ 102 if (trans->in_kernel != 0) 103 clear_trans_current(trans); 104 105 if (!trans->in_kernel && trans->cookie == NO_COOKIE) 106 trans->anon = find_anon_mapping(trans); 107 108 /* get the current sfile if needed */ 109 if (!trans->current) 110 trans->current = sfile_find(trans); 111 112 /* 113 * can happen if kernel sample falls through the cracks, or if 114 * it's a sample from an anon region we couldn't find 115 */ 116 if (!trans->current) 117 goto out; 118 119 /* FIXME: this logic is perhaps too harsh? */ 120 if (trans->current->ignored || (trans->last && trans->last->ignored)) 121 goto out; 122 123 /* log the sample or arc */ 124 sfile_log_sample(trans); 125 126 out: 127 /* switch to trace mode */ 128 if (trans->tracing == TRACING_START) 129 trans->tracing = TRACING_ON; 130 131 update_trans_last(trans); 132 } 133 134 135 static void code_unknown(struct transient * trans __attribute__((unused))) 136 { 137 fprintf(stderr, "Unknown code !\n"); 138 abort(); 139 } 140 141 142 static void code_ctx_switch(struct transient * trans) 143 { 144 clear_trans_current(trans); 145 146 if (!enough_remaining(trans, 5)) { 147 trans->remaining = 0; 148 return; 149 } 150 151 trans->tid = pop_buffer_value(trans); 152 trans->app_cookie = pop_buffer_value(trans); 153 /* must be ESCAPE_CODE, CTX_TGID_CODE, tgid. Like this 154 * because tgid was added later in a compatible manner. 155 */ 156 pop_buffer_value(trans); 157 pop_buffer_value(trans); 158 trans->tgid = pop_buffer_value(trans); 159 160 if (vmisc) { 161 char const * app = find_cookie(trans->app_cookie); 162 printf("CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n", 163 (unsigned long)trans->tid, (unsigned long)trans->tgid, 164 trans->app_cookie, app ? app : "none"); 165 } 166 } 167 168 169 static void code_cpu_switch(struct transient * trans) 170 { 171 clear_trans_current(trans); 172 173 if (!enough_remaining(trans, 1)) { 174 trans->remaining = 0; 175 return; 176 } 177 178 trans->cpu = pop_buffer_value(trans); 179 verbprintf(vmisc, "CPU_SWITCH to %lu\n", trans->cpu); 180 } 181 182 183 static void code_cookie_switch(struct transient * trans) 184 { 185 clear_trans_current(trans); 186 187 if (!enough_remaining(trans, 1)) { 188 trans->remaining = 0; 189 return; 190 } 191 192 trans->cookie = pop_buffer_value(trans); 193 194 if (vmisc) { 195 char const * name = verbose_cookie(trans->cookie); 196 verbprintf(vmisc, "COOKIE_SWITCH to cookie %s(%llx)\n", 197 name, trans->cookie); 198 } 199 } 200 201 202 static void code_kernel_enter(struct transient * trans) 203 { 204 verbprintf(vmisc, "KERNEL_ENTER_SWITCH to kernel\n"); 205 trans->in_kernel = 1; 206 clear_trans_current(trans); 207 /* subtlety: we must keep trans->cookie cached, 208 * even though it's meaningless for the kernel - 209 * we won't necessarily get a cookie switch on 210 * kernel exit. See comments in opd_sfile.c 211 */ 212 } 213 214 215 static void code_user_enter(struct transient * trans) 216 { 217 verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n"); 218 trans->in_kernel = 0; 219 clear_trans_current(trans); 220 clear_trans_last(trans); 221 } 222 223 224 static void code_module_loaded(struct transient * trans __attribute__((unused))) 225 { 226 verbprintf(vmodule, "MODULE_LOADED_CODE\n"); 227 opd_reread_module_info(); 228 clear_trans_current(trans); 229 clear_trans_last(trans); 230 } 231 232 233 /* 234 * This also implicitly signals the end of the previous 235 * trace, so we never explicitly set TRACING_OFF when 236 * processing a buffer. 237 */ 238 static void code_trace_begin(struct transient * trans) 239 { 240 verbprintf(varcs, "TRACE_BEGIN\n"); 241 trans->tracing = TRACING_START; 242 } 243 244 static void code_xen_enter(struct transient * trans) 245 { 246 verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n"); 247 trans->in_kernel = 1; 248 trans->current = NULL; 249 /* subtlety: we must keep trans->cookie cached, even though it's 250 * meaningless for Xen - we won't necessarily get a cookie switch 251 * on Xen exit. See comments in opd_sfile.c. It seems that we can 252 * get away with in_kernel = 1 as long as we supply the correct 253 * Xen image, and its address range in startup find_kernel_image 254 * is modified to look in the Xen image also 255 */ 256 } 257 258 extern void code_spu_profiling(struct transient * trans); 259 extern void code_spu_ctx_switch(struct transient * trans); 260 261 extern void code_ibs_fetch_sample(struct transient * trans); 262 extern void code_ibs_op_sample(struct transient * trans); 263 264 handler_t handlers[LAST_CODE + 1] = { 265 &code_unknown, 266 &code_ctx_switch, 267 &code_cpu_switch, 268 &code_cookie_switch, 269 &code_kernel_enter, 270 &code_user_enter, 271 &code_module_loaded, 272 /* tgid handled differently */ 273 &code_unknown, 274 &code_trace_begin, 275 &code_unknown, 276 &code_xen_enter, 277 #if defined(__powerpc__) 278 &code_spu_profiling, 279 &code_spu_ctx_switch, 280 #else 281 &code_unknown, 282 &code_unknown, 283 #endif 284 &code_ibs_fetch_sample, 285 &code_ibs_op_sample, 286 }; 287 288 extern void (*special_processor)(struct transient *); 289 290 void opd_process_samples(char const * buffer, size_t count) 291 { 292 struct transient trans = { 293 .buffer = buffer, 294 .remaining = count, 295 .tracing = TRACING_OFF, 296 .current = NULL, 297 .last = NULL, 298 .cookie = INVALID_COOKIE, 299 .app_cookie = INVALID_COOKIE, 300 .anon = NULL, 301 .last_anon = NULL, 302 .pc = 0, 303 .last_pc = 0, 304 .event = 0, 305 .in_kernel = -1, 306 .cpu = -1, 307 .tid = -1, 308 .embedded_offset = UNUSED_EMBEDDED_OFFSET, 309 .tgid = -1, 310 .ext = NULL 311 }; 312 313 /* FIXME: was uint64_t but it can't compile on alpha where uint64_t 314 * is an unsigned long and below the printf("..." %llu\n", code) 315 * generate a warning, this look like a stopper to use c98 types :/ 316 */ 317 unsigned long long code; 318 319 if (special_processor) { 320 special_processor(&trans); 321 return; 322 } 323 324 while (trans.remaining) { 325 code = pop_buffer_value(&trans); 326 327 if (!is_escape_code(code)) { 328 opd_put_sample(&trans, code); 329 continue; 330 } 331 332 if (!trans.remaining) { 333 verbprintf(vmisc, "Dangling ESCAPE_CODE.\n"); 334 opd_stats[OPD_DANGLING_CODE]++; 335 break; 336 } 337 338 // started with ESCAPE_CODE, next is type 339 code = pop_buffer_value(&trans); 340 341 if (code >= LAST_CODE) { 342 fprintf(stderr, "Unknown code %llu\n", code); 343 abort(); 344 } 345 346 handlers[code](&trans); 347 } 348 } 349