// File: /workspace/github_c_makefile_star2_O0/melynx[P]peekaboo/read_trace.c
// Function: main
int main(int argc, char *argv[])
{
    // Init capstone
#ifdef ASM_CAPSTONE
    if (cs_open(CS_ARCH_X86, CS_MODE_64, &capstone_handler) != CS_ERR_OK) PEEKABOO_DIE("Capstone init error.");
#endif
    write_bytes = 0;
    read_bytes = 0;
    int loop_starts = 1;                    // Default is 1 for printing from beginning
    int loop_ends = 0;                      // Default is 0 for printing till the end
    char *pattern_file_path;                // Path to the pattern file for pattern search mode
    bool is_search = false;                 // Pattern search mode
    bool print_syscall_only = false;        // Strace mode 
    uint64_t target_addr = (uint64_t) -1;   // Target memory address for memory access search mode
    uint32_t target_addr_size = 1;          // Buffer size for memory access search mode. By default only check 1 byte
    bool target_addr_size_hex = false;      // Does user type-in buffer size in hex? For memory access search mode
    char *comma_pos, *size_ptr;             // Temp pointers for arg parsing. For memory access search mode
    uint64_t printed_instr_num = 0;         // Counter for how many instr have been printed for non-pattern-search modes

    // Argument parsing
    int opt;
    while ((opt = getopt(argc, argv, "hrms:p:e:a:y")) != -1) {
        switch (opt) {
        case 'r':
            print_register = true;
            break;
        case 'm':
            print_memory = true;
            break;
        case 'p':
            pattern_file_path = optarg;
            is_search = true;
            break;
        case 's':
            loop_starts = atoi(optarg);
            if (loop_starts == 0) PEEKABOO_DIE("Starting point could not be 0. Traces always start at 1.\n");
            break;
        case 'e':
            loop_ends = atoi(optarg);
            if (loop_ends <= 0) PEEKABOO_DIE("End point must be greater than 0\n");
            break;
        case 'a':
            comma_pos = strrchr(optarg, ',');
            if (optarg[0] == '0' && optarg[1] == 'x')
                target_addr = strtol(optarg+2, NULL, 16);
            else
                target_addr = strtol(optarg, NULL, 16);
            if (comma_pos != NULL)
            {
                size_ptr = comma_pos + 1;
                if (size_ptr[0] == '0' && size_ptr[1] == 'x')
                {
                    target_addr_size = strtol(size_ptr+2, NULL, 16);
                    target_addr_size_hex = true;
                }
                else
                {
                    target_addr_size = strtol(size_ptr, NULL, 10);
                    target_addr_size_hex = false;
                }
            }
            break;
        case 'y':
            print_syscall_only = true;
            break;
        case 'h':
            print_usage(argv[0]);
            exit(EXIT_FAILURE);
            break;
        }
    }
    // Check mandatory argument, path to a trace folder
    if (optind >= argc) 
    {
        print_usage(argv[0]);
        PEEKABOO_DIE("\nMissing argument: Trace path at the end expected.\n");
    }

    // Print current libpeekaboo version
    fprintf(stderr, "libpeekaboo version: %d\n", LIBPEEKABOO_VER);

    // Print info for memory access search
    if (target_addr != (uint64_t) -1)
    {
        if (target_addr_size > 1)  
        {
            printf("Search for memory access to buffer at 0x%lx with size of ",target_addr);
            if (target_addr_size_hex) // Buffer size is taken in hex or dec
                printf("0x%x bytes.\n", target_addr_size);
            else
                printf("%u bytes.\n", target_addr_size);
        }
        else
        {
            printf("Search for memory access @0x%lx.\n", target_addr);
        }
    }

    // Load trace
    char *trace_path = argv[argc - 1];
    peekaboo_trace_t *peekaboo_trace_ptr = malloc(sizeof(peekaboo_trace_t));
    if (peekaboo_trace_ptr == NULL) PEEKABOO_DIE("Fail to malloc trace structure.");
    load_trace(trace_path, peekaboo_trace_ptr);

    // Get and print the length of the trace
    const size_t num_insn = get_num_insn(peekaboo_trace_ptr);
    digits = (uint8_t) log10(num_insn) + 2;

    // Load and Print search pattern
    cache_linked_list_t pattern;
    pattern.length = 0;
    pattern.head = NULL;
    pattern.tail = NULL;
    if (is_search) load_pattern(&pattern, pattern_file_path);
    if (pattern.length) print_pattern(&pattern);

    // Prepare buffer for pattern searching
    cache_linked_list_t instr_buffer;
    instr_buffer.length = 0;
    instr_buffer.head = NULL;
    instr_buffer.tail = NULL;
    uint64_t num_found_block = 0;
    matched_list_node_t *matched_list_header = NULL;

    // We print instructions sequentially. 
    // Please note the first instruction's index is 1, instead of 0.
    const size_t _loop_ends = (loop_ends) ? loop_ends : num_insn;
    const size_t _loop_starts = (loop_starts < 0) ? (_loop_ends + loop_starts + 1) : loop_starts;
    printf("Range: from %lu to %lu (%lu in total)\n", _loop_starts, _loop_ends, num_insn);
    for (size_t insn_idx=_loop_starts; insn_idx<=_loop_ends; insn_idx++)
    {
        // Get instruction ptr by instruction index
        peekaboo_insn_t *insn = get_peekaboo_insn(insn_idx, peekaboo_trace_ptr);
        
        // strace mode
        if (print_syscall_only)
        {
            if (insn->size == 2 && insn->rawbytes[0]=='\x0f' && insn->rawbytes[1]=='\x05')
            {
                print_peekaboo_insn(insn, peekaboo_trace_ptr, insn_idx, false, true);
                printed_instr_num++;
            }
            free_peekaboo_insn(insn);
            continue;
        }

        // Pattern search
        if (pattern.length)
        {
            update_raw_byte_buffer(&instr_buffer, insn->rawbytes, insn->size, pattern.length);
            uint32_t matched_bytes_num = is_buffer_matched(&instr_buffer, &pattern);
            if (matched_bytes_num)
            {
                num_found_block ++;
                print_next = PRINT_NEXT;
                if (num_found_block) printf("\n");
                printf("[Target block %lu] ends at [%lu]0x%"PRIx64":\n", num_found_block, insn_idx, insn->addr);
                print_back(matched_bytes_num, peekaboo_trace_ptr, insn_idx);
                append2macthed_list(&matched_list_header, insn->addr);
                free_peekaboo_insn(insn);
                continue;
            }
        }

        // Call print_filter() to decide what should be printed
        if (!print_filter(insn, insn_idx, num_insn, is_search, target_addr, target_addr_size))
        {   
            // We are NOT going to print this instruction. Free and skip!
            free_peekaboo_insn(insn);
            continue;
        }
        else
        {   
            // We are going to print this instruction.
            printed_instr_num++;
        }
        

        // Body of print
        print_peekaboo_insn(insn, peekaboo_trace_ptr, insn_idx, false, false);

        // Free instruction ptr
        free_peekaboo_insn(insn);
    }

    
    if (pattern.length)
    {   
        // Print pattern search summary and free linked list
        printf("%lu code snippet(s) matched with the given pattern", num_found_block);
        if (num_found_block)
        {
            printf(":\n");
            matched_list_node_t *node = matched_list_header;
            while (node != NULL)
            {
                printf("  Found pattern at 0x%lx for %ld time(s)\n", node->addr, node->cnt);
                matched_list_node_t *this_node = node;
                node = node->succ;
                free(this_node);
            }
        }
    }
    else
    {   
        // Print a total info for non-pattern modes
        printf("End of printing. Totol printed instructions: %lu.\n", printed_instr_num);
    }
    

#ifdef ASM_CAPSTONE
	cs_close(&capstone_handler);
#endif
    if (pattern.length)
    {
        free_dulinked_list(&pattern);
        free_dulinked_list(&instr_buffer);
    }
    free_peekaboo_trace(peekaboo_trace_ptr);
    
    return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq $0x0, 0x7a24(%rip) # 0xd138
movq $0x0, 0x7a21(%rip) # 0xd140
movl $0x1, -0x14(%rbp)
movl $0x0, -0x18(%rbp)
movb $0x0, -0x21(%rbp)
movb $0x0, -0x22(%rbp)
movq $-0x1, -0x30(%rbp)
movl $0x1, -0x34(%rbp)
movb $0x0, -0x35(%rbp)
movq $0x0, -0x50(%rbp)
movl -0x8(%rbp), %edi
movq -0x10(%rbp), %rsi
leaq 0x2e5b(%rip), %rdx      # 0x85b9
callq 0x41e0
movl %eax, -0x54(%rbp)
cmpl $-0x1, %eax
je 0x594f
movl -0x54(%rbp), %eax
addl $-0x61, %eax
movl %eax, %ecx
movq %rcx, -0xf0(%rbp)
subl $0x18, %eax
ja 0x594a
movq -0xf0(%rbp), %rax
leaq 0x289b(%rip), %rcx      # 0x8030
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, 0x7984(%rip)      # 0xd129
jmp 0x594a
movb $0x1, 0x7977(%rip)      # 0xd128
jmp 0x594a
movq 0x781b(%rip), %rax      # 0xcfd8
movq (%rax), %rax
movq %rax, -0x20(%rbp)
movb $0x1, -0x21(%rbp)
jmp 0x594a
movq 0x7804(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
callq 0x41f0
movl %eax, -0x14(%rbp)
cmpl $0x0, -0x14(%rbp)
jne 0x5807
movq 0x780c(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2dd0(%rip), %rsi      # 0x85c6
movb $0x0, %al
callq 0x4130
movl $0x1, %edi
callq 0x4200
jmp 0x594a
movq 0x77c5(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
callq 0x41f0
movl %eax, -0x18(%rbp)
cmpl $0x0, -0x18(%rbp)
jg 0x5846
movq 0x77cd(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2dcb(%rip), %rsi      # 0x8600
movb $0x0, %al
callq 0x4130
movl $0x1, %edi
callq 0x4200
jmp 0x594a
movq 0x7786(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
movl $0x2c, %esi
callq 0x40e0
movq %rax, -0x40(%rbp)
movq 0x776e(%rip), %rax      # 0xcfd8
movq (%rax), %rax
movsbl (%rax), %eax
cmpl $0x30, %eax
jne 0x58aa
movq 0x775c(%rip), %rax      # 0xcfd8
movq (%rax), %rax
movsbl 0x1(%rax), %eax
cmpl $0x78, %eax
jne 0x58aa
movq 0x7749(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
addq $0x2, %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x10, %edx
callq 0x4160
movq %rax, -0x30(%rbp)
jmp 0x58c6
movq 0x7727(%rip), %rax      # 0xcfd8
movq (%rax), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x10, %edx
callq 0x4160
movq %rax, -0x30(%rbp)
cmpq $0x0, -0x40(%rbp)
je 0x592c
movq -0x40(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movsbl (%rax), %eax
cmpl $0x30, %eax
jne 0x5911
movq -0x48(%rbp), %rax
movsbl 0x1(%rax), %eax
cmpl $0x78, %eax
jne 0x5911
movq -0x48(%rbp), %rdi
addq $0x2, %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x10, %edx
callq 0x4160
movl %eax, -0x34(%rbp)
movb $0x1, -0x35(%rbp)
jmp 0x592a
movq -0x48(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0xa, %edx
callq 0x4160
movl %eax, -0x34(%rbp)
movb $0x0, -0x35(%rbp)
jmp 0x592c
jmp 0x594a
movb $0x1, -0x22(%rbp)
jmp 0x594a
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x5490
movl $0x1, %edi
callq 0x4200
jmp 0x5750
movq 0x767a(%rip), %rax      # 0xcfd0
movl (%rax), %eax
cmpl -0x8(%rbp), %eax
jl 0x598b
movq -0x10(%rbp), %rax
movq (%rax), %rdi
callq 0x5490
movq 0x7688(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2ca8(%rip), %rsi      # 0x8622
movb $0x0, %al
callq 0x4130
movl $0x1, %edi
callq 0x4200
movq 0x7666(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x3d19(%rip), %rsi      # 0x96b5
movl $0x4, %edx
movb $0x0, %al
callq 0x4130
cmpq $-0x1, -0x30(%rbp)
je 0x5a07
cmpl $0x1, -0x34(%rbp)
jbe 0x59f3
movq -0x30(%rbp), %rsi
leaq 0x2c96(%rip), %rdi      # 0x8656
movb $0x0, %al
callq 0x40b0
testb $0x1, -0x35(%rbp)
je 0x59e0
movl -0x34(%rbp), %esi
leaq 0x2cb9(%rip), %rdi      # 0x8690
movb $0x0, %al
callq 0x40b0
jmp 0x59f1
movl -0x34(%rbp), %esi
leaq 0x2cb3(%rip), %rdi      # 0x869d
movb $0x0, %al
callq 0x40b0
jmp 0x5a05
movq -0x30(%rbp), %rsi
leaq 0x2caa(%rip), %rdi      # 0x86a8
movb $0x0, %al
callq 0x40b0
jmp 0x5a07
movq -0x10(%rbp), %rax
movl -0x8(%rbp), %ecx
subl $0x1, %ecx
movslq %ecx, %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x60(%rbp)
movl $0x40, %edi
callq 0x4190
movq %rax, -0x68(%rbp)
cmpq $0x0, -0x68(%rbp)
jne 0x5a53
movq 0x75c0(%rip), %rax      # 0xcff8
movq (%rax), %rdi
leaq 0x2c88(%rip), %rsi      # 0x86ca
movb $0x0, %al
callq 0x4130
movl $0x1, %edi
callq 0x4200
movq -0x60(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x6b20
movq -0x68(%rbp), %rdi
callq 0x6560
movq %rax, -0x70(%rbp)
movaps 0x259c(%rip), %xmm1     # 0x8010
movq -0x70(%rbp), %xmm0
punpckldq %xmm1, %xmm0    # xmm0 = xmm0[0],xmm1[0],xmm0[1],xmm1[1]
movapd 0x259b(%rip), %xmm1     # 0x8020
subpd %xmm1, %xmm0
movaps %xmm0, %xmm1
unpckhpd %xmm0, %xmm0            # xmm0 = xmm0[1,1]
addsd %xmm1, %xmm0
callq 0x4120
cvttsd2si %xmm0, %eax
movzbl %al, %eax
addl $0x2, %eax
movb %al, 0x7687(%rip)       # 0xd130
movq $0x0, -0x78(%rbp)
movq $0x0, -0x88(%rbp)
movq $0x0, -0x80(%rbp)
testb $0x1, -0x21(%rbp)
je 0x5ada
movq -0x20(%rbp), %rsi
leaq -0x88(%rbp), %rdi
callq 0x5120
cmpq $0x0, -0x78(%rbp)
je 0x5aed
leaq -0x88(%rbp), %rdi
callq 0x5360
movq $0x0, -0x90(%rbp)
movq $0x0, -0xa0(%rbp)
movq $0x0, -0x98(%rbp)
movq $0x0, -0xa8(%rbp)
movq $0x0, -0xb0(%rbp)
cmpl $0x0, -0x18(%rbp)
je 0x5b37
movslq -0x18(%rbp), %rax
movq %rax, -0xf8(%rbp)
jmp 0x5b42
movq -0x70(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rax
movq %rax, -0xb8(%rbp)
cmpl $0x0, -0x14(%rbp)
jge 0x5b71
movq -0xb8(%rbp), %rax
movslq -0x14(%rbp), %rcx
addq %rcx, %rax
addq $0x1, %rax
movq %rax, -0x100(%rbp)
jmp 0x5b7c
movslq -0x14(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x100(%rbp), %rax
movq %rax, -0xc0(%rbp)
movq -0xc0(%rbp), %rsi
movq -0xb8(%rbp), %rdx
movq -0x70(%rbp), %rcx
leaq 0x2b47(%rip), %rdi      # 0x86ea
movb $0x0, %al
callq 0x40b0
movq -0xc0(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
cmpq -0xb8(%rbp), %rax
ja 0x5dc9
movq -0xc8(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x7200
movq %rax, -0xd0(%rbp)
testb $0x1, -0x22(%rbp)
je 0x5c53
movq -0xd0(%rbp), %rax
cmpq $0x2, 0x8(%rax)
jne 0x5c42
movq -0xd0(%rbp), %rax
movzbl 0x10(%rax), %eax
cmpl $0xf, %eax
jne 0x5c42
movq -0xd0(%rbp), %rax
movzbl 0x11(%rax), %eax
cmpl $0x5, %eax
jne 0x5c42
movq -0xd0(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0xc8(%rbp), %rdx
xorl %ecx, %ecx
movl $0x1, %r8d
callq 0x49a0
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
movq -0xd0(%rbp), %rdi
callq 0x7550
jmp 0x5db2
cmpq $0x0, -0x78(%rbp)
je 0x5d44
movq -0xd0(%rbp), %rsi
addq $0x10, %rsi
movq -0xd0(%rbp), %rax
movq 0x8(%rax), %rax
movl %eax, %edx
movq -0x78(%rbp), %rcx
leaq -0xa0(%rbp), %rdi
callq 0x4680
leaq -0xa0(%rbp), %rdi
leaq -0x88(%rbp), %rsi
callq 0x4870
movl %eax, -0xd4(%rbp)
cmpl $0x0, -0xd4(%rbp)
je 0x5d42
movq -0xa8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xa8(%rbp)
movl $0xf, 0x7464(%rip)      # 0xd12c
cmpq $0x0, -0xa8(%rbp)
je 0x5ce0
leaq 0x387d(%rip), %rdi      # 0x9556
movb $0x0, %al
callq 0x40b0
movq -0xa8(%rbp), %rsi
movq -0xc8(%rbp), %rdx
movq -0xd0(%rbp), %rax
movq (%rax), %rcx
leaq 0x2a12(%rip), %rdi      # 0x8711
movb $0x0, %al
callq 0x40b0
movl -0xd4(%rbp), %eax
movl %eax, %edi
movq -0x68(%rbp), %rsi
movq -0xc8(%rbp), %rdx
callq 0x4e30
movq -0xd0(%rbp), %rax
movq (%rax), %rsi
leaq -0xb0(%rbp), %rdi
callq 0x55a0
movq -0xd0(%rbp), %rdi
callq 0x7550
jmp 0x5db2
jmp 0x5d44
movq -0xd0(%rbp), %rdi
movq -0xc8(%rbp), %rsi
movq -0x70(%rbp), %rdx
movb -0x21(%rbp), %al
movq -0x30(%rbp), %r8
movl -0x34(%rbp), %r9d
andb $0x1, %al
movzbl %al, %ecx
callq 0x4320
testb $0x1, %al
jne 0x5d7d
movq -0xd0(%rbp), %rdi
callq 0x7550
jmp 0x5db2
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
movq -0xd0(%rbp), %rdi
movq -0x68(%rbp), %rsi
movq -0xc8(%rbp), %rdx
xorl %r8d, %r8d
movl %r8d, %ecx
callq 0x49a0
movq -0xd0(%rbp), %rdi
callq 0x7550
movq -0xc8(%rbp), %rax
addq $0x1, %rax
movq %rax, -0xc8(%rbp)
jmp 0x5bb8
cmpq $0x0, -0x78(%rbp)
je 0x5e6e
movq -0xa8(%rbp), %rsi
leaq 0x2957(%rip), %rdi      # 0x8739
movb $0x0, %al
callq 0x40b0
cmpq $0x0, -0xa8(%rbp)
je 0x5e6c
leaq 0x24de(%rip), %rdi      # 0x82d8
movb $0x0, %al
callq 0x40b0
movq -0xb0(%rbp), %rax
movq %rax, -0xe0(%rbp)
cmpq $0x0, -0xe0(%rbp)
je 0x5e6a
movq -0xe0(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0xe0(%rbp), %rax
movq 0x10(%rax), %rdx
leaq 0x2936(%rip), %rdi      # 0x876c
movb $0x0, %al
callq 0x40b0
movq -0xe0(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq -0xe0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0xe0(%rbp)
movq -0xe8(%rbp), %rdi
callq 0x4030
jmp 0x5e0f
jmp 0x5e6c
jmp 0x5e80
movq -0x50(%rbp), %rsi
leaq 0x291d(%rip), %rdi      # 0x8796
movb $0x0, %al
callq 0x40b0
cmpq $0x0, -0x78(%rbp)
je 0x5e9f
leaq -0x88(%rbp), %rdi
callq 0x52f0
leaq -0xa0(%rbp), %rdi
callq 0x52f0
movq -0x68(%rbp), %rdi
callq 0x70f0
xorl %eax, %eax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
nopw %cs:(%rax,%rax)
nopl (%rax)