// File: coduin[P]epiphany-bin-info/epiphany-bin-info.cpp
// Function: parseFile(char*, unsigned long)
int parseFile(char* buffer, size_t fsize) {
    Elf32_Ehdr* ehdr = (Elf32_Ehdr*)buffer;
    Elf32_Phdr* phdr;
    Elf32_Shdr* shdr;
    const char* strtab;

    // Array of program headers
    phdr = (Elf32_Phdr*)&buffer[ehdr->e_phoff];
    // Array of section headers
    shdr = (Elf32_Shdr*)&buffer[ehdr->e_shoff];

    // Check if header matches Epiphany signature
    // Check if all section headers point to something within file buffer
    if (fsize < sizeof(Elf32_Ehdr) || !isEpiphanyElf(ehdr) ||
        (ehdr->e_phoff + ehdr->e_phnum * sizeof(Elf32_Phdr) > fsize ||
         (ehdr->e_shoff + ehdr->e_shnum * sizeof(Elf32_Shdr)) > fsize) ||
        (ehdr->e_shstrndx >= ehdr->e_shnum) ||
        ((shdr[ehdr->e_shstrndx].sh_offset + shdr[ehdr->e_shstrndx].sh_size) >
         fsize)) {
        return 1;
    }

    // By the check above, we can be sure that we stay inside the buffer
    parseProgramHeader(phdr, ehdr->e_phnum);

    strtab = &buffer[shdr[ehdr->e_shstrndx].sh_offset];
    parseSections(shdr, ehdr->e_shnum, strtab, shdr[ehdr->e_shstrndx].sh_size);

    for (size_t i = 0; i < ehdr->e_shnum; i++) {
        if (shdr[i].sh_type == SHT_SYMTAB) {
            Elf32_Sym* symbol = (Elf32_Sym*)&buffer[shdr[i].sh_offset];
            size_t count = shdr[i].sh_size / shdr[i].sh_entsize;

            // Check if all symbols are within file buffer
            if (shdr[i].sh_offset + count * sizeof(Elf32_Sym) > fsize)
                return 1;

            // Section with symbol names
            Elf32_Shdr* symstrhdr = &shdr[shdr[i].sh_link];

            // Check if the symbol name table is within file buffer
            if (shdr[i].sh_link >= ehdr->e_shnum)
                return 1;
            if (symstrhdr->sh_offset + symstrhdr->sh_size > fsize)
                return 1;

            const char* symstr = &buffer[symstrhdr->sh_offset];

            parseSymbolTable(symbol, count, symstr, symstrhdr->sh_size);
        }
    }

    return 0;
}

// Assembly:
subq $0x68, %rsp
movq %rdi, 0x58(%rsp)
movq %rsi, 0x50(%rsp)
movq 0x58(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x58(%rsp), %rax
movq 0x48(%rsp), %rcx
movl 0x1c(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x40(%rsp)
movq 0x58(%rsp), %rax
movq 0x48(%rsp), %rcx
movl 0x20(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x38(%rsp)
cmpq $0x34, 0x50(%rsp)
jb 0x387e
movq 0x48(%rsp), %rdi
callq 0x2850
testb $0x1, %al
jne 0x37f1
jmp 0x387e
movq 0x48(%rsp), %rax
movl 0x1c(%rax), %eax
movq 0x48(%rsp), %rcx
movzwl 0x2c(%rcx), %ecx
shlq $0x5, %rcx
addq %rcx, %rax
cmpq 0x50(%rsp), %rax
ja 0x387e
movq 0x48(%rsp), %rax
movl 0x20(%rax), %eax
movq 0x48(%rsp), %rcx
movzwl 0x30(%rcx), %ecx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
cmpq 0x50(%rsp), %rax
ja 0x387e
movq 0x48(%rsp), %rax
movzwl 0x32(%rax), %eax
movq 0x48(%rsp), %rcx
movzwl 0x30(%rcx), %ecx
cmpl %ecx, %eax
jge 0x387e
movq 0x38(%rsp), %rax
movq 0x48(%rsp), %rcx
movzwl 0x32(%rcx), %ecx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movl 0x10(%rax), %eax
movq 0x38(%rsp), %rcx
movq 0x48(%rsp), %rdx
movzwl 0x32(%rdx), %edx
imulq $0x28, %rdx, %rdx
addq %rdx, %rcx
addl 0x14(%rcx), %eax
movl %eax, %eax
cmpq 0x50(%rsp), %rax
jbe 0x388b
movl $0x1, 0x64(%rsp)
jmp 0x3a68
movq 0x40(%rsp), %rdi
movq 0x48(%rsp), %rax
movzwl 0x2c(%rax), %eax
movl %eax, %esi
callq 0x28e0
movq 0x58(%rsp), %rax
movq 0x38(%rsp), %rcx
movq 0x48(%rsp), %rdx
movzwl 0x32(%rdx), %edx
imulq $0x28, %rdx, %rdx
addq %rdx, %rcx
movl 0x10(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x30(%rsp)
movq 0x38(%rsp), %rdi
movq 0x48(%rsp), %rax
movzwl 0x30(%rax), %eax
movl %eax, %esi
movq 0x30(%rsp), %rdx
movq 0x38(%rsp), %rax
movq 0x48(%rsp), %rcx
movzwl 0x32(%rcx), %ecx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movl 0x14(%rax), %eax
movl %eax, %ecx
callq 0x2e30
movq $0x0, 0x28(%rsp)
movq 0x28(%rsp), %rax
movq 0x48(%rsp), %rcx
movzwl 0x30(%rcx), %ecx
cmpq %rcx, %rax
jae 0x3a60
movq 0x38(%rsp), %rax
imulq $0x28, 0x28(%rsp), %rcx
addq %rcx, %rax
cmpl $0x2, 0x4(%rax)
jne 0x3a4b
movq 0x58(%rsp), %rax
movq 0x38(%rsp), %rcx
imulq $0x28, 0x28(%rsp), %rdx
addq %rdx, %rcx
movl 0x10(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x20(%rsp)
movq 0x38(%rsp), %rax
imulq $0x28, 0x28(%rsp), %rcx
addq %rcx, %rax
movl 0x14(%rax), %eax
movq 0x38(%rsp), %rcx
imulq $0x28, 0x28(%rsp), %rdx
addq %rdx, %rcx
xorl %edx, %edx
divl 0x24(%rcx)
movl %eax, %eax
movq %rax, 0x18(%rsp)
movq 0x38(%rsp), %rax
imulq $0x28, 0x28(%rsp), %rcx
addq %rcx, %rax
movl 0x10(%rax), %eax
movq 0x18(%rsp), %rcx
shlq $0x4, %rcx
addq %rcx, %rax
cmpq 0x50(%rsp), %rax
jbe 0x39ab
movl $0x1, 0x64(%rsp)
jmp 0x3a68
movq 0x38(%rsp), %rax
movq 0x38(%rsp), %rcx
imulq $0x28, 0x28(%rsp), %rdx
addq %rdx, %rcx
movl 0x18(%rcx), %ecx
imulq $0x28, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x10(%rsp)
movq 0x38(%rsp), %rax
imulq $0x28, 0x28(%rsp), %rcx
addq %rcx, %rax
movl 0x18(%rax), %eax
movq 0x48(%rsp), %rcx
movzwl 0x30(%rcx), %ecx
cmpl %ecx, %eax
jb 0x39f5
movl $0x1, 0x64(%rsp)
jmp 0x3a68
movq 0x10(%rsp), %rax
movl 0x10(%rax), %eax
movq 0x10(%rsp), %rcx
addl 0x14(%rcx), %eax
movl %eax, %eax
cmpq 0x50(%rsp), %rax
jbe 0x3a18
movl $0x1, 0x64(%rsp)
jmp 0x3a68
movq 0x58(%rsp), %rax
movq 0x10(%rsp), %rcx
movl 0x10(%rcx), %ecx
addq %rcx, %rax
movq %rax, 0x8(%rsp)
movq 0x20(%rsp), %rdi
movq 0x18(%rsp), %rsi
movq 0x8(%rsp), %rdx
movq 0x10(%rsp), %rax
movl 0x14(%rax), %eax
movl %eax, %ecx
callq 0x3020
jmp 0x3a4d
movq 0x28(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x28(%rsp)
jmp 0x3902
movl $0x0, 0x64(%rsp)
movl 0x64(%rsp), %eax
addq $0x68, %rsp
retq
nopw %cs:(%rax,%rax)