Path: blob/21.2-virgl/src/freedreno/decode/cffdump.c
4565 views
/*1* Copyright (c) 2012 Rob Clark <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,19* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE20* SOFTWARE.21*/2223#include <assert.h>24#include <ctype.h>25#include <err.h>26#include <errno.h>27#include <fcntl.h>28#include <getopt.h>29#include <signal.h>30#include <stdarg.h>31#include <stdbool.h>32#include <stdint.h>33#include <stdio.h>34#include <stdlib.h>35#include <string.h>36#include <unistd.h>37#include <sys/stat.h>38#include <sys/types.h>39#include <sys/wait.h>4041#include "buffers.h"42#include "cffdec.h"43#include "disasm.h"44#include "io.h"45#include "pager.h"46#include "redump.h"47#include "rnnutil.h"48#include "script.h"4950static struct cffdec_options options = {51.gpu_id = 220,52};5354static bool needs_wfi = false;55static bool is_blob = false;56static int show_comp = false;57static int interactive;58static int vertices;59static const char *exename;6061static int handle_file(const char *filename, int start, int end, int draw);6263static void64print_usage(const char *name)65{66/* clang-format off */67fprintf(stderr, "Usage:\n\n"68"\t%s [OPTSIONS]... FILE...\n\n"69"Options:\n"70"\t-v, --verbose - more verbose disassembly\n"71"\t--dump-shaders - dump each shader to a raw file\n"72"\t--no-color - disable colorized output (default for non-console\n"73"\t output)\n"74"\t--color - enable colorized output (default for tty output)\n"75"\t--no-pager - disable pager (default for non-console output)\n"76"\t--pager - enable pager (default for tty output)\n"77"\t-s, --summary - don't show individual register writes, but just\n"78"\t register values on draws\n"79"\t-a, --allregs - show all registers (including ones not written\n"80"\t since previous draw) on each draw\n"81"\t-S, --start=N - start decoding from frame N\n"82"\t-E, --end=N - stop decoding after frame N\n"83"\t-F, --frame=N - decode only frame N\n"84"\t-D, --draw=N - decode only draw N\n"85"\t-e, --exe=NAME - only decode cmdstream from named process\n"86"\t--textures - dump texture contents (if possible)\n"87"\t-L, --script=LUA - run specified lua script to analyze state\n"88"\t-q, --query=REG - query mode, dump only specified query registers on\n"89"\t each draw; multiple --query/-q args can be given to\n"90"\t dump multiple registers; register can be specified\n"91"\t either by name or numeric offset\n"92"\t--query-all - in query mode, show all queried regs on each draw\n"93"\t (default query mode)\n"94"\t--query-written - in query mode, show queried regs on draws if any of\n"95"\t them have been written since previous draw\n"96"\t--query-delta - in query mode, show queried regs on draws if any of\n"97"\t them have changed since previous draw\n"98"\t--query-compare - dump registers for BINNING vs GMEM/BYPASS per draw;\n"99"\t only applicable for regs set via SDS group (a6xx+),\n"100"\t implies --once, can be combined with --query-all,\n"101"\t --query-written, or --query-delta\n"102"\t--once - decode cmdstream only once (per draw mode); if same\n"103"\t cmdstream is executed for each tile, this will decode\n"104"\t it only for the first tile and skip the remainder,\n"105"\t which can be useful when looking at state that does\n"106"\t not change per tile\n"107"\t--not-once - decode cmdstream for each IB (default)\n"108"\t-h, --help - show this message\n"109, name);110/* clang-format on */111exit(2);112}113114/* clang-format off */115static const struct option opts[] = {116/* Long opts that simply set a flag (no corresponding short alias: */117{ "dump-shaders", no_argument, &options.dump_shaders, 1 },118{ "no-color", no_argument, &options.color, 0 },119{ "color", no_argument, &options.color, 1 },120{ "no-pager", no_argument, &interactive, 0 },121{ "pager", no_argument, &interactive, 1 },122{ "textures", no_argument, &options.dump_textures, 1 },123{ "show-compositor", no_argument, &show_comp, 1 },124{ "query-all", no_argument, &options.query_mode, QUERY_ALL },125{ "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },126{ "query-delta", no_argument, &options.query_mode, QUERY_DELTA },127{ "query-compare", no_argument, &options.query_compare, 1 },128{ "once", no_argument, &options.once, 1 },129{ "not-once", no_argument, &options.once, 0 },130131/* Long opts with short alias: */132{ "verbose", no_argument, 0, 'v' },133{ "summary", no_argument, 0, 's' },134{ "allregs", no_argument, 0, 'a' },135{ "start", required_argument, 0, 'S' },136{ "end", required_argument, 0, 'E' },137{ "frame", required_argument, 0, 'F' },138{ "draw", required_argument, 0, 'D' },139{ "exe", required_argument, 0, 'e' },140{ "script", required_argument, 0, 'L' },141{ "query", required_argument, 0, 'q' },142{ "help", no_argument, 0, 'h' },143};144/* clang-format on */145146int147main(int argc, char **argv)148{149enum debug_t debug = PRINT_RAW | PRINT_STATS;150int ret = -1;151int start = 0, end = 0x7ffffff, draw = -1;152int c;153154interactive = isatty(STDOUT_FILENO);155156options.color = interactive;157158while ((c = getopt_long(argc, argv, "vsaS:E:F:D:e:L:q:h", opts, NULL)) !=159-1) {160switch (c) {161case 0:162/* option that set a flag, nothing to do */163break;164case 'v':165debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);166break;167case 's':168options.summary = true;169break;170case 'a':171options.allregs = true;172break;173case 'S':174start = atoi(optarg);175break;176case 'E':177end = atoi(optarg);178break;179case 'F':180start = end = atoi(optarg);181break;182case 'D':183draw = atoi(optarg);184break;185case 'e':186exename = optarg;187break;188case 'L':189options.script = optarg;190if (script_load(options.script)) {191errx(-1, "error loading %s\n", options.script);192}193break;194case 'q':195options.querystrs =196realloc(options.querystrs,197(options.nquery + 1) * sizeof(*options.querystrs));198options.querystrs[options.nquery] = optarg;199options.nquery++;200interactive = 0;201break;202case 'h':203default:204print_usage(argv[0]);205}206}207208disasm_a2xx_set_debug(debug);209disasm_a3xx_set_debug(debug);210211if (interactive) {212pager_open();213}214215while (optind < argc) {216ret = handle_file(argv[optind], start, end, draw);217if (ret) {218fprintf(stderr, "error reading: %s\n", argv[optind]);219fprintf(stderr, "continuing..\n");220}221optind++;222}223224if (ret)225print_usage(argv[0]);226227if ((options.query_mode || options.query_compare) && !options.nquery) {228fprintf(stderr, "query options only valid in query mode!\n");229print_usage(argv[0]);230}231232script_finish();233234if (interactive) {235pager_close();236}237238return ret;239}240241static void242parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)243{244*gpuaddr = buf[0];245*len = buf[1];246if (sz > 8)247*gpuaddr |= ((uint64_t)(buf[2])) << 32;248}249250static int251handle_file(const char *filename, int start, int end, int draw)252{253enum rd_sect_type type = RD_NONE;254void *buf = NULL;255struct io *io;256int submit = 0, got_gpu_id = 0;257int sz, ret = 0;258bool needs_reset = false;259bool skip = false;260261options.draw_filter = draw;262263cffdec_init(&options);264265printf("Reading %s...\n", filename);266267script_start_cmdstream(filename);268269if (!strcmp(filename, "-"))270io = io_openfd(0);271else272io = io_open(filename);273274if (!io) {275fprintf(stderr, "could not open: %s\n", filename);276return -1;277}278279struct {280unsigned int len;281uint64_t gpuaddr;282} gpuaddr = {0};283284while (true) {285uint32_t arr[2];286287ret = io_readn(io, arr, 8);288if (ret <= 0)289goto end;290291while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {292ret = io_readn(io, arr, 8);293if (ret <= 0)294goto end;295}296297type = arr[0];298sz = arr[1];299300if (sz < 0) {301ret = -1;302goto end;303}304305free(buf);306307needs_wfi = false;308309buf = malloc(sz + 1);310((char *)buf)[sz] = '\0';311ret = io_readn(io, buf, sz);312if (ret < 0)313goto end;314315switch (type) {316case RD_TEST:317printl(1, "test: %s\n", (char *)buf);318break;319case RD_CMD:320is_blob = true;321printl(2, "cmd: %s\n", (char *)buf);322skip = false;323if (exename) {324skip |= (strstr(buf, exename) != buf);325} else if (!show_comp) {326skip |= (strstr(buf, "fdperf") == buf);327skip |= (strstr(buf, "chrome") == buf);328skip |= (strstr(buf, "surfaceflinger") == buf);329skip |= ((char *)buf)[0] == 'X';330}331break;332case RD_VERT_SHADER:333printl(2, "vertex shader:\n%s\n", (char *)buf);334break;335case RD_FRAG_SHADER:336printl(2, "fragment shader:\n%s\n", (char *)buf);337break;338case RD_GPUADDR:339if (needs_reset) {340reset_buffers();341needs_reset = false;342}343parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);344break;345case RD_BUFFER_CONTENTS:346add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);347buf = NULL;348break;349case RD_CMDSTREAM_ADDR:350if ((start <= submit) && (submit <= end)) {351unsigned int sizedwords;352uint64_t gpuaddr;353parse_addr(buf, sz, &sizedwords, &gpuaddr);354printl(2, "############################################################\n");355printl(2, "cmdstream: %d dwords\n", sizedwords);356if (!skip) {357script_start_submit();358dump_commands(hostptr(gpuaddr), sizedwords, 0);359script_end_submit();360}361printl(2, "############################################################\n");362printl(2, "vertices: %d\n", vertices);363}364needs_reset = true;365submit++;366break;367case RD_GPU_ID:368if (!got_gpu_id) {369options.gpu_id = *((unsigned int *)buf);370printl(2, "gpu_id: %d\n", options.gpu_id);371cffdec_init(&options);372got_gpu_id = 1;373}374break;375default:376break;377}378}379380end:381script_end_cmdstream();382383io_close(io);384fflush(stdout);385386if (ret < 0) {387printf("corrupt file\n");388}389return 0;390}391392393