mirror of
https://github.com/joel16/VitaShell.git
synced 2024-11-23 03:39:39 +00:00
338 lines
8.4 KiB
C
338 lines
8.4 KiB
C
/*
|
|
VitaShell
|
|
Copyright (C) 2015-2018, TheFloW
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "main.h"
|
|
#include "file.h"
|
|
#include "utils.h"
|
|
#include "theme.h"
|
|
#include "coredump.h"
|
|
#include "elf.h"
|
|
|
|
typedef struct {
|
|
int unk_0; // 0x00
|
|
int size; // 0x04
|
|
int unk_8; // 0x08
|
|
char name[16]; // 0x0C
|
|
int unk_1C; // 0x1C
|
|
int num; // 0x20
|
|
} InfoHeader; // 0x24
|
|
|
|
typedef struct {
|
|
int unk; // 0x00
|
|
int perm; // 0x04
|
|
uint32_t addr; // 0x08
|
|
uint32_t size; // 0x0C
|
|
int unk_10; // 0x10
|
|
} ModuleSegment; // 0x14
|
|
|
|
typedef struct {
|
|
int unk_0; // 0x00
|
|
int uid; // 0x04
|
|
int sdk_version; // 0x08
|
|
int version; // 0xC
|
|
int unk_10; // 0x10
|
|
int addr_14; // 0x14
|
|
int unk_18; // 0x18
|
|
int addr_1C; // 0x1C
|
|
int unk_20; // 0x20
|
|
char name[28]; // 0x24
|
|
int unk_44; // 0x40
|
|
int unk_48; // 0x44 2
|
|
uint32_t nid; // 0x48
|
|
int num_segments; // 0x4C
|
|
ModuleSegment segments[1]; // 0x50
|
|
uint32_t addr[4]; // 0x78
|
|
} ModuleInfoOneSegment; // 0x88
|
|
|
|
typedef struct {
|
|
int unk_0; // 0x00
|
|
int uid; // 0x04
|
|
int sdk_version; // 0x08
|
|
int version; // 0xC
|
|
int unk_10; // 0x10
|
|
int addr_14; // 0x14
|
|
int unk_18; // 0x18
|
|
int addr_1C; // 0x1C
|
|
int unk_20; // 0x20
|
|
char name[28]; // 0x24
|
|
int unk_44; // 0x40
|
|
int unk_48; // 0x44 2
|
|
uint32_t nid; // 0x48
|
|
int num_segments; // 0x4C
|
|
ModuleSegment segments[2]; // 0x50
|
|
uint32_t addr[4]; // 0x78
|
|
} ModuleInfoTwoSegment; // 0x88
|
|
|
|
typedef struct {
|
|
int unk; // 0x00
|
|
int uid; // 0x04
|
|
char name[32]; // 0x08
|
|
int type; // 0x28
|
|
uint32_t vaddr; // 0x2C
|
|
uint32_t vsize; // 0x30
|
|
int unk_34;
|
|
int unk_38;
|
|
int unk_3C;
|
|
int unk_40;
|
|
int unk_44;
|
|
} MemBlkInfo; // 0x48
|
|
|
|
typedef struct {
|
|
int size; // 0x00
|
|
int uid; // 0x04
|
|
char name[32]; // 0x08
|
|
int unk_28; // 0x28
|
|
int unk_2C[18]; // 0x2C
|
|
int cause; // 0x74
|
|
int unk_78[9]; // 0x78
|
|
uint32_t pc; // 0x9C
|
|
int unk_A0[10]; // 0xA0
|
|
} ThreadInfo; // 0xC8
|
|
|
|
typedef struct {
|
|
int size; // 0x00
|
|
int uid; // 0x04
|
|
uint32_t regs[16]; // 0x08
|
|
int unk[75]; // 0x48
|
|
uint32_t bad_v_addr; // 0x174
|
|
} ThreadRegInfo; // 0x178
|
|
|
|
// ARM registers
|
|
static char *regnames[] = { "a1", "a2", "a3", "a4",
|
|
"v1", "v2", "v3", "v4",
|
|
"v5", "v6", "v7", "v8",
|
|
"ip", "sp", "lr", "pc" };
|
|
|
|
static char *getCauseName(int cause) {
|
|
switch (cause) {
|
|
case 0x30002:
|
|
return "Undefined instruction exception";
|
|
|
|
case 0x30003:
|
|
return "Prefetch abort exception";
|
|
|
|
case 0x30004:
|
|
return "Data abort exception";
|
|
|
|
case 0x60080:
|
|
return "Division by zero";
|
|
}
|
|
|
|
return "Unknown cause";
|
|
}
|
|
|
|
static int decompressGzip(uint8_t *dst, int size_dst, uint8_t *src, int size_src) {
|
|
z_stream z;
|
|
memset(&z, 0, sizeof(z_stream));
|
|
|
|
z.avail_in = size_src;
|
|
z.next_in = src;
|
|
z.avail_out = size_dst;
|
|
z.next_out = dst;
|
|
|
|
if (inflateInit2(&z, 15 + 32) != Z_OK)
|
|
return -1;
|
|
|
|
if (inflate(&z, Z_FINISH) != Z_STREAM_END) {
|
|
inflateEnd(&z);
|
|
return -2;
|
|
}
|
|
|
|
inflateEnd(&z);
|
|
return z.total_out;
|
|
}
|
|
|
|
int coredumpViewer(const char *file) {
|
|
void *buffer = memalign(4096, BIG_BUFFER_SIZE);
|
|
if (!buffer)
|
|
return VITASHELL_ERROR_NO_MEMORY;
|
|
|
|
int size = ReadFile(file, buffer, BIG_BUFFER_SIZE);
|
|
|
|
if (*(uint16_t *)buffer == 0x8B1F) {
|
|
void *out_buf = memalign(4096, BIG_BUFFER_SIZE);
|
|
if (!out_buf) {
|
|
free(buffer);
|
|
return VITASHELL_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
int out_size = decompressGzip(out_buf, BIG_BUFFER_SIZE, buffer, size);
|
|
if (out_size < 0) {
|
|
free(out_buf);
|
|
free(buffer);
|
|
return -3;
|
|
}
|
|
|
|
memcpy(buffer, out_buf, out_size);
|
|
|
|
free(out_buf);
|
|
}
|
|
|
|
Elf32_Ehdr *ehdr = (Elf32_Ehdr *)buffer;
|
|
Elf32_Phdr *phdr = (Elf32_Phdr *)((uint32_t)buffer + ehdr->e_phoff);
|
|
|
|
if (ehdr->e_ident[EI_MAG0] != ELFMAG0 ||
|
|
ehdr->e_ident[EI_MAG1] != ELFMAG1 ||
|
|
ehdr->e_ident[EI_MAG2] != ELFMAG2 ||
|
|
ehdr->e_ident[EI_MAG3] != ELFMAG3) {
|
|
free(buffer);
|
|
return VITASHELL_ERROR_INVALID_MAGIC;
|
|
}
|
|
|
|
char thname[32], modname[32];
|
|
SceUID thid = -1, modid = -1;
|
|
uint32_t epc = -1, rel_epc = -1;
|
|
int cause = -1;
|
|
uint32_t bad_v_addr = -1;
|
|
uint32_t regs[16];
|
|
|
|
int i;
|
|
for (i = 0; i < ehdr->e_phnum; i++) {
|
|
if (phdr[i].p_type == 0x4) {
|
|
void *program = malloc(phdr[i].p_filesz);
|
|
if (!program) {
|
|
free(buffer);
|
|
return VITASHELL_ERROR_NO_MEMORY;
|
|
}
|
|
|
|
memcpy(program, buffer + phdr[i].p_offset, phdr[i].p_filesz);
|
|
|
|
InfoHeader *info = (InfoHeader *)program;
|
|
|
|
if (strcmp(info->name, "THREAD_INFO") == 0) {
|
|
int j;
|
|
for (j = 0; j < ((InfoHeader *)program)->num; j++) {
|
|
ThreadInfo *thread_info = (ThreadInfo *)(program + sizeof(InfoHeader));
|
|
if (thread_info[j].cause != 0) {
|
|
strcpy(thname, thread_info[j].name);
|
|
thid = thread_info[j].uid;
|
|
epc = thread_info[j].pc;
|
|
cause = thread_info[j].cause;
|
|
break;
|
|
}
|
|
}
|
|
} else if (strcmp(info->name, "THREAD_REG_INFO") == 0) {
|
|
int j;
|
|
for (j = 0; j < ((InfoHeader *)program)->num; j++) {
|
|
ThreadRegInfo *thread_reg_info = (ThreadRegInfo *)(program + sizeof(InfoHeader));
|
|
|
|
if (thread_reg_info[j].uid == thid) {
|
|
memcpy(®s, thread_reg_info[j].regs, sizeof(regs));
|
|
bad_v_addr = thread_reg_info[j].bad_v_addr;
|
|
break;
|
|
}
|
|
}
|
|
} else if (strcmp(info->name, "MODULE_INFO") == 0) {
|
|
uint32_t offset = 0;
|
|
|
|
int j;
|
|
for (j = 0; j < ((InfoHeader *)program)->num; j++) {
|
|
ModuleInfoTwoSegment *mod_info = (ModuleInfoTwoSegment *)(program + sizeof(InfoHeader) + offset);
|
|
|
|
if (epc >= mod_info->segments[0].addr && epc < (mod_info->segments[0].addr+mod_info->segments[0].size)) {
|
|
strcpy(modname, mod_info->name);
|
|
modid = mod_info->uid;
|
|
rel_epc = epc - mod_info->segments[0].addr;
|
|
break;
|
|
}
|
|
|
|
if (mod_info->num_segments == 2) {
|
|
offset += sizeof(ModuleInfoTwoSegment);
|
|
} else {
|
|
offset += sizeof(ModuleInfoOneSegment);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(program);
|
|
}
|
|
}
|
|
|
|
while (1) {
|
|
readPad();
|
|
|
|
if (pressed_pad[PAD_CANCEL]) {
|
|
break;
|
|
}
|
|
|
|
// Start drawing
|
|
startDrawing(bg_text_image);
|
|
|
|
// Draw shell info
|
|
drawShellInfo(file);
|
|
|
|
float y = START_Y;
|
|
|
|
// Exception
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Exception");
|
|
pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, getCauseName(cause));
|
|
y += FONT_Y_SPACE;
|
|
|
|
// Thread ID
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread ID");
|
|
pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", thid);
|
|
y += FONT_Y_SPACE;
|
|
|
|
// Thread name
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Thread name");
|
|
pgf_draw_text(COREDUMP_INFO_X, y, TEXT_COLOR, thname);
|
|
y += FONT_Y_SPACE;
|
|
|
|
// EPC
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "EPC");
|
|
if (rel_epc != -1)
|
|
pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "%s + 0x%08X", modname, rel_epc);
|
|
else
|
|
pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", epc);
|
|
y += FONT_Y_SPACE;
|
|
|
|
// Cause
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "Cause");
|
|
pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", cause);
|
|
y += FONT_Y_SPACE;
|
|
|
|
// BadVAddr
|
|
pgf_draw_text(SHELL_MARGIN_X, y, TEXT_COLOR, "BadVAddr");
|
|
pgf_draw_textf(COREDUMP_INFO_X, y, TEXT_COLOR, "0x%08X", bad_v_addr);
|
|
y += FONT_Y_SPACE;
|
|
|
|
// Registers
|
|
int j;
|
|
for (j = 0; j < 4; j++) {
|
|
float x = SHELL_MARGIN_X;
|
|
|
|
int i;
|
|
for (i = 0; i < 4; i++) {
|
|
pgf_draw_textf(x, y, TEXT_COLOR, "%s:", regnames[j * 4 + i]);
|
|
x += COREDUMP_REGISTER_NAME_SPACE;
|
|
|
|
pgf_draw_textf(x, y, TEXT_COLOR, "0x%08X", regs[j * 4 + i]);
|
|
x += COREDUMP_REGISTER_SPACE;
|
|
}
|
|
|
|
y += FONT_Y_SPACE;
|
|
}
|
|
|
|
// End drawing
|
|
endDrawing();
|
|
}
|
|
|
|
free(buffer);
|
|
return 0;
|
|
}
|