#include <iostream>
#include <fstream>
#include <vector>
#include <regex>
#include <elf.h>
#include <string>
#include <cassert>

#include "ui.h"

using namespace std;

// memset( 0x0000000000100000 0 4096 -1 )=0x0000000000100000~0xffffffff80027b2d
// !memset( 0xffff800073ccb1a0 0 2432 )=0xffff800073ccb1a0~0xffffffff8009aadb
// memcpy( 0x0000000000102000 0x0000000000100000 4096 -1 )=0x0000000000102000~0xffffffff8007477f
// !memcpy( 0x0000000000102000 0x0000000000100000 4096 )=0x0000000000102000~0xffffffff80027d15
// memmove( 0x0000000001cd2000 0x0000000001caa000 1 -1 )=0x0000000001cd2000~0xffffffff8000f458
// RequestPages( 2 )=0x0000000000100000~0xffffffff80027b03
// FreePage( 0x00000000020bb000 )~0xffffffff8002f654
// !FreePages( 0x0000000001d50000 1001 )~0xffffffff80033201
// malloc( 32 )=0x0000000001319000~0xffffffff80028faa
// free( 0x000000000131d000 )~0xffffffff80029ab3
// new( 32 )=0x0000000001319000~0xffffffff80027f71
// new[]( 14 )=0x000000000131b000~0xffffffff800c23f4
// delete( 0x00000000019ed000 4 )~0xffffffff800ba9fd
// delete[]( 0x000000000131d000 )~0xffffffff800d6851
// Rsrv( 0x0x0000000000000000 0x0x0000000000000000 )

struct memset_t
{
    uintptr_t dest;
    int val;
    size_t len;
    size_t slen;

    uintptr_t ret;
    uintptr_t caller;
};

struct memcpy_t
{
    uintptr_t dest;
    uintptr_t src;
    size_t len;
    size_t slen;

    uintptr_t ret;
    uintptr_t caller;
};

struct memmove_t
{
    uintptr_t dest;
    uintptr_t src;
    size_t len;
    size_t slen;

    uintptr_t ret;
    uintptr_t caller;
};

struct ReqPages_t
{
    size_t pages;

    uintptr_t ret;
    uintptr_t caller;
};

struct FreePage_t
{
    uintptr_t ptr;

    uintptr_t ret;
    uintptr_t caller;
};

struct FreePages_t
{
    uintptr_t ptr;
    size_t pages;

    uintptr_t ret;
    uintptr_t caller;
};

struct malloc_t
{
    size_t size;

    uintptr_t ret;
    uintptr_t caller;
};

struct free_t
{
    uintptr_t ptr;

    uintptr_t ret;
    uintptr_t caller;
};

struct new_t
{
    size_t size;

    uintptr_t ret;
    uintptr_t caller;
};

struct new_array_t
{
    size_t size;

    uintptr_t ret;
    uintptr_t caller;
};

struct delete_t
{
    uintptr_t ptr;
    size_t size;

    uintptr_t ret;
    uintptr_t caller;
};

struct delete_array_t
{
    uintptr_t ptr;

    uintptr_t ret;
    uintptr_t caller;
};

struct rsv_t
{
    uintptr_t ptr;
    size_t size;
};

enum mem_collection_enum_t
{
    memset_e,
    memcpy_e,
    memmove_e,
    ReqPages_e,
    FreePage_e,
    FreePages_e,
    malloc_e,
    free_e,
    new_e,
    new_array_e,
    delete_e,
    delete_array_e,
    rsv_e
};

struct mem_collection_t
{
    mem_collection_enum_t type;
    memset_t memset;
    memcpy_t memcpy;
    memmove_t memmove;
    ReqPages_t ReqPages;
    FreePage_t FreePage;
    FreePages_t FreePages;
    malloc_t malloc;
    free_t free;
    new_t new_;
    new_array_t new_array;
    delete_t delete_;
    delete_array_t delete_array;
    rsv_t rsv;
};

namespace SymbolResolver
{
    class Symbols
    {
    private:
        struct SymbolTable
        {
            uintptr_t Address;
            char *FunctionName;
        };

        SymbolTable SymTable[0x10000];
        uintptr_t TotalEntries = 0;

    public:
        Symbols(uintptr_t ImageAddress);
        ~Symbols();
        const char *GetSymbolFromAddress(uintptr_t Address);
        void AddSymbol(uintptr_t Address, const char *Name);
    };
}

namespace SymbolResolver
{
    Symbols::Symbols(uintptr_t ImageAddress)
    {
        printf("Solving symbols for address: %#lx\n", ImageAddress);
        Elf64_Ehdr *Header = (Elf64_Ehdr *)ImageAddress;
        if (Header->e_ident[0] != 0x7F &&
            Header->e_ident[1] != 'E' &&
            Header->e_ident[2] != 'L' &&
            Header->e_ident[3] != 'F')
        {
            printf("Invalid ELF header\n");
            return;
        }
        Elf64_Shdr *ElfSections = (Elf64_Shdr *)(ImageAddress + Header->e_shoff);
        Elf64_Sym *ElfSymbols = nullptr;
        char *strtab = nullptr;

        for (uint16_t i = 0; i < Header->e_shnum; i++)
            switch (ElfSections[i].sh_type)
            {
            case SHT_SYMTAB:
                ElfSymbols = (Elf64_Sym *)(ImageAddress + ElfSections[i].sh_offset);
                this->TotalEntries = ElfSections[i].sh_size / sizeof(Elf64_Sym);
                if (this->TotalEntries >= 0x10000)
                    this->TotalEntries = 0x10000 - 1;

                printf("Symbol table found, %ld entries\n", this->TotalEntries);
                break;
            case SHT_STRTAB:
                if (Header->e_shstrndx == i)
                {
                    printf("String table found, %ld entries\n", ElfSections[i].sh_size);
                }
                else
                {
                    strtab = (char *)(ImageAddress + ElfSections[i].sh_offset);
                    printf("String table found, %ld entries\n", ElfSections[i].sh_size);
                }
                break;
            }

        if (ElfSymbols != nullptr && strtab != nullptr)
        {
            uintptr_t Index, MinimumIndex;
            for (uintptr_t i = 0; i < this->TotalEntries - 1; i++)
            {
                MinimumIndex = i;
                for (Index = i + 1; Index < this->TotalEntries; Index++)
                    if (ElfSymbols[Index].st_value < ElfSymbols[MinimumIndex].st_value)
                        MinimumIndex = Index;
                Elf64_Sym tmp = ElfSymbols[MinimumIndex];
                ElfSymbols[MinimumIndex] = ElfSymbols[i];
                ElfSymbols[i] = tmp;
            }

            while (ElfSymbols[0].st_value == 0)
            {
                ElfSymbols++;
                this->TotalEntries--;
            }

            static int once = 0;
            printf("Symbol table loaded, %ld entries (%ldKB)\n", this->TotalEntries, (this->TotalEntries * sizeof(SymbolTable) / 1024));
            for (uintptr_t i = 0, g = this->TotalEntries; i < g; i++)
            {
                this->SymTable[i].Address = ElfSymbols[i].st_value;
                this->SymTable[i].FunctionName = &strtab[ElfSymbols[i].st_name];
                if (once)
                    printf("Symbol %ld: %#lx %s\n", i, this->SymTable[i].Address, this->SymTable[i].FunctionName);
            }

            if (!once)
                once++;
        }
    }

    Symbols::~Symbols() {}

    const char *Symbols::GetSymbolFromAddress(uintptr_t Address)
    {
        Symbols::SymbolTable Result{0, (char *)"<unknown>"};
        for (uintptr_t i = 0; i < this->TotalEntries; i++)
            if (this->SymTable[i].Address <= Address && this->SymTable[i].Address > Result.Address)
                Result = this->SymTable[i];
        return Result.FunctionName;
    }

    void Symbols::AddSymbol(uintptr_t Address, const char *Name)
    {
        if (this->TotalEntries >= 0x10000)
        {
            printf("Symbol table is full\n");
            return;
        }

        this->SymTable[this->TotalEntries].Address = Address;
        strcpy(this->SymTable[this->TotalEntries].FunctionName, Name);
        this->TotalEntries++;
    }
}

SymbolResolver::Symbols *Symbols = nullptr;

void load_kernel_symbols()
{
    const char *kernel_path = kernel_path_inputbox->value();
    FILE *kernel_file = fopen(kernel_path, "rb");
    if (!kernel_file)
    {
        cout << "Unable to open file" << endl;
        return;
    }

    struct stat kernel_stat_buf;
    int rc = stat(kernel_path, &kernel_stat_buf);
    if (rc != 0)
    {
        cout << "Unable to stat file" << endl;
        return;
    }
    void *kernel_data = malloc(kernel_stat_buf.st_size);
    rc = fread(kernel_data, 1, kernel_stat_buf.st_size, kernel_file);
    if (rc != kernel_stat_buf.st_size)
    {
        cout << "Unable to read file" << endl;
        return;
    }
    fclose(kernel_file);
    Symbols = new SymbolResolver::Symbols((uintptr_t)kernel_data);
}

void main_thread()
{
    /* TODO: This is not complete
        - Detect where is a memory corruption or leak
        - Detect misuses of memset/memcpy/memmove
        - Print on screen the results
     */

    printf("Hello, world!\n");

    regex pattern_memset("memset\\(\\s*(\\S+)\\s+(\\d+)\\s+(\\d+)\\s+(\\S+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_memset_not("memset\\(\\s*(\\S+)\\s+(\\d+)\\s+(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_memcpy("memcpy\\(\\s*(\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(\\S+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_memcpy_not("memcpy\\(\\s*(\\S+)\\s+(\\S+)\\s+(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_memmove("memmove\\(\\s*(\\S+)\\s+(\\S+)\\s+(\\d+)\\s+(\\S+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_ReqPages("RequestPages\\(\\s*(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_FreePage("FreePage\\(\\s*(\\S+)\\s*\\)~(\\S+)");
    regex pattern_FreePages("!FreePages\\(\\s*(\\S+)\\s+(\\d+)\\s*\\)~(\\S+)");
    regex pattern_malloc("malloc\\(\\s*(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_free("free\\(\\s*(\\S+)\\s*\\)~(\\S+)");
    regex pattern_new("new\\(\\s*(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_new_array("new\\[\\]\\(\\s*(\\d+)\\s*\\)=(\\S+)~(\\S+)");
    regex pattern_delete("delete\\(\\s*(\\S+)\\s+(\\d+)\\s*\\)~(\\S+)");
    regex pattern_delete_array("delete\\[\\]\\(\\s*(\\S+)\\s*\\)~(\\S+)");
    regex pattern_Rsrv("Rsrv\\(\\s*(\\S+)\\s+(\\S+)\\s*\\)~(\\S+)");

    vector<mem_collection_t> mem_collection_list;

    string line;

    ifstream input_file(file_path_inputbox->value());
    if (!input_file.is_open())
    {
        cout << "Unable to open file" << endl;
        return;
    }

    printf("Loading kernel symbols\n");
    load_kernel_symbols();

    while (getline(input_file, line))
    {
        smatch match;
        if (regex_search(line, match, pattern_memset) ||
            regex_search(line, match, pattern_memset_not))
        {
            memset_t memset = {
                .dest = strtoull(match[1].str().c_str(), nullptr, 16),
                .val = stoi(match[2].str()),
                .len = stoul(match[3].str()),
                .slen = stoul(match[4].str()),
                .ret = strtoull(match[5].str().c_str(), nullptr, 16),
                .caller = strtoull(match[6].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = memset_e,
                .memset = memset,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_memcpy) ||
                 regex_search(line, match, pattern_memcpy_not))
        {
            memcpy_t memcpy = {
                .dest = strtoull(match[1].str().c_str(), nullptr, 16),
                .src = strtoull(match[2].str().c_str(), nullptr, 16),
                .len = stoul(match[3].str()),
                .slen = stoul(match[4].str()),
                .ret = strtoull(match[5].str().c_str(), nullptr, 16),
                .caller = strtoull(match[6].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = memcpy_e,
                .memcpy = memcpy,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_memmove))
        {
            memmove_t memmove = {
                .dest = strtoull(match[1].str().c_str(), nullptr, 16),
                .src = strtoull(match[2].str().c_str(), nullptr, 16),
                .len = stoul(match[3].str()),
                .slen = stoul(match[4].str()),
                .ret = strtoull(match[5].str().c_str(), nullptr, 16),
                .caller = strtoull(match[6].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = memmove_e,
                .memmove = memmove,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_ReqPages))
        {
            ReqPages_t ReqPages = {
                .pages = stoul(match[1].str()),
                .ret = strtoull(match[2].str().c_str(), nullptr, 16),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = ReqPages_e,
                .ReqPages = ReqPages,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_FreePage))
        {
            FreePage_t FreePage = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .caller = strtoull(match[2].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = FreePage_e,
                .FreePage = FreePage,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_FreePages))
        {
            FreePages_t FreePages = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .pages = stoul(match[2].str()),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = FreePages_e,
                .FreePages = FreePages,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_malloc))
        {
            malloc_t malloc = {
                .size = stoul(match[1].str()),
                .ret = strtoull(match[2].str().c_str(), nullptr, 16),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = malloc_e,
                .malloc = malloc,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_free))
        {
            free_t free = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .caller = strtoull(match[2].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = free_e,
                .free = free,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_new))
        {
            new_t new_ = {
                .size = stoul(match[1].str()),
                .ret = strtoull(match[2].str().c_str(), nullptr, 16),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = new_e,
                .new_ = new_,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_new_array))
        {
            new_array_t new_array = {
                .size = stoul(match[1].str()),
                .ret = strtoull(match[2].str().c_str(), nullptr, 16),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = new_array_e,
                .new_array = new_array,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_delete))
        {
            delete_t delete_ = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .size = stoul(match[2].str()),
                .caller = strtoull(match[3].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = delete_e,
                .delete_ = delete_,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_delete_array))
        {
            delete_array_t delete_array = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .caller = strtoull(match[2].str().c_str(), nullptr, 16),
            };
            mem_collection_t mem_c = {
                .type = delete_array_e,
                .delete_array = delete_array,
            };
            mem_collection_list.push_back(mem_c);
        }
        else if (regex_search(line, match, pattern_Rsrv))
        {
            rsv_t Rsrv = {
                .ptr = strtoull(match[1].str().c_str(), nullptr, 16),
                .size = stoul(match[2].str()),
            };
            mem_collection_t mem_c = {
                .type = rsv_e,
                .rsv = Rsrv,
            };
            mem_collection_list.push_back(mem_c);
        }
    }

    printf("Printing collected memory operations (%lu)\n", mem_collection_list.size());
    assert(mem_collection_list.size() > 0);

    if (false) /* We don't need this right now. */
        for (const auto &m : mem_collection_list)
        {
            switch (m.type)
            {
            case memset_e:
                printf("memset( %#lx %#x %lu %#lx )=%#lx~%#lx(%s)\n",
                       m.memset.dest, m.memset.val, m.memset.len, m.memset.slen,
                       m.memset.ret, m.memset.caller, Symbols->GetSymbolFromAddress(m.memset.caller));
                break;
            case memcpy_e:
                printf("memcpy( %#lx %#lx %lu %#lx )=%#lx~%#lx(%s)\n",
                       m.memcpy.dest, m.memcpy.src, m.memcpy.len, m.memcpy.slen,
                       m.memcpy.ret, m.memcpy.caller, Symbols->GetSymbolFromAddress(m.memcpy.caller));
                break;
            case memmove_e:
                printf("memmove( %#lx %#lx %lu %#lx )=%#lx~%#lx(%s)\n",
                       m.memmove.dest, m.memmove.src, m.memmove.len, m.memmove.slen,
                       m.memmove.ret, m.memmove.caller, Symbols->GetSymbolFromAddress(m.memmove.caller));
                break;
            case ReqPages_e:
                printf("RequestPages( %lu )=%#lx~%#lx(%s)\n",
                       m.ReqPages.pages, m.ReqPages.ret, m.ReqPages.caller, Symbols->GetSymbolFromAddress(m.ReqPages.caller));
                break;
            case FreePage_e:
                printf("FreePage( %#lx )=%#lx~%#lx(%s)\n",
                       m.FreePage.ptr, m.FreePage.caller, m.FreePage.caller, Symbols->GetSymbolFromAddress(m.FreePage.caller));
                break;
            case FreePages_e:
                printf("FreePages( %#lx %lu )=%#lx~%#lx(%s)\n",
                       m.FreePages.ptr, m.FreePages.pages, m.FreePages.caller, m.FreePages.caller, Symbols->GetSymbolFromAddress(m.FreePages.caller));
                break;
            case malloc_e:
                printf("malloc( %lu )=%#lx~%#lx(%s)\n",
                       m.malloc.size, m.malloc.ret, m.malloc.caller, Symbols->GetSymbolFromAddress(m.malloc.caller));
                break;
            case free_e:
                printf("free( %#lx )=%#lx~%#lx(%s)\n",
                       m.free.ptr, m.free.caller, m.free.caller, Symbols->GetSymbolFromAddress(m.free.caller));
                break;
            case new_e:
                printf("new( %lu )=%#lx~%#lx(%s)\n",
                       m.new_.size, m.new_.ret, m.new_.caller, Symbols->GetSymbolFromAddress(m.new_.caller));
                break;
            case new_array_e:
                printf("new[]( %lu )=%#lx~%#lx(%s)\n",
                       m.new_array.size, m.new_array.ret, m.new_array.caller, Symbols->GetSymbolFromAddress(m.new_array.caller));
                break;
            case delete_e:
                printf("delete( %#lx %lu )=%#lx~%#lx(%s)\n",
                       m.delete_.ptr, m.delete_.size, m.delete_.caller, m.delete_.caller, Symbols->GetSymbolFromAddress(m.delete_.caller));
                break;
            case delete_array_e:
                printf("delete[]( %#lx )=%#lx~%#lx(%s)\n",
                       m.delete_array.ptr, m.delete_array.caller, m.delete_array.caller, Symbols->GetSymbolFromAddress(m.delete_array.caller));
                break;
            case rsv_e:
                printf("rsv( %#lx %lu )\n",
                       m.rsv.ptr, m.rsv.size);
                break;
            default:
                printf("unknown type %d\n", m.type);
                break;
            }
        }

    int64_t AllocatedPages = 0;
    int64_t AllocatedMemory = 0;

    for (const auto &m : mem_collection_list)
    {
        switch (m.type)
        {
        case ReqPages_e:
        {
            AllocatedPages += m.ReqPages.pages;
            break;
        }
        case FreePage_e:
        {
            bool found = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == ReqPages_e && c.ReqPages.ret == m.FreePage.ptr)
                {
                    if (c.ReqPages.pages != 1)
                        printf("FreePage( %#lx )=%#lx~%#lx(%s) found in ReqPages but pages != 1 (%lu)\n",
                               m.FreePage.ptr, m.FreePage.caller, m.FreePage.caller, Symbols->GetSymbolFromAddress(m.FreePage.caller), c.ReqPages.pages);
                    found = true;
                    break;
                }
            }

            if (!found)
                printf("FreePage( %#lx )=%#lx~%#lx(%s) not found in ReqPages\n",
                       m.FreePage.ptr, m.FreePage.caller, m.FreePage.caller, Symbols->GetSymbolFromAddress(m.FreePage.caller));

            AllocatedPages -= 1;
            break;
        }
        case FreePages_e:
        {
            bool found = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == ReqPages_e && c.ReqPages.ret == m.FreePages.ptr)
                {
                    if (c.ReqPages.pages != m.FreePages.pages)
                        printf("FreePages( %#lx %lu )=%#lx~%#lx(%s) found in ReqPages but pages != %lu\n",
                               m.FreePages.ptr, m.FreePages.pages, m.FreePages.caller, m.FreePages.caller, Symbols->GetSymbolFromAddress(m.FreePages.caller), c.ReqPages.pages);
                    found = true;
                    break;
                }
            }

            if (!found)
                printf("FreePages( %#lx %lu )=%#lx~%#lx(%s) not found in ReqPages\n",
                       m.FreePages.ptr, m.FreePages.pages, m.FreePages.caller, m.FreePages.caller, Symbols->GetSymbolFromAddress(m.FreePages.caller));

            AllocatedPages -= m.FreePages.pages;
            break;
        }
        case malloc_e:
        {
            AllocatedMemory += m.malloc.size;
            break;
        }
        case free_e:
        {
            bool found = false;
            uint64_t size = 0;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == malloc_e && c.malloc.ret == m.free.ptr)
                {
                    found = true;
                    size = c.malloc.size;
                    break;
                }
            }

            if (!found)
                printf("free( %#lx )=%#lx~%#lx(%s) not found in malloc",
                       m.free.ptr, m.free.caller, m.free.caller, Symbols->GetSymbolFromAddress(m.free.caller));

            AllocatedMemory -= size;
            break;
        }
        case new_e:
        {
            AllocatedMemory += m.new_.size;
            break;
        }
        case new_array_e:
        {
            AllocatedMemory += m.new_array.size;
            break;
        }
        case delete_e:
        {
            bool found = false;
            uint64_t size = 0;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == new_e && c.new_.ret == m.delete_.ptr)
                {
                    found = true;
                    size = c.new_.size;
                    break;
                }
            }

            if (!found)
                printf("delete( %#lx )=%#lx~%#lx(%s) not found in new\n",
                       m.delete_.ptr, m.delete_.caller, m.delete_.caller, Symbols->GetSymbolFromAddress(m.delete_.caller));

            AllocatedMemory -= size;
            break;
        }
        case delete_array_e:
        {
            bool found = false;
            uint64_t size = 0;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == new_array_e && c.new_array.ret == m.delete_array.ptr)
                {
                    found = true;
                    size = c.new_array.size;
                    break;
                }
            }

            if (!found)
                printf("delete[]( %#lx )=%#lx~%#lx(%s) not found in new[]\n",
                       m.delete_array.ptr, m.delete_array.caller, m.delete_array.caller, Symbols->GetSymbolFromAddress(m.delete_array.caller));

            AllocatedMemory -= size;
            break;
        }
        default:
            break;
        }
    }

    for (const auto &m : mem_collection_list)
    {
        switch (m.type)
        {
        case memset_e:
        {
            bool skip = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == rsv_e)
                {
                    if (c.rsv.ptr >= m.memset.dest && c.rsv.ptr + c.rsv.size < m.memset.dest + m.memset.len)
                    {
                        skip = true;
                        break;
                    }
                }
            }

            if (skip)
                break;

            bool found = false;
            bool invalid = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == new_e)
                {
                    if (c.new_.ret >= m.memset.dest)
                    {
                        found = true;
                        if (c.new_.ret + c.new_.size < m.memset.dest + m.memset.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == new_array_e)
                {
                    if (c.new_array.ret >= m.memset.dest)
                    {
                        found = true;
                        if (c.new_array.ret + c.new_array.size < m.memset.dest + m.memset.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == malloc_e)
                {
                    if (c.malloc.ret >= m.memset.dest)
                    {
                        found = true;
                        if (c.malloc.ret + c.malloc.size < m.memset.dest + m.memset.len)
                            invalid = true;
                    }
                    break;
                }
            }

            if (!found)
                printf("memset( %#lx %lu )=%#lx~%#lx(%s) not found in allocated memory\n",
                       m.memset.dest, m.memset.len, m.memset.caller, m.memset.caller, Symbols->GetSymbolFromAddress(m.memset.caller));
            else if (invalid)
                printf("memset( %#lx %lu )=%#lx~%#lx(%s) found in allocated memory but is invalid\n",
                       m.memset.dest, m.memset.len, m.memset.caller, m.memset.caller, Symbols->GetSymbolFromAddress(m.memset.caller));
            break;
        }
        case memcpy_e:
        {
            bool skip = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == rsv_e)
                {
                    if (c.rsv.ptr >= m.memset.dest && c.rsv.ptr + c.rsv.size < m.memset.dest + m.memset.len)
                    {
                        skip = true;
                        break;
                    }
                }
            }

            if (skip)
                break;

            bool found = false;
            bool invalid = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == new_e)
                {
                    if (c.new_.ret >= m.memcpy.dest)
                    {
                        found = true;
                        if (c.new_.ret + c.new_.size < m.memcpy.dest + m.memcpy.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == new_array_e)
                {
                    if (c.new_array.ret >= m.memcpy.dest)
                    {
                        found = true;
                        if (c.new_array.ret + c.new_array.size < m.memcpy.dest + m.memcpy.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == malloc_e)
                {
                    if (c.malloc.ret >= m.memcpy.dest)
                    {
                        found = true;
                        if (c.malloc.ret + c.malloc.size < m.memcpy.dest + m.memcpy.len)
                            invalid = true;
                    }
                    break;
                }
            }

            if (!found)
                printf("memcpy( %#lx %lu )=%#lx~%#lx(%s) not found in allocated memory\n",
                       m.memcpy.dest, m.memcpy.len, m.memcpy.caller, m.memcpy.caller, Symbols->GetSymbolFromAddress(m.memcpy.caller));
            else if (invalid)
                printf("memcpy( %#lx %lu )=%#lx~%#lx(%s) found in allocated memory but is invalid\n",
                       m.memcpy.dest, m.memcpy.len, m.memcpy.caller, m.memcpy.caller, Symbols->GetSymbolFromAddress(m.memcpy.caller));
            break;
        }
        case memmove_e:
        {
            bool skip = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == rsv_e)
                {
                    if (c.rsv.ptr >= m.memset.dest && c.rsv.ptr + c.rsv.size < m.memset.dest + m.memset.len)
                    {
                        skip = true;
                        break;
                    }
                }
            }

            if (skip)
                break;

            bool found = false;
            bool invalid = false;
            for (const auto &c : mem_collection_list)
            {
                if (c.type == new_e)
                {
                    if (c.new_.ret >= m.memmove.dest)
                    {
                        found = true;
                        if (c.new_.ret + c.new_.size < m.memmove.dest + m.memmove.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == new_array_e)
                {
                    if (c.new_array.ret >= m.memmove.dest)
                    {
                        found = true;
                        if (c.new_array.ret + c.new_array.size < m.memmove.dest + m.memmove.len)
                            invalid = true;
                    }
                    break;
                }
                else if (c.type == malloc_e)
                {
                    if (c.malloc.ret >= m.memmove.dest)
                    {
                        found = true;
                        if (c.malloc.ret + c.malloc.size < m.memmove.dest + m.memmove.len)
                            invalid = true;
                    }
                    break;
                }
            }

            if (!found)
                printf("memmove( %#lx %lu )=%#lx~%#lx(%s) not found in allocated memory\n",
                       m.memmove.dest, m.memmove.len, m.memmove.caller, m.memmove.caller, Symbols->GetSymbolFromAddress(m.memmove.caller));
            else if (invalid)
                printf("memmove( %#lx %lu )=%#lx~%#lx(%s) found in allocated memory but is invalid\n",
                       m.memmove.dest, m.memmove.len, m.memmove.caller, m.memmove.caller, Symbols->GetSymbolFromAddress(m.memmove.caller));
            break;
        }
        default:
            break;
        }
    }

    return;
}

int main()
{
    Fl_Double_Window *w = make_window();
    file_path_inputbox->value("../../memtrk.dmp");
    kernel_path_inputbox->value("../../Kernel/kernel.fsys");
    w->show();

    datatable->rows(10);
    datatable->cols(7);
    datatable->row_header(1);
    // add a row with the data "hello world" without "set"

    pthread_t thread;
    pthread_create(&thread, NULL, (void *(*)(void *))main_thread, NULL);
    return Fl::run();
}
