opd_trans.c revision 10e23eebca4175a8dfe3a788b2bebacb1fcfce54
137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang/**
22da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * @file daemon/opd_trans.c
32da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * Processing the sample buffer
437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * @remark Copyright 2002 OProfile authors
637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * @remark Read the file COPYING
72da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang *
82da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * @author John Levon
937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * @author Philippe Elie
1037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Modified by Aravind Menon for Xen
1137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * These modifications are:
1237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Copyright (C) 2005 Hewlett-Packard Co.
1337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang *
1437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * Modified by Maynard Johnson <maynardj@us.ibm.com>
1537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang * These modifications are:
162da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang * (C) Copyright IBM Corporation 2007
172da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang */
182da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang
192da723a953a18e3c7fec194cec1216cf31130c86Gloria Wang#include "opd_trans.h"
2037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_kernel.h"
2137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_sfile.h"
2237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_anon.h"
2337fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_stats.h"
2437fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_printf.h"
2537fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include "opd_interface.h"
2637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang
2737fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <limits.h>
2837fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <string.h>
2937fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <stdlib.h>
3037fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <stdint.h>
3137fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <stdio.h>
3237fe158a8611dd11ec0253ab1552399b780988dcGloria Wang#include <errno.h>
337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangextern size_t kernel_pointer_size;
357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3637fe158a8611dd11ec0253ab1552399b780988dcGloria Wang
377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvoid clear_trans_last(struct transient * trans)
387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->last = NULL;
407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->last_anon = NULL;
417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvoid clear_trans_current(struct transient * trans)
457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->current = NULL;
477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->anon = NULL;
487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanguint64_t pop_buffer_value(struct transient * trans)
527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	uint64_t val;
547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!trans->remaining) {
567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		fprintf(stderr, "BUG: popping empty buffer !\n");
577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		abort();
587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (kernel_pointer_size == 4) {
617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		uint32_t const * lbuf = (void const *)trans->buffer;
627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		val = *lbuf;
637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	} else {
647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		uint64_t const * lbuf = (void const *)trans->buffer;
657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		val = *lbuf;
667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->remaining--;
697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->buffer += kernel_pointer_size;
707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return val;
717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangint enough_remaining(struct transient * trans, size_t size)
757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (trans->remaining >= size)
777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return 1;
787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	opd_stats[OPD_DANGLING_CODE]++;
817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	return 0;
827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void opd_put_sample(struct transient * trans, unsigned long long pc)
867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	unsigned long long event;
887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!enough_remaining(trans, 1)) {
907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->remaining = 0;
917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return;
927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	event = pop_buffer_value(trans);
957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (trans->tracing != TRACING_ON)
977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->event = event;
987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->pc = pc;
1007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* sfile can change at each sample for kernel */
1027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (trans->in_kernel != 0)
1037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		clear_trans_current(trans);
1047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!trans->in_kernel && trans->cookie == NO_COOKIE)
1067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->anon = find_anon_mapping(trans);
1077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* get the current sfile if needed */
1097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!trans->current)
1107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->current = sfile_find(trans);
1117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/*
1137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * can happen if kernel sample falls through the cracks, or if
1147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * it's a sample from an anon region we couldn't find
1157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 */
1167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!trans->current)
1177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		goto out;
1187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* FIXME: this logic is perhaps too harsh? */
1207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (trans->current->ignored || (trans->last && trans->last->ignored))
1217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		goto out;
1227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* log the sample or arc */
1247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	sfile_log_sample(trans);
1257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangout:
1277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* switch to trace mode */
1287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (trans->tracing == TRACING_START)
1297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->tracing = TRACING_ON;
1307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	update_trans_last(trans);
1327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_unknown(struct transient * trans __attribute__((unused)))
1367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
1377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	fprintf(stderr, "Unknown code !\n");
1387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	abort();
1397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_ctx_switch(struct transient * trans)
1437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
1447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
1457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!enough_remaining(trans, 5)) {
1477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->remaining = 0;
1487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return;
1497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
1507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->tid = pop_buffer_value(trans);
1527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->app_cookie = pop_buffer_value(trans);
1537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* must be ESCAPE_CODE, CTX_TGID_CODE, tgid. Like this
1547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * because tgid was added later in a compatible manner.
1557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 */
1567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	pop_buffer_value(trans);
1577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	pop_buffer_value(trans);
1587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->tgid = pop_buffer_value(trans);
1597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (vmisc) {
1617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		char const * app = find_cookie(trans->app_cookie);
1627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		printf("CTX_SWITCH to tid %lu, tgid %lu, cookie %llx(%s)\n",
1637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		       (unsigned long)trans->tid, (unsigned long)trans->tgid,
1647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		       trans->app_cookie, app ? app : "none");
1657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
1667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_cpu_switch(struct transient * trans)
1707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
1717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
1727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!enough_remaining(trans, 1)) {
1747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->remaining = 0;
1757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return;
1767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
1777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->cpu = pop_buffer_value(trans);
1797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(vmisc, "CPU_SWITCH to %lu\n", trans->cpu);
1807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
1817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_cookie_switch(struct transient * trans)
1847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
1857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
1867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (!enough_remaining(trans, 1)) {
1887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		trans->remaining = 0;
1897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return;
190ea4d754fcb81fced7bd1f33ad67f7b50d5fbb291Marco Nelissen	}
1917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->cookie = pop_buffer_value(trans);
1937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
1947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (vmisc) {
1957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		char const * name = verbose_cookie(trans->cookie);
1967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		verbprintf(vmisc, "COOKIE_SWITCH to cookie %s(%llx)\n",
1977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		           name, trans->cookie);
1987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
1997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_kernel_enter(struct transient * trans)
2037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(vmisc, "KERNEL_ENTER_SWITCH to kernel\n");
2057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->in_kernel = 1;
2067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
2077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* subtlety: we must keep trans->cookie cached,
2087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * even though it's meaningless for the kernel -
2097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * we won't necessarily get a cookie switch on
2107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * kernel exit. See comments in opd_sfile.c
2117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 */
2127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_user_enter(struct transient * trans)
2167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
217d52f6d76f66e2e419bd18cc09395a0008edd649cBruce Beare	verbprintf(vmisc, "USER_ENTER_SWITCH to user-space\n");
2187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->in_kernel = 0;
2197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
220ea4d754fcb81fced7bd1f33ad67f7b50d5fbb291Marco Nelissen	clear_trans_last(trans);
221ea4d754fcb81fced7bd1f33ad67f7b50d5fbb291Marco Nelissen}
2227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_module_loaded(struct transient * trans __attribute__((unused)))
2257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(vmodule, "MODULE_LOADED_CODE\n");
2277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	opd_reread_module_info();
2287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	clear_trans_current(trans);
229b46673f19ebfff0984b7cbc69554239992ea21bbDouglas Leung	clear_trans_last(trans);
230b46673f19ebfff0984b7cbc69554239992ea21bbDouglas Leung}
2317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang/*
2347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * This also implicitly signals the end of the previous
2357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * trace, so we never explicitly set TRACING_OFF when
2367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang * processing a buffer.
2377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang */
2387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_trace_begin(struct transient * trans)
2397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(varcs, "TRACE_BEGIN\n");
2417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->tracing = TRACING_START;
2427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangstatic void code_xen_enter(struct transient * trans)
2457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	verbprintf(vmisc, "XEN_ENTER_SWITCH to xen\n");
2477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->in_kernel = 1;
2487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	trans->current = NULL;
2497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* subtlety: we must keep trans->cookie cached, even though it's
2507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * meaningless for Xen - we won't necessarily get a cookie switch
2517913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * on Xen exit. See comments in opd_sfile.c. It seems that we can
2527913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * get away with in_kernel = 1 as long as we supply the correct
2537913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * Xen image, and its address range in startup find_kernel_image
2547913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * is modified to look in the Xen image also
2557913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 */
2567913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
2577913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2587913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangextern void code_spu_profiling(struct transient * trans);
2597913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangextern void code_spu_ctx_switch(struct transient * trans);
2607913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2617913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wanghandler_t handlers[LAST_CODE + 1] = {
2627913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_unknown,
2637913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_ctx_switch,
2647913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_cpu_switch,
2657913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_cookie_switch,
2667913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_kernel_enter,
2677913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang 	&code_user_enter,
2687913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_module_loaded,
2697913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* tgid handled differently */
2707913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_unknown,
2717913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_trace_begin,
2727913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_unknown,
2737913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang 	&code_xen_enter,
2747913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#if defined(__powerpc__)
2757913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_spu_profiling,
2767913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_spu_ctx_switch,
2777913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang#endif
2787913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	&code_unknown,
2797913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang};
2807913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2817913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangextern void (*special_processor)(struct transient *);
2827913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
2837913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wangvoid opd_process_samples(char const * buffer, size_t count)
2847913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang{
2857913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	struct transient trans = {
2867913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.buffer = buffer,
2877913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.remaining = count,
2887913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.tracing = TRACING_OFF,
2897913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.current = NULL,
2907913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.last = NULL,
2917913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.cookie = INVALID_COOKIE,
2927913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.app_cookie = INVALID_COOKIE,
2937913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.anon = NULL,
2947913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.last_anon = NULL,
2957913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.pc = 0,
2967913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.last_pc = 0,
2977913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.event = 0,
2987913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.in_kernel = -1,
2997913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.cpu = -1,
3007913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.tid = -1,
3017913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.embedded_offset = UNUSED_EMBEDDED_OFFSET,
3027913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		.tgid = -1
3037913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	};
3047913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3057913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	/* FIXME: was uint64_t but it can't compile on alpha where uint64_t
3067913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * is an unsigned long and below the printf("..." %llu\n", code)
3077913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 * generate a warning, this look like a stopper to use c98 types :/
3087913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	 */
3097913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	unsigned long long code;
3107913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3117913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	if (special_processor) {
3127913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		special_processor(&trans);
3137913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		return;
3147913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
3157913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3167913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    int i;
3177913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3187913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    for (i = 0; i < count && i < 200; i++) {
3197913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        verbprintf(vmisc, "buffer[%d] is %x\n", i, buffer[i]);
3207913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang    }
3217913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3227913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	while (trans.remaining) {
3237913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		code = pop_buffer_value(&trans);
3247913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3257913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        verbprintf(vmisc, "In opd_process_samples (code is %lld)\n", code);
3267913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3277913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		if (!is_escape_code(code)) {
3287913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			opd_put_sample(&trans, code);
3297913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			continue;
3307913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		}
3317913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3327913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		if (!trans.remaining) {
3337913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			verbprintf(vmisc, "Dangling ESCAPE_CODE.\n");
3347913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			opd_stats[OPD_DANGLING_CODE]++;
3357913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			break;
3367913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		}
3377913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3387913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		// started with ESCAPE_CODE, next is type
3397913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		code = pop_buffer_value(&trans);
3407913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3417913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang        verbprintf(vmisc, "next code is %lld\n", code);
3427913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		if (code >= LAST_CODE) {
3437913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			fprintf(stderr, "Unknown code %llu\n", code);
3447913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang			abort();
3457913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		}
3467913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang
3477913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang		handlers[code](&trans);
3487913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang	}
3497913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang}
3507913073ddf11ca3dd7b0439998e1b17d443bb0baGloria Wang