mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 18:18:06 +02:00
ac/parse_ib: Annotate addresses with UAF/OOB info
Reviewed-by: Marek Olšák <marek.olsak@amd.com> Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/27451>
This commit is contained in:
parent
badd2131b5
commit
fea21e5649
5 changed files with 133 additions and 40 deletions
|
|
@ -40,7 +40,13 @@ struct ac_wave_info {
|
|||
bool matched; /* whether the wave is used by a currently-bound shader */
|
||||
};
|
||||
|
||||
typedef void *(*ac_debug_addr_callback)(void *data, uint64_t addr);
|
||||
struct ac_addr_info {
|
||||
void *cpu_addr;
|
||||
bool valid;
|
||||
bool use_after_free;
|
||||
};
|
||||
|
||||
typedef void (*ac_debug_addr_callback)(void *data, uint64_t addr, struct ac_addr_info *info);
|
||||
|
||||
/* ac_debug.c */
|
||||
const struct si_reg *ac_find_register(enum amd_gfx_level gfx_level, enum radeon_family family,
|
||||
|
|
|
|||
|
|
@ -242,7 +242,9 @@ static void ac_parse_set_reg_pairs_packed_packet(FILE *f, unsigned count, unsign
|
|||
}
|
||||
}
|
||||
|
||||
static void print_addr(struct ac_ib_parser *ib, const char *name, uint64_t addr)
|
||||
#define AC_ADDR_SIZE_NOT_MEMORY 0xFFFFFFFF
|
||||
|
||||
static void print_addr(struct ac_ib_parser *ib, const char *name, uint64_t addr, uint32_t size)
|
||||
{
|
||||
FILE *f = ib->f;
|
||||
|
||||
|
|
@ -251,7 +253,27 @@ static void print_addr(struct ac_ib_parser *ib, const char *name, uint64_t addr)
|
|||
O_COLOR_YELLOW, name,
|
||||
O_COLOR_RESET);
|
||||
|
||||
fprintf(f, "0x%llx\n", (unsigned long long)addr);
|
||||
fprintf(f, "0x%llx", (unsigned long long)addr);
|
||||
|
||||
if (ib->addr_callback && size != AC_ADDR_SIZE_NOT_MEMORY) {
|
||||
struct ac_addr_info addr_info;
|
||||
ib->addr_callback(ib->addr_callback_data, addr, &addr_info);
|
||||
|
||||
struct ac_addr_info addr_info2 = addr_info;
|
||||
if (size)
|
||||
ib->addr_callback(ib->addr_callback_data, addr + size - 1, &addr_info2);
|
||||
|
||||
uint32_t invalid_count = !addr_info.valid + !addr_info2.valid;
|
||||
|
||||
if (addr_info.use_after_free && addr_info2.use_after_free)
|
||||
fprintf(f, " used after free");
|
||||
else if (invalid_count == 2)
|
||||
fprintf(f, " invalid");
|
||||
else if (invalid_count == 1)
|
||||
fprintf(f, " out of bounds");
|
||||
}
|
||||
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
|
||||
static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
||||
|
|
@ -374,7 +396,7 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
print_named_value(f, "EVENT_INDEX", (event_dw >> 8) & 0xf, 4);
|
||||
print_named_value(f, "INV_L2", (event_dw >> 20) & 0x1, 1);
|
||||
if (count > 0)
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib), 0);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
@ -389,10 +411,24 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
print_named_value(f, "TCL1_ACTION_ENA", (event_dw >> 16) & 0x1, 1);
|
||||
print_named_value(f, "TC_ACTION_ENA", (event_dw >> 17) & 0x1, 1);
|
||||
uint64_t addr = ac_ib_get64(ib);
|
||||
print_addr(ib, "ADDR", ac_sext_addr48(addr));
|
||||
uint32_t data_sel = addr >> 61;
|
||||
uint32_t data_size;
|
||||
switch (data_sel) {
|
||||
case EOP_DATA_SEL_VALUE_32BIT:
|
||||
data_size = 4;
|
||||
break;
|
||||
case EOP_DATA_SEL_VALUE_64BIT:
|
||||
case EOP_DATA_SEL_TIMESTAMP:
|
||||
data_size = 8;
|
||||
break;
|
||||
default:
|
||||
data_size = AC_ADDR_SIZE_NOT_MEMORY;
|
||||
break;
|
||||
}
|
||||
print_addr(ib, "ADDR", ac_sext_addr48(addr), data_size);
|
||||
print_named_value(f, "DST_SEL", (addr >> 48) & 0x3, 2);
|
||||
print_named_value(f, "INT_SEL", (addr >> 56) & 0x7, 3);
|
||||
print_named_value(f, "DATA_SEL", addr >> 61, 3);
|
||||
print_named_value(f, "DATA_SEL", data_sel, 3);
|
||||
print_named_value(f, "DATA_LO", ac_ib_get(ib), 32);
|
||||
print_named_value(f, "DATA_HI", ac_ib_get(ib), 32);
|
||||
break;
|
||||
|
|
@ -439,7 +475,7 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
break;
|
||||
case PKT3_DRAW_INDEX_2:
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_028A78_VGT_DMA_MAX_SIZE, ac_ib_get(ib), ~0);
|
||||
print_addr(ib, "INDEX_ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "INDEX_ADDR", ac_ib_get64(ib), 0);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_030930_VGT_NUM_INDICES, ac_ib_get(ib), ~0);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_0287F0_VGT_DRAW_INITIATOR, ac_ib_get(ib), ~0);
|
||||
break;
|
||||
|
|
@ -449,12 +485,18 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
case PKT3_NUM_INSTANCES:
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_030934_VGT_NUM_INSTANCES, ac_ib_get(ib), ~0);
|
||||
break;
|
||||
case PKT3_WRITE_DATA:
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_370_CONTROL, ac_ib_get(ib), ~0);
|
||||
print_addr(ib, "DST_ADDR", ac_ib_get64(ib));
|
||||
while (ib->cur_dw <= first_dw + count)
|
||||
case PKT3_WRITE_DATA: {
|
||||
uint32_t control = ac_ib_get(ib);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_370_CONTROL, control, ~0);
|
||||
uint32_t dst_sel = G_370_DST_SEL(control);
|
||||
uint64_t addr = ac_ib_get64(ib);
|
||||
uint32_t dword_count = first_dw + count + 1 - ib->cur_dw;
|
||||
bool writes_memory = dst_sel == V_370_MEM_GRBM || dst_sel == V_370_TC_L2 || dst_sel == V_370_MEM;
|
||||
print_addr(ib, "DST_ADDR", addr, writes_memory ? dword_count * 4 : AC_ADDR_SIZE_NOT_MEMORY);
|
||||
for (uint32_t i = 0; i < dword_count; i++)
|
||||
print_data_dword(f, ac_ib_get(ib), "data");
|
||||
break;
|
||||
}
|
||||
case PKT3_CP_DMA:
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_410_CP_DMA_WORD0, ac_ib_get(ib), ~0);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_411_CP_DMA_WORD1, ac_ib_get(ib), ~0);
|
||||
|
|
@ -462,12 +504,30 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
ac_dump_reg(f, ib->gfx_level, ib->family, R_413_CP_DMA_WORD3, ac_ib_get(ib), ~0);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_415_COMMAND, ac_ib_get(ib), ~0);
|
||||
break;
|
||||
case PKT3_DMA_DATA:
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_501_DMA_DATA_WORD0, ac_ib_get(ib), ~0);
|
||||
print_addr(ib, "SRC_ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "DST_ADDR", ac_ib_get64(ib));
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_415_COMMAND, ac_ib_get(ib), ~0);
|
||||
case PKT3_DMA_DATA: {
|
||||
uint32_t header = ac_ib_get(ib);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_501_DMA_DATA_WORD0, header, ~0);
|
||||
|
||||
uint64_t src_addr = ac_ib_get64(ib);
|
||||
uint64_t dst_addr = ac_ib_get64(ib);
|
||||
|
||||
uint32_t command = ac_ib_get(ib);
|
||||
uint32_t size = ib->gfx_level >= GFX9 ? G_415_BYTE_COUNT_GFX9(command)
|
||||
: G_415_BYTE_COUNT_GFX6(command);
|
||||
|
||||
uint32_t src_sel = G_501_SRC_SEL(header);
|
||||
bool src_mem = (src_sel == V_501_SRC_ADDR && G_415_SAS(command) == V_415_MEMORY) ||
|
||||
src_sel == V_411_SRC_ADDR_TC_L2;
|
||||
|
||||
uint32_t dst_sel = G_501_DST_SEL(header);
|
||||
bool dst_mem = (dst_sel == V_501_DST_ADDR && G_415_DAS(command) == V_415_MEMORY) ||
|
||||
dst_sel == V_411_DST_ADDR_TC_L2;
|
||||
|
||||
print_addr(ib, "SRC_ADDR", src_addr, src_mem ? size : AC_ADDR_SIZE_NOT_MEMORY);
|
||||
print_addr(ib, "DST_ADDR", dst_addr, dst_mem ? size : AC_ADDR_SIZE_NOT_MEMORY);
|
||||
ac_dump_reg(f, ib->gfx_level, ib->family, R_415_COMMAND, command, ~0);
|
||||
break;
|
||||
}
|
||||
case PKT3_INDIRECT_BUFFER_SI:
|
||||
case PKT3_INDIRECT_BUFFER_CONST:
|
||||
case PKT3_INDIRECT_BUFFER: {
|
||||
|
|
@ -482,7 +542,9 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
break;
|
||||
|
||||
uint64_t addr = ((uint64_t)base_hi_dw << 32) | base_lo_dw;
|
||||
void *data = ib->addr_callback(ib->addr_callback_data, addr);
|
||||
struct ac_addr_info addr_info;
|
||||
ib->addr_callback(ib->addr_callback_data, addr, &addr_info);
|
||||
void *data = addr_info.cpu_addr;
|
||||
if (!data)
|
||||
break;
|
||||
|
||||
|
|
@ -568,14 +630,14 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
case PKT3_SET_BASE:
|
||||
tmp = ac_ib_get(ib);
|
||||
print_string_value(f, "BASE_INDEX", tmp == 1 ? "INDIRECT_BASE" : COLOR_RED "UNKNOWN" COLOR_RESET);
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib), 0);
|
||||
break;
|
||||
case PKT3_PRIME_UTCL2:
|
||||
tmp = ac_ib_get(ib);
|
||||
print_named_value(f, "CACHE_PERM[rwx]", tmp & 0x7, 3);
|
||||
print_string_value(f, "PRIME_MODE", tmp & 0x8 ? "WAIT_FOR_XACK" : "DONT_WAIT_FOR_XACK");
|
||||
print_named_value(f, "ENGINE_SEL", tmp >> 30, 2);
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib), 0);
|
||||
print_named_value(f, "REQUESTED_PAGES", ac_ib_get(ib), 14);
|
||||
break;
|
||||
case PKT3_ATOMIC_MEM:
|
||||
|
|
@ -584,7 +646,7 @@ static void ac_parse_packet3(FILE *f, uint32_t header, struct ac_ib_parser *ib,
|
|||
print_named_value(f, "COMMAND", (tmp >> 8) & 0xf, 4);
|
||||
print_named_value(f, "CACHE_POLICY", (tmp >> 25) & 0x3, 2);
|
||||
print_named_value(f, "ENGINE_SEL", tmp >> 30, 2);
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib));
|
||||
print_addr(ib, "ADDR", ac_ib_get64(ib), 8);
|
||||
print_named_value(f, "SRC_DATA_LO", ac_ib_get(ib), 32);
|
||||
print_named_value(f, "SRC_DATA_HI", ac_ib_get(ib), 32);
|
||||
print_named_value(f, "CMP_DATA_LO", ac_ib_get(ib), 32);
|
||||
|
|
|
|||
|
|
@ -254,15 +254,6 @@ radv_amdgpu_winsys_bo_virtual_bind(struct radeon_winsys *_ws, struct radeon_wins
|
|||
return VK_SUCCESS;
|
||||
}
|
||||
|
||||
struct radv_amdgpu_winsys_bo_log {
|
||||
struct list_head list;
|
||||
uint64_t va;
|
||||
uint64_t size;
|
||||
uint64_t timestamp; /* CPU timestamp */
|
||||
uint8_t is_virtual : 1;
|
||||
uint8_t destroyed : 1;
|
||||
};
|
||||
|
||||
static void
|
||||
radv_amdgpu_log_bo(struct radv_amdgpu_winsys *ws, struct radv_amdgpu_winsys_bo *bo, bool destroyed)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,6 +31,15 @@
|
|||
|
||||
#include "radv_amdgpu_winsys.h"
|
||||
|
||||
struct radv_amdgpu_winsys_bo_log {
|
||||
struct list_head list;
|
||||
uint64_t va;
|
||||
uint64_t size;
|
||||
uint64_t timestamp; /* CPU timestamp */
|
||||
uint8_t is_virtual : 1;
|
||||
uint8_t destroyed : 1;
|
||||
};
|
||||
|
||||
struct radv_amdgpu_map_range {
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
|
|
|
|||
|
|
@ -1339,19 +1339,40 @@ out:
|
|||
return result;
|
||||
}
|
||||
|
||||
static void *
|
||||
radv_amdgpu_winsys_get_cpu_addr(void *_cs, uint64_t addr)
|
||||
static void
|
||||
radv_amdgpu_winsys_get_cpu_addr(void *_cs, uint64_t addr, struct ac_addr_info *info)
|
||||
{
|
||||
struct radv_amdgpu_cs *cs = (struct radv_amdgpu_cs *)_cs;
|
||||
void *ret = NULL;
|
||||
|
||||
memset(info, 0, sizeof(struct ac_addr_info));
|
||||
|
||||
if (cs->ws->debug_log_bos) {
|
||||
u_rwlock_rdlock(&cs->ws->log_bo_list_lock);
|
||||
list_for_each_entry_rev (struct radv_amdgpu_winsys_bo_log, bo_log, &cs->ws->log_bo_list, list) {
|
||||
if (addr >= bo_log->va && addr - bo_log->va < bo_log->size) {
|
||||
info->use_after_free = bo_log->destroyed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
u_rwlock_rdunlock(&cs->ws->log_bo_list_lock);
|
||||
}
|
||||
|
||||
if (info->use_after_free)
|
||||
return;
|
||||
|
||||
info->valid = !cs->ws->debug_all_bos;
|
||||
|
||||
for (unsigned i = 0; i < cs->num_ib_buffers; ++i) {
|
||||
struct radv_amdgpu_ib *ib = &cs->ib_buffers[i];
|
||||
struct radv_amdgpu_winsys_bo *bo = (struct radv_amdgpu_winsys_bo *)ib->bo;
|
||||
|
||||
if (addr >= bo->base.va && addr - bo->base.va < bo->size) {
|
||||
if (amdgpu_bo_cpu_map(bo->bo, &ret) == 0)
|
||||
return (char *)ret + (addr - bo->base.va);
|
||||
if (amdgpu_bo_cpu_map(bo->bo, &ret) == 0) {
|
||||
info->cpu_addr = (char *)ret + (addr - bo->base.va);
|
||||
info->valid = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
u_rwlock_rdlock(&cs->ws->global_bo_list.lock);
|
||||
|
|
@ -1360,13 +1381,15 @@ radv_amdgpu_winsys_get_cpu_addr(void *_cs, uint64_t addr)
|
|||
if (addr >= bo->base.va && addr - bo->base.va < bo->size) {
|
||||
if (amdgpu_bo_cpu_map(bo->bo, &ret) == 0) {
|
||||
u_rwlock_rdunlock(&cs->ws->global_bo_list.lock);
|
||||
return (char *)ret + (addr - bo->base.va);
|
||||
info->valid = true;
|
||||
info->cpu_addr = (char *)ret + (addr - bo->base.va);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
u_rwlock_rdunlock(&cs->ws->global_bo_list.lock);
|
||||
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1378,14 +1401,16 @@ radv_amdgpu_winsys_cs_dump(struct radeon_cmdbuf *_cs, FILE *file, const int *tra
|
|||
|
||||
if (cs->use_ib) {
|
||||
struct radv_amdgpu_cs_ib_info ib_info = radv_amdgpu_cs_ib_to_info(cs, cs->ib_buffers[0]);
|
||||
void *ib = radv_amdgpu_winsys_get_cpu_addr(cs, ib_info.ib_mc_address);
|
||||
assert(ib);
|
||||
|
||||
struct ac_addr_info addr_info;
|
||||
radv_amdgpu_winsys_get_cpu_addr(cs, ib_info.ib_mc_address, &addr_info);
|
||||
assert(addr_info.cpu_addr);
|
||||
|
||||
if (type == RADV_CS_DUMP_TYPE_IBS) {
|
||||
ac_parse_ib(file, ib, cs->ib_buffers[0].cdw, trace_ids, trace_id_count, "main IB", ws->info.gfx_level,
|
||||
ws->info.family, cs->hw_ip, radv_amdgpu_winsys_get_cpu_addr, cs);
|
||||
ac_parse_ib(file, addr_info.cpu_addr, cs->ib_buffers[0].cdw, trace_ids, trace_id_count, "main IB",
|
||||
ws->info.gfx_level, ws->info.family, cs->hw_ip, radv_amdgpu_winsys_get_cpu_addr, cs);
|
||||
} else {
|
||||
uint32_t *ib_dw = ib;
|
||||
uint32_t *ib_dw = addr_info.cpu_addr;
|
||||
ac_gather_context_rolls(file, &ib_dw, &cs->ib_buffers[0].cdw, 1, &ws->info);
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue