|
Packit |
b1f7ae |
/*
|
|
Packit |
b1f7ae |
* Copyright (c) 2013-2017, Intel Corporation
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
b1f7ae |
* modification, are permitted provided that the following conditions are met:
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* * Redistributions of source code must retain the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer.
|
|
Packit |
b1f7ae |
* * Redistributions in binary form must reproduce the above copyright notice,
|
|
Packit |
b1f7ae |
* this list of conditions and the following disclaimer in the documentation
|
|
Packit |
b1f7ae |
* and/or other materials provided with the distribution.
|
|
Packit |
b1f7ae |
* * Neither the name of Intel Corporation nor the names of its contributors
|
|
Packit |
b1f7ae |
* may be used to endorse or promote products derived from this software
|
|
Packit |
b1f7ae |
* without specific prior written permission.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
Packit |
b1f7ae |
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
Packit |
b1f7ae |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
Packit |
b1f7ae |
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
Packit |
b1f7ae |
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
Packit |
b1f7ae |
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
Packit |
b1f7ae |
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
Packit |
b1f7ae |
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
Packit |
b1f7ae |
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
Packit |
b1f7ae |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
Packit |
b1f7ae |
* POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#if defined(FEATURE_ELF)
|
|
Packit |
b1f7ae |
# include "load_elf.h"
|
|
Packit |
b1f7ae |
#endif /* defined(FEATURE_ELF) */
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "pt_cpu.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include "intel-pt.h"
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <stdlib.h>
|
|
Packit |
b1f7ae |
#include <stdio.h>
|
|
Packit |
b1f7ae |
#include <string.h>
|
|
Packit |
b1f7ae |
#include <inttypes.h>
|
|
Packit |
b1f7ae |
#include <errno.h>
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
#include <xed-interface.h>
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The type of decoder to be used. */
|
|
Packit |
b1f7ae |
enum ptxed_decoder_type {
|
|
Packit |
b1f7ae |
pdt_insn_decoder,
|
|
Packit |
b1f7ae |
pdt_block_decoder
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The decoder to use. */
|
|
Packit |
b1f7ae |
struct ptxed_decoder {
|
|
Packit |
b1f7ae |
/* The decoder type. */
|
|
Packit |
b1f7ae |
enum ptxed_decoder_type type;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The actual decoder. */
|
|
Packit |
b1f7ae |
union {
|
|
Packit |
b1f7ae |
/* If @type == pdt_insn_decoder */
|
|
Packit |
b1f7ae |
struct pt_insn_decoder *insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If @type == pdt_block_decoder */
|
|
Packit |
b1f7ae |
struct pt_block_decoder *block;
|
|
Packit |
b1f7ae |
} variant;
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* A collection of options. */
|
|
Packit |
b1f7ae |
struct ptxed_options {
|
|
Packit |
b1f7ae |
/* Do not print the instruction. */
|
|
Packit |
b1f7ae |
uint32_t dont_print_insn:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Remain as quiet as possible - excluding error messages. */
|
|
Packit |
b1f7ae |
uint32_t quiet:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print statistics (overrides quiet). */
|
|
Packit |
b1f7ae |
uint32_t print_stats:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print information about section loads and unloads. */
|
|
Packit |
b1f7ae |
uint32_t track_image:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Track blocks in the output.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* This only applies to the block decoder.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
uint32_t track_blocks:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print in AT&T format. */
|
|
Packit |
b1f7ae |
uint32_t att_format:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print the offset into the trace file. */
|
|
Packit |
b1f7ae |
uint32_t print_offset:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print the current timestamp. */
|
|
Packit |
b1f7ae |
uint32_t print_time:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Print the raw bytes for an insn. */
|
|
Packit |
b1f7ae |
uint32_t print_raw_insn:1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Perform checks. */
|
|
Packit |
b1f7ae |
uint32_t check:1;
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* A collection of flags selecting which stats to collect/print. */
|
|
Packit |
b1f7ae |
enum ptxed_stats_flag {
|
|
Packit |
b1f7ae |
/* Collect number of instructions. */
|
|
Packit |
b1f7ae |
ptxed_stat_insn = (1 << 0),
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Collect number of blocks. */
|
|
Packit |
b1f7ae |
ptxed_stat_blocks = (1 << 1)
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* A collection of statistics. */
|
|
Packit |
b1f7ae |
struct ptxed_stats {
|
|
Packit |
b1f7ae |
/* The number of instructions. */
|
|
Packit |
b1f7ae |
uint64_t insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The number of blocks.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* This only applies to the block decoder.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
uint64_t blocks;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* A collection of flags saying which statistics to collect/print. */
|
|
Packit |
b1f7ae |
uint32_t flags;
|
|
Packit |
b1f7ae |
};
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int ptxed_have_decoder(const struct ptxed_decoder *decoder)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
/* It suffices to check for one decoder in the variant union. */
|
|
Packit |
b1f7ae |
return decoder && decoder->variant.insn;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void ptxed_free_decoder(struct ptxed_decoder *decoder)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!decoder)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (decoder->type) {
|
|
Packit |
b1f7ae |
case pdt_insn_decoder:
|
|
Packit |
b1f7ae |
pt_insn_free_decoder(decoder->variant.insn);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case pdt_block_decoder:
|
|
Packit |
b1f7ae |
pt_blk_free_decoder(decoder->variant.block);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void version(const char *name)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_version v = pt_library_version();
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("%s-%d.%d.%d%s / libipt-%" PRIu8 ".%" PRIu8 ".%" PRIu32 "%s\n",
|
|
Packit |
b1f7ae |
name, PT_VERSION_MAJOR, PT_VERSION_MINOR, PT_VERSION_BUILD,
|
|
Packit |
b1f7ae |
PT_VERSION_EXT, v.major, v.minor, v.build, v.ext);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void help(const char *name)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
printf("usage: %s [<options>]\n\n", name);
|
|
Packit |
b1f7ae |
printf("options:\n");
|
|
Packit |
b1f7ae |
printf(" --help|-h this text.\n");
|
|
Packit |
b1f7ae |
printf(" --version display version information and exit.\n");
|
|
Packit |
b1f7ae |
printf(" --att print instructions in att format.\n");
|
|
Packit |
b1f7ae |
printf(" --no-inst do not print instructions (only addresses).\n");
|
|
Packit |
b1f7ae |
printf(" --quiet|-q do not print anything (except errors).\n");
|
|
Packit |
b1f7ae |
printf(" --offset print the offset into the trace file.\n");
|
|
Packit |
b1f7ae |
printf(" --time print the current timestamp.\n");
|
|
Packit |
b1f7ae |
printf(" --raw-insn print the raw bytes of each instruction.\n");
|
|
Packit |
b1f7ae |
printf(" --check perform checks (expensive).\n");
|
|
Packit |
b1f7ae |
printf(" --stat print statistics (even when quiet).\n");
|
|
Packit |
b1f7ae |
printf(" collects all statistics unless one or more are selected.\n");
|
|
Packit |
b1f7ae |
printf(" --stat:insn collect number of instructions.\n");
|
|
Packit |
b1f7ae |
printf(" --verbose|-v print various information (even when quiet).\n");
|
|
Packit |
b1f7ae |
printf(" --pt <file>[:<from>[-<to>]] load the processor trace data from <file>.\n");
|
|
Packit |
b1f7ae |
printf(" an optional offset or range can be given.\n");
|
|
Packit |
b1f7ae |
#if defined(FEATURE_ELF)
|
|
Packit |
b1f7ae |
printf(" --elf <<file>[:<base>] load an ELF from <file> at address <base>.\n");
|
|
Packit |
b1f7ae |
printf(" use the default load address if <base> is omitted.\n");
|
|
Packit |
b1f7ae |
#endif /* defined(FEATURE_ELF) */
|
|
Packit |
b1f7ae |
printf(" --raw <file>[:<from>[-<to>]]:<base> load a raw binary from <file> at address <base>.\n");
|
|
Packit |
b1f7ae |
printf(" an optional offset or range can be given.\n");
|
|
Packit |
b1f7ae |
printf(" --cpu none|auto|f/m[/s] set cpu to the given value and decode according to:\n");
|
|
Packit |
b1f7ae |
printf(" none spec (default)\n");
|
|
Packit |
b1f7ae |
printf(" auto current cpu\n");
|
|
Packit |
b1f7ae |
printf(" f/m[/s] family/model[/stepping]\n");
|
|
Packit |
b1f7ae |
printf(" --mtc-freq <n> set the MTC frequency (IA32_RTIT_CTL[17:14]) to <n>.\n");
|
|
Packit |
b1f7ae |
printf(" --nom-freq <n> set the nominal frequency (MSR_PLATFORM_INFO[15:8]) to <n>.\n");
|
|
Packit |
b1f7ae |
printf(" --cpuid-0x15.eax set the value of cpuid[0x15].eax.\n");
|
|
Packit |
b1f7ae |
printf(" --cpuid-0x15.ebx set the value of cpuid[0x15].ebx.\n");
|
|
Packit |
b1f7ae |
printf(" --insn-decoder use the instruction flow decoder (default).\n");
|
|
Packit |
b1f7ae |
printf(" --block-decoder use the block decoder.\n");
|
|
Packit |
b1f7ae |
printf(" --block:show-blocks show blocks in the output.\n");
|
|
Packit |
b1f7ae |
printf(" --block:end-on-call set the end-on-call block decoder flag.\n");
|
|
Packit |
b1f7ae |
printf("\n");
|
|
Packit |
b1f7ae |
#if defined(FEATURE_ELF)
|
|
Packit |
b1f7ae |
printf("You must specify at least one binary or ELF file (--raw|--elf).\n");
|
|
Packit |
b1f7ae |
#else /* defined(FEATURE_ELF) */
|
|
Packit |
b1f7ae |
printf("You must specify at least one binary file (--raw).\n");
|
|
Packit |
b1f7ae |
#endif /* defined(FEATURE_ELF) */
|
|
Packit |
b1f7ae |
printf("You must specify exactly one processor trace file (--pt).\n");
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int extract_base(char *arg, uint64_t *base)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
char *sep, *rest;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
sep = strrchr(arg, ':');
|
|
Packit |
b1f7ae |
if (sep) {
|
|
Packit |
b1f7ae |
uint64_t num;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!sep[1])
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errno = 0;
|
|
Packit |
b1f7ae |
num = strtoull(sep+1, &rest, 0);
|
|
Packit |
b1f7ae |
if (errno || *rest)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*base = num;
|
|
Packit |
b1f7ae |
*sep = 0;
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int parse_range(const char *arg, uint64_t *begin, uint64_t *end)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
char *rest;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!arg || !*arg)
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errno = 0;
|
|
Packit |
b1f7ae |
*begin = strtoull(arg, &rest, 0);
|
|
Packit |
b1f7ae |
if (errno)
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!*rest)
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (*rest != '-')
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*end = strtoull(rest+1, &rest, 0);
|
|
Packit |
b1f7ae |
if (errno || *rest)
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 2;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Preprocess a filename argument.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* A filename may optionally be followed by a file offset or a file range
|
|
Packit |
b1f7ae |
* argument separated by ':'. Split the original argument into the filename
|
|
Packit |
b1f7ae |
* part and the offset/range part.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* If no end address is specified, set @size to zero.
|
|
Packit |
b1f7ae |
* If no offset is specified, set @offset to zero.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Returns zero on success, a negative error code otherwise.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
static int preprocess_filename(char *filename, uint64_t *offset, uint64_t *size)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t begin, end;
|
|
Packit |
b1f7ae |
char *range;
|
|
Packit |
b1f7ae |
int parts;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!filename || !offset || !size)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Search from the end as the filename may also contain ':'. */
|
|
Packit |
b1f7ae |
range = strrchr(filename, ':');
|
|
Packit |
b1f7ae |
if (!range) {
|
|
Packit |
b1f7ae |
*offset = 0ull;
|
|
Packit |
b1f7ae |
*size = 0ull;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Let's try to parse an optional range suffix.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* If we can, remove it from the filename argument.
|
|
Packit |
b1f7ae |
* If we can not, assume that the ':' is part of the filename, e.g. a
|
|
Packit |
b1f7ae |
* drive letter on Windows.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
parts = parse_range(range + 1, &begin, &end;;
|
|
Packit |
b1f7ae |
if (parts <= 0) {
|
|
Packit |
b1f7ae |
*offset = 0ull;
|
|
Packit |
b1f7ae |
*size = 0ull;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (parts == 1) {
|
|
Packit |
b1f7ae |
*offset = begin;
|
|
Packit |
b1f7ae |
*size = 0ull;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*range = 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (parts == 2) {
|
|
Packit |
b1f7ae |
if (end <= begin)
|
|
Packit |
b1f7ae |
return -pte_invalid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*offset = begin;
|
|
Packit |
b1f7ae |
*size = end - begin;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*range = 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int load_file(uint8_t **buffer, size_t *psize, const char *filename,
|
|
Packit |
b1f7ae |
uint64_t offset, uint64_t size, const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint8_t *content;
|
|
Packit |
b1f7ae |
size_t read;
|
|
Packit |
b1f7ae |
FILE *file;
|
|
Packit |
b1f7ae |
long fsize, begin, end;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!buffer || !psize || !filename || !prog) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: internal error.\n", prog ? prog : "");
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errno = 0;
|
|
Packit |
b1f7ae |
file = fopen(filename, "rb");
|
|
Packit |
b1f7ae |
if (!file) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to open %s: %d.\n",
|
|
Packit |
b1f7ae |
prog, filename, errno);
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = fseek(file, 0, SEEK_END);
|
|
Packit |
b1f7ae |
if (errcode) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to determine size of %s: %d.\n",
|
|
Packit |
b1f7ae |
prog, filename, errno);
|
|
Packit |
b1f7ae |
goto err_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fsize = ftell(file);
|
|
Packit |
b1f7ae |
if (fsize < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to determine size of %s: %d.\n",
|
|
Packit |
b1f7ae |
prog, filename, errno);
|
|
Packit |
b1f7ae |
goto err_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
begin = (long) offset;
|
|
Packit |
b1f7ae |
if (((uint64_t) begin != offset) || (fsize <= begin)) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: bad offset 0x%" PRIx64 " into %s.\n",
|
|
Packit |
b1f7ae |
prog, offset, filename);
|
|
Packit |
b1f7ae |
goto err_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
end = fsize;
|
|
Packit |
b1f7ae |
if (size) {
|
|
Packit |
b1f7ae |
uint64_t range_end;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
range_end = offset + size;
|
|
Packit |
b1f7ae |
if ((uint64_t) end < range_end) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: bad range 0x%" PRIx64 " in %s.\n",
|
|
Packit |
b1f7ae |
prog, range_end, filename);
|
|
Packit |
b1f7ae |
goto err_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
end = (long) range_end;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fsize = end - begin;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
content = malloc(fsize);
|
|
Packit |
b1f7ae |
if (!content) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to allocated memory %s.\n",
|
|
Packit |
b1f7ae |
prog, filename);
|
|
Packit |
b1f7ae |
goto err_file;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = fseek(file, begin, SEEK_SET);
|
|
Packit |
b1f7ae |
if (errcode) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to load %s: %d.\n",
|
|
Packit |
b1f7ae |
prog, filename, errno);
|
|
Packit |
b1f7ae |
goto err_content;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
read = fread(content, fsize, 1, file);
|
|
Packit |
b1f7ae |
if (read != 1) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to load %s: %d.\n",
|
|
Packit |
b1f7ae |
prog, filename, errno);
|
|
Packit |
b1f7ae |
goto err_content;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fclose(file);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*buffer = content;
|
|
Packit |
b1f7ae |
*psize = fsize;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
err_content:
|
|
Packit |
b1f7ae |
free(content);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
err_file:
|
|
Packit |
b1f7ae |
fclose(file);
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int load_pt(struct pt_config *config, char *arg, const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t foffset, fsize;
|
|
Packit |
b1f7ae |
uint8_t *buffer;
|
|
Packit |
b1f7ae |
size_t size;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = preprocess_filename(arg, &foffset, &fsize);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: bad file %s: %s.\n", prog, arg,
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = load_file(&buffer, &size, arg, foffset, fsize, prog);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
return errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
config->begin = buffer;
|
|
Packit |
b1f7ae |
config->end = buffer + size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int load_raw(struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
struct pt_image *image, char *arg, const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t base, foffset, fsize;
|
|
Packit |
b1f7ae |
int isid, errcode, has_base;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
has_base = extract_base(arg, &base);
|
|
Packit |
b1f7ae |
if (has_base <= 0)
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = preprocess_filename(arg, &foffset, &fsize);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: bad file %s: %s.\n", prog, arg,
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!fsize)
|
|
Packit |
b1f7ae |
fsize = UINT64_MAX;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
isid = pt_iscache_add_file(iscache, arg, foffset, fsize, base);
|
|
Packit |
b1f7ae |
if (isid < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to add %s at 0x%" PRIx64 ": %s.\n",
|
|
Packit |
b1f7ae |
prog, arg, base, pt_errstr(pt_errcode(isid)));
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_image_add_cached(image, iscache, isid, NULL);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to add %s at 0x%" PRIx64 ": %s.\n",
|
|
Packit |
b1f7ae |
prog, arg, base, pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return -1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static xed_machine_mode_enum_t translate_mode(enum pt_exec_mode mode)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
switch (mode) {
|
|
Packit |
b1f7ae |
case ptem_unknown:
|
|
Packit |
b1f7ae |
return XED_MACHINE_MODE_INVALID;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptem_16bit:
|
|
Packit |
b1f7ae |
return XED_MACHINE_MODE_LEGACY_16;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptem_32bit:
|
|
Packit |
b1f7ae |
return XED_MACHINE_MODE_LEGACY_32;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptem_64bit:
|
|
Packit |
b1f7ae |
return XED_MACHINE_MODE_LONG_64;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return XED_MACHINE_MODE_INVALID;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static const char *visualize_iclass(enum pt_insn_class iclass)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
switch (iclass) {
|
|
Packit |
b1f7ae |
case ptic_error:
|
|
Packit |
b1f7ae |
return "unknown/error";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_other:
|
|
Packit |
b1f7ae |
return "other";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_call:
|
|
Packit |
b1f7ae |
return "near call";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_return:
|
|
Packit |
b1f7ae |
return "near return";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_jump:
|
|
Packit |
b1f7ae |
return "near jump";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_cond_jump:
|
|
Packit |
b1f7ae |
return "cond jump";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_call:
|
|
Packit |
b1f7ae |
return "far call";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_return:
|
|
Packit |
b1f7ae |
return "far return";
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_jump:
|
|
Packit |
b1f7ae |
return "far jump";
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return "undefined";
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void check_insn_iclass(const xed_inst_t *inst,
|
|
Packit |
b1f7ae |
const struct pt_insn *insn, uint64_t offset)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_category_enum_t category;
|
|
Packit |
b1f7ae |
xed_iclass_enum_t iclass;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!inst || !insn) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
category = xed_inst_category(inst);
|
|
Packit |
b1f7ae |
iclass = xed_inst_iclass(inst);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (insn->iclass) {
|
|
Packit |
b1f7ae |
case ptic_error:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_other:
|
|
Packit |
b1f7ae |
switch (category) {
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case XED_CATEGORY_CALL:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_RET:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_COND_BR:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_UNCOND_BR:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_INTERRUPT:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_SYSCALL:
|
|
Packit |
b1f7ae |
case XED_CATEGORY_SYSRET:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_call:
|
|
Packit |
b1f7ae |
if (iclass == XED_ICLASS_CALL_NEAR)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_return:
|
|
Packit |
b1f7ae |
if (iclass == XED_ICLASS_RET_NEAR)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_jump:
|
|
Packit |
b1f7ae |
if (iclass == XED_ICLASS_JMP)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_cond_jump:
|
|
Packit |
b1f7ae |
if (category == XED_CATEGORY_COND_BR)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_call:
|
|
Packit |
b1f7ae |
switch (iclass) {
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case XED_ICLASS_CALL_FAR:
|
|
Packit |
b1f7ae |
case XED_ICLASS_INT:
|
|
Packit |
b1f7ae |
case XED_ICLASS_INT1:
|
|
Packit |
b1f7ae |
case XED_ICLASS_INT3:
|
|
Packit |
b1f7ae |
case XED_ICLASS_INTO:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSCALL:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSCALL_AMD:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSENTER:
|
|
Packit |
b1f7ae |
case XED_ICLASS_VMCALL:
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_return:
|
|
Packit |
b1f7ae |
switch (iclass) {
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case XED_ICLASS_RET_FAR:
|
|
Packit |
b1f7ae |
case XED_ICLASS_IRET:
|
|
Packit |
b1f7ae |
case XED_ICLASS_IRETD:
|
|
Packit |
b1f7ae |
case XED_ICLASS_IRETQ:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSRET:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSRET_AMD:
|
|
Packit |
b1f7ae |
case XED_ICLASS_SYSEXIT:
|
|
Packit |
b1f7ae |
case XED_ICLASS_VMLAUNCH:
|
|
Packit |
b1f7ae |
case XED_ICLASS_VMRESUME:
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case ptic_far_jump:
|
|
Packit |
b1f7ae |
if (iclass == XED_ICLASS_JMP_FAR)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If we get here, @insn->iclass doesn't match XED's classification. */
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": iclass error: iclass: %s, "
|
|
Packit |
b1f7ae |
"xed iclass: %s, category: %s]\n", offset, insn->ip,
|
|
Packit |
b1f7ae |
visualize_iclass(insn->iclass), xed_iclass_enum_t2str(iclass),
|
|
Packit |
b1f7ae |
xed_category_enum_t2str(category));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void check_insn_decode(xed_decoded_inst_t *inst,
|
|
Packit |
b1f7ae |
const struct pt_insn *insn, uint64_t offset)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_error_enum_t errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!inst || !insn) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_decoded_inst_set_mode(inst, translate_mode(insn->mode),
|
|
Packit |
b1f7ae |
XED_ADDRESS_WIDTH_INVALID);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Decode the instruction (again).
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We may have decoded the instruction already for printing. In this
|
|
Packit |
b1f7ae |
* case, we will decode it twice.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* The more common use-case, however, is to check the instruction class
|
|
Packit |
b1f7ae |
* while not printing instructions since the latter is too expensive for
|
|
Packit |
b1f7ae |
* regular use with long traces.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = xed_decode(inst, insn->raw, insn->size);
|
|
Packit |
b1f7ae |
if (errcode != XED_ERROR_NONE) {
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": xed error: (%u) %s]\n",
|
|
Packit |
b1f7ae |
offset, insn->ip, errcode,
|
|
Packit |
b1f7ae |
xed_error_enum_t2str(errcode));
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!xed_decoded_inst_valid(inst)) {
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": xed error: "
|
|
Packit |
b1f7ae |
"invalid instruction]\n", offset, insn->ip);
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void check_insn(const struct pt_insn *insn, uint64_t offset)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_decoded_inst_t inst;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_decoded_inst_zero(&inst);
|
|
Packit |
b1f7ae |
check_insn_decode(&inst, insn, offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need a valid instruction in order to do further checks.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Invalid instructions have already been diagnosed.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (!xed_decoded_inst_valid(&inst))
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
check_insn_iclass(xed_decoded_inst_inst(&inst), insn, offset);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void xed_print_insn(const xed_decoded_inst_t *inst, uint64_t ip,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_print_info_t pi;
|
|
Packit |
b1f7ae |
char buffer[256];
|
|
Packit |
b1f7ae |
xed_bool_t ok;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!inst || !options) {
|
|
Packit |
b1f7ae |
printf(" [internal error]");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_raw_insn) {
|
|
Packit |
b1f7ae |
xed_uint_t length, i;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
length = xed_decoded_inst_get_length(inst);
|
|
Packit |
b1f7ae |
for (i = 0; i < length; ++i)
|
|
Packit |
b1f7ae |
printf(" %02x", xed_decoded_inst_get_byte(inst, i));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (; i < pt_max_insn_size; ++i)
|
|
Packit |
b1f7ae |
printf(" ");
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_init_print_info(&pi);
|
|
Packit |
b1f7ae |
pi.p = inst;
|
|
Packit |
b1f7ae |
pi.buf = buffer;
|
|
Packit |
b1f7ae |
pi.blen = sizeof(buffer);
|
|
Packit |
b1f7ae |
pi.runtime_address = ip;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->att_format)
|
|
Packit |
b1f7ae |
pi.syntax = XED_SYNTAX_ATT;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ok = xed_format_generic(&pi);
|
|
Packit |
b1f7ae |
if (!ok) {
|
|
Packit |
b1f7ae |
printf(" [xed print error]");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf(" %s", buffer);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void print_insn(const struct pt_insn *insn, xed_state_t *xed,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options, uint64_t offset,
|
|
Packit |
b1f7ae |
uint64_t time)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!insn || !options) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->resynced)
|
|
Packit |
b1f7ae |
printf("[overflow]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->enabled)
|
|
Packit |
b1f7ae |
printf("[enabled]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->resumed)
|
|
Packit |
b1f7ae |
printf("[resumed]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->speculative)
|
|
Packit |
b1f7ae |
printf("? ");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_offset)
|
|
Packit |
b1f7ae |
printf("%016" PRIx64 " ", offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_time)
|
|
Packit |
b1f7ae |
printf("%016" PRIx64 " ", time);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("%016" PRIx64, insn->ip);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options->dont_print_insn) {
|
|
Packit |
b1f7ae |
xed_machine_mode_enum_t mode;
|
|
Packit |
b1f7ae |
xed_decoded_inst_t inst;
|
|
Packit |
b1f7ae |
xed_error_enum_t errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mode = translate_mode(insn->mode);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_state_set_machine_mode(xed, mode);
|
|
Packit |
b1f7ae |
xed_decoded_inst_zero_set_mode(&inst, xed);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = xed_decode(&inst, insn->raw, insn->size);
|
|
Packit |
b1f7ae |
switch (errcode) {
|
|
Packit |
b1f7ae |
case XED_ERROR_NONE:
|
|
Packit |
b1f7ae |
xed_print_insn(&inst, insn->ip, options);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
printf(" [xed decode error: (%u) %s]", errcode,
|
|
Packit |
b1f7ae |
xed_error_enum_t2str(errcode));
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->interrupted)
|
|
Packit |
b1f7ae |
printf("[interrupt]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->aborted)
|
|
Packit |
b1f7ae |
printf("[aborted]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->committed)
|
|
Packit |
b1f7ae |
printf("[committed]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->disabled)
|
|
Packit |
b1f7ae |
printf("[disabled]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (insn->stopped)
|
|
Packit |
b1f7ae |
printf("[stopped]\n");
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void diagnose_insn(const char *errtype, struct pt_insn_decoder *decoder,
|
|
Packit |
b1f7ae |
struct pt_insn *insn, int errcode)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
int err;
|
|
Packit |
b1f7ae |
uint64_t pos;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
err = pt_insn_get_offset(decoder, &pos;;
|
|
Packit |
b1f7ae |
if (err < 0) {
|
|
Packit |
b1f7ae |
printf("could not determine offset: %s\n",
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(err)));
|
|
Packit |
b1f7ae |
printf("[?, %" PRIx64 ": %s: %s]\n", insn->ip, errtype,
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
} else
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": %s: %s]\n", pos,
|
|
Packit |
b1f7ae |
insn->ip, errtype, pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void decode_insn(struct pt_insn_decoder *decoder,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options,
|
|
Packit |
b1f7ae |
struct ptxed_stats *stats)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_state_t xed;
|
|
Packit |
b1f7ae |
uint64_t offset, sync, time;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_state_zero(&xed);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
offset = 0ull;
|
|
Packit |
b1f7ae |
sync = 0ull;
|
|
Packit |
b1f7ae |
time = 0ull;
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
struct pt_insn insn;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Initialize the IP - we use it for error reporting. */
|
|
Packit |
b1f7ae |
insn.ip = 0ull;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_insn_sync_forward(decoder);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
uint64_t new_sync;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (errcode == -pte_eos)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
diagnose_insn("sync error", decoder, &insn, errcode);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Let's see if we made any progress. If we haven't,
|
|
Packit |
b1f7ae |
* we likely never will. Bail out.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We intentionally report the error twice to indicate
|
|
Packit |
b1f7ae |
* that we tried to re-sync. Maybe it even changed.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_insn_get_offset(decoder, &new_sync);
|
|
Packit |
b1f7ae |
if (errcode < 0 || (new_sync <= sync))
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
sync = new_sync;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
if (options->print_offset || options->check) {
|
|
Packit |
b1f7ae |
errcode = pt_insn_get_offset(decoder, &offset);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_time) {
|
|
Packit |
b1f7ae |
errcode = pt_insn_time(decoder, &time, NULL,
|
|
Packit |
b1f7ae |
NULL);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_insn_next(decoder, &insn, sizeof(insn));
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
/* Even in case of errors, we may have succeeded
|
|
Packit |
b1f7ae |
* in decoding the current instruction.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (insn.iclass != ptic_error) {
|
|
Packit |
b1f7ae |
if (!options->quiet)
|
|
Packit |
b1f7ae |
print_insn(&insn, &xed, options,
|
|
Packit |
b1f7ae |
offset, time);
|
|
Packit |
b1f7ae |
if (stats)
|
|
Packit |
b1f7ae |
stats->insn += 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->check)
|
|
Packit |
b1f7ae |
check_insn(&insn, offset);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options->quiet)
|
|
Packit |
b1f7ae |
print_insn(&insn, &xed, options, offset, time);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stats)
|
|
Packit |
b1f7ae |
stats->insn += 1;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->check)
|
|
Packit |
b1f7ae |
check_insn(&insn, offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (errcode & pts_eos) {
|
|
Packit |
b1f7ae |
if (!insn.disabled && !options->quiet)
|
|
Packit |
b1f7ae |
printf("[end of trace]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = -pte_eos;
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We shouldn't break out of the loop without an error. */
|
|
Packit |
b1f7ae |
if (!errcode)
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We're done when we reach the end of the trace stream. */
|
|
Packit |
b1f7ae |
if (errcode == -pte_eos)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
diagnose_insn("error", decoder, &insn, errcode);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int xed_next_ip(uint64_t *pip, const xed_decoded_inst_t *inst,
|
|
Packit |
b1f7ae |
uint64_t ip)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_uint_t length, disp_width;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!pip || !inst)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
length = xed_decoded_inst_get_length(inst);
|
|
Packit |
b1f7ae |
if (!length) {
|
|
Packit |
b1f7ae |
printf("[xed error: failed to determine instruction length]\n");
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ip += length;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If it got a branch displacement it must be a branch.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* This includes conditional branches for which we don't know whether
|
|
Packit |
b1f7ae |
* they were taken. The next IP won't be used in this case as a
|
|
Packit |
b1f7ae |
* conditional branch ends a block. The next block will start with the
|
|
Packit |
b1f7ae |
* correct IP.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
disp_width = xed_decoded_inst_get_branch_displacement_width(inst);
|
|
Packit |
b1f7ae |
if (disp_width)
|
|
Packit |
b1f7ae |
ip += xed_decoded_inst_get_branch_displacement(inst);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*pip = ip;
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int block_fetch_insn(struct pt_insn *insn, const struct pt_block *block,
|
|
Packit |
b1f7ae |
uint64_t ip, struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!insn || !block)
|
|
Packit |
b1f7ae |
return -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We can't read from an empty block. */
|
|
Packit |
b1f7ae |
if (!block->ninsn)
|
|
Packit |
b1f7ae |
return -pte_invalid;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(insn, 0, sizeof(*insn));
|
|
Packit |
b1f7ae |
insn->mode = block->mode;
|
|
Packit |
b1f7ae |
insn->ip = ip;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* The last instruction in a block may be truncated. */
|
|
Packit |
b1f7ae |
if ((ip == block->end_ip) && block->truncated) {
|
|
Packit |
b1f7ae |
if (!block->size || (sizeof(insn->raw) < (size_t) block->size))
|
|
Packit |
b1f7ae |
return -pte_bad_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
insn->size = block->size;
|
|
Packit |
b1f7ae |
memcpy(insn->raw, block->raw, insn->size);
|
|
Packit |
b1f7ae |
} else {
|
|
Packit |
b1f7ae |
int size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
size = pt_iscache_read(iscache, insn->raw, sizeof(insn->raw),
|
|
Packit |
b1f7ae |
block->isid, ip);
|
|
Packit |
b1f7ae |
if (size < 0)
|
|
Packit |
b1f7ae |
return size;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
insn->isid = block->isid;
|
|
Packit |
b1f7ae |
insn->size = (uint8_t) size;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void diagnose_block_at(const char *errtype, int errcode,
|
|
Packit |
b1f7ae |
struct pt_block_decoder *decoder, uint64_t ip)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t pos;
|
|
Packit |
b1f7ae |
int err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
err = pt_blk_get_offset(decoder, &pos;;
|
|
Packit |
b1f7ae |
if (err < 0) {
|
|
Packit |
b1f7ae |
printf("[could not determine offset: %s]\n",
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(err)));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("[?, %" PRIx64 ": %s: %s]\n", ip, errtype,
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
} else
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": %s: %s]\n", pos, ip,
|
|
Packit |
b1f7ae |
errtype, pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void diagnose_block(const char *errtype, int errcode,
|
|
Packit |
b1f7ae |
const struct pt_block *block,
|
|
Packit |
b1f7ae |
struct pt_block_decoder *decoder,
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t ip;
|
|
Packit |
b1f7ae |
int err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!block) {
|
|
Packit |
b1f7ae |
printf("ptxed: internal error");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Determine the IP at which to report the error.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Depending on the type of error, the IP varies between that of the
|
|
Packit |
b1f7ae |
* last instruction in @block or the next instruction outside of @block.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* When the block is empty, we use the IP of the block itself,
|
|
Packit |
b1f7ae |
* i.e. where the first instruction should have been.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (!block->ninsn)
|
|
Packit |
b1f7ae |
ip = block->ip;
|
|
Packit |
b1f7ae |
else {
|
|
Packit |
b1f7ae |
ip = block->end_ip;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (errcode) {
|
|
Packit |
b1f7ae |
case -pte_nomap:
|
|
Packit |
b1f7ae |
case -pte_bad_insn: {
|
|
Packit |
b1f7ae |
struct pt_insn insn;
|
|
Packit |
b1f7ae |
xed_decoded_inst_t inst;
|
|
Packit |
b1f7ae |
xed_error_enum_t xederr;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Decode failed when trying to fetch or decode the next
|
|
Packit |
b1f7ae |
* instruction. Since indirect or conditional branches
|
|
Packit |
b1f7ae |
* end a block and don't cause an additional fetch, we
|
|
Packit |
b1f7ae |
* should be able to reach that IP from the last
|
|
Packit |
b1f7ae |
* instruction in @block.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We ignore errors and fall back to the IP of the last
|
|
Packit |
b1f7ae |
* instruction.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
err = block_fetch_insn(&insn, block, ip, iscache);
|
|
Packit |
b1f7ae |
if (err < 0)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_decoded_inst_zero(&inst);
|
|
Packit |
b1f7ae |
xed_decoded_inst_set_mode(&inst,
|
|
Packit |
b1f7ae |
translate_mode(insn.mode),
|
|
Packit |
b1f7ae |
XED_ADDRESS_WIDTH_INVALID);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xederr = xed_decode(&inst, insn.raw, insn.size);
|
|
Packit |
b1f7ae |
if (xederr != XED_ERROR_NONE)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
(void) xed_next_ip(&ip, &inst, insn.ip);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
default:
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
diagnose_block_at(errtype, errcode, decoder, ip);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void print_block(const struct pt_block *block,
|
|
Packit |
b1f7ae |
struct pt_block_decoder *decoder,
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options,
|
|
Packit |
b1f7ae |
const struct ptxed_stats *stats,
|
|
Packit |
b1f7ae |
uint64_t offset, uint64_t time)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
xed_machine_mode_enum_t mode;
|
|
Packit |
b1f7ae |
xed_state_t xed;
|
|
Packit |
b1f7ae |
uint64_t ip;
|
|
Packit |
b1f7ae |
uint16_t ninsn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!block || !options) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->resynced)
|
|
Packit |
b1f7ae |
printf("[overflow]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->enabled)
|
|
Packit |
b1f7ae |
printf("[enabled]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->resumed)
|
|
Packit |
b1f7ae |
printf("[resumed]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->track_blocks) {
|
|
Packit |
b1f7ae |
printf("[block");
|
|
Packit |
b1f7ae |
if (stats)
|
|
Packit |
b1f7ae |
printf(" %" PRIx64, stats->blocks);
|
|
Packit |
b1f7ae |
printf("]\n");
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
mode = translate_mode(block->mode);
|
|
Packit |
b1f7ae |
xed_state_init2(&xed, mode, XED_ADDRESS_WIDTH_INVALID);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ip = block->ip;
|
|
Packit |
b1f7ae |
ninsn = block->ninsn;
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
struct pt_insn insn;
|
|
Packit |
b1f7ae |
xed_decoded_inst_t inst;
|
|
Packit |
b1f7ae |
xed_error_enum_t xederrcode;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->speculative)
|
|
Packit |
b1f7ae |
printf("? ");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_offset)
|
|
Packit |
b1f7ae |
printf("%016" PRIx64 " ", offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_time)
|
|
Packit |
b1f7ae |
printf("%016" PRIx64 " ", time);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("%016" PRIx64, ip);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = block_fetch_insn(&insn, block, ip, iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
printf(" [fetch error: %s]\n",
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_decoded_inst_zero_set_mode(&inst, &xed);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xederrcode = xed_decode(&inst, insn.raw, insn.size);
|
|
Packit |
b1f7ae |
if (xederrcode != XED_ERROR_NONE) {
|
|
Packit |
b1f7ae |
printf(" [xed decode error: (%u) %s]\n", xederrcode,
|
|
Packit |
b1f7ae |
xed_error_enum_t2str(xederrcode));
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options->dont_print_insn)
|
|
Packit |
b1f7ae |
xed_print_insn(&inst, insn.ip, options);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
printf("\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ninsn -= 1;
|
|
Packit |
b1f7ae |
if (!ninsn)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = xed_next_ip(&ip, &inst, ip);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
diagnose_block_at("reconstruct error", errcode,
|
|
Packit |
b1f7ae |
decoder, ip);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Decode should have brought us to @block->end_ip. */
|
|
Packit |
b1f7ae |
if (ip != block->end_ip)
|
|
Packit |
b1f7ae |
diagnose_block_at("reconstruct error", -pte_nosync, decoder,
|
|
Packit |
b1f7ae |
ip);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->interrupted)
|
|
Packit |
b1f7ae |
printf("[interrupt]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->aborted)
|
|
Packit |
b1f7ae |
printf("[aborted]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->committed)
|
|
Packit |
b1f7ae |
printf("[committed]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->disabled)
|
|
Packit |
b1f7ae |
printf("[disabled]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (block->stopped)
|
|
Packit |
b1f7ae |
printf("[stopped]\n");
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void check_block(const struct pt_block *block,
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
uint64_t offset)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_insn insn;
|
|
Packit |
b1f7ae |
xed_decoded_inst_t inst;
|
|
Packit |
b1f7ae |
uint64_t ip;
|
|
Packit |
b1f7ae |
uint16_t ninsn;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!block) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* There's nothing to check for an empty block. */
|
|
Packit |
b1f7ae |
ninsn = block->ninsn;
|
|
Packit |
b1f7ae |
if (!ninsn)
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
ip = block->ip;
|
|
Packit |
b1f7ae |
do {
|
|
Packit |
b1f7ae |
errcode = block_fetch_insn(&insn, block, ip, iscache);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": fetch error: %s]\n",
|
|
Packit |
b1f7ae |
offset, ip, pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_decoded_inst_zero(&inst);
|
|
Packit |
b1f7ae |
check_insn_decode(&inst, &insn, offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We need a valid instruction in order to do further checks.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Invalid instructions have already been diagnosed.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (!xed_decoded_inst_valid(&inst))
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = xed_next_ip(&ip, &inst, ip);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": error: %s]\n",
|
|
Packit |
b1f7ae |
offset, ip, pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
} while (--ninsn);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We reached the end of the block. Both @insn and @inst refer to the
|
|
Packit |
b1f7ae |
* last instruction in @block.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* Check that we reached the end IP of the block.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (insn.ip != block->end_ip) {
|
|
Packit |
b1f7ae |
printf("[%" PRIx64 ", %" PRIx64 ": error: did not reach end: %"
|
|
Packit |
b1f7ae |
PRIx64 "]\n", offset, insn.ip, block->end_ip);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Check the last instruction's classification, if available. */
|
|
Packit |
b1f7ae |
insn.iclass = block->iclass;
|
|
Packit |
b1f7ae |
if (insn.iclass)
|
|
Packit |
b1f7ae |
check_insn_iclass(xed_decoded_inst_inst(&inst), &insn, offset);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void decode_block(struct pt_block_decoder *decoder,
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options,
|
|
Packit |
b1f7ae |
struct ptxed_stats *stats)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t offset, sync, time;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
offset = 0ull;
|
|
Packit |
b1f7ae |
sync = 0ull;
|
|
Packit |
b1f7ae |
time = 0ull;
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
struct pt_block block;
|
|
Packit |
b1f7ae |
int errcode;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Initialize IP and ninsn - we use it for error reporting. */
|
|
Packit |
b1f7ae |
block.ip = 0ull;
|
|
Packit |
b1f7ae |
block.ninsn = 0u;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_blk_sync_forward(decoder);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
uint64_t new_sync;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (errcode == -pte_eos)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
diagnose_block("sync error", errcode, &block, decoder,
|
|
Packit |
b1f7ae |
iscache);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* Let's see if we made any progress. If we haven't,
|
|
Packit |
b1f7ae |
* we likely never will. Bail out.
|
|
Packit |
b1f7ae |
*
|
|
Packit |
b1f7ae |
* We intentionally report the error twice to indicate
|
|
Packit |
b1f7ae |
* that we tried to re-sync. Maybe it even changed.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
errcode = pt_blk_get_offset(decoder, &new_sync);
|
|
Packit |
b1f7ae |
if (errcode < 0 || (new_sync <= sync))
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
sync = new_sync;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (;;) {
|
|
Packit |
b1f7ae |
if (options->print_offset || options->check) {
|
|
Packit |
b1f7ae |
errcode = pt_blk_get_offset(decoder, &offset);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->print_time) {
|
|
Packit |
b1f7ae |
errcode = pt_blk_time(decoder, &time, NULL,
|
|
Packit |
b1f7ae |
NULL);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_blk_next(decoder, &block, sizeof(block));
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
/* Even in case of errors, we may have succeeded
|
|
Packit |
b1f7ae |
* in decoding some instructions.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (block.ninsn) {
|
|
Packit |
b1f7ae |
if (stats) {
|
|
Packit |
b1f7ae |
stats->insn += block.ninsn;
|
|
Packit |
b1f7ae |
stats->blocks += 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options->quiet)
|
|
Packit |
b1f7ae |
print_block(&block, decoder,
|
|
Packit |
b1f7ae |
iscache, options,
|
|
Packit |
b1f7ae |
stats, offset,
|
|
Packit |
b1f7ae |
time);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->check)
|
|
Packit |
b1f7ae |
check_block(&block, iscache,
|
|
Packit |
b1f7ae |
offset);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stats) {
|
|
Packit |
b1f7ae |
stats->insn += block.ninsn;
|
|
Packit |
b1f7ae |
stats->blocks += 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!options->quiet)
|
|
Packit |
b1f7ae |
print_block(&block, decoder, iscache, options,
|
|
Packit |
b1f7ae |
stats, offset, time);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options->check)
|
|
Packit |
b1f7ae |
check_block(&block, iscache, offset);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (errcode & pts_eos) {
|
|
Packit |
b1f7ae |
if (!block.disabled && !options->quiet)
|
|
Packit |
b1f7ae |
printf("[end of trace]\n");
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = -pte_eos;
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We shouldn't break out of the loop without an error. */
|
|
Packit |
b1f7ae |
if (!errcode)
|
|
Packit |
b1f7ae |
errcode = -pte_internal;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* We're done when we reach the end of the trace stream. */
|
|
Packit |
b1f7ae |
if (errcode == -pte_eos)
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
diagnose_block("error", errcode, &block, decoder, iscache);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void decode(struct ptxed_decoder *decoder,
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache,
|
|
Packit |
b1f7ae |
const struct ptxed_options *options,
|
|
Packit |
b1f7ae |
struct ptxed_stats *stats)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!decoder) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (decoder->type) {
|
|
Packit |
b1f7ae |
case pdt_insn_decoder:
|
|
Packit |
b1f7ae |
decode_insn(decoder->variant.insn, options, stats);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case pdt_block_decoder:
|
|
Packit |
b1f7ae |
decode_block(decoder->variant.block, iscache, options, stats);
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static void print_stats(struct ptxed_stats *stats)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
if (!stats) {
|
|
Packit |
b1f7ae |
printf("[internal error]\n");
|
|
Packit |
b1f7ae |
return;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stats->flags & ptxed_stat_insn)
|
|
Packit |
b1f7ae |
printf("insn: %" PRIu64 ".\n", stats->insn);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (stats->flags & ptxed_stat_blocks)
|
|
Packit |
b1f7ae |
printf("blocks:\t%" PRIu64 ".\n", stats->blocks);
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int get_arg_uint64(uint64_t *value, const char *option, const char *arg,
|
|
Packit |
b1f7ae |
const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
char *rest;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!value || !option || !prog) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: internal error.\n", prog ? prog : "?");
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!arg || (arg[0] == '-' && arg[1] == '-')) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: %s: missing argument.\n", prog, option);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errno = 0;
|
|
Packit |
b1f7ae |
*value = strtoull(arg, &rest, 0);
|
|
Packit |
b1f7ae |
if (errno || *rest) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: %s: bad argument: %s.\n", prog, option,
|
|
Packit |
b1f7ae |
arg);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int get_arg_uint32(uint32_t *value, const char *option, const char *arg,
|
|
Packit |
b1f7ae |
const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!get_arg_uint64(&val, option, arg, prog))
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (val > UINT32_MAX) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: %s: value too big: %s.\n", prog, option,
|
|
Packit |
b1f7ae |
arg);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*value = (uint32_t) val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
static int get_arg_uint8(uint8_t *value, const char *option, const char *arg,
|
|
Packit |
b1f7ae |
const char *prog)
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
uint64_t val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!get_arg_uint64(&val, option, arg, prog))
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (val > UINT8_MAX) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: %s: value too big: %s.\n", prog, option,
|
|
Packit |
b1f7ae |
arg);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
*value = (uint8_t) val;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
extern int main(int argc, char *argv[])
|
|
Packit |
b1f7ae |
{
|
|
Packit |
b1f7ae |
struct pt_image_section_cache *iscache;
|
|
Packit |
b1f7ae |
struct ptxed_decoder decoder;
|
|
Packit |
b1f7ae |
struct ptxed_options options;
|
|
Packit |
b1f7ae |
struct ptxed_stats stats;
|
|
Packit |
b1f7ae |
struct pt_config config;
|
|
Packit |
b1f7ae |
struct pt_image *image;
|
|
Packit |
b1f7ae |
const char *prog;
|
|
Packit |
b1f7ae |
int errcode, i;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!argc) {
|
|
Packit |
b1f7ae |
help("");
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
prog = argv[0];
|
|
Packit |
b1f7ae |
iscache = NULL;
|
|
Packit |
b1f7ae |
image = NULL;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(&decoder, 0, sizeof(decoder));
|
|
Packit |
b1f7ae |
decoder.type = pdt_block_decoder;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
memset(&options, 0, sizeof(options));
|
|
Packit |
b1f7ae |
memset(&stats, 0, sizeof(stats));
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
pt_config_init(&config);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
iscache = pt_iscache_alloc(NULL);
|
|
Packit |
b1f7ae |
if (!iscache) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: failed to allocate image section cache.\n", prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
image = pt_image_alloc(NULL);
|
|
Packit |
b1f7ae |
if (!image) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to allocate image.\n", prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
for (i = 1; i < argc;) {
|
|
Packit |
b1f7ae |
char *arg;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
arg = argv[i++];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0) {
|
|
Packit |
b1f7ae |
help(prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--version") == 0) {
|
|
Packit |
b1f7ae |
version(prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--pt") == 0) {
|
|
Packit |
b1f7ae |
if (argc <= i) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: --pt: missing argument.\n", prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
arg = argv[i++];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (ptxed_have_decoder(&decoder)) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: duplicate pt sources: %s.\n",
|
|
Packit |
b1f7ae |
prog, arg);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_cpu_errata(&config.errata, &config.cpu);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = load_pt(&config, arg, prog);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
switch (decoder.type) {
|
|
Packit |
b1f7ae |
case pdt_insn_decoder:
|
|
Packit |
b1f7ae |
decoder.variant.insn =
|
|
Packit |
b1f7ae |
pt_insn_alloc_decoder(&config);
|
|
Packit |
b1f7ae |
if (!decoder.variant.insn) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to create "
|
|
Packit |
b1f7ae |
"decoder.\n", prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode =
|
|
Packit |
b1f7ae |
pt_insn_set_image(decoder.variant.insn,
|
|
Packit |
b1f7ae |
image);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: failed to set image.\n",
|
|
Packit |
b1f7ae |
prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
case pdt_block_decoder:
|
|
Packit |
b1f7ae |
decoder.variant.block =
|
|
Packit |
b1f7ae |
pt_blk_alloc_decoder(&config);
|
|
Packit |
b1f7ae |
if (!decoder.variant.block) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: failed to create "
|
|
Packit |
b1f7ae |
"decoder.\n", prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode =
|
|
Packit |
b1f7ae |
pt_blk_set_image(decoder.variant.block,
|
|
Packit |
b1f7ae |
image);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: failed to set image.\n",
|
|
Packit |
b1f7ae |
prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
break;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--raw") == 0) {
|
|
Packit |
b1f7ae |
if (argc <= i) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: --raw: missing argument.\n", prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
arg = argv[i++];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = load_raw(iscache, image, arg, prog);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
#if defined(FEATURE_ELF)
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--elf") == 0) {
|
|
Packit |
b1f7ae |
uint64_t base;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (argc <= i) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: --elf: missing argument.\n", prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
arg = argv[i++];
|
|
Packit |
b1f7ae |
base = 0ull;
|
|
Packit |
b1f7ae |
errcode = extract_base(arg, &base);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = load_elf(iscache, image, arg, base, prog,
|
|
Packit |
b1f7ae |
options.track_image);
|
|
Packit |
b1f7ae |
if (errcode < 0)
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
#endif /* defined(FEATURE_ELF) */
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--att") == 0) {
|
|
Packit |
b1f7ae |
options.att_format = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--no-inst") == 0) {
|
|
Packit |
b1f7ae |
options.dont_print_insn = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--quiet") == 0 || strcmp(arg, "-q") == 0) {
|
|
Packit |
b1f7ae |
options.quiet = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--offset") == 0) {
|
|
Packit |
b1f7ae |
options.print_offset = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--time") == 0) {
|
|
Packit |
b1f7ae |
options.print_time = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--raw-insn") == 0) {
|
|
Packit |
b1f7ae |
options.print_raw_insn = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--check") == 0) {
|
|
Packit |
b1f7ae |
options.check = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--stat") == 0) {
|
|
Packit |
b1f7ae |
options.print_stats = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--stat:insn") == 0) {
|
|
Packit |
b1f7ae |
stats.flags |= ptxed_stat_insn;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--stat:blocks") == 0) {
|
|
Packit |
b1f7ae |
stats.flags |= ptxed_stat_blocks;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--cpu") == 0) {
|
|
Packit |
b1f7ae |
/* override cpu information before the decoder
|
|
Packit |
b1f7ae |
* is initialized.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (ptxed_have_decoder(&decoder)) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: please specify cpu before the pt source file.\n",
|
|
Packit |
b1f7ae |
prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (argc <= i) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: --cpu: missing argument.\n", prog);
|
|
Packit |
b1f7ae |
goto out;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
arg = argv[i++];
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "auto") == 0) {
|
|
Packit |
b1f7ae |
errcode = pt_cpu_read(&config.cpu);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: error reading cpu: %s.\n",
|
|
Packit |
b1f7ae |
prog,
|
|
Packit |
b1f7ae |
pt_errstr(pt_errcode(errcode)));
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "none") == 0) {
|
|
Packit |
b1f7ae |
memset(&config.cpu, 0, sizeof(config.cpu));
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
errcode = pt_cpu_parse(&config.cpu, arg);
|
|
Packit |
b1f7ae |
if (errcode < 0) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: cpu must be specified as f/m[/s]\n",
|
|
Packit |
b1f7ae |
prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--mtc-freq") == 0) {
|
|
Packit |
b1f7ae |
if (!get_arg_uint8(&config.mtc_freq, "--mtc-freq",
|
|
Packit |
b1f7ae |
argv[i++], prog))
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--nom-freq") == 0) {
|
|
Packit |
b1f7ae |
if (!get_arg_uint8(&config.nom_freq, "--nom-freq",
|
|
Packit |
b1f7ae |
argv[i++], prog))
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--cpuid-0x15.eax") == 0) {
|
|
Packit |
b1f7ae |
if (!get_arg_uint32(&config.cpuid_0x15_eax,
|
|
Packit |
b1f7ae |
"--cpuid-0x15.eax", argv[i++],
|
|
Packit |
b1f7ae |
prog))
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--cpuid-0x15.ebx") == 0) {
|
|
Packit |
b1f7ae |
if (!get_arg_uint32(&config.cpuid_0x15_ebx,
|
|
Packit |
b1f7ae |
"--cpuid-0x15.ebx", argv[i++],
|
|
Packit |
b1f7ae |
prog))
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--verbose") == 0 || strcmp(arg, "-v") == 0) {
|
|
Packit |
b1f7ae |
options.track_image = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--insn-decoder") == 0) {
|
|
Packit |
b1f7ae |
if (ptxed_have_decoder(&decoder)) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: please specify %s before the pt "
|
|
Packit |
b1f7ae |
"source file.\n", arg, prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
decoder.type = pdt_insn_decoder;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--block-decoder") == 0) {
|
|
Packit |
b1f7ae |
if (ptxed_have_decoder(&decoder)) {
|
|
Packit |
b1f7ae |
fprintf(stderr,
|
|
Packit |
b1f7ae |
"%s: please specify %s before the pt "
|
|
Packit |
b1f7ae |
"source file.\n", arg, prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
decoder.type = pdt_block_decoder;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--block:show-blocks") == 0) {
|
|
Packit |
b1f7ae |
options.track_blocks = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (strcmp(arg, "--block:end-on-call") == 0) {
|
|
Packit |
b1f7ae |
config.flags.variant.block.end_on_call = 1;
|
|
Packit |
b1f7ae |
continue;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: unknown option: %s.\n", prog, arg);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (!ptxed_have_decoder(&decoder)) {
|
|
Packit |
b1f7ae |
fprintf(stderr, "%s: no pt file.\n", prog);
|
|
Packit |
b1f7ae |
goto err;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
xed_tables_init();
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
/* If we didn't select any statistics, select them all depending on the
|
|
Packit |
b1f7ae |
* decoder type.
|
|
Packit |
b1f7ae |
*/
|
|
Packit |
b1f7ae |
if (options.print_stats && !stats.flags) {
|
|
Packit |
b1f7ae |
stats.flags |= ptxed_stat_insn;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (decoder.type == pdt_block_decoder)
|
|
Packit |
b1f7ae |
stats.flags |= ptxed_stat_blocks;
|
|
Packit |
b1f7ae |
}
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
decode(&decoder, iscache, &options,
|
|
Packit |
b1f7ae |
options.print_stats ? &stats : NULL);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
if (options.print_stats)
|
|
Packit |
b1f7ae |
print_stats(&stats);
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
out:
|
|
Packit |
b1f7ae |
ptxed_free_decoder(&decoder);
|
|
Packit |
b1f7ae |
pt_image_free(image);
|
|
Packit |
b1f7ae |
pt_iscache_free(iscache);
|
|
Packit |
b1f7ae |
free(config.begin);
|
|
Packit |
b1f7ae |
return 0;
|
|
Packit |
b1f7ae |
|
|
Packit |
b1f7ae |
err:
|
|
Packit |
b1f7ae |
ptxed_free_decoder(&decoder);
|
|
Packit |
b1f7ae |
pt_image_free(image);
|
|
Packit |
b1f7ae |
pt_iscache_free(iscache);
|
|
Packit |
b1f7ae |
free(config.begin);
|
|
Packit |
b1f7ae |
return 1;
|
|
Packit |
b1f7ae |
}
|