00001
00019 #include "opd_trans.h"
00020 #include "opd_kernel.h"
00021 #include "opd_sfile.h"
00022 #include "opd_anon.h"
00023 #include "opd_stats.h"
00024 #include "opd_printf.h"
00025 #include "opd_interface.h"
00026
00027 #include <limits.h>
00028 #include <string.h>
00029 #include <stdlib.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <errno.h>
00033
00034 extern size_t kernel_pointer_size;
00035
00036
00037 void clear_trans_last(struct transient * trans)
00038 {
00039 trans->last = NULL;
00040 trans->last_anon = NULL;
00041 }
00042
00043
00044 void clear_trans_current(struct transient * trans)
00045 {
00046 trans->current = NULL;
00047 trans->anon = NULL;
00048 }
00049
00050
00051 uint64_t pop_buffer_value(struct transient * trans)
00052 {
00053 uint64_t val;
00054
00055 if (!trans->remaining) {
00056 fprintf(stderr, "BUG: popping empty buffer !\n");
00057 abort();
00058 }
00059
00060 if (kernel_pointer_size == 4) {
00061 uint32_t const * lbuf = (void const *)trans->buffer;
00062 val = *lbuf;
00063 } else {
00064 uint64_t const * lbuf = (void const *)trans->buffer;
00065 val = *lbuf;
00066 }
00067
00068 trans->remaining--;
00069 trans->buffer += kernel_pointer_size;
00070 return val;
00071 }
00072
00073
00074 int enough_remaining(struct transient * trans, size_t size)
00075 {
00076 if (trans->remaining >= size)
00077 return 1;
00078
00079 verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
00080 opd_stats[OPD_DANGLING_CODE]++;
00081 return 0;
00082 }
00083
00084
00085 static void opd_put_sample(struct transient * trans, unsigned long long pc)
00086 {
00087 unsigned long long event;
00088
00089 if (!enough_remaining(trans, 1)) {
00090 trans->remaining = 0;
00091 return;
00092 }
00093
00094 event = pop_buffer_value(trans);
00095
00096 if (trans->tracing != TRACING_ON)
00097 trans->event = event;
00098
00099 trans->pc = pc;
00100
00101
00102 if (trans->in_kernel != 0)
00103 clear_trans_current(trans);
00104
00105 if (!trans->in_kernel && trans->cookie == NO_COOKIE)
00106 trans->anon = find_anon_mapping(trans);
00107
00108
00109 if (!trans->current)
00110 trans->current = sfile_find(trans);
00111
00112
00113
00114
00115
00116 if (!trans->current)
00117 goto out;
00118
00119 if (trans->tracing != TRACING_ON) {
00120 opd_stats[OPD_SAMPLES]++;
00121 opd_stats[trans->in_kernel == 1 ? OPD_KERNEL : OPD_PROCESS]++;
00122 }
00123
00124
00125
00126 if (trans->current->ignored || (trans->last && trans->last->ignored))
00127 goto out;
00128
00129
00130 sfile_log_sample(trans);
00131
00132 out:
00133
00134 if (trans->tracing == TRACING_START)
00135 trans->tracing = TRACING_ON;
00136
00137 update_trans_last(trans);
00138 }
00139
00140
00141 static void code_unknown(struct transient * trans __attribute__((unused)))
00142 {
00143 fprintf(stderr, "Unknown code !\n");
00144 abort();
00145 }
00146
00147
00148 static void code_ctx_switch(struct transient * trans)
00149 {
00150 clear_trans_current(trans);
00151
00152 if (!enough_remaining(trans, 5)) {
00153 trans->remaining = 0;
00154 return;
00155 }
00156
00157 trans->tid = pop_buffer_value(trans);
00158 trans->app_cookie = pop_buffer_value(trans);
00159
00160
00161
00162 pop_buffer_value(trans);
00163 pop_buffer_value(trans);
00164 trans->tgid = pop_buffer_value(trans);
00165
00166 if (vmisc) {
00167 char const * app = find_cookie(trans->app_cookie);
00168 printf("CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
00169 (unsigned long)trans->tid, (unsigned long)trans->tgid,
00170 trans->app_cookie, app ? app : "none");
00171 }
00172 }
00173
00174
00175 static void code_cpu_switch(struct transient * trans)
00176 {
00177 clear_trans_current(trans);
00178
00179 if (!enough_remaining(trans, 1)) {
00180 trans->remaining = 0;
00181 return;
00182 }
00183
00184 trans->cpu = pop_buffer_value(trans);
00185 verbprintf(vmisc, "CPU_SWITCH to %lu\n", trans->cpu);
00186 }
00187
00188
00189 static void code_cookie_switch(struct transient * trans)
00190 {
00191 clear_trans_current(trans);
00192
00193 if (!enough_remaining(trans, 1)) {
00194 trans->remaining = 0;
00195 return;
00196 }
00197
00198 trans->cookie = pop_buffer_value(trans);
00199
00200 if (vmisc) {
00201 char const * name = verbose_cookie(trans->cookie);
00202 verbprintf(vmisc, "COOKIE_SWITCH to cookie %s(%llx)\n",
00203 name, trans->cookie);
00204 }
00205 }
00206
00207
00208 static void code_kernel_enter(struct transient * trans)
00209 {
00210 verbprintf(vmisc, "KERNEL_ENTER_SWITCH to kernel\n");
00211 trans->in_kernel = 1;
00212 clear_trans_current(trans);
00213
00214
00215
00216
00217
00218 }
00219
00220
00221 static void code_user_enter(struct transient * trans)
00222 {
00223 verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
00224 trans->in_kernel = 0;
00225 clear_trans_current(trans);
00226 clear_trans_last(trans);
00227 }
00228
00229
00230 static void code_module_loaded(struct transient * trans __attribute__((unused)))
00231 {
00232 verbprintf(vmodule, "MODULE_LOADED_CODE\n");
00233 opd_reread_module_info();
00234 clear_trans_current(trans);
00235 clear_trans_last(trans);
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 static void code_trace_begin(struct transient * trans)
00245 {
00246 verbprintf(varcs, "TRACE_BEGIN\n");
00247 trans->tracing = TRACING_START;
00248 }
00249
00250 static void code_xen_enter(struct transient * trans)
00251 {
00252 verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
00253 trans->in_kernel = 1;
00254 trans->current = NULL;
00255
00256
00257
00258
00259
00260
00261
00262 }
00263
00264 extern void code_spu_profiling(struct transient * trans);
00265 extern void code_spu_ctx_switch(struct transient * trans);
00266
00267 extern void code_ibs_fetch_sample(struct transient * trans);
00268 extern void code_ibs_op_sample(struct transient * trans);
00269
00270 handler_t handlers[LAST_CODE + 1] = {
00271 &code_unknown,
00272 &code_ctx_switch,
00273 &code_cpu_switch,
00274 &code_cookie_switch,
00275 &code_kernel_enter,
00276 &code_user_enter,
00277 &code_module_loaded,
00278
00279 &code_unknown,
00280 &code_trace_begin,
00281 &code_unknown,
00282 &code_xen_enter,
00283 #if defined(__powerpc__)
00284 &code_spu_profiling,
00285 &code_spu_ctx_switch,
00286 #else
00287 &code_unknown,
00288 &code_unknown,
00289 #endif
00290 &code_ibs_fetch_sample,
00291 &code_ibs_op_sample,
00292 };
00293
00294 extern void (*special_processor)(struct transient *);
00295
00296 void opd_process_samples(char const * buffer, size_t count)
00297 {
00298 struct transient trans = {
00299 .buffer = buffer,
00300 .remaining = count,
00301 .tracing = TRACING_OFF,
00302 .current = NULL,
00303 .last = NULL,
00304 .cookie = INVALID_COOKIE,
00305 .app_cookie = INVALID_COOKIE,
00306 .anon = NULL,
00307 .last_anon = NULL,
00308 .pc = 0,
00309 .last_pc = 0,
00310 .event = 0,
00311 .in_kernel = -1,
00312 .cpu = -1,
00313 .tid = -1,
00314 .embedded_offset = UNUSED_EMBEDDED_OFFSET,
00315 .tgid = -1,
00316 .ext = NULL
00317 };
00318
00319
00320
00321
00322
00323 unsigned long long code;
00324
00325 if (special_processor) {
00326 special_processor(&trans);
00327 return;
00328 }
00329
00330 while (trans.remaining) {
00331 code = pop_buffer_value(&trans);
00332
00333 if (!is_escape_code(code)) {
00334 opd_put_sample(&trans, code);
00335 continue;
00336 }
00337
00338 if (!trans.remaining) {
00339 verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
00340 opd_stats[OPD_DANGLING_CODE]++;
00341 break;
00342 }
00343
00344
00345 code = pop_buffer_value(&trans);
00346
00347 if (code >= LAST_CODE) {
00348 fprintf(stderr, "Unknown code %llu\n", code);
00349 abort();
00350 }
00351
00352 handlers[code](&trans);
00353 }
00354 }