Blame ptdump/fastdecode.c

Packit d4ea60
/*
Packit d4ea60
 * This is modified version of Simple PT dumper by Andi Kleen
Packit d4ea60
 * https://github.com/andikleen/simple-pt
Packit d4ea60
 */
Packit d4ea60
Packit d4ea60
/*
Packit d4ea60
 * Copyright (c) 2015, Intel Corporation
Packit d4ea60
 * Author: Andi Kleen
Packit d4ea60
 * All rights reserved.
Packit d4ea60
 *
Packit d4ea60
 * Redistribution and use in source and binary forms, with or without
Packit d4ea60
 * modification, are permitted provided that the following conditions are met:
Packit d4ea60
 *
Packit d4ea60
 * 1. Redistributions of source code must retain the above copyright notice,
Packit d4ea60
 * this list of conditions and the following disclaimer.
Packit d4ea60
 *
Packit d4ea60
 * 2. Redistributions in binary form must reproduce the above copyright
Packit d4ea60
 * notice, this list of conditions and the following disclaimer in the
Packit d4ea60
 * documentation and/or other materials provided with the distribution.
Packit d4ea60
 *
Packit d4ea60
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit d4ea60
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit d4ea60
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
Packit d4ea60
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
Packit d4ea60
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
Packit d4ea60
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
Packit d4ea60
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
Packit d4ea60
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit d4ea60
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
Packit d4ea60
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
Packit d4ea60
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
Packit d4ea60
 * OF THE POSSIBILITY OF SUCH DAMAGE.
Packit d4ea60
*/
Packit d4ea60
Packit d4ea60
#define _GNU_SOURCE 1
Packit d4ea60
#include <sys/mman.h>
Packit d4ea60
#include <sys/fcntl.h>
Packit d4ea60
#include <sys/stat.h>
Packit d4ea60
#include <stdio.h>
Packit d4ea60
#include <stdlib.h>
Packit d4ea60
#include <string.h>
Packit d4ea60
#include <stdint.h>
Packit d4ea60
#include <unistd.h>
Packit d4ea60
Packit d4ea60
#include "defs.h"
Packit d4ea60
#include "map.h"
Packit d4ea60
Packit d4ea60
#define BIT(x) (1U << (x))
Packit d4ea60
Packit d4ea60
typedef unsigned long long u64;
Packit d4ea60
Packit d4ea60
static FILE *out_fp;
Packit d4ea60
Packit d4ea60
static char psb[16] = {
Packit d4ea60
	0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82,
Packit d4ea60
	0x02, 0x82, 0x02, 0x82, 0x02, 0x82, 0x02, 0x82
Packit d4ea60
};
Packit d4ea60
Packit d4ea60
#define LEFT(x) ((end - p) >= (x))
Packit d4ea60
Packit d4ea60
/* Caller must have checked length */
Packit d4ea60
static u64 get_ip_val(unsigned char **pp, unsigned char *end, int len, uint64_t *last_ip)
Packit d4ea60
{
Packit d4ea60
	unsigned char *p = *pp;
Packit d4ea60
	u64 v = *last_ip;
Packit d4ea60
	int i;
Packit d4ea60
	unsigned shift = 0;
Packit d4ea60
Packit d4ea60
	if (len == 0) {
Packit d4ea60
		*last_ip = 0;
Packit d4ea60
		return 0; /* out of context */
Packit d4ea60
	}
Packit d4ea60
	if (len < 4) {
Packit d4ea60
		if (!LEFT(len)) {
Packit d4ea60
			*last_ip = 0;
Packit d4ea60
			return 0; /* XXX error */
Packit d4ea60
		}
Packit d4ea60
		for (i = 0; i < len; i++, shift += 16, p += 2) {
Packit d4ea60
			uint64_t b = *(uint16_t *)p;
Packit d4ea60
			v = (v & ~(0xffffULL << shift)) | (b << shift);
Packit d4ea60
		}
Packit d4ea60
		v = ((int64_t)(v << (64 - 48))) >> (64 - 48); /* sign extension */
Packit d4ea60
	} else {
Packit d4ea60
		return 0; /* XXX error */
Packit d4ea60
	}
Packit d4ea60
	*pp = p;
Packit d4ea60
	*last_ip = v;
Packit d4ea60
	return v;
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
static char *get_ip_symbol(u64 ip, char *buf, int bufsize)
Packit d4ea60
{
Packit d4ea60
	struct syment *sm;
Packit d4ea60
	ulong offset;
Packit d4ea60
Packit d4ea60
	sm = value_search(ip, &offset);
Packit d4ea60
Packit d4ea60
	if (sm) {
Packit d4ea60
		if (!offset)
Packit d4ea60
			sprintf(buf, "%s", sm->name);
Packit d4ea60
		else
Packit d4ea60
			sprintf(buf, "%s+%lu", sm->name, offset);
Packit d4ea60
Packit d4ea60
		return buf;
Packit d4ea60
	}
Packit d4ea60
Packit d4ea60
	return NULL;
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
/* Caller must have checked length */
Packit d4ea60
static u64 get_val(unsigned char **pp, int len)
Packit d4ea60
{
Packit d4ea60
	unsigned char *p = *pp;
Packit d4ea60
	u64 v = 0;
Packit d4ea60
	int i;
Packit d4ea60
	unsigned shift = 0;
Packit d4ea60
Packit d4ea60
	for (i = 0; i < len; i++, shift += 8)
Packit d4ea60
		v |= ((uint64_t)(*p++)) << shift;
Packit d4ea60
	*pp = p;
Packit d4ea60
	return v;
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
static void print_unknown(unsigned char *p, unsigned char *end, unsigned char *map)
Packit d4ea60
{
Packit d4ea60
	fprintf(out_fp, "unknown packet: ");
Packit d4ea60
	unsigned len = end - p;
Packit d4ea60
	int i;
Packit d4ea60
	if (len > 16)
Packit d4ea60
		len = 16;
Packit d4ea60
	for (i = 0; i < len; i++)
Packit d4ea60
		fprintf(out_fp, "%02x ", p[i]);
Packit d4ea60
	fprintf(out_fp, "\n");
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
static void print_tnt_byte(unsigned char v, int max)
Packit d4ea60
{
Packit d4ea60
	int i;
Packit d4ea60
	for (i = max - 1; i >= 0; i--)
Packit d4ea60
		if (v & BIT(i))
Packit d4ea60
			fprintf(out_fp, "T");
Packit d4ea60
		else
Packit d4ea60
			fprintf(out_fp, "N");
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
static void print_tnt_stop(unsigned char v)
Packit d4ea60
{
Packit d4ea60
	int j;
Packit d4ea60
	for (j = 7; j >= 0; j--) {
Packit d4ea60
		if (v & BIT(j))
Packit d4ea60
			break;
Packit d4ea60
	}
Packit d4ea60
	print_tnt_byte(v, j);
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
static void print_multi_tnt(unsigned char *p, int len)
Packit d4ea60
{
Packit d4ea60
	int i;
Packit d4ea60
Packit d4ea60
	for (i = len - 1; i >= 0 && p[i] == 0; i--)
Packit d4ea60
		;
Packit d4ea60
	if (i >= 0) {
Packit d4ea60
		print_tnt_stop(p[i]);
Packit d4ea60
		i--;
Packit d4ea60
	} else {
Packit d4ea60
		fprintf(out_fp, "??? no stop bit");
Packit d4ea60
		return;
Packit d4ea60
	}
Packit d4ea60
	for (; i >= 0; i--)
Packit d4ea60
		print_tnt_byte(p[i], 8);
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
void decode_buffer(unsigned char *map, size_t len)
Packit d4ea60
{
Packit d4ea60
	unsigned char *end = map + len;
Packit d4ea60
	unsigned char *p;
Packit d4ea60
	size_t skipped = 0;
Packit d4ea60
	size_t overflow = 0;
Packit d4ea60
	uint64_t last_ip = 0;
Packit d4ea60
	u64 ip;
Packit d4ea60
	char buf[64];
Packit d4ea60
Packit d4ea60
	for (p = map; p < end; ) {
Packit d4ea60
		unsigned char *prev = p;
Packit d4ea60
		/* look for PSB */
Packit d4ea60
		p = memmem(p, end - p, psb, 16);
Packit d4ea60
		if (!p) {
Packit d4ea60
			p = end;
Packit d4ea60
			break;
Packit d4ea60
		}
Packit d4ea60
		skipped += p - prev;
Packit d4ea60
		while (p < end) {
Packit d4ea60
			fprintf(out_fp, "%lx\t", p - map);
Packit d4ea60
Packit d4ea60
			if (*p == 2 && LEFT(2)) {
Packit d4ea60
				if (p[1] == 0xa3 && LEFT(8)) { /* long TNT */
Packit d4ea60
					fprintf(out_fp, "tnt64 ");
Packit d4ea60
					print_multi_tnt(p + 2, 6);
Packit d4ea60
					fprintf(out_fp, "\n");
Packit d4ea60
					p += 8;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 0x43 && LEFT(8)) { /* PIP */
Packit d4ea60
					p += 2;
Packit d4ea60
					fprintf(out_fp, "pip\t%llx\n", (get_val(&p, 6) >> 1) << 5);
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 3 && LEFT(4) && p[3] == 0) { /* CBR */
Packit d4ea60
					fprintf(out_fp, "cbr\t%u\n", p[2]);
Packit d4ea60
					p += 4;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 0b10000011) {
Packit d4ea60
					fprintf(out_fp, "tracestop\n");
Packit d4ea60
					p += 2;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 0b11110011 && LEFT(8)) { /* OVF */
Packit d4ea60
					fprintf(out_fp, "ovf\n");
Packit d4ea60
					p += 8;
Packit d4ea60
					overflow++;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 0x82 && LEFT(16) && !memcmp(p, psb, 16)) { /* PSB */
Packit d4ea60
					fprintf(out_fp, "psb\n");
Packit d4ea60
					p += 16;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				if (p[1] == 0b100011) { /* PSBEND */
Packit d4ea60
					fprintf(out_fp, "psbend\n");
Packit d4ea60
					p += 2;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				/* MNT */
Packit d4ea60
				if (p[1] == 0b11000011 && LEFT(11) && p[2] == 0b10001000) {
Packit d4ea60
					fprintf(out_fp, "mnt\t%llx\n",
Packit d4ea60
						p[3] |
Packit d4ea60
						((u64)p[4] << 8) |
Packit d4ea60
						((u64)p[5] << 16) |
Packit d4ea60
						((u64)p[6] << 24) |
Packit d4ea60
						((u64)p[7] << 32) |
Packit d4ea60
						((u64)p[8] << 40) |
Packit d4ea60
						((u64)p[9] << 48) |
Packit d4ea60
						((u64)p[10] << 56));
Packit d4ea60
					p += 10;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				/* TMA */
Packit d4ea60
				if (p[1] == 0b01110011 && LEFT(7)) {
Packit d4ea60
					fprintf(out_fp, "tma\tctc=%u fc=%u\n",
Packit d4ea60
							p[2] | (p[3] << 8),
Packit d4ea60
							p[5] | ((p[6] & 1) << 8));
Packit d4ea60
					p += 7;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				/* VMCS */
Packit d4ea60
				if (p[1] == 0b11001000 && LEFT(7)) {
Packit d4ea60
					fprintf(out_fp, "vmcs\t%llx\n",
Packit d4ea60
						((u64)p[2] << 12) |
Packit d4ea60
						((u64)p[3] << 20) |
Packit d4ea60
						((u64)p[4] << 28) |
Packit d4ea60
						((u64)p[5] << 36) |
Packit d4ea60
						((u64)p[6] << 44));
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
			}
Packit d4ea60
Packit d4ea60
			if ((*p & BIT(0)) == 0) {
Packit d4ea60
				if (*p == 0) { /* PAD */
Packit d4ea60
					fprintf(out_fp, "pad\n");
Packit d4ea60
					p++;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
				fprintf(out_fp, "tnt8 ");
Packit d4ea60
				print_tnt_stop(*p >> 1);
Packit d4ea60
				fprintf(out_fp, "\n");
Packit d4ea60
				p++;
Packit d4ea60
				continue;
Packit d4ea60
			}
Packit d4ea60
Packit d4ea60
			char *name = NULL;
Packit d4ea60
			switch (*p & 0x1f) {
Packit d4ea60
			case 0xd:
Packit d4ea60
				name = "tip";
Packit d4ea60
				break;
Packit d4ea60
			case 0x11:
Packit d4ea60
				name = "tip.pge";
Packit d4ea60
				break;
Packit d4ea60
			case 0x1:
Packit d4ea60
				name = "tip.pgd";
Packit d4ea60
				break;
Packit d4ea60
			case 0x1d:
Packit d4ea60
				name = "fup";
Packit d4ea60
				break;
Packit d4ea60
			}
Packit d4ea60
			if (name) {
Packit d4ea60
				int ipl = *p >> 5;
Packit d4ea60
				p++;
Packit d4ea60
				ip = get_ip_val(&p, end, ipl, &last_ip);
Packit d4ea60
				fprintf(out_fp, "%s\t%d: %llx", name, ipl, ip);
Packit d4ea60
				if (get_ip_symbol(ip, buf, sizeof(buf)))
Packit d4ea60
					fprintf(out_fp, " <%s>\n", buf);
Packit d4ea60
				else
Packit d4ea60
					fprintf(out_fp, "\n");
Packit d4ea60
				continue;
Packit d4ea60
			}
Packit d4ea60
			if (*p == 0x99 && LEFT(2)) { /* MODE */
Packit d4ea60
				if ((p[1] >> 5) == 1) {
Packit d4ea60
					fprintf(out_fp, "mode.tsx");
Packit d4ea60
					if (p[1] & BIT(0))
Packit d4ea60
						fprintf(out_fp, " intx");
Packit d4ea60
					if (p[1] & BIT(1))
Packit d4ea60
						fprintf(out_fp, " txabort");
Packit d4ea60
					fprintf(out_fp, "\n");
Packit d4ea60
					p += 2;
Packit d4ea60
					continue;
Packit d4ea60
				} else if ((p[1] >> 5) == 0) {
Packit d4ea60
					fprintf(out_fp, "mode.exec");
Packit d4ea60
					fprintf(out_fp, " lma=%d", (p[1] & BIT(0)));
Packit d4ea60
					fprintf(out_fp, " cs.d=%d", !!(p[1] & BIT(1)));
Packit d4ea60
					fprintf(out_fp, "\n");
Packit d4ea60
					p += 2;
Packit d4ea60
					continue;
Packit d4ea60
				}
Packit d4ea60
			}
Packit d4ea60
Packit d4ea60
			if (*p == 0x19 && LEFT(8)) {  /* TSC */
Packit d4ea60
				p++;
Packit d4ea60
				fprintf(out_fp, "tsc\t%llu\n", get_val(&p, 7));
Packit d4ea60
				continue;
Packit d4ea60
			}
Packit d4ea60
			if (*p == 0b01011001 && LEFT(2)) { /* MTC */
Packit d4ea60
				fprintf(out_fp, "mtc\t%u\n", p[1]);
Packit d4ea60
				p += 2;
Packit d4ea60
				continue;
Packit d4ea60
			}
Packit d4ea60
			if ((*p & 3) == 3) { /* CYC */
Packit d4ea60
				u64 cyc = *p >> 2;
Packit d4ea60
				unsigned shift = 4;
Packit d4ea60
				if ((*p & 4) && LEFT(1)) {
Packit d4ea60
					do {
Packit d4ea60
						p++;
Packit d4ea60
						cyc |= (*p >> 1) << shift;
Packit d4ea60
						shift += 7;
Packit d4ea60
					} while ((*p & 1) && LEFT(1));
Packit d4ea60
				}
Packit d4ea60
				fprintf(out_fp, "cyc\t%llu\n", cyc);
Packit d4ea60
				p++;
Packit d4ea60
				continue;
Packit d4ea60
			}
Packit d4ea60
Packit d4ea60
			print_unknown(p, end, map);
Packit d4ea60
			break;
Packit d4ea60
		}
Packit d4ea60
	}
Packit d4ea60
	if (p < end || skipped)
Packit d4ea60
		fprintf(out_fp, "%lu bytes undecoded\n", (end - p) + skipped);
Packit d4ea60
	if (overflow)
Packit d4ea60
		fprintf(out_fp, "%lu overflows\n", overflow);
Packit d4ea60
}
Packit d4ea60
Packit d4ea60
int fastdecode(char *in, char *out)
Packit d4ea60
{
Packit d4ea60
	size_t len;
Packit d4ea60
	unsigned char *map = mapfile(in, &len;;
Packit d4ea60
	if (!map) {
Packit d4ea60
		fprintf(fp, "Cannot map file: %s\n", in);
Packit d4ea60
		return FALSE;
Packit d4ea60
	}
Packit d4ea60
Packit d4ea60
	if ((out_fp = fopen(out, "w")) == NULL) {
Packit d4ea60
		fprintf(fp, "Cannot open file: %s\n", out);
Packit d4ea60
		return FALSE;
Packit d4ea60
	}
Packit d4ea60
Packit d4ea60
	decode_buffer(map, len);
Packit d4ea60
	unmapfile(map, len);
Packit d4ea60
	fclose(out_fp);
Packit d4ea60
Packit d4ea60
	return TRUE;
Packit d4ea60
}
Packit d4ea60