freedreno/decode: Re-indent
clang-format -fallback-style=none --style=file -i src/freedreno/decode/*.[ch] Signed-off-by: Rob Clark <robdclark@chromium.org> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10293>
This commit is contained in:
parent
3894bc9664
commit
45856c5fbc
|
@ -90,6 +90,7 @@ ForEachMacros:
|
|||
- foreach_batch
|
||||
- hash_table_foreach
|
||||
- set_foreach
|
||||
- foreach_line_in_section
|
||||
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
|
|
|
@ -29,143 +29,148 @@
|
|||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "buffers.h"
|
||||
#include "util/rb_tree.h"
|
||||
#include "buffers.h"
|
||||
|
||||
struct buffer {
|
||||
struct rb_node node;
|
||||
void *hostptr;
|
||||
unsigned int len;
|
||||
uint64_t gpuaddr;
|
||||
struct rb_node node;
|
||||
void *hostptr;
|
||||
unsigned int len;
|
||||
uint64_t gpuaddr;
|
||||
|
||||
/* for 'once' mode, for buffers containing cmdstream keep track per offset
|
||||
* into buffer of which modes it has already been dumped;
|
||||
*/
|
||||
struct {
|
||||
unsigned offset;
|
||||
unsigned dumped_mask;
|
||||
} offsets[64];
|
||||
unsigned noffsets;
|
||||
/* for 'once' mode, for buffers containing cmdstream keep track per offset
|
||||
* into buffer of which modes it has already been dumped;
|
||||
*/
|
||||
struct {
|
||||
unsigned offset;
|
||||
unsigned dumped_mask;
|
||||
} offsets[64];
|
||||
unsigned noffsets;
|
||||
};
|
||||
|
||||
static struct rb_tree buffers;
|
||||
|
||||
static int buffer_insert_cmp(const struct rb_node *n1, const struct rb_node *n2)
|
||||
static int
|
||||
buffer_insert_cmp(const struct rb_node *n1, const struct rb_node *n2)
|
||||
{
|
||||
const struct buffer *buf1 = (const struct buffer *) n1;
|
||||
const struct buffer *buf2 = (const struct buffer *) n2;
|
||||
return buf1->gpuaddr - buf2->gpuaddr;
|
||||
const struct buffer *buf1 = (const struct buffer *)n1;
|
||||
const struct buffer *buf2 = (const struct buffer *)n2;
|
||||
return buf1->gpuaddr - buf2->gpuaddr;
|
||||
}
|
||||
|
||||
static int buffer_search_cmp(const struct rb_node *node, const void *addrptr)
|
||||
static int
|
||||
buffer_search_cmp(const struct rb_node *node, const void *addrptr)
|
||||
{
|
||||
const struct buffer *buf = (const struct buffer *) node;
|
||||
uint64_t gpuaddr = *(uint64_t *)addrptr;
|
||||
if (buf->gpuaddr + buf->len <= gpuaddr)
|
||||
return -1;
|
||||
else if (buf->gpuaddr > gpuaddr)
|
||||
return 1;
|
||||
return 0;
|
||||
const struct buffer *buf = (const struct buffer *)node;
|
||||
uint64_t gpuaddr = *(uint64_t *)addrptr;
|
||||
if (buf->gpuaddr + buf->len <= gpuaddr)
|
||||
return -1;
|
||||
else if (buf->gpuaddr > gpuaddr)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct buffer *get_buffer(uint64_t gpuaddr)
|
||||
static struct buffer *
|
||||
get_buffer(uint64_t gpuaddr)
|
||||
{
|
||||
if (gpuaddr == 0)
|
||||
return NULL;
|
||||
return (struct buffer *) rb_tree_search(&buffers, &gpuaddr, buffer_search_cmp);
|
||||
if (gpuaddr == 0)
|
||||
return NULL;
|
||||
return (struct buffer *)rb_tree_search(&buffers, &gpuaddr,
|
||||
buffer_search_cmp);
|
||||
}
|
||||
|
||||
static int
|
||||
buffer_contains_hostptr(struct buffer *buf, void *hostptr)
|
||||
{
|
||||
return (buf->hostptr <= hostptr) && (hostptr < (buf->hostptr + buf->len));
|
||||
return (buf->hostptr <= hostptr) && (hostptr < (buf->hostptr + buf->len));
|
||||
}
|
||||
|
||||
|
||||
uint64_t
|
||||
gpuaddr(void *hostptr)
|
||||
{
|
||||
rb_tree_foreach(struct buffer, buf, &buffers, node) {
|
||||
if (buffer_contains_hostptr(buf, hostptr))
|
||||
return buf->gpuaddr + (hostptr - buf->hostptr);
|
||||
}
|
||||
return 0;
|
||||
rb_tree_foreach(struct buffer, buf, &buffers, node)
|
||||
{
|
||||
if (buffer_contains_hostptr(buf, hostptr))
|
||||
return buf->gpuaddr + (hostptr - buf->hostptr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
gpubaseaddr(uint64_t gpuaddr)
|
||||
{
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->gpuaddr;
|
||||
else
|
||||
return 0;
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->gpuaddr;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *
|
||||
hostptr(uint64_t gpuaddr)
|
||||
{
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->hostptr + (gpuaddr - buf->gpuaddr);
|
||||
else
|
||||
return 0;
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->hostptr + (gpuaddr - buf->gpuaddr);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned
|
||||
hostlen(uint64_t gpuaddr)
|
||||
{
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->len + buf->gpuaddr - gpuaddr;
|
||||
else
|
||||
return 0;
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
if (buf)
|
||||
return buf->len + buf->gpuaddr - gpuaddr;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool
|
||||
has_dumped(uint64_t gpuaddr, unsigned enable_mask)
|
||||
{
|
||||
if (!gpuaddr)
|
||||
return false;
|
||||
if (!gpuaddr)
|
||||
return false;
|
||||
|
||||
struct buffer *b = get_buffer(gpuaddr);
|
||||
if (!b)
|
||||
return false;
|
||||
struct buffer *b = get_buffer(gpuaddr);
|
||||
if (!b)
|
||||
return false;
|
||||
|
||||
assert(gpuaddr >= b->gpuaddr);
|
||||
unsigned offset = gpuaddr - b->gpuaddr;
|
||||
assert(gpuaddr >= b->gpuaddr);
|
||||
unsigned offset = gpuaddr - b->gpuaddr;
|
||||
|
||||
unsigned n = 0;
|
||||
while (n < b->noffsets) {
|
||||
if (offset == b->offsets[n].offset)
|
||||
break;
|
||||
n++;
|
||||
}
|
||||
unsigned n = 0;
|
||||
while (n < b->noffsets) {
|
||||
if (offset == b->offsets[n].offset)
|
||||
break;
|
||||
n++;
|
||||
}
|
||||
|
||||
/* if needed, allocate a new offset entry: */
|
||||
if (n == b->noffsets) {
|
||||
b->noffsets++;
|
||||
assert(b->noffsets < ARRAY_SIZE(b->offsets));
|
||||
b->offsets[n].dumped_mask = 0;
|
||||
b->offsets[n].offset = offset;
|
||||
}
|
||||
/* if needed, allocate a new offset entry: */
|
||||
if (n == b->noffsets) {
|
||||
b->noffsets++;
|
||||
assert(b->noffsets < ARRAY_SIZE(b->offsets));
|
||||
b->offsets[n].dumped_mask = 0;
|
||||
b->offsets[n].offset = offset;
|
||||
}
|
||||
|
||||
if ((b->offsets[n].dumped_mask & enable_mask) == enable_mask)
|
||||
return true;
|
||||
if ((b->offsets[n].dumped_mask & enable_mask) == enable_mask)
|
||||
return true;
|
||||
|
||||
b->offsets[n].dumped_mask |= enable_mask;
|
||||
b->offsets[n].dumped_mask |= enable_mask;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
reset_buffers(void)
|
||||
{
|
||||
rb_tree_foreach_safe(struct buffer, buf, &buffers, node) {
|
||||
rb_tree_remove(&buffers, &buf->node);
|
||||
free(buf->hostptr);
|
||||
free(buf);
|
||||
}
|
||||
rb_tree_foreach_safe(struct buffer, buf, &buffers, node)
|
||||
{
|
||||
rb_tree_remove(&buffers, &buf->node);
|
||||
free(buf->hostptr);
|
||||
free(buf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -175,16 +180,16 @@ reset_buffers(void)
|
|||
void
|
||||
add_buffer(uint64_t gpuaddr, unsigned int len, void *hostptr)
|
||||
{
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
struct buffer *buf = get_buffer(gpuaddr);
|
||||
|
||||
if (!buf) {
|
||||
buf = calloc(sizeof(struct buffer), 1);
|
||||
buf->gpuaddr = gpuaddr;
|
||||
rb_tree_insert(&buffers, &buf->node, buffer_insert_cmp);
|
||||
}
|
||||
if (!buf) {
|
||||
buf = calloc(sizeof(struct buffer), 1);
|
||||
buf->gpuaddr = gpuaddr;
|
||||
rb_tree_insert(&buffers, &buf->node, buffer_insert_cmp);
|
||||
}
|
||||
|
||||
assert(buf->gpuaddr == gpuaddr);
|
||||
assert(buf->gpuaddr == gpuaddr);
|
||||
|
||||
buf->hostptr = hostptr;
|
||||
buf->len = len;
|
||||
buf->hostptr = hostptr;
|
||||
buf->len = len;
|
||||
}
|
||||
|
|
|
@ -24,12 +24,12 @@
|
|||
#ifndef __BUFFERS_H__
|
||||
#define __BUFFERS_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t gpuaddr(void *hostptr);
|
||||
uint64_t gpubaseaddr(uint64_t gpuaddr);
|
||||
void * hostptr(uint64_t gpuaddr);
|
||||
void *hostptr(uint64_t gpuaddr);
|
||||
unsigned hostlen(uint64_t gpuaddr);
|
||||
bool has_dumped(uint64_t gpuaddr, unsigned enable_mask);
|
||||
|
||||
|
@ -37,7 +37,7 @@ void reset_buffers(void);
|
|||
void add_buffer(uint64_t gpuaddr, unsigned int len, void *hostptr);
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
|
||||
#endif /* __BUFFERS_H__ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,57 +27,57 @@
|
|||
#include <stdbool.h>
|
||||
|
||||
enum query_mode {
|
||||
/* default mode, dump all queried regs on each draw: */
|
||||
QUERY_ALL = 0,
|
||||
/* default mode, dump all queried regs on each draw: */
|
||||
QUERY_ALL = 0,
|
||||
|
||||
/* only dump if any of the queried regs were written
|
||||
* since last draw:
|
||||
*/
|
||||
QUERY_WRITTEN,
|
||||
/* only dump if any of the queried regs were written
|
||||
* since last draw:
|
||||
*/
|
||||
QUERY_WRITTEN,
|
||||
|
||||
/* only dump if any of the queried regs changed since
|
||||
* last draw:
|
||||
*/
|
||||
QUERY_DELTA,
|
||||
/* only dump if any of the queried regs changed since
|
||||
* last draw:
|
||||
*/
|
||||
QUERY_DELTA,
|
||||
};
|
||||
|
||||
struct cffdec_options {
|
||||
unsigned gpu_id;
|
||||
int draw_filter;
|
||||
int color;
|
||||
int dump_shaders;
|
||||
int summary;
|
||||
int allregs;
|
||||
int dump_textures;
|
||||
int decode_markers;
|
||||
char *script;
|
||||
unsigned gpu_id;
|
||||
int draw_filter;
|
||||
int color;
|
||||
int dump_shaders;
|
||||
int summary;
|
||||
int allregs;
|
||||
int dump_textures;
|
||||
int decode_markers;
|
||||
char *script;
|
||||
|
||||
int query_compare; /* binning vs SYSMEM/GMEM compare mode */
|
||||
int query_mode; /* enum query_mode */
|
||||
char **querystrs;
|
||||
int nquery;
|
||||
int query_compare; /* binning vs SYSMEM/GMEM compare mode */
|
||||
int query_mode; /* enum query_mode */
|
||||
char **querystrs;
|
||||
int nquery;
|
||||
|
||||
/* In "once" mode, only decode a cmdstream buffer once (per draw
|
||||
* mode, in the case of a6xx+ where a single cmdstream buffer can
|
||||
* be used for both binning and draw pass), rather than each time
|
||||
* encountered (ie. once per tile/bin in GMEM draw passes)
|
||||
*/
|
||||
int once;
|
||||
/* In "once" mode, only decode a cmdstream buffer once (per draw
|
||||
* mode, in the case of a6xx+ where a single cmdstream buffer can
|
||||
* be used for both binning and draw pass), rather than each time
|
||||
* encountered (ie. once per tile/bin in GMEM draw passes)
|
||||
*/
|
||||
int once;
|
||||
|
||||
/* for crashdec, where we know CP_IBx_REM_SIZE, we can use this
|
||||
* to highlight the cmdstream not parsed yet, to make it easier
|
||||
* to see how far along the CP is.
|
||||
*/
|
||||
struct {
|
||||
uint64_t base;
|
||||
uint32_t rem;
|
||||
} ibs[4];
|
||||
/* for crashdec, where we know CP_IBx_REM_SIZE, we can use this
|
||||
* to highlight the cmdstream not parsed yet, to make it easier
|
||||
* to see how far along the CP is.
|
||||
*/
|
||||
struct {
|
||||
uint64_t base;
|
||||
uint32_t rem;
|
||||
} ibs[4];
|
||||
};
|
||||
|
||||
void printl(int lvl, const char *fmt, ...);
|
||||
const char * pktname(unsigned opc);
|
||||
const char *pktname(unsigned opc);
|
||||
uint32_t regbase(const char *name);
|
||||
const char * regname(uint32_t regbase, int color);
|
||||
const char *regname(uint32_t regbase, int color);
|
||||
bool reg_written(uint32_t regbase);
|
||||
uint32_t reg_lastval(uint32_t regbase);
|
||||
uint32_t reg_val(uint32_t regbase);
|
||||
|
@ -91,16 +91,15 @@ void dump_commands(uint32_t *dwords, uint32_t sizedwords, int level);
|
|||
* Helpers for packet parsing:
|
||||
*/
|
||||
|
||||
|
||||
#define CP_TYPE0_PKT 0x00000000
|
||||
#define CP_TYPE2_PKT 0x80000000
|
||||
#define CP_TYPE3_PKT 0xc0000000
|
||||
#define CP_TYPE4_PKT 0x40000000
|
||||
#define CP_TYPE7_PKT 0x70000000
|
||||
|
||||
#define pkt_is_type0(pkt) (((pkt) & 0XC0000000) == CP_TYPE0_PKT)
|
||||
#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
#define type0_pkt_offset(pkt) ((pkt) & 0x7FFF)
|
||||
#define pkt_is_type0(pkt) (((pkt)&0XC0000000) == CP_TYPE0_PKT)
|
||||
#define type0_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
#define type0_pkt_offset(pkt) ((pkt)&0x7FFF)
|
||||
|
||||
#define pkt_is_type2(pkt) ((pkt) == CP_TYPE2_PKT)
|
||||
|
||||
|
@ -109,40 +108,37 @@ void dump_commands(uint32_t *dwords, uint32_t sizedwords, int level);
|
|||
* and 15 are 0
|
||||
*/
|
||||
|
||||
static inline uint pm4_calc_odd_parity_bit(uint val)
|
||||
static inline uint
|
||||
pm4_calc_odd_parity_bit(uint val)
|
||||
{
|
||||
return (0x9669 >> (0xf & ((val) ^
|
||||
((val) >> 4) ^ ((val) >> 8) ^ ((val) >> 12) ^
|
||||
((val) >> 16) ^ ((val) >> 20) ^ ((val) >> 24) ^
|
||||
((val) >> 28)))) & 1;
|
||||
return (0x9669 >> (0xf & ((val) ^ ((val) >> 4) ^ ((val) >> 8) ^
|
||||
((val) >> 12) ^ ((val) >> 16) ^ ((val) >> 20) ^
|
||||
((val) >> 24) ^ ((val) >> 28)))) &
|
||||
1;
|
||||
}
|
||||
|
||||
#define pkt_is_type3(pkt) \
|
||||
((((pkt) & 0xC0000000) == CP_TYPE3_PKT) && \
|
||||
(((pkt) & 0x80FE) == 0))
|
||||
#define pkt_is_type3(pkt) \
|
||||
((((pkt)&0xC0000000) == CP_TYPE3_PKT) && (((pkt)&0x80FE) == 0))
|
||||
|
||||
#define cp_type3_opcode(pkt) (((pkt) >> 8) & 0xFF)
|
||||
#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
#define type3_pkt_size(pkt) ((((pkt) >> 16) & 0x3FFF) + 1)
|
||||
|
||||
#define pkt_is_type4(pkt) \
|
||||
((((pkt) & 0xF0000000) == CP_TYPE4_PKT) && \
|
||||
((((pkt) >> 27) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(type4_pkt_offset(pkt))) \
|
||||
&& ((((pkt) >> 7) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(type4_pkt_size(pkt))))
|
||||
#define pkt_is_type4(pkt) \
|
||||
((((pkt)&0xF0000000) == CP_TYPE4_PKT) && \
|
||||
((((pkt) >> 27) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(type4_pkt_offset(pkt))) && \
|
||||
((((pkt) >> 7) & 0x1) == pm4_calc_odd_parity_bit(type4_pkt_size(pkt))))
|
||||
|
||||
#define type4_pkt_offset(pkt) (((pkt) >> 8) & 0x7FFFF)
|
||||
#define type4_pkt_size(pkt) ((pkt) & 0x7F)
|
||||
#define type4_pkt_size(pkt) ((pkt)&0x7F)
|
||||
|
||||
#define pkt_is_type7(pkt) \
|
||||
((((pkt) & 0xF0000000) == CP_TYPE7_PKT) && \
|
||||
(((pkt) & 0x0F000000) == 0) && \
|
||||
((((pkt) >> 23) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(cp_type7_opcode(pkt))) \
|
||||
&& ((((pkt) >> 15) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(type7_pkt_size(pkt))))
|
||||
#define pkt_is_type7(pkt) \
|
||||
((((pkt)&0xF0000000) == CP_TYPE7_PKT) && (((pkt)&0x0F000000) == 0) && \
|
||||
((((pkt) >> 23) & 0x1) == \
|
||||
pm4_calc_odd_parity_bit(cp_type7_opcode(pkt))) && \
|
||||
((((pkt) >> 15) & 0x1) == pm4_calc_odd_parity_bit(type7_pkt_size(pkt))))
|
||||
|
||||
#define cp_type7_opcode(pkt) (((pkt) >> 16) & 0x7F)
|
||||
#define type7_pkt_size(pkt) ((pkt) & 0x3FFF)
|
||||
#define type7_pkt_size(pkt) ((pkt)&0x3FFF)
|
||||
|
||||
#endif /* __CFFDEC_H__ */
|
||||
|
|
|
@ -24,33 +24,32 @@
|
|||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "redump.h"
|
||||
#include "disasm.h"
|
||||
#include "script.h"
|
||||
#include "io.h"
|
||||
#include "rnnutil.h"
|
||||
#include "pager.h"
|
||||
#include "buffers.h"
|
||||
#include "cffdec.h"
|
||||
#include "disasm.h"
|
||||
#include "io.h"
|
||||
#include "pager.h"
|
||||
#include "redump.h"
|
||||
#include "rnnutil.h"
|
||||
#include "script.h"
|
||||
|
||||
static struct cffdec_options options = {
|
||||
.gpu_id = 220,
|
||||
.gpu_id = 220,
|
||||
};
|
||||
|
||||
static bool needs_wfi = false;
|
||||
|
@ -62,321 +61,331 @@ static const char *exename;
|
|||
|
||||
static int handle_file(const char *filename, int start, int end, int draw);
|
||||
|
||||
static void print_usage(const char *name)
|
||||
static void
|
||||
print_usage(const char *name)
|
||||
{
|
||||
fprintf(stderr, "Usage:\n\n"
|
||||
"\t%s [OPTSIONS]... FILE...\n\n"
|
||||
"Options:\n"
|
||||
"\t-v, --verbose - more verbose disassembly\n"
|
||||
"\t--dump-shaders - dump each shader to a raw file\n"
|
||||
"\t--no-color - disable colorized output (default for non-console\n"
|
||||
"\t output)\n"
|
||||
"\t--color - enable colorized output (default for tty output)\n"
|
||||
"\t--no-pager - disable pager (default for non-console output)\n"
|
||||
"\t--pager - enable pager (default for tty output)\n"
|
||||
"\t-s, --summary - don't show individual register writes, but just\n"
|
||||
"\t register values on draws\n"
|
||||
"\t-a, --allregs - show all registers (including ones not written\n"
|
||||
"\t since previous draw) on each draw\n"
|
||||
"\t-S, --start=N - start decoding from frame N\n"
|
||||
"\t-E, --end=N - stop decoding after frame N\n"
|
||||
"\t-F, --frame=N - decode only frame N\n"
|
||||
"\t-D, --draw=N - decode only draw N\n"
|
||||
"\t-e, --exe=NAME - only decode cmdstream from named process\n"
|
||||
"\t--textures - dump texture contents (if possible)\n"
|
||||
"\t-L, --script=LUA - run specified lua script to analyze state\n"
|
||||
"\t-q, --query=REG - query mode, dump only specified query registers on\n"
|
||||
"\t each draw; multiple --query/-q args can be given to\n"
|
||||
"\t dump multiple registers; register can be specified\n"
|
||||
"\t either by name or numeric offset\n"
|
||||
"\t--query-all - in query mode, show all queried regs on each draw\n"
|
||||
"\t (default query mode)\n"
|
||||
"\t--query-written - in query mode, show queried regs on draws if any of\n"
|
||||
"\t them have been written since previous draw\n"
|
||||
"\t--query-delta - in query mode, show queried regs on draws if any of\n"
|
||||
"\t them have changed since previous draw\n"
|
||||
"\t--query-compare - dump registers for BINNING vs GMEM/BYPASS per draw;\n"
|
||||
"\t only applicable for regs set via SDS group (a6xx+),\n"
|
||||
"\t implies --once, can be combined with --query-all,\n"
|
||||
"\t --query-written, or --query-delta\n"
|
||||
"\t--once - decode cmdstream only once (per draw mode); if same\n"
|
||||
"\t cmdstream is executed for each tile, this will decode\n"
|
||||
"\t it only for the first tile and skip the remainder,\n"
|
||||
"\t which can be useful when looking at state that does\n"
|
||||
"\t not change per tile\n"
|
||||
"\t--not-once - decode cmdstream for each IB (default)\n"
|
||||
"\t-h, --help - show this message\n"
|
||||
, name);
|
||||
exit(2);
|
||||
/* clang-format off */
|
||||
fprintf(stderr, "Usage:\n\n"
|
||||
"\t%s [OPTSIONS]... FILE...\n\n"
|
||||
"Options:\n"
|
||||
"\t-v, --verbose - more verbose disassembly\n"
|
||||
"\t--dump-shaders - dump each shader to a raw file\n"
|
||||
"\t--no-color - disable colorized output (default for non-console\n"
|
||||
"\t output)\n"
|
||||
"\t--color - enable colorized output (default for tty output)\n"
|
||||
"\t--no-pager - disable pager (default for non-console output)\n"
|
||||
"\t--pager - enable pager (default for tty output)\n"
|
||||
"\t-s, --summary - don't show individual register writes, but just\n"
|
||||
"\t register values on draws\n"
|
||||
"\t-a, --allregs - show all registers (including ones not written\n"
|
||||
"\t since previous draw) on each draw\n"
|
||||
"\t-S, --start=N - start decoding from frame N\n"
|
||||
"\t-E, --end=N - stop decoding after frame N\n"
|
||||
"\t-F, --frame=N - decode only frame N\n"
|
||||
"\t-D, --draw=N - decode only draw N\n"
|
||||
"\t-e, --exe=NAME - only decode cmdstream from named process\n"
|
||||
"\t--textures - dump texture contents (if possible)\n"
|
||||
"\t-L, --script=LUA - run specified lua script to analyze state\n"
|
||||
"\t-q, --query=REG - query mode, dump only specified query registers on\n"
|
||||
"\t each draw; multiple --query/-q args can be given to\n"
|
||||
"\t dump multiple registers; register can be specified\n"
|
||||
"\t either by name or numeric offset\n"
|
||||
"\t--query-all - in query mode, show all queried regs on each draw\n"
|
||||
"\t (default query mode)\n"
|
||||
"\t--query-written - in query mode, show queried regs on draws if any of\n"
|
||||
"\t them have been written since previous draw\n"
|
||||
"\t--query-delta - in query mode, show queried regs on draws if any of\n"
|
||||
"\t them have changed since previous draw\n"
|
||||
"\t--query-compare - dump registers for BINNING vs GMEM/BYPASS per draw;\n"
|
||||
"\t only applicable for regs set via SDS group (a6xx+),\n"
|
||||
"\t implies --once, can be combined with --query-all,\n"
|
||||
"\t --query-written, or --query-delta\n"
|
||||
"\t--once - decode cmdstream only once (per draw mode); if same\n"
|
||||
"\t cmdstream is executed for each tile, this will decode\n"
|
||||
"\t it only for the first tile and skip the remainder,\n"
|
||||
"\t which can be useful when looking at state that does\n"
|
||||
"\t not change per tile\n"
|
||||
"\t--not-once - decode cmdstream for each IB (default)\n"
|
||||
"\t-h, --help - show this message\n"
|
||||
, name);
|
||||
/* clang-format on */
|
||||
exit(2);
|
||||
}
|
||||
|
||||
/* clang-format off */
|
||||
static const struct option opts[] = {
|
||||
/* Long opts that simply set a flag (no corresponding short alias: */
|
||||
{ "dump-shaders", no_argument, &options.dump_shaders, 1 },
|
||||
{ "no-color", no_argument, &options.color, 0 },
|
||||
{ "color", no_argument, &options.color, 1 },
|
||||
{ "no-pager", no_argument, &interactive, 0 },
|
||||
{ "pager", no_argument, &interactive, 1 },
|
||||
{ "textures", no_argument, &options.dump_textures, 1 },
|
||||
{ "show-compositor", no_argument, &show_comp, 1 },
|
||||
{ "query-all", no_argument, &options.query_mode, QUERY_ALL },
|
||||
{ "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },
|
||||
{ "query-delta", no_argument, &options.query_mode, QUERY_DELTA },
|
||||
{ "query-compare", no_argument, &options.query_compare, 1 },
|
||||
{ "once", no_argument, &options.once, 1 },
|
||||
{ "not-once", no_argument, &options.once, 0 },
|
||||
/* Long opts that simply set a flag (no corresponding short alias: */
|
||||
{ "dump-shaders", no_argument, &options.dump_shaders, 1 },
|
||||
{ "no-color", no_argument, &options.color, 0 },
|
||||
{ "color", no_argument, &options.color, 1 },
|
||||
{ "no-pager", no_argument, &interactive, 0 },
|
||||
{ "pager", no_argument, &interactive, 1 },
|
||||
{ "textures", no_argument, &options.dump_textures, 1 },
|
||||
{ "show-compositor", no_argument, &show_comp, 1 },
|
||||
{ "query-all", no_argument, &options.query_mode, QUERY_ALL },
|
||||
{ "query-written", no_argument, &options.query_mode, QUERY_WRITTEN },
|
||||
{ "query-delta", no_argument, &options.query_mode, QUERY_DELTA },
|
||||
{ "query-compare", no_argument, &options.query_compare, 1 },
|
||||
{ "once", no_argument, &options.once, 1 },
|
||||
{ "not-once", no_argument, &options.once, 0 },
|
||||
|
||||
/* Long opts with short alias: */
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "summary", no_argument, 0, 's' },
|
||||
{ "allregs", no_argument, 0, 'a' },
|
||||
{ "start", required_argument, 0, 'S' },
|
||||
{ "end", required_argument, 0, 'E' },
|
||||
{ "frame", required_argument, 0, 'F' },
|
||||
{ "draw", required_argument, 0, 'D' },
|
||||
{ "exe", required_argument, 0, 'e' },
|
||||
{ "script", required_argument, 0, 'L' },
|
||||
{ "query", required_argument, 0, 'q' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
/* Long opts with short alias: */
|
||||
{ "verbose", no_argument, 0, 'v' },
|
||||
{ "summary", no_argument, 0, 's' },
|
||||
{ "allregs", no_argument, 0, 'a' },
|
||||
{ "start", required_argument, 0, 'S' },
|
||||
{ "end", required_argument, 0, 'E' },
|
||||
{ "frame", required_argument, 0, 'F' },
|
||||
{ "draw", required_argument, 0, 'D' },
|
||||
{ "exe", required_argument, 0, 'e' },
|
||||
{ "script", required_argument, 0, 'L' },
|
||||
{ "query", required_argument, 0, 'q' },
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
};
|
||||
/* clang-format on */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
enum debug_t debug = PRINT_RAW | PRINT_STATS;
|
||||
int ret = -1;
|
||||
int start = 0, end = 0x7ffffff, draw = -1;
|
||||
int c;
|
||||
enum debug_t debug = PRINT_RAW | PRINT_STATS;
|
||||
int ret = -1;
|
||||
int start = 0, end = 0x7ffffff, draw = -1;
|
||||
int c;
|
||||
|
||||
interactive = isatty(STDOUT_FILENO);
|
||||
interactive = isatty(STDOUT_FILENO);
|
||||
|
||||
options.color = interactive;
|
||||
options.color = interactive;
|
||||
|
||||
while ((c = getopt_long(argc, argv, "vsaS:E:F:D:e:L:q:h", opts, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
/* option that set a flag, nothing to do */
|
||||
break;
|
||||
case 'v':
|
||||
debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
|
||||
break;
|
||||
case 's':
|
||||
options.summary = true;
|
||||
break;
|
||||
case 'a':
|
||||
options.allregs = true;
|
||||
break;
|
||||
case 'S':
|
||||
start = atoi(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
end = atoi(optarg);
|
||||
break;
|
||||
case 'F':
|
||||
start = end = atoi(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
draw = atoi(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
exename = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
options.script = optarg;
|
||||
if (script_load(options.script)) {
|
||||
errx(-1, "error loading %s\n", options.script);
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
options.querystrs = realloc(options.querystrs,
|
||||
(options.nquery + 1) * sizeof(*options.querystrs));
|
||||
options.querystrs[options.nquery] = optarg;
|
||||
options.nquery++;
|
||||
interactive = 0;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
}
|
||||
while ((c = getopt_long(argc, argv, "vsaS:E:F:D:e:L:q:h", opts, NULL)) !=
|
||||
-1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
/* option that set a flag, nothing to do */
|
||||
break;
|
||||
case 'v':
|
||||
debug |= (PRINT_RAW | EXPAND_REPEAT | PRINT_VERBOSE);
|
||||
break;
|
||||
case 's':
|
||||
options.summary = true;
|
||||
break;
|
||||
case 'a':
|
||||
options.allregs = true;
|
||||
break;
|
||||
case 'S':
|
||||
start = atoi(optarg);
|
||||
break;
|
||||
case 'E':
|
||||
end = atoi(optarg);
|
||||
break;
|
||||
case 'F':
|
||||
start = end = atoi(optarg);
|
||||
break;
|
||||
case 'D':
|
||||
draw = atoi(optarg);
|
||||
break;
|
||||
case 'e':
|
||||
exename = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
options.script = optarg;
|
||||
if (script_load(options.script)) {
|
||||
errx(-1, "error loading %s\n", options.script);
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
options.querystrs =
|
||||
realloc(options.querystrs,
|
||||
(options.nquery + 1) * sizeof(*options.querystrs));
|
||||
options.querystrs[options.nquery] = optarg;
|
||||
options.nquery++;
|
||||
interactive = 0;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
disasm_a2xx_set_debug(debug);
|
||||
disasm_a3xx_set_debug(debug);
|
||||
disasm_a2xx_set_debug(debug);
|
||||
disasm_a3xx_set_debug(debug);
|
||||
|
||||
if (interactive) {
|
||||
pager_open();
|
||||
}
|
||||
if (interactive) {
|
||||
pager_open();
|
||||
}
|
||||
|
||||
while (optind < argc) {
|
||||
ret = handle_file(argv[optind], start, end, draw);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error reading: %s\n", argv[optind]);
|
||||
fprintf(stderr, "continuing..\n");
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
while (optind < argc) {
|
||||
ret = handle_file(argv[optind], start, end, draw);
|
||||
if (ret) {
|
||||
fprintf(stderr, "error reading: %s\n", argv[optind]);
|
||||
fprintf(stderr, "continuing..\n");
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
|
||||
if (ret)
|
||||
print_usage(argv[0]);
|
||||
if (ret)
|
||||
print_usage(argv[0]);
|
||||
|
||||
if ((options.query_mode || options.query_compare) && !options.nquery) {
|
||||
fprintf(stderr, "query options only valid in query mode!\n");
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
if ((options.query_mode || options.query_compare) && !options.nquery) {
|
||||
fprintf(stderr, "query options only valid in query mode!\n");
|
||||
print_usage(argv[0]);
|
||||
}
|
||||
|
||||
script_finish();
|
||||
script_finish();
|
||||
|
||||
if (interactive) {
|
||||
pager_close();
|
||||
}
|
||||
if (interactive) {
|
||||
pager_close();
|
||||
}
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
|
||||
static void
|
||||
parse_addr(uint32_t *buf, int sz, unsigned int *len, uint64_t *gpuaddr)
|
||||
{
|
||||
*gpuaddr = buf[0];
|
||||
*len = buf[1];
|
||||
if (sz > 8)
|
||||
*gpuaddr |= ((uint64_t)(buf[2])) << 32;
|
||||
*gpuaddr = buf[0];
|
||||
*len = buf[1];
|
||||
if (sz > 8)
|
||||
*gpuaddr |= ((uint64_t)(buf[2])) << 32;
|
||||
}
|
||||
|
||||
static int handle_file(const char *filename, int start, int end, int draw)
|
||||
static int
|
||||
handle_file(const char *filename, int start, int end, int draw)
|
||||
{
|
||||
enum rd_sect_type type = RD_NONE;
|
||||
void *buf = NULL;
|
||||
struct io *io;
|
||||
int submit = 0, got_gpu_id = 0;
|
||||
int sz, ret = 0;
|
||||
bool needs_reset = false;
|
||||
bool skip = false;
|
||||
enum rd_sect_type type = RD_NONE;
|
||||
void *buf = NULL;
|
||||
struct io *io;
|
||||
int submit = 0, got_gpu_id = 0;
|
||||
int sz, ret = 0;
|
||||
bool needs_reset = false;
|
||||
bool skip = false;
|
||||
|
||||
options.draw_filter = draw;
|
||||
options.draw_filter = draw;
|
||||
|
||||
cffdec_init(&options);
|
||||
cffdec_init(&options);
|
||||
|
||||
printf("Reading %s...\n", filename);
|
||||
printf("Reading %s...\n", filename);
|
||||
|
||||
script_start_cmdstream(filename);
|
||||
script_start_cmdstream(filename);
|
||||
|
||||
if (!strcmp(filename, "-"))
|
||||
io = io_openfd(0);
|
||||
else
|
||||
io = io_open(filename);
|
||||
if (!strcmp(filename, "-"))
|
||||
io = io_openfd(0);
|
||||
else
|
||||
io = io_open(filename);
|
||||
|
||||
if (!io) {
|
||||
fprintf(stderr, "could not open: %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
if (!io) {
|
||||
fprintf(stderr, "could not open: %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
struct {
|
||||
unsigned int len;
|
||||
uint64_t gpuaddr;
|
||||
} gpuaddr = {0};
|
||||
struct {
|
||||
unsigned int len;
|
||||
uint64_t gpuaddr;
|
||||
} gpuaddr = {0};
|
||||
|
||||
while (true) {
|
||||
uint32_t arr[2];
|
||||
while (true) {
|
||||
uint32_t arr[2];
|
||||
|
||||
ret = io_readn(io, arr, 8);
|
||||
if (ret <= 0)
|
||||
goto end;
|
||||
ret = io_readn(io, arr, 8);
|
||||
if (ret <= 0)
|
||||
goto end;
|
||||
|
||||
while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
|
||||
ret = io_readn(io, arr, 8);
|
||||
if (ret <= 0)
|
||||
goto end;
|
||||
}
|
||||
while ((arr[0] == 0xffffffff) && (arr[1] == 0xffffffff)) {
|
||||
ret = io_readn(io, arr, 8);
|
||||
if (ret <= 0)
|
||||
goto end;
|
||||
}
|
||||
|
||||
type = arr[0];
|
||||
sz = arr[1];
|
||||
type = arr[0];
|
||||
sz = arr[1];
|
||||
|
||||
if (sz < 0) {
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
if (sz < 0) {
|
||||
ret = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
free(buf);
|
||||
|
||||
needs_wfi = false;
|
||||
needs_wfi = false;
|
||||
|
||||
buf = malloc(sz + 1);
|
||||
((char *)buf)[sz] = '\0';
|
||||
ret = io_readn(io, buf, sz);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
buf = malloc(sz + 1);
|
||||
((char *)buf)[sz] = '\0';
|
||||
ret = io_readn(io, buf, sz);
|
||||
if (ret < 0)
|
||||
goto end;
|
||||
|
||||
switch(type) {
|
||||
case RD_TEST:
|
||||
printl(1, "test: %s\n", (char *)buf);
|
||||
break;
|
||||
case RD_CMD:
|
||||
is_blob = true;
|
||||
printl(2, "cmd: %s\n", (char *)buf);
|
||||
skip = false;
|
||||
if (exename) {
|
||||
skip |= (strstr(buf, exename) != buf);
|
||||
} else if (!show_comp) {
|
||||
skip |= (strstr(buf, "fdperf") == buf);
|
||||
skip |= (strstr(buf, "chrome") == buf);
|
||||
skip |= (strstr(buf, "surfaceflinger") == buf);
|
||||
skip |= ((char *)buf)[0] == 'X';
|
||||
}
|
||||
break;
|
||||
case RD_VERT_SHADER:
|
||||
printl(2, "vertex shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_FRAG_SHADER:
|
||||
printl(2, "fragment shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_GPUADDR:
|
||||
if (needs_reset) {
|
||||
reset_buffers();
|
||||
needs_reset = false;
|
||||
}
|
||||
parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
|
||||
break;
|
||||
case RD_BUFFER_CONTENTS:
|
||||
add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
|
||||
buf = NULL;
|
||||
break;
|
||||
case RD_CMDSTREAM_ADDR:
|
||||
if ((start <= submit) && (submit <= end)) {
|
||||
unsigned int sizedwords;
|
||||
uint64_t gpuaddr;
|
||||
parse_addr(buf, sz, &sizedwords, &gpuaddr);
|
||||
printl(2, "############################################################\n");
|
||||
printl(2, "cmdstream: %d dwords\n", sizedwords);
|
||||
if (!skip) {
|
||||
script_start_submit();
|
||||
dump_commands(hostptr(gpuaddr), sizedwords, 0);
|
||||
script_end_submit();
|
||||
}
|
||||
printl(2, "############################################################\n");
|
||||
printl(2, "vertices: %d\n", vertices);
|
||||
}
|
||||
needs_reset = true;
|
||||
submit++;
|
||||
break;
|
||||
case RD_GPU_ID:
|
||||
if (!got_gpu_id) {
|
||||
options.gpu_id = *((unsigned int *)buf);
|
||||
printl(2, "gpu_id: %d\n", options.gpu_id);
|
||||
cffdec_init(&options);
|
||||
got_gpu_id = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case RD_TEST:
|
||||
printl(1, "test: %s\n", (char *)buf);
|
||||
break;
|
||||
case RD_CMD:
|
||||
is_blob = true;
|
||||
printl(2, "cmd: %s\n", (char *)buf);
|
||||
skip = false;
|
||||
if (exename) {
|
||||
skip |= (strstr(buf, exename) != buf);
|
||||
} else if (!show_comp) {
|
||||
skip |= (strstr(buf, "fdperf") == buf);
|
||||
skip |= (strstr(buf, "chrome") == buf);
|
||||
skip |= (strstr(buf, "surfaceflinger") == buf);
|
||||
skip |= ((char *)buf)[0] == 'X';
|
||||
}
|
||||
break;
|
||||
case RD_VERT_SHADER:
|
||||
printl(2, "vertex shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_FRAG_SHADER:
|
||||
printl(2, "fragment shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_GPUADDR:
|
||||
if (needs_reset) {
|
||||
reset_buffers();
|
||||
needs_reset = false;
|
||||
}
|
||||
parse_addr(buf, sz, &gpuaddr.len, &gpuaddr.gpuaddr);
|
||||
break;
|
||||
case RD_BUFFER_CONTENTS:
|
||||
add_buffer(gpuaddr.gpuaddr, gpuaddr.len, buf);
|
||||
buf = NULL;
|
||||
break;
|
||||
case RD_CMDSTREAM_ADDR:
|
||||
if ((start <= submit) && (submit <= end)) {
|
||||
unsigned int sizedwords;
|
||||
uint64_t gpuaddr;
|
||||
parse_addr(buf, sz, &sizedwords, &gpuaddr);
|
||||
printl(2, "############################################################\n");
|
||||
printl(2, "cmdstream: %d dwords\n", sizedwords);
|
||||
if (!skip) {
|
||||
script_start_submit();
|
||||
dump_commands(hostptr(gpuaddr), sizedwords, 0);
|
||||
script_end_submit();
|
||||
}
|
||||
printl(2, "############################################################\n");
|
||||
printl(2, "vertices: %d\n", vertices);
|
||||
}
|
||||
needs_reset = true;
|
||||
submit++;
|
||||
break;
|
||||
case RD_GPU_ID:
|
||||
if (!got_gpu_id) {
|
||||
options.gpu_id = *((unsigned int *)buf);
|
||||
printl(2, "gpu_id: %d\n", options.gpu_id);
|
||||
cffdec_init(&options);
|
||||
got_gpu_id = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
script_end_cmdstream();
|
||||
script_end_cmdstream();
|
||||
|
||||
io_close(io);
|
||||
fflush(stdout);
|
||||
io_close(io);
|
||||
fflush(stdout);
|
||||
|
||||
if (ret < 0) {
|
||||
printf("corrupt file\n");
|
||||
}
|
||||
return 0;
|
||||
if (ret < 0) {
|
||||
printf("corrupt file\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,138 +26,145 @@
|
|||
* Rob Clark <robclark@freedesktop.org>
|
||||
*/
|
||||
|
||||
#include <archive.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <archive.h>
|
||||
#include <sys/types.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#include "io.h"
|
||||
|
||||
struct io {
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
unsigned offset;
|
||||
struct archive *a;
|
||||
struct archive_entry *entry;
|
||||
unsigned offset;
|
||||
};
|
||||
|
||||
static void io_error(struct io *io)
|
||||
static void
|
||||
io_error(struct io *io)
|
||||
{
|
||||
fprintf(stderr, "%s\n", archive_error_string(io->a));
|
||||
io_close(io);
|
||||
fprintf(stderr, "%s\n", archive_error_string(io->a));
|
||||
io_close(io);
|
||||
}
|
||||
|
||||
static struct io * io_new(void)
|
||||
static struct io *
|
||||
io_new(void)
|
||||
{
|
||||
struct io *io = calloc(1, sizeof(*io));
|
||||
int ret;
|
||||
struct io *io = calloc(1, sizeof(*io));
|
||||
int ret;
|
||||
|
||||
if (!io)
|
||||
return NULL;
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
io->a = archive_read_new();
|
||||
ret = archive_read_support_filter_gzip(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
io->a = archive_read_new();
|
||||
ret = archive_read_support_filter_gzip(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = archive_read_support_filter_none(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_support_filter_none(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = archive_read_support_format_all(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_support_format_all(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = archive_read_support_format_raw(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_support_format_raw(io->a);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
return io;
|
||||
}
|
||||
|
||||
struct io * io_open(const char *filename)
|
||||
struct io *
|
||||
io_open(const char *filename)
|
||||
{
|
||||
struct io *io = io_new();
|
||||
int ret;
|
||||
struct io *io = io_new();
|
||||
int ret;
|
||||
|
||||
if (!io)
|
||||
return NULL;
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
ret = archive_read_open_filename(io->a, filename, 10240);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_open_filename(io->a, filename, 10240);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = archive_read_next_header(io->a, &io->entry);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_next_header(io->a, &io->entry);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
return io;
|
||||
}
|
||||
|
||||
struct io * io_openfd(int fd)
|
||||
struct io *
|
||||
io_openfd(int fd)
|
||||
{
|
||||
struct io *io = io_new();
|
||||
int ret;
|
||||
struct io *io = io_new();
|
||||
int ret;
|
||||
|
||||
if (!io)
|
||||
return NULL;
|
||||
if (!io)
|
||||
return NULL;
|
||||
|
||||
ret = archive_read_open_fd(io->a, fd, 10240);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_open_fd(io->a, fd, 10240);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = archive_read_next_header(io->a, &io->entry);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
ret = archive_read_next_header(io->a, &io->entry);
|
||||
if (ret != ARCHIVE_OK) {
|
||||
io_error(io);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return io;
|
||||
return io;
|
||||
}
|
||||
|
||||
void io_close(struct io *io)
|
||||
void
|
||||
io_close(struct io *io)
|
||||
{
|
||||
archive_read_free(io->a);
|
||||
free(io);
|
||||
archive_read_free(io->a);
|
||||
free(io);
|
||||
}
|
||||
|
||||
unsigned io_offset(struct io *io)
|
||||
unsigned
|
||||
io_offset(struct io *io)
|
||||
{
|
||||
return io->offset;
|
||||
return io->offset;
|
||||
}
|
||||
|
||||
#include <assert.h>
|
||||
int io_readn(struct io *io, void *buf, int nbytes)
|
||||
int
|
||||
io_readn(struct io *io, void *buf, int nbytes)
|
||||
{
|
||||
char *ptr = buf;
|
||||
int ret = 0;
|
||||
while (nbytes > 0) {
|
||||
int n = archive_read_data(io->a, ptr, nbytes);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "%s\n", archive_error_string(io->a));
|
||||
return n;
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
ptr += n;
|
||||
nbytes -= n;
|
||||
ret += n;
|
||||
io->offset += n;
|
||||
}
|
||||
return ret;
|
||||
char *ptr = buf;
|
||||
int ret = 0;
|
||||
while (nbytes > 0) {
|
||||
int n = archive_read_data(io->a, ptr, nbytes);
|
||||
if (n < 0) {
|
||||
fprintf(stderr, "%s\n", archive_error_string(io->a));
|
||||
return n;
|
||||
}
|
||||
if (n == 0)
|
||||
break;
|
||||
ptr += n;
|
||||
nbytes -= n;
|
||||
ret += n;
|
||||
io->offset += n;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -35,17 +35,16 @@
|
|||
|
||||
struct io;
|
||||
|
||||
struct io * io_open(const char *filename);
|
||||
struct io * io_openfd(int fd);
|
||||
struct io *io_open(const char *filename);
|
||||
struct io *io_openfd(int fd);
|
||||
void io_close(struct io *io);
|
||||
unsigned io_offset(struct io *io);
|
||||
int io_readn(struct io *io, void *buf, int nbytes);
|
||||
|
||||
|
||||
static inline int
|
||||
check_extension(const char *path, const char *ext)
|
||||
{
|
||||
return strcmp(path + strlen(path) - strlen(ext), ext) == 0;
|
||||
return strcmp(path + strlen(path) - strlen(ext), ext) == 0;
|
||||
}
|
||||
|
||||
#endif /* IO_H_ */
|
||||
|
|
|
@ -27,73 +27,72 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "pager.h"
|
||||
|
||||
static pid_t pager_pid;
|
||||
|
||||
|
||||
static void
|
||||
pager_death(int n)
|
||||
{
|
||||
exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void
|
||||
pager_open(void)
|
||||
{
|
||||
int fd[2];
|
||||
int fd[2];
|
||||
|
||||
if (pipe(fd) < 0) {
|
||||
fprintf(stderr, "Failed to create pager pipe: %m\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (pipe(fd) < 0) {
|
||||
fprintf(stderr, "Failed to create pager pipe: %m\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
pager_pid = fork();
|
||||
if (pager_pid < 0) {
|
||||
fprintf(stderr, "Failed to fork pager: %m\n");
|
||||
exit(-1);
|
||||
}
|
||||
pager_pid = fork();
|
||||
if (pager_pid < 0) {
|
||||
fprintf(stderr, "Failed to fork pager: %m\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (pager_pid == 0) {
|
||||
const char* less_opts;
|
||||
if (pager_pid == 0) {
|
||||
const char *less_opts;
|
||||
|
||||
dup2(fd[0], STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
dup2(fd[0], STDIN_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
|
||||
less_opts = "FRSMKX";
|
||||
setenv("LESS", less_opts, 1);
|
||||
less_opts = "FRSMKX";
|
||||
setenv("LESS", less_opts, 1);
|
||||
|
||||
execlp("less", "less", NULL);
|
||||
execlp("less", "less", NULL);
|
||||
|
||||
} else {
|
||||
/* we want to kill the parent process when pager exits: */
|
||||
signal(SIGCHLD, pager_death);
|
||||
dup2(fd[1], STDOUT_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
} else {
|
||||
/* we want to kill the parent process when pager exits: */
|
||||
signal(SIGCHLD, pager_death);
|
||||
dup2(fd[1], STDOUT_FILENO);
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
pager_close(void)
|
||||
{
|
||||
siginfo_t status;
|
||||
siginfo_t status;
|
||||
|
||||
close(STDOUT_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
|
||||
while (true) {
|
||||
memset(&status, 0, sizeof(status));
|
||||
if (waitid(P_PID, pager_pid, &status, WEXITED) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -errno;
|
||||
}
|
||||
while (true) {
|
||||
memset(&status, 0, sizeof(status));
|
||||
if (waitid(P_PID, pager_pid, &status, WEXITED) < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -36,550 +36,569 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stddef.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "redump.h"
|
||||
#include "disasm.h"
|
||||
#include "io.h"
|
||||
#include "redump.h"
|
||||
#include "util.h"
|
||||
|
||||
const char *infile;
|
||||
static int dump_full = 0;
|
||||
static int dump_offsets = 0;
|
||||
static int gpu_id = 320;
|
||||
static int shaderdb = 0; /* output shaderdb style traces to stderr */
|
||||
static int shaderdb = 0; /* output shaderdb style traces to stderr */
|
||||
|
||||
struct state {
|
||||
char *buf;
|
||||
int sz;
|
||||
int lvl;
|
||||
char *buf;
|
||||
int sz;
|
||||
int lvl;
|
||||
|
||||
/* current shader_info section, some offsets calculated relative to
|
||||
* this, rather than relative to start of buffer.
|
||||
*/
|
||||
void *shader;
|
||||
/* current shader_info section, some offsets calculated relative to
|
||||
* this, rather than relative to start of buffer.
|
||||
*/
|
||||
void *shader;
|
||||
|
||||
/* size of each entry within a shader_descriptor_blk: */
|
||||
int desc_size;
|
||||
/* size of each entry within a shader_descriptor_blk: */
|
||||
int desc_size;
|
||||
|
||||
const char *shader_type;
|
||||
int full_regs;
|
||||
int half_regs;
|
||||
const char *shader_type;
|
||||
int full_regs;
|
||||
int half_regs;
|
||||
};
|
||||
|
||||
#define PACKED __attribute__((__packed__))
|
||||
|
||||
#define OFF(field) do { \
|
||||
if (dump_offsets) \
|
||||
printf("%08x: ", (uint32_t)((char *)&field - state->buf));\
|
||||
} while (0)
|
||||
#define OFF(field) \
|
||||
do { \
|
||||
if (dump_offsets) \
|
||||
printf("%08x: ", (uint32_t)((char *)&field - state->buf)); \
|
||||
} while (0)
|
||||
|
||||
/* decode field as hex */
|
||||
#define X(s, field) do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t0x%x\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
#define X(s, field) \
|
||||
do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t0x%x\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
|
||||
/* decode field as digit */
|
||||
#define D(s, field) do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%u\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
#define D(s, field) \
|
||||
do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%u\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
|
||||
/* decode field as float/hex */
|
||||
#define F(s, field) do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%f (0x%0x)\n", tab(state->lvl), #field, \
|
||||
d2f(s->field), s->field); \
|
||||
} while (0)
|
||||
#define F(s, field) \
|
||||
do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%f (0x%0x)\n", tab(state->lvl), #field, d2f(s->field), \
|
||||
s->field); \
|
||||
} while (0)
|
||||
|
||||
/* decode field as register: (type is 'r' or 'c') */
|
||||
#define R(s, field, type) do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%c%u.%c\n", tab(state->lvl), #field, type, \
|
||||
(s->field >> 2), "xyzw"[s->field & 0x3]); \
|
||||
} while (0)
|
||||
#define R(s, field, type) \
|
||||
do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%c%u.%c\n", tab(state->lvl), #field, type, \
|
||||
(s->field >> 2), "xyzw"[s->field & 0x3]); \
|
||||
} while (0)
|
||||
|
||||
/* decode inline string (presumably null terminated?) */
|
||||
#define S(s, field) do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%s\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
#define S(s, field) \
|
||||
do { \
|
||||
OFF(s->field); \
|
||||
printf("%s%12s:\t%s\n", tab(state->lvl), #field, s->field); \
|
||||
} while (0)
|
||||
|
||||
/* decode string-table string */
|
||||
#define T(s, field) TODO
|
||||
#define T(s, field) TODO
|
||||
|
||||
/* decode field as unknown */
|
||||
#define U(s, start, end) \
|
||||
dump_unknown(state, s->unk_ ## start ## _ ## end, 0x ## start, (4 + 0x ## end - 0x ## start) / 4)
|
||||
#define U(s, start, end) \
|
||||
dump_unknown(state, s->unk_##start##_##end, 0x##start, \
|
||||
(4 + 0x##end - 0x##start) / 4)
|
||||
|
||||
/* decode field as offset to other section */
|
||||
#define O(s, field, type) do { \
|
||||
X(s, field); \
|
||||
assert(s->field < state->sz); \
|
||||
void *_p = &state->buf[s->field]; \
|
||||
state->lvl++; \
|
||||
decode_ ## type (state, _p); \
|
||||
state->lvl--; \
|
||||
} while (0)
|
||||
#define O(s, field, type) \
|
||||
do { \
|
||||
X(s, field); \
|
||||
assert(s->field < state->sz); \
|
||||
void *_p = &state->buf[s->field]; \
|
||||
state->lvl++; \
|
||||
decode_##type(state, _p); \
|
||||
state->lvl--; \
|
||||
} while (0)
|
||||
|
||||
struct shader_info;
|
||||
static void decode_shader_info(struct state *state, struct shader_info *info);
|
||||
|
||||
static void dump_unknown(struct state *state, void *buf, unsigned start, unsigned n)
|
||||
static void
|
||||
dump_unknown(struct state *state, void *buf, unsigned start, unsigned n)
|
||||
{
|
||||
uint32_t *ptr = buf;
|
||||
uint8_t *ascii = buf;
|
||||
uint32_t *ptr = buf;
|
||||
uint8_t *ascii = buf;
|
||||
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
uint32_t d = ptr[i];
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
uint32_t d = ptr[i];
|
||||
|
||||
if (dump_offsets)
|
||||
printf("%08x:", (uint32_t)((char *)&ptr[i] - state->buf));
|
||||
if (dump_offsets)
|
||||
printf("%08x:", (uint32_t)((char *)&ptr[i] - state->buf));
|
||||
|
||||
printf("%s %04x:\t%08x", tab(state->lvl), start + i * 4, d);
|
||||
printf("%s %04x:\t%08x", tab(state->lvl), start + i * 4, d);
|
||||
|
||||
printf("\t|");
|
||||
for (unsigned j = 0; j < 4; j++) {
|
||||
uint8_t c = *(ascii++);
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\t%f", d2f(d));
|
||||
printf("\t|");
|
||||
for (unsigned j = 0; j < 4; j++) {
|
||||
uint8_t c = *(ascii++);
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\t%f", d2f(d));
|
||||
|
||||
/* TODO maybe scan for first non-null and non-ascii char starting from
|
||||
* end of shader binary to (roughly) establish the start of the string
|
||||
* table.. that would be a bit better filter for deciding if something
|
||||
* might be a pointer into the string table. Also, the previous char
|
||||
* to what it points to should probably be null.
|
||||
*/
|
||||
if ((d < state->sz) &&
|
||||
isascii(state->buf[d]) &&
|
||||
(strlen(&state->buf[d]) > 2) &&
|
||||
isascii(state->buf[d+1]))
|
||||
printf("\t<== %s", &state->buf[d]);
|
||||
/* TODO maybe scan for first non-null and non-ascii char starting from
|
||||
* end of shader binary to (roughly) establish the start of the string
|
||||
* table.. that would be a bit better filter for deciding if something
|
||||
* might be a pointer into the string table. Also, the previous char
|
||||
* to what it points to should probably be null.
|
||||
*/
|
||||
if ((d < state->sz) && isascii(state->buf[d]) &&
|
||||
(strlen(&state->buf[d]) > 2) && isascii(state->buf[d + 1]))
|
||||
printf("\t<== %s", &state->buf[d]);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
struct PACKED header {
|
||||
uint32_t version; /* I guess, always b10bcace ? */
|
||||
uint32_t unk_0004_0014[5];
|
||||
uint32_t size;
|
||||
uint32_t size2; /* just to be sure? */
|
||||
uint32_t unk_0020_0020[1];
|
||||
uint32_t chksum; /* I guess? Small changes seem to result in big diffs here */
|
||||
uint32_t unk_0028_0050[11];
|
||||
uint32_t fs_info; /* offset of FS shader_info section */
|
||||
uint32_t unk_0058_0090[15];
|
||||
uint32_t vs_info; /* offset of VS shader_info section */
|
||||
uint32_t unk_0098_00b0[7];
|
||||
uint32_t vs_info2; /* offset of VS shader_info section (again?) */
|
||||
uint32_t unk_00b8_0110[23];
|
||||
uint32_t bs_info; /* offset of binning shader_info section */
|
||||
uint32_t version; /* I guess, always b10bcace ? */
|
||||
uint32_t unk_0004_0014[5];
|
||||
uint32_t size;
|
||||
uint32_t size2; /* just to be sure? */
|
||||
uint32_t unk_0020_0020[1];
|
||||
uint32_t
|
||||
chksum; /* I guess? Small changes seem to result in big diffs here */
|
||||
uint32_t unk_0028_0050[11];
|
||||
uint32_t fs_info; /* offset of FS shader_info section */
|
||||
uint32_t unk_0058_0090[15];
|
||||
uint32_t vs_info; /* offset of VS shader_info section */
|
||||
uint32_t unk_0098_00b0[7];
|
||||
uint32_t vs_info2; /* offset of VS shader_info section (again?) */
|
||||
uint32_t unk_00b8_0110[23];
|
||||
uint32_t bs_info; /* offset of binning shader_info section */
|
||||
};
|
||||
|
||||
static void decode_header(struct state *state, struct header *hdr)
|
||||
static void
|
||||
decode_header(struct state *state, struct header *hdr)
|
||||
{
|
||||
X(hdr, version);
|
||||
U(hdr, 0004, 0014);
|
||||
X(hdr, size);
|
||||
X(hdr, size2);
|
||||
U(hdr, 0020, 0020);
|
||||
X(hdr, chksum);
|
||||
U(hdr, 0028, 0050);
|
||||
state->shader_type = "FRAG";
|
||||
O(hdr, fs_info, shader_info);
|
||||
U(hdr, 0058, 0090);
|
||||
state->shader_type = "VERT";
|
||||
O(hdr, vs_info, shader_info);
|
||||
U(hdr, 0098, 00b0);
|
||||
assert(hdr->vs_info == hdr->vs_info2); /* not sure what this if it is ever different */
|
||||
X(hdr, vs_info2);
|
||||
U(hdr, 00b8, 0110);
|
||||
state->shader_type = "BVERT";
|
||||
O(hdr, bs_info, shader_info);
|
||||
X(hdr, version);
|
||||
U(hdr, 0004, 0014);
|
||||
X(hdr, size);
|
||||
X(hdr, size2);
|
||||
U(hdr, 0020, 0020);
|
||||
X(hdr, chksum);
|
||||
U(hdr, 0028, 0050);
|
||||
state->shader_type = "FRAG";
|
||||
O(hdr, fs_info, shader_info);
|
||||
U(hdr, 0058, 0090);
|
||||
state->shader_type = "VERT";
|
||||
O(hdr, vs_info, shader_info);
|
||||
U(hdr, 0098, 00b0);
|
||||
assert(hdr->vs_info ==
|
||||
hdr->vs_info2); /* not sure what this if it is ever different */
|
||||
X(hdr, vs_info2);
|
||||
U(hdr, 00b8, 0110);
|
||||
state->shader_type = "BVERT";
|
||||
O(hdr, bs_info, shader_info);
|
||||
|
||||
/* not sure how much of the rest of contents before start of fs_info
|
||||
* is the header, vs other things.. just dump it all as unknown for
|
||||
* now:
|
||||
*/
|
||||
dump_unknown(state, (void *)hdr + sizeof(*hdr),
|
||||
sizeof(*hdr), (hdr->fs_info - sizeof(*hdr)) / 4);
|
||||
/* not sure how much of the rest of contents before start of fs_info
|
||||
* is the header, vs other things.. just dump it all as unknown for
|
||||
* now:
|
||||
*/
|
||||
dump_unknown(state, (void *)hdr + sizeof(*hdr), sizeof(*hdr),
|
||||
(hdr->fs_info - sizeof(*hdr)) / 4);
|
||||
}
|
||||
|
||||
struct PACKED shader_entry_point {
|
||||
/* entry point name, ie. "main" of TBD length, followed by unknown */
|
||||
char name[8];
|
||||
/* entry point name, ie. "main" of TBD length, followed by unknown */
|
||||
char name[8];
|
||||
};
|
||||
|
||||
static void decode_shader_entry_point(struct state *state,
|
||||
struct shader_entry_point *e)
|
||||
static void
|
||||
decode_shader_entry_point(struct state *state, struct shader_entry_point *e)
|
||||
{
|
||||
S(e, name);
|
||||
S(e, name);
|
||||
}
|
||||
|
||||
struct PACKED shader_config {
|
||||
uint32_t unk_0000_0008[3];
|
||||
uint32_t full_regs;
|
||||
uint32_t half_regs;
|
||||
uint32_t unk_0000_0008[3];
|
||||
uint32_t full_regs;
|
||||
uint32_t half_regs;
|
||||
};
|
||||
|
||||
static void decode_shader_config(struct state *state, struct shader_config *cfg)
|
||||
static void
|
||||
decode_shader_config(struct state *state, struct shader_config *cfg)
|
||||
{
|
||||
U(cfg, 0000, 0008);
|
||||
D(cfg, full_regs);
|
||||
D(cfg, half_regs);
|
||||
U(cfg, 0000, 0008);
|
||||
D(cfg, full_regs);
|
||||
D(cfg, half_regs);
|
||||
|
||||
state->full_regs = cfg->full_regs;
|
||||
state->half_regs = cfg->half_regs;
|
||||
state->full_regs = cfg->full_regs;
|
||||
state->half_regs = cfg->half_regs;
|
||||
|
||||
/* dump reset of unknown (size differs btwn versions) */
|
||||
dump_unknown(state, (void *)cfg + sizeof(*cfg), sizeof(*cfg),
|
||||
(state->desc_size - sizeof(*cfg))/4);
|
||||
/* dump reset of unknown (size differs btwn versions) */
|
||||
dump_unknown(state, (void *)cfg + sizeof(*cfg), sizeof(*cfg),
|
||||
(state->desc_size - sizeof(*cfg)) / 4);
|
||||
}
|
||||
|
||||
struct PACKED shader_io_block {
|
||||
/* name of TBD length followed by unknown.. 42 dwords total */
|
||||
char name[20];
|
||||
uint32_t unk_0014_00a4[37];
|
||||
/* name of TBD length followed by unknown.. 42 dwords total */
|
||||
char name[20];
|
||||
uint32_t unk_0014_00a4[37];
|
||||
};
|
||||
|
||||
static void decode_shader_io_block(struct state *state,
|
||||
struct shader_io_block *io)
|
||||
static void
|
||||
decode_shader_io_block(struct state *state, struct shader_io_block *io)
|
||||
{
|
||||
S(io, name);
|
||||
U(io, 0014, 00a4);
|
||||
S(io, name);
|
||||
U(io, 0014, 00a4);
|
||||
}
|
||||
|
||||
struct PACKED shader_constant_block {
|
||||
uint32_t value;
|
||||
uint32_t unk_0004_000c[3];
|
||||
uint32_t regid;
|
||||
uint32_t unk_0014_0024[5];
|
||||
uint32_t value;
|
||||
uint32_t unk_0004_000c[3];
|
||||
uint32_t regid;
|
||||
uint32_t unk_0014_0024[5];
|
||||
};
|
||||
|
||||
static void decode_shader_constant_block(struct state *state,
|
||||
struct shader_constant_block *c)
|
||||
static void
|
||||
decode_shader_constant_block(struct state *state,
|
||||
struct shader_constant_block *c)
|
||||
{
|
||||
F(c, value);
|
||||
U(c, 0004, 000c);
|
||||
R(c, regid, 'c');
|
||||
U(c, 0014, 0024);
|
||||
F(c, value);
|
||||
U(c, 0004, 000c);
|
||||
R(c, regid, 'c');
|
||||
U(c, 0014, 0024);
|
||||
}
|
||||
|
||||
enum {
|
||||
ENTRY_POINT = 0, /* shader_entry_point */
|
||||
SHADER_CONFIG = 1, /* XXX placeholder name */
|
||||
SHADER_INPUT = 2, /* shader_io_block */
|
||||
SHADER_OUTPUT = 3, /* shader_io_block */
|
||||
CONSTANTS = 6, /* shader_constant_block */
|
||||
INTERNAL = 8, /* internal input, like bary.f coord */
|
||||
SHADER = 10,
|
||||
ENTRY_POINT = 0, /* shader_entry_point */
|
||||
SHADER_CONFIG = 1, /* XXX placeholder name */
|
||||
SHADER_INPUT = 2, /* shader_io_block */
|
||||
SHADER_OUTPUT = 3, /* shader_io_block */
|
||||
CONSTANTS = 6, /* shader_constant_block */
|
||||
INTERNAL = 8, /* internal input, like bary.f coord */
|
||||
SHADER = 10,
|
||||
} shader_info_block_type;
|
||||
|
||||
/* Refers to location of some type of records, with an offset relative to
|
||||
* start of shader_info block.
|
||||
*/
|
||||
struct PACKED shader_descriptor_block {
|
||||
uint32_t type; /* block type */
|
||||
uint32_t offset; /* offset (relative to start of shader_info block) */
|
||||
uint32_t size; /* size in bytes */
|
||||
uint32_t count; /* number of records */
|
||||
uint32_t unk_0010_0010[1];
|
||||
uint32_t type; /* block type */
|
||||
uint32_t offset; /* offset (relative to start of shader_info block) */
|
||||
uint32_t size; /* size in bytes */
|
||||
uint32_t count; /* number of records */
|
||||
uint32_t unk_0010_0010[1];
|
||||
};
|
||||
|
||||
static void decode_shader_descriptor_block(struct state *state,
|
||||
struct shader_descriptor_block *blk)
|
||||
static void
|
||||
decode_shader_descriptor_block(struct state *state,
|
||||
struct shader_descriptor_block *blk)
|
||||
{
|
||||
D(blk, type);
|
||||
X(blk, offset);
|
||||
D(blk, size);
|
||||
D(blk, count);
|
||||
U(blk, 0010, 0010);
|
||||
D(blk, type);
|
||||
X(blk, offset);
|
||||
D(blk, size);
|
||||
D(blk, count);
|
||||
U(blk, 0010, 0010);
|
||||
|
||||
/* offset relative to current shader block: */
|
||||
void *ptr = state->shader + blk->offset;
|
||||
/* offset relative to current shader block: */
|
||||
void *ptr = state->shader + blk->offset;
|
||||
|
||||
if (blk->count == 0) {
|
||||
assert(blk->size == 0);
|
||||
} else {
|
||||
assert((blk->size % blk->count) == 0);
|
||||
}
|
||||
if (blk->count == 0) {
|
||||
assert(blk->size == 0);
|
||||
} else {
|
||||
assert((blk->size % blk->count) == 0);
|
||||
}
|
||||
|
||||
state->desc_size = blk->size / blk->count;
|
||||
state->lvl++;
|
||||
for (unsigned i = 0; i < blk->count; i++) {
|
||||
switch (blk->type) {
|
||||
case ENTRY_POINT:
|
||||
printf("%sentry point %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_entry_point(state, ptr);
|
||||
break;
|
||||
case SHADER_CONFIG:
|
||||
printf("%sconfig %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_config(state, ptr);
|
||||
break;
|
||||
case SHADER_INPUT:
|
||||
printf("%sinput %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case SHADER_OUTPUT:
|
||||
printf("%soutput %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case INTERNAL:
|
||||
printf("%sinternal input %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case CONSTANTS:
|
||||
printf("%sconstant %u:\n", tab(state->lvl-1), i);
|
||||
decode_shader_constant_block(state, ptr);
|
||||
break;
|
||||
case SHADER: {
|
||||
struct shader_stats stats;
|
||||
printf("%sshader %u:\n", tab(state->lvl-1), i);
|
||||
disasm_a3xx_stat(ptr, blk->size/4, state->lvl, stdout, gpu_id, &stats);
|
||||
if (shaderdb) {
|
||||
unsigned dwords = 2 * stats.instlen;
|
||||
state->desc_size = blk->size / blk->count;
|
||||
state->lvl++;
|
||||
for (unsigned i = 0; i < blk->count; i++) {
|
||||
switch (blk->type) {
|
||||
case ENTRY_POINT:
|
||||
printf("%sentry point %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_entry_point(state, ptr);
|
||||
break;
|
||||
case SHADER_CONFIG:
|
||||
printf("%sconfig %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_config(state, ptr);
|
||||
break;
|
||||
case SHADER_INPUT:
|
||||
printf("%sinput %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case SHADER_OUTPUT:
|
||||
printf("%soutput %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case INTERNAL:
|
||||
printf("%sinternal input %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_io_block(state, ptr);
|
||||
break;
|
||||
case CONSTANTS:
|
||||
printf("%sconstant %u:\n", tab(state->lvl - 1), i);
|
||||
decode_shader_constant_block(state, ptr);
|
||||
break;
|
||||
case SHADER: {
|
||||
struct shader_stats stats;
|
||||
printf("%sshader %u:\n", tab(state->lvl - 1), i);
|
||||
disasm_a3xx_stat(ptr, blk->size / 4, state->lvl, stdout, gpu_id,
|
||||
&stats);
|
||||
if (shaderdb) {
|
||||
unsigned dwords = 2 * stats.instlen;
|
||||
|
||||
if (gpu_id >= 400) {
|
||||
dwords = ALIGN(dwords, 16 * 2);
|
||||
} else {
|
||||
dwords = ALIGN(dwords, 4 * 2);
|
||||
}
|
||||
if (gpu_id >= 400) {
|
||||
dwords = ALIGN(dwords, 16 * 2);
|
||||
} else {
|
||||
dwords = ALIGN(dwords, 4 * 2);
|
||||
}
|
||||
|
||||
unsigned half_regs = state->half_regs;
|
||||
unsigned full_regs = state->full_regs;
|
||||
unsigned half_regs = state->half_regs;
|
||||
unsigned full_regs = state->full_regs;
|
||||
|
||||
/* On a6xx w/ merged/conflicting half and full regs, the
|
||||
* full_regs footprint will be max of full_regs and half
|
||||
* of half_regs.. we only care about which value is higher.
|
||||
*/
|
||||
if (gpu_id >= 600) {
|
||||
/* footprint of half_regs in units of full_regs: */
|
||||
unsigned half_full = (half_regs + 1) / 2;
|
||||
if (half_full > full_regs)
|
||||
full_regs = half_full;
|
||||
half_regs = 0;
|
||||
}
|
||||
/* On a6xx w/ merged/conflicting half and full regs, the
|
||||
* full_regs footprint will be max of full_regs and half
|
||||
* of half_regs.. we only care about which value is higher.
|
||||
*/
|
||||
if (gpu_id >= 600) {
|
||||
/* footprint of half_regs in units of full_regs: */
|
||||
unsigned half_full = (half_regs + 1) / 2;
|
||||
if (half_full > full_regs)
|
||||
full_regs = half_full;
|
||||
half_regs = 0;
|
||||
}
|
||||
|
||||
fprintf(stderr,
|
||||
"%s shader: %u inst, %u nops, %u non-nops, %u dwords, "
|
||||
"%u half, %u full, %u constlen, "
|
||||
"%u (ss), %u (sy), %d max_sun, %d loops\n",
|
||||
state->shader_type, stats.instructions,
|
||||
stats.nops, stats.instructions - stats.nops,
|
||||
dwords, half_regs, full_regs,
|
||||
stats.constlen, stats.ss, stats.sy,
|
||||
0, 0); /* max_sun or loops not possible */
|
||||
}
|
||||
/* this is a special case in a way, blk->count is # of
|
||||
* instructions but disasm_a3xx() decodes all instructions,
|
||||
* so just bail.
|
||||
*/
|
||||
i = blk->count;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dump_unknown(state, ptr, 0, state->desc_size/4);
|
||||
break;
|
||||
}
|
||||
ptr += state->desc_size;
|
||||
}
|
||||
state->lvl--;
|
||||
fprintf(stderr,
|
||||
"%s shader: %u inst, %u nops, %u non-nops, %u dwords, "
|
||||
"%u half, %u full, %u constlen, "
|
||||
"%u (ss), %u (sy), %d max_sun, %d loops\n",
|
||||
state->shader_type, stats.instructions, stats.nops,
|
||||
stats.instructions - stats.nops, dwords, half_regs,
|
||||
full_regs, stats.constlen, stats.ss, stats.sy, 0,
|
||||
0); /* max_sun or loops not possible */
|
||||
}
|
||||
/* this is a special case in a way, blk->count is # of
|
||||
* instructions but disasm_a3xx() decodes all instructions,
|
||||
* so just bail.
|
||||
*/
|
||||
i = blk->count;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dump_unknown(state, ptr, 0, state->desc_size / 4);
|
||||
break;
|
||||
}
|
||||
ptr += state->desc_size;
|
||||
}
|
||||
state->lvl--;
|
||||
}
|
||||
|
||||
/* there looks like one of these per shader, followed by "main" and
|
||||
* some more info, and then the shader itself.
|
||||
*/
|
||||
struct PACKED shader_info {
|
||||
uint32_t unk_0000_0010[5];
|
||||
uint32_t desc_off; /* offset to first descriptor block */
|
||||
uint32_t num_blocks;
|
||||
uint32_t unk_0000_0010[5];
|
||||
uint32_t desc_off; /* offset to first descriptor block */
|
||||
uint32_t num_blocks;
|
||||
};
|
||||
|
||||
static void decode_shader_info(struct state *state, struct shader_info *info)
|
||||
static void
|
||||
decode_shader_info(struct state *state, struct shader_info *info)
|
||||
{
|
||||
assert((info->desc_off % 4) == 0);
|
||||
assert((info->desc_off % 4) == 0);
|
||||
|
||||
U(info, 0000, 0010);
|
||||
X(info, desc_off);
|
||||
D(info, num_blocks);
|
||||
U(info, 0000, 0010);
|
||||
X(info, desc_off);
|
||||
D(info, num_blocks);
|
||||
|
||||
dump_unknown(state, &info[1], 0, (info->desc_off - sizeof(*info))/4);
|
||||
dump_unknown(state, &info[1], 0, (info->desc_off - sizeof(*info)) / 4);
|
||||
|
||||
state->shader = info;
|
||||
state->shader = info;
|
||||
|
||||
struct shader_descriptor_block *blocks = ((void *)info) + info->desc_off;
|
||||
for (unsigned i = 0; i < info->num_blocks; i++) {
|
||||
printf("%sdescriptor %u:\n", tab(state->lvl), i);
|
||||
state->lvl++;
|
||||
decode_shader_descriptor_block(state, &blocks[i]);
|
||||
state->lvl--;
|
||||
}
|
||||
struct shader_descriptor_block *blocks = ((void *)info) + info->desc_off;
|
||||
for (unsigned i = 0; i < info->num_blocks; i++) {
|
||||
printf("%sdescriptor %u:\n", tab(state->lvl), i);
|
||||
state->lvl++;
|
||||
decode_shader_descriptor_block(state, &blocks[i]);
|
||||
state->lvl--;
|
||||
}
|
||||
}
|
||||
|
||||
static void dump_program(struct state *state)
|
||||
static void
|
||||
dump_program(struct state *state)
|
||||
{
|
||||
struct header *hdr = (void *)state->buf;
|
||||
struct header *hdr = (void *)state->buf;
|
||||
|
||||
if (dump_full)
|
||||
dump_unknown(state, state->buf, 0, state->sz/4);
|
||||
if (dump_full)
|
||||
dump_unknown(state, state->buf, 0, state->sz / 4);
|
||||
|
||||
decode_header(state, hdr);
|
||||
decode_header(state, hdr);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
enum rd_sect_type type = RD_NONE;
|
||||
enum debug_t debug = PRINT_RAW | PRINT_STATS;
|
||||
void *buf = NULL;
|
||||
int sz;
|
||||
struct io *io;
|
||||
int raw_program = 0;
|
||||
enum rd_sect_type type = RD_NONE;
|
||||
enum debug_t debug = PRINT_RAW | PRINT_STATS;
|
||||
void *buf = NULL;
|
||||
int sz;
|
||||
struct io *io;
|
||||
int raw_program = 0;
|
||||
|
||||
/* lame argument parsing: */
|
||||
/* lame argument parsing: */
|
||||
|
||||
while (1) {
|
||||
if ((argc > 1) && !strcmp(argv[1], "--verbose")) {
|
||||
debug |= PRINT_RAW | PRINT_VERBOSE;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--expand")) {
|
||||
debug |= EXPAND_REPEAT;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--full")) {
|
||||
/* only short dump, original shader, symbol table, and disassembly */
|
||||
dump_full = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--dump-offsets")) {
|
||||
dump_offsets = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--raw")) {
|
||||
raw_program = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--shaderdb")) {
|
||||
shaderdb = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
while (1) {
|
||||
if ((argc > 1) && !strcmp(argv[1], "--verbose")) {
|
||||
debug |= PRINT_RAW | PRINT_VERBOSE;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--expand")) {
|
||||
debug |= EXPAND_REPEAT;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--full")) {
|
||||
/* only short dump, original shader, symbol table, and disassembly */
|
||||
dump_full = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--dump-offsets")) {
|
||||
dump_offsets = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--raw")) {
|
||||
raw_program = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
if ((argc > 1) && !strcmp(argv[1], "--shaderdb")) {
|
||||
shaderdb = 1;
|
||||
argv++;
|
||||
argc--;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: pgmdump2 [--verbose] [--expand] [--full] [--dump-offsets] [--raw] [--shaderdb] testlog.rd\n");
|
||||
return -1;
|
||||
}
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: pgmdump2 [--verbose] [--expand] [--full] "
|
||||
"[--dump-offsets] [--raw] [--shaderdb] testlog.rd\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
disasm_a3xx_set_debug(debug);
|
||||
disasm_a3xx_set_debug(debug);
|
||||
|
||||
infile = argv[1];
|
||||
infile = argv[1];
|
||||
|
||||
io = io_open(infile);
|
||||
if (!io) {
|
||||
fprintf(stderr, "could not open: %s\n", infile);
|
||||
return -1;
|
||||
}
|
||||
io = io_open(infile);
|
||||
if (!io) {
|
||||
fprintf(stderr, "could not open: %s\n", infile);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (raw_program)
|
||||
{
|
||||
io_readn(io, &sz, 4);
|
||||
free(buf);
|
||||
if (raw_program) {
|
||||
io_readn(io, &sz, 4);
|
||||
free(buf);
|
||||
|
||||
/* note: allow hex dumps to go a bit past the end of the buffer..
|
||||
* might see some garbage, but better than missing the last few bytes..
|
||||
*/
|
||||
buf = calloc(1, sz + 3);
|
||||
io_readn(io, buf + 4, sz);
|
||||
(*(int*)buf) = sz;
|
||||
/* note: allow hex dumps to go a bit past the end of the buffer..
|
||||
* might see some garbage, but better than missing the last few bytes..
|
||||
*/
|
||||
buf = calloc(1, sz + 3);
|
||||
io_readn(io, buf + 4, sz);
|
||||
(*(int *)buf) = sz;
|
||||
|
||||
struct state state = {
|
||||
.buf = buf,
|
||||
.sz = sz,
|
||||
};
|
||||
printf("############################################################\n");
|
||||
printf("program:\n");
|
||||
dump_program(&state);
|
||||
printf("############################################################\n");
|
||||
return 0;
|
||||
}
|
||||
struct state state = {
|
||||
.buf = buf,
|
||||
.sz = sz,
|
||||
};
|
||||
printf("############################################################\n");
|
||||
printf("program:\n");
|
||||
dump_program(&state);
|
||||
printf("############################################################\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* figure out what sort of input we are dealing with: */
|
||||
if (!(check_extension(infile, ".rd") || check_extension(infile, ".rd.gz"))) {
|
||||
int ret;
|
||||
buf = calloc(1, 100 * 1024);
|
||||
ret = io_readn(io, buf, 100 * 1024);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: %m");
|
||||
return -1;
|
||||
}
|
||||
return disasm_a3xx(buf, ret/4, 0, stdout, gpu_id);
|
||||
}
|
||||
/* figure out what sort of input we are dealing with: */
|
||||
if (!(check_extension(infile, ".rd") || check_extension(infile, ".rd.gz"))) {
|
||||
int ret;
|
||||
buf = calloc(1, 100 * 1024);
|
||||
ret = io_readn(io, buf, 100 * 1024);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "error: %m");
|
||||
return -1;
|
||||
}
|
||||
return disasm_a3xx(buf, ret / 4, 0, stdout, gpu_id);
|
||||
}
|
||||
|
||||
while ((io_readn(io, &type, sizeof(type)) > 0) && (io_readn(io, &sz, 4) > 0)) {
|
||||
free(buf);
|
||||
while ((io_readn(io, &type, sizeof(type)) > 0) &&
|
||||
(io_readn(io, &sz, 4) > 0)) {
|
||||
free(buf);
|
||||
|
||||
/* note: allow hex dumps to go a bit past the end of the buffer..
|
||||
* might see some garbage, but better than missing the last few bytes..
|
||||
*/
|
||||
buf = calloc(1, sz + 3);
|
||||
io_readn(io, buf, sz);
|
||||
/* note: allow hex dumps to go a bit past the end of the buffer..
|
||||
* might see some garbage, but better than missing the last few bytes..
|
||||
*/
|
||||
buf = calloc(1, sz + 3);
|
||||
io_readn(io, buf, sz);
|
||||
|
||||
switch(type) {
|
||||
case RD_TEST:
|
||||
if (dump_full)
|
||||
printf("test: %s\n", (char *)buf);
|
||||
break;
|
||||
case RD_VERT_SHADER:
|
||||
printf("vertex shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_FRAG_SHADER:
|
||||
printf("fragment shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_PROGRAM: {
|
||||
struct state state = {
|
||||
.buf = buf,
|
||||
.sz = sz,
|
||||
};
|
||||
printf("############################################################\n");
|
||||
printf("program:\n");
|
||||
dump_program(&state);
|
||||
printf("############################################################\n");
|
||||
break;
|
||||
}
|
||||
case RD_GPU_ID:
|
||||
gpu_id = *((unsigned int *)buf);
|
||||
printf("gpu_id: %d\n", gpu_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (type) {
|
||||
case RD_TEST:
|
||||
if (dump_full)
|
||||
printf("test: %s\n", (char *)buf);
|
||||
break;
|
||||
case RD_VERT_SHADER:
|
||||
printf("vertex shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_FRAG_SHADER:
|
||||
printf("fragment shader:\n%s\n", (char *)buf);
|
||||
break;
|
||||
case RD_PROGRAM: {
|
||||
struct state state = {
|
||||
.buf = buf,
|
||||
.sz = sz,
|
||||
};
|
||||
printf(
|
||||
"############################################################\n");
|
||||
printf("program:\n");
|
||||
dump_program(&state);
|
||||
printf(
|
||||
"############################################################\n");
|
||||
break;
|
||||
}
|
||||
case RD_GPU_ID:
|
||||
gpu_id = *((unsigned int *)buf);
|
||||
printf("gpu_id: %d\n", gpu_id);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
io_close(io);
|
||||
io_close(io);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,52 +25,65 @@
|
|||
#define REDUMP_H_
|
||||
|
||||
enum rd_sect_type {
|
||||
RD_NONE,
|
||||
RD_TEST, /* ascii text */
|
||||
RD_CMD, /* ascii text */
|
||||
RD_GPUADDR, /* u32 gpuaddr, u32 size */
|
||||
RD_CONTEXT, /* raw dump */
|
||||
RD_CMDSTREAM, /* raw dump */
|
||||
RD_CMDSTREAM_ADDR, /* gpu addr of cmdstream */
|
||||
RD_PARAM, /* u32 param_type, u32 param_val, u32 bitlen */
|
||||
RD_FLUSH, /* empty, clear previous params */
|
||||
RD_PROGRAM, /* shader program, raw dump */
|
||||
RD_VERT_SHADER,
|
||||
RD_FRAG_SHADER,
|
||||
RD_BUFFER_CONTENTS,
|
||||
RD_GPU_ID,
|
||||
RD_NONE,
|
||||
RD_TEST, /* ascii text */
|
||||
RD_CMD, /* ascii text */
|
||||
RD_GPUADDR, /* u32 gpuaddr, u32 size */
|
||||
RD_CONTEXT, /* raw dump */
|
||||
RD_CMDSTREAM, /* raw dump */
|
||||
RD_CMDSTREAM_ADDR, /* gpu addr of cmdstream */
|
||||
RD_PARAM, /* u32 param_type, u32 param_val, u32 bitlen */
|
||||
RD_FLUSH, /* empty, clear previous params */
|
||||
RD_PROGRAM, /* shader program, raw dump */
|
||||
RD_VERT_SHADER,
|
||||
RD_FRAG_SHADER,
|
||||
RD_BUFFER_CONTENTS,
|
||||
RD_GPU_ID,
|
||||
};
|
||||
|
||||
/* RD_PARAM types: */
|
||||
enum rd_param_type {
|
||||
RD_PARAM_SURFACE_WIDTH,
|
||||
RD_PARAM_SURFACE_HEIGHT,
|
||||
RD_PARAM_SURFACE_PITCH,
|
||||
RD_PARAM_COLOR,
|
||||
RD_PARAM_BLIT_X,
|
||||
RD_PARAM_BLIT_Y,
|
||||
RD_PARAM_BLIT_WIDTH,
|
||||
RD_PARAM_BLIT_HEIGHT,
|
||||
RD_PARAM_BLIT_X2, /* BLIT_X + BLIT_WIDTH */
|
||||
RD_PARAM_BLIT_Y2, /* BLIT_Y + BLIT_WIDTH */
|
||||
RD_PARAM_SURFACE_WIDTH,
|
||||
RD_PARAM_SURFACE_HEIGHT,
|
||||
RD_PARAM_SURFACE_PITCH,
|
||||
RD_PARAM_COLOR,
|
||||
RD_PARAM_BLIT_X,
|
||||
RD_PARAM_BLIT_Y,
|
||||
RD_PARAM_BLIT_WIDTH,
|
||||
RD_PARAM_BLIT_HEIGHT,
|
||||
RD_PARAM_BLIT_X2, /* BLIT_X + BLIT_WIDTH */
|
||||
RD_PARAM_BLIT_Y2, /* BLIT_Y + BLIT_WIDTH */
|
||||
};
|
||||
|
||||
void rd_start(const char *name, const char *fmt, ...) __attribute__((weak));
|
||||
void rd_end(void) __attribute__((weak));
|
||||
void rd_write_section(enum rd_sect_type type, const void *buf, int sz) __attribute__((weak));
|
||||
void rd_write_section(enum rd_sect_type type, const void *buf, int sz)
|
||||
__attribute__((weak));
|
||||
|
||||
/* for code that should run with and without libwrap, use the following
|
||||
* macros which check if the fxns are present before calling
|
||||
*/
|
||||
#define RD_START(n,f,...) do { if (rd_start) rd_start(n,f,##__VA_ARGS__); } while (0)
|
||||
#define RD_END() do { if (rd_end) rd_end(); } while (0)
|
||||
#define RD_WRITE_SECTION(t,b,s) do { if (rd_write_section) rd_write_section(t,b,s); } while (0)
|
||||
#define RD_START(n, f, ...) \
|
||||
do { \
|
||||
if (rd_start) \
|
||||
rd_start(n, f, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#define RD_END() \
|
||||
do { \
|
||||
if (rd_end) \
|
||||
rd_end(); \
|
||||
} while (0)
|
||||
#define RD_WRITE_SECTION(t, b, s) \
|
||||
do { \
|
||||
if (rd_write_section) \
|
||||
rd_write_section(t, b, s); \
|
||||
} while (0)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
#endif
|
||||
#undef ALIGN
|
||||
#define ALIGN(v,a) (((v) + (a) - 1) & ~((a) - 1))
|
||||
#define ALIGN(v, a) (((v) + (a)-1) & ~((a)-1))
|
||||
|
||||
#define min(a, b) (((a) < (b)) ? (a) : (b))
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
|
|
|
@ -26,183 +26,198 @@
|
|||
* Rob Clark <robclark@freedesktop.org>
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rnnutil.h"
|
||||
|
||||
static struct rnndomain *finddom(struct rnn *rnn, uint32_t regbase)
|
||||
static struct rnndomain *
|
||||
finddom(struct rnn *rnn, uint32_t regbase)
|
||||
{
|
||||
if (rnndec_checkaddr(rnn->vc, rnn->dom[0], regbase, 0))
|
||||
return rnn->dom[0];
|
||||
return rnn->dom[1];
|
||||
if (rnndec_checkaddr(rnn->vc, rnn->dom[0], regbase, 0))
|
||||
return rnn->dom[0];
|
||||
return rnn->dom[1];
|
||||
}
|
||||
|
||||
void _rnn_init(struct rnn *rnn, int nocolor)
|
||||
void
|
||||
_rnn_init(struct rnn *rnn, int nocolor)
|
||||
{
|
||||
rnn_init();
|
||||
rnn_init();
|
||||
|
||||
rnn->db = rnn_newdb();
|
||||
rnn->vc_nocolor = rnndec_newcontext(rnn->db);
|
||||
rnn->vc_nocolor->colors = &envy_null_colors;
|
||||
if (nocolor) {
|
||||
rnn->vc = rnn->vc_nocolor;
|
||||
} else {
|
||||
rnn->vc = rnndec_newcontext(rnn->db);
|
||||
rnn->vc->colors = &envy_def_colors;
|
||||
}
|
||||
rnn->db = rnn_newdb();
|
||||
rnn->vc_nocolor = rnndec_newcontext(rnn->db);
|
||||
rnn->vc_nocolor->colors = &envy_null_colors;
|
||||
if (nocolor) {
|
||||
rnn->vc = rnn->vc_nocolor;
|
||||
} else {
|
||||
rnn->vc = rnndec_newcontext(rnn->db);
|
||||
rnn->vc->colors = &envy_def_colors;
|
||||
}
|
||||
}
|
||||
|
||||
struct rnn *rnn_new(int nocolor)
|
||||
struct rnn *
|
||||
rnn_new(int nocolor)
|
||||
{
|
||||
struct rnn *rnn = calloc(sizeof(*rnn), 1);
|
||||
struct rnn *rnn = calloc(sizeof(*rnn), 1);
|
||||
|
||||
if (!rnn)
|
||||
return NULL;
|
||||
if (!rnn)
|
||||
return NULL;
|
||||
|
||||
_rnn_init(rnn, nocolor);
|
||||
_rnn_init(rnn, nocolor);
|
||||
|
||||
return rnn;
|
||||
return rnn;
|
||||
}
|
||||
|
||||
static void init(struct rnn *rnn, char *file, char *domain)
|
||||
static void
|
||||
init(struct rnn *rnn, char *file, char *domain)
|
||||
{
|
||||
/* prepare rnn stuff for lookup */
|
||||
rnn_parsefile(rnn->db, file);
|
||||
rnn_prepdb(rnn->db);
|
||||
rnn->dom[0] = rnn_finddomain(rnn->db, domain);
|
||||
if ((strcmp(domain, "A2XX") == 0) || (strcmp(domain, "A3XX") == 0)) {
|
||||
rnn->dom[1] = rnn_finddomain(rnn->db, "AXXX");
|
||||
} else {
|
||||
rnn->dom[1] = rnn->dom[0];
|
||||
}
|
||||
if (!rnn->dom[0] && rnn->dom[1]) {
|
||||
fprintf(stderr, "Could not find domain %s in %s\n", domain, file);
|
||||
}
|
||||
rnn->variant = domain;
|
||||
/* prepare rnn stuff for lookup */
|
||||
rnn_parsefile(rnn->db, file);
|
||||
rnn_prepdb(rnn->db);
|
||||
rnn->dom[0] = rnn_finddomain(rnn->db, domain);
|
||||
if ((strcmp(domain, "A2XX") == 0) || (strcmp(domain, "A3XX") == 0)) {
|
||||
rnn->dom[1] = rnn_finddomain(rnn->db, "AXXX");
|
||||
} else {
|
||||
rnn->dom[1] = rnn->dom[0];
|
||||
}
|
||||
if (!rnn->dom[0] && rnn->dom[1]) {
|
||||
fprintf(stderr, "Could not find domain %s in %s\n", domain, file);
|
||||
}
|
||||
rnn->variant = domain;
|
||||
|
||||
rnndec_varadd(rnn->vc, "chip", domain);
|
||||
if (rnn->vc != rnn->vc_nocolor)
|
||||
rnndec_varadd(rnn->vc_nocolor, "chip", domain);
|
||||
if (rnn->db->estatus)
|
||||
errx(rnn->db->estatus, "failed to parse register database");
|
||||
rnndec_varadd(rnn->vc, "chip", domain);
|
||||
if (rnn->vc != rnn->vc_nocolor)
|
||||
rnndec_varadd(rnn->vc_nocolor, "chip", domain);
|
||||
if (rnn->db->estatus)
|
||||
errx(rnn->db->estatus, "failed to parse register database");
|
||||
}
|
||||
|
||||
void rnn_load_file(struct rnn *rnn, char *file, char *domain)
|
||||
void
|
||||
rnn_load_file(struct rnn *rnn, char *file, char *domain)
|
||||
{
|
||||
init(rnn, file, domain);
|
||||
init(rnn, file, domain);
|
||||
}
|
||||
|
||||
void rnn_load(struct rnn *rnn, const char *gpuname)
|
||||
void
|
||||
rnn_load(struct rnn *rnn, const char *gpuname)
|
||||
{
|
||||
if (strstr(gpuname, "a2")) {
|
||||
init(rnn, "adreno/a2xx.xml", "A2XX");
|
||||
} else if (strstr(gpuname, "a3")) {
|
||||
init(rnn, "adreno/a3xx.xml", "A3XX");
|
||||
} else if (strstr(gpuname, "a4")) {
|
||||
init(rnn, "adreno/a4xx.xml", "A4XX");
|
||||
} else if (strstr(gpuname, "a5")) {
|
||||
init(rnn, "adreno/a5xx.xml", "A5XX");
|
||||
} else if (strstr(gpuname, "a6")) {
|
||||
init(rnn, "adreno/a6xx.xml", "A6XX");
|
||||
}
|
||||
if (strstr(gpuname, "a2")) {
|
||||
init(rnn, "adreno/a2xx.xml", "A2XX");
|
||||
} else if (strstr(gpuname, "a3")) {
|
||||
init(rnn, "adreno/a3xx.xml", "A3XX");
|
||||
} else if (strstr(gpuname, "a4")) {
|
||||
init(rnn, "adreno/a4xx.xml", "A4XX");
|
||||
} else if (strstr(gpuname, "a5")) {
|
||||
init(rnn, "adreno/a5xx.xml", "A5XX");
|
||||
} else if (strstr(gpuname, "a6")) {
|
||||
init(rnn, "adreno/a6xx.xml", "A6XX");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t rnn_regbase(struct rnn *rnn, const char *name)
|
||||
uint32_t
|
||||
rnn_regbase(struct rnn *rnn, const char *name)
|
||||
{
|
||||
uint32_t regbase = rnndec_decodereg(rnn->vc_nocolor, rnn->dom[0], name);
|
||||
if (!regbase)
|
||||
regbase = rnndec_decodereg(rnn->vc_nocolor, rnn->dom[1], name);
|
||||
return regbase;
|
||||
uint32_t regbase = rnndec_decodereg(rnn->vc_nocolor, rnn->dom[0], name);
|
||||
if (!regbase)
|
||||
regbase = rnndec_decodereg(rnn->vc_nocolor, rnn->dom[1], name);
|
||||
return regbase;
|
||||
}
|
||||
|
||||
const char *rnn_regname(struct rnn *rnn, uint32_t regbase, int color)
|
||||
const char *
|
||||
rnn_regname(struct rnn *rnn, uint32_t regbase, int color)
|
||||
{
|
||||
static char buf[128];
|
||||
struct rnndecaddrinfo *info;
|
||||
static char buf[128];
|
||||
struct rnndecaddrinfo *info;
|
||||
|
||||
info = rnndec_decodeaddr(color ? rnn->vc : rnn->vc_nocolor,
|
||||
finddom(rnn, regbase), regbase, 0);
|
||||
if (info) {
|
||||
strcpy(buf, info->name);
|
||||
free(info->name);
|
||||
free(info);
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
info = rnndec_decodeaddr(color ? rnn->vc : rnn->vc_nocolor,
|
||||
finddom(rnn, regbase), regbase, 0);
|
||||
if (info) {
|
||||
strcpy(buf, info->name);
|
||||
free(info->name);
|
||||
free(info);
|
||||
return buf;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rnndecaddrinfo *rnn_reginfo(struct rnn *rnn, uint32_t regbase)
|
||||
struct rnndecaddrinfo *
|
||||
rnn_reginfo(struct rnn *rnn, uint32_t regbase)
|
||||
{
|
||||
return rnndec_decodeaddr(rnn->vc, finddom(rnn, regbase), regbase, 0);
|
||||
return rnndec_decodeaddr(rnn->vc, finddom(rnn, regbase), regbase, 0);
|
||||
}
|
||||
|
||||
const char *rnn_enumname(struct rnn *rnn, const char *name, uint32_t val)
|
||||
const char *
|
||||
rnn_enumname(struct rnn *rnn, const char *name, uint32_t val)
|
||||
{
|
||||
return rnndec_decode_enum(rnn->vc, name, val);
|
||||
return rnndec_decode_enum(rnn->vc, name, val);
|
||||
}
|
||||
|
||||
static struct rnndelem *regelem(struct rnndomain *domain, const char *name)
|
||||
static struct rnndelem *
|
||||
regelem(struct rnndomain *domain, const char *name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < domain->subelemsnum; i++) {
|
||||
struct rnndelem *elem = domain->subelems[i];
|
||||
if (!strcmp(elem->name, name))
|
||||
return elem;
|
||||
}
|
||||
return NULL;
|
||||
int i;
|
||||
for (i = 0; i < domain->subelemsnum; i++) {
|
||||
struct rnndelem *elem = domain->subelems[i];
|
||||
if (!strcmp(elem->name, name))
|
||||
return elem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup rnndelem by name: */
|
||||
struct rnndelem *rnn_regelem(struct rnn *rnn, const char *name)
|
||||
struct rnndelem *
|
||||
rnn_regelem(struct rnn *rnn, const char *name)
|
||||
{
|
||||
struct rnndelem *elem = regelem(rnn->dom[0], name);
|
||||
if (elem)
|
||||
return elem;
|
||||
return regelem(rnn->dom[1], name);
|
||||
struct rnndelem *elem = regelem(rnn->dom[0], name);
|
||||
if (elem)
|
||||
return elem;
|
||||
return regelem(rnn->dom[1], name);
|
||||
}
|
||||
|
||||
static struct rnndelem *regoff(struct rnndomain *domain, uint32_t offset)
|
||||
static struct rnndelem *
|
||||
regoff(struct rnndomain *domain, uint32_t offset)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < domain->subelemsnum; i++) {
|
||||
struct rnndelem *elem = domain->subelems[i];
|
||||
if (elem->offset == offset)
|
||||
return elem;
|
||||
}
|
||||
return NULL;
|
||||
int i;
|
||||
for (i = 0; i < domain->subelemsnum; i++) {
|
||||
struct rnndelem *elem = domain->subelems[i];
|
||||
if (elem->offset == offset)
|
||||
return elem;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Lookup rnndelem by offset: */
|
||||
struct rnndelem *rnn_regoff(struct rnn *rnn, uint32_t offset)
|
||||
struct rnndelem *
|
||||
rnn_regoff(struct rnn *rnn, uint32_t offset)
|
||||
{
|
||||
struct rnndelem *elem = regoff(rnn->dom[0], offset);
|
||||
if (elem)
|
||||
return elem;
|
||||
return regoff(rnn->dom[1], offset);
|
||||
struct rnndelem *elem = regoff(rnn->dom[0], offset);
|
||||
if (elem)
|
||||
return elem;
|
||||
return regoff(rnn->dom[1], offset);
|
||||
}
|
||||
|
||||
enum rnnttype rnn_decodelem(struct rnn *rnn, struct rnntypeinfo *info,
|
||||
uint32_t regval, union rnndecval *val)
|
||||
enum rnnttype
|
||||
rnn_decodelem(struct rnn *rnn, struct rnntypeinfo *info, uint32_t regval,
|
||||
union rnndecval *val)
|
||||
{
|
||||
val->u = regval;
|
||||
switch (info->type) {
|
||||
case RNN_TTYPE_INLINE_ENUM:
|
||||
case RNN_TTYPE_ENUM:
|
||||
case RNN_TTYPE_HEX:
|
||||
case RNN_TTYPE_INT:
|
||||
case RNN_TTYPE_UINT:
|
||||
case RNN_TTYPE_FLOAT:
|
||||
case RNN_TTYPE_BOOLEAN:
|
||||
return info->type;
|
||||
case RNN_TTYPE_FIXED:
|
||||
case RNN_TTYPE_UFIXED:
|
||||
/* TODO */
|
||||
default:
|
||||
return RNN_TTYPE_INVALID;
|
||||
}
|
||||
val->u = regval;
|
||||
switch (info->type) {
|
||||
case RNN_TTYPE_INLINE_ENUM:
|
||||
case RNN_TTYPE_ENUM:
|
||||
case RNN_TTYPE_HEX:
|
||||
case RNN_TTYPE_INT:
|
||||
case RNN_TTYPE_UINT:
|
||||
case RNN_TTYPE_FLOAT:
|
||||
case RNN_TTYPE_BOOLEAN:
|
||||
return info->type;
|
||||
case RNN_TTYPE_FIXED:
|
||||
case RNN_TTYPE_UFIXED:
|
||||
/* TODO */
|
||||
default:
|
||||
return RNN_TTYPE_INVALID;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,24 +29,24 @@
|
|||
#ifndef RNNUTIL_H_
|
||||
#define RNNUTIL_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "rnn.h"
|
||||
#include "rnndec.h"
|
||||
|
||||
struct rnn {
|
||||
struct rnndb *db;
|
||||
struct rnndeccontext *vc, *vc_nocolor;
|
||||
struct rnndomain *dom[2];
|
||||
const char *variant;
|
||||
struct rnndb *db;
|
||||
struct rnndeccontext *vc, *vc_nocolor;
|
||||
struct rnndomain *dom[2];
|
||||
const char *variant;
|
||||
};
|
||||
|
||||
union rnndecval {
|
||||
uint32_t u;
|
||||
int32_t i;
|
||||
float f;
|
||||
uint32_t u;
|
||||
int32_t i;
|
||||
float f;
|
||||
};
|
||||
|
||||
void _rnn_init(struct rnn *rnn, int nocolor);
|
||||
|
@ -61,6 +61,6 @@ const char *rnn_enumname(struct rnn *rnn, const char *name, uint32_t val);
|
|||
struct rnndelem *rnn_regelem(struct rnn *rnn, const char *name);
|
||||
struct rnndelem *rnn_regoff(struct rnn *rnn, uint32_t offset);
|
||||
enum rnnttype rnn_decodelem(struct rnn *rnn, struct rnntypeinfo *info,
|
||||
uint32_t regval, union rnndecval *val);
|
||||
uint32_t regval, union rnndecval *val);
|
||||
|
||||
#endif /* RNNUTIL_H_ */
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -31,7 +31,6 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// XXX make script support optional
|
||||
#define ENABLE_SCRIPTING 1
|
||||
|
||||
|
@ -53,7 +52,8 @@ struct rnn;
|
|||
struct rnndomain;
|
||||
__attribute__((weak))
|
||||
void script_packet(uint32_t *dwords, uint32_t sizedwords,
|
||||
struct rnn *rnn, struct rnndomain *dom);
|
||||
struct rnn *rnn,
|
||||
struct rnndomain *dom);
|
||||
|
||||
/* maybe at some point it is interesting to add additional script
|
||||
* hooks for CP_EVENT_WRITE, etc?
|
||||
|
@ -72,5 +72,4 @@ void script_finish(void);
|
|||
// TODO no-op stubs..
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* SCRIPT_H_ */
|
||||
|
|
|
@ -30,175 +30,177 @@
|
|||
|
||||
/* old-style program binary XOR'd ascii w/ 0xff */
|
||||
#ifndef ASCII_XOR
|
||||
# define ASCII_XOR 0
|
||||
#define ASCII_XOR 0
|
||||
#endif
|
||||
|
||||
static inline const char *tab(int lvl)
|
||||
static inline const char *
|
||||
tab(int lvl)
|
||||
{
|
||||
const char *TAB = "\t\t\t\t\t\t\t\t\0";
|
||||
return &TAB[strlen(TAB) - lvl];
|
||||
const char *TAB = "\t\t\t\t\t\t\t\t\0";
|
||||
return &TAB[strlen(TAB) - lvl];
|
||||
}
|
||||
|
||||
/* convert float to dword */
|
||||
static inline float d2f(uint32_t d)
|
||||
static inline float
|
||||
d2f(uint32_t d)
|
||||
{
|
||||
union {
|
||||
float f;
|
||||
uint32_t d;
|
||||
} u = {
|
||||
.d = d,
|
||||
};
|
||||
return u.f;
|
||||
union {
|
||||
float f;
|
||||
uint32_t d;
|
||||
} u = {
|
||||
.d = d,
|
||||
};
|
||||
return u.f;
|
||||
}
|
||||
|
||||
static inline void dump_hex(const void *buf, int sz)
|
||||
static inline void
|
||||
dump_hex(const void *buf, int sz)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
int i = 0;
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
int i = 0;
|
||||
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
|
||||
printf((i % 8) ? " " : "\t");
|
||||
printf((i % 8) ? " " : "\t");
|
||||
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
|
||||
printf("%08x", d);
|
||||
printf("%08x", d);
|
||||
|
||||
if ((i % 8) == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
if ((i % 8) == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i % 8) {
|
||||
printf("\n");
|
||||
}
|
||||
if (i % 8) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
dump_float(const void *buf, int sz)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz - 3;
|
||||
int i = 0;
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz - 3;
|
||||
int i = 0;
|
||||
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
|
||||
printf((i % 8) ? " " : "\t");
|
||||
printf((i % 8) ? " " : "\t");
|
||||
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
|
||||
printf("%8f", d2f(d));
|
||||
printf("%8f", d2f(d));
|
||||
|
||||
if ((i % 8) == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
if ((i % 8) == 7) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i % 8) {
|
||||
printf("\n");
|
||||
}
|
||||
if (i % 8) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
#define is_ok_ascii(c) \
|
||||
(isascii(c) && ((c == '\t') || !iscntrl(c)))
|
||||
#define is_ok_ascii(c) (isascii(c) && ((c == '\t') || !iscntrl(c)))
|
||||
|
||||
static inline void
|
||||
clean_ascii(char *buf, int sz)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
while (ptr < end) {
|
||||
*(ptr++) ^= ASCII_XOR;
|
||||
}
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
while (ptr < end) {
|
||||
*(ptr++) ^= ASCII_XOR;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
dump_ascii(const void *buf, int sz)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
printf("\t");
|
||||
while (ptr < end) {
|
||||
uint8_t c = *(ptr++) ^ ASCII_XOR;
|
||||
if (c == '\n') {
|
||||
printf("\n\t");
|
||||
} else if (c == '\0') {
|
||||
printf("\n\t-----------------------------------\n\t");
|
||||
} else if (is_ok_ascii(c)) {
|
||||
printf("%c", c);
|
||||
} else {
|
||||
printf("?");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
printf("\t");
|
||||
while (ptr < end) {
|
||||
uint8_t c = *(ptr++) ^ ASCII_XOR;
|
||||
if (c == '\n') {
|
||||
printf("\n\t");
|
||||
} else if (c == '\0') {
|
||||
printf("\n\t-----------------------------------\n\t");
|
||||
} else if (is_ok_ascii(c)) {
|
||||
printf("%c", c);
|
||||
} else {
|
||||
printf("?");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static inline void
|
||||
dump_hex_ascii(const void *buf, int sz, int level)
|
||||
{
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
uint8_t *ascii = ptr;
|
||||
int i = 0;
|
||||
uint8_t *ptr = (uint8_t *)buf;
|
||||
uint8_t *end = ptr + sz;
|
||||
uint8_t *ascii = ptr;
|
||||
int i = 0;
|
||||
|
||||
printf("%s-----------------------------------------------\n", tab(level));
|
||||
printf("%s%d (0x%x) bytes\n", tab(level), sz, sz);
|
||||
printf("%s-----------------------------------------------\n", tab(level));
|
||||
printf("%s%d (0x%x) bytes\n", tab(level), sz, sz);
|
||||
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
while (ptr < end) {
|
||||
uint32_t d = 0;
|
||||
|
||||
if (i % 4) {
|
||||
printf(" ");
|
||||
} else {
|
||||
printf("%s%06x: ", tab(level), (uint32_t)(ptr - (uint8_t *)buf));
|
||||
}
|
||||
if (i % 4) {
|
||||
printf(" ");
|
||||
} else {
|
||||
printf("%s%06x: ", tab(level), (uint32_t)(ptr - (uint8_t *)buf));
|
||||
}
|
||||
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
d |= *(ptr++) << 0;
|
||||
d |= *(ptr++) << 8;
|
||||
d |= *(ptr++) << 16;
|
||||
d |= *(ptr++) << 24;
|
||||
|
||||
printf("%08x", d);
|
||||
printf("%08x", d);
|
||||
|
||||
if ((i % 4) == 3) {
|
||||
int j;
|
||||
printf("\t|");
|
||||
for (j = 0; j < 16; j++) {
|
||||
uint8_t c = *(ascii++);
|
||||
c ^= ASCII_XOR;
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
if ((i % 4) == 3) {
|
||||
int j;
|
||||
printf("\t|");
|
||||
for (j = 0; j < 16; j++) {
|
||||
uint8_t c = *(ascii++);
|
||||
c ^= ASCII_XOR;
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i % 4) {
|
||||
for (int j = 4 - (i % 4); j > 0; j--) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("\t|");
|
||||
while (ascii < end) {
|
||||
uint8_t c = *(ascii++);
|
||||
c ^= ASCII_XOR;
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
if (i % 4) {
|
||||
for (int j = 4 - (i % 4); j > 0; j--) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("\t|");
|
||||
while (ascii < end) {
|
||||
uint8_t c = *(ascii++);
|
||||
c ^= ASCII_XOR;
|
||||
printf("%c", (isascii(c) && !iscntrl(c)) ? c : '.');
|
||||
}
|
||||
printf("|\n");
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __UTIL_H__ */
|
||||
|
|
Loading…
Reference in New Issue