// File: /workspace/github_c_makefile_star2_O2/mikeakohn[P]print_pe/build/../src/print_minidump.c
// Function: main
int main(int argc, char *argv[])
{
  FILE *in;
  const char *filename = NULL;
  struct minidump_header_t minidump_header;
  struct minidump_dir_t minidump_dir;
  struct memory_print_t memory_print = { 0 };
  uint32_t n, i;
  uint32_t cpu_arch = 0;

  memory_print.word_size = 1;

  printf("\nprint_minidump (January 11, 2022) - MiniDump Crash Analyzer\n");
  printf("Copyright 2005-2022 - Michael Kohn  http://www.mikekohn.net/\n\n");

  for (n = 1; n < argc; n++)
  {
    if (argv[n][0] == '-')
    {
      if (strcmp(argv[n], "-start") == 0)
      {
        memory_print.start = strtoll(argv[++n], NULL, 0);
      }
        else
      if (strcmp(argv[n], "-end") == 0)
      {
        memory_print.end = strtoll(argv[++n], NULL, 0);
      }
        else
      if (strcmp(argv[n], "-count") == 0)
      {
        memory_print.count = strtoll(argv[++n], NULL, 0);
      }
        else
      if (strcmp(argv[n], "-word_size") == 0)
      {
        memory_print.word_size = atoi(argv[++n]);

        switch (memory_print.word_size)
        {
          case 8:  memory_print.word_size = 1; break;
          case 16: memory_print.word_size = 2; break;
          case 32: memory_print.word_size = 4; break;
          case 64: memory_print.word_size = 8; break;
          default:
            printf("Error: Unknown word size %d\n", memory_print.word_size);
            exit(1);
        }
      }
        else
      {
        printf("Error: Unknown option %s\n", argv[n]);
        exit(1);
      }
    }
      else
    {
      filename = argv[n];
    }
  }

  if (filename == NULL)
  {
    printf("Usage: print_pe [options] <input file>\n");
    printf("  -start <address>        (starting memory address to dump)\n");
    printf("  -end <address>          (ending memory address to dump)\n");
    printf("  -count <count>          (length of region to dump)\n");
    printf("  -word_size <8/16/32/64> (word size of data to dump)\n");
    exit(0);
  }

  in = fopen(filename, "rb");

  if (in == NULL)
  {
    printf("Could not open input file %s for reading.\n", argv[1]);
    exit(1);
  }

  read_minidump_header(&minidump_header, in);
  print_minidump_header(&minidump_header);

  // Need to find cpu_arch in order to parse ThreadContext.
  fseek(in, minidump_header.ofs_streams, SEEK_SET);
  for (i = 0; i < minidump_header.num_streams; i++)
  {
    read_minidump_dir(&minidump_dir, in);

    if (minidump_dir.stream_type == STREAM_SYSTEM_INFO)
    {
      long marker = ftell(in);
      fseek(in, minidump_dir.ofs_data, SEEK_SET);

      cpu_arch = read_uint16(in);

      fseek(in, marker, SEEK_SET);
    }
  }

  fseek(in, minidump_header.ofs_streams, SEEK_SET);

  for (i = 0; i < minidump_header.num_streams; i++)
  {
    read_minidump_dir(&minidump_dir, in);
    print_minidump_dir(&minidump_dir, i);

    long marker = ftell(in);
    fseek(in, minidump_dir.ofs_data, SEEK_SET);

    switch (minidump_dir.stream_type)
    {
      case STREAM_THREAD_LIST:
        print_minidump_thread_list(in, cpu_arch);
        break;
      case STREAM_MODULE_LIST:
        print_minidump_module_list(in);
        break;
      case STREAM_MEMORY_LIST:
        print_minidump_memory_list(in);
        break;
      case STREAM_MEMORY_INFO_LIST:
        print_minidump_memory_info_list(in);
        break;
      case STREAM_EXCEPTION:
        print_minidump_exception(in);
        break;
      case STREAM_SYSTEM_INFO:
        print_minidump_system_info(in);
        break;
      case STREAM_MEMORY64_LIST:
        print_minidump_memory64_list(in, &memory_print);
        break;
      case STREAM_HANDLE_DATA:
        print_minidump_handle_data(in);
        break;
      case STREAM_MISC_INFO:
        print_minidump_misc_info(in);
        break;
      case STREAM_THREAD_INFO_LIST:
        print_minidump_thread_info_list(in);
        break;
      default:
        break;
    }

    fseek(in, marker, SEEK_SET);
  }

  printf("\n");

  if (memory_print.start != 0)
  {
    if (memory_print.file_offset == 0)
    {
      printf("Error: Memory region 0x%" PRIx64 " doesn't exist.\n",
        memory_print.start);
    }
      else
    {
      printf("Found 0x%" PRIx64 " in range 0x%" PRIx64 "-0x%" PRIx64 "\n",
        memory_print.start,
        memory_print.region_start,
        memory_print.region_end);

      if (memory_print.end == 0)
      {
        memory_print.end = memory_print.start + memory_print.word_size;
      }

      uint64_t length = memory_print.end - memory_print.start;
      uint64_t address = memory_print.start;
      uint64_t i;
      int modulo = 1;

      if (memory_print.count != 0)
      {
        length = memory_print.count;
      }

      switch (memory_print.word_size)
      {
        case 1: modulo = 16; break;
        case 2: modulo = 8;  break;
        case 4: modulo = 4;  break;
        case 8: modulo = 1;  break;
      }

      fseek(in, memory_print.file_offset, SEEK_SET);

      for (i = 0; i < length; i += memory_print.word_size)
      {
        if ((i % modulo) == 0)
        {
          printf("\n%08" PRIx64 ":", address);
        }

        switch (memory_print.word_size)
        {
          case 1: printf(" %02x",  (uint8_t)read_uint8(in)); break;
          case 2: printf(" %04x",  read_uint16(in)); break;
          case 4: printf(" %08x",  read_uint32(in)); break;
          case 8: printf(" %016" PRIx64 , read_uint64(in)); break;
        }

        address += memory_print.word_size;
      }

      printf("\n\n");
    }
  }

  fclose(in);

  return 0;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %rsi, %r14
movl %edi, %ebx
xorps %xmm0, %xmm0
movaps %xmm0, 0x30(%rsp)
movaps %xmm0, 0x20(%rsp)
movaps %xmm0, 0x10(%rsp)
andq $0x0, 0x40(%rsp)
movb $0x1, 0x40(%rsp)
leaq 0x2f3f(%rip), %rdi      # 0x4172
callq 0x1040
leaq 0x2f70(%rip), %rdi      # 0x41af
callq 0x1040
pushq $0x1
popq %r13
xorl %ebp, %ebp
cmpl %ebx, %r13d
jae 0x135e
movl %r13d, %r12d
movq (%r14,%r12,8), %r15
cmpb $0x2d, (%r15)
jne 0x12f6
movq %r15, %rdi
leaq 0x2e12(%rip), %rsi      # 0x4080
callq 0x1070
testl %eax, %eax
je 0x12fb
movq %r15, %rdi
leaq 0x2e02(%rip), %rsi      # 0x4087
callq 0x1070
testl %eax, %eax
je 0x1313
movq %r15, %rdi
leaq 0x2df0(%rip), %rsi      # 0x408c
callq 0x1070
testl %eax, %eax
je 0x132b
movq %r15, %rdi
leaq 0x2de0(%rip), %rsi      # 0x4093
callq 0x1070
testl %eax, %eax
jne 0x1651
movq 0x8(%r14,%r12,8), %rdi
callq 0x10d0
movzbl %al, %esi
leal -0x8(%rsi), %eax
roll $0x1d, %eax
cmpl $0x7, %eax
ja 0x16ba
incl %r13d
leaq 0x2d7a(%rip), %rcx      # 0x4060
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, 0x40(%rsp)
jmp 0x1356
movq %r15, %rbp
jmp 0x1356
incl %r13d
movq 0x8(%r14,%r12,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x18(%rsp)
jmp 0x1356
incl %r13d
movq 0x8(%r14,%r12,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x20(%rsp)
jmp 0x1356
incl %r13d
movq 0x8(%r14,%r12,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x28(%rsp)
jmp 0x1356
movb $0x4, 0x40(%rsp)
jmp 0x1356
movb $0x8, 0x40(%rsp)
jmp 0x1356
movb $0x2, 0x40(%rsp)
incl %r13d
jmp 0x124a
testq %rbp, %rbp
je 0x165d
leaq 0x2d67(%rip), %rsi      # 0x40d5
movq %rbp, %rdi
callq 0x10c0
testq %rax, %rax
je 0x16a0
movq %rax, %rbx
leaq 0x48(%rsp), %r14
movq %r14, %rdi
movq %rax, %rsi
callq 0x19d8
movq %r14, %rdi
callq 0x1aaf
movl 0xc(%r14), %esi
xorl %r12d, %r12d
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
leaq 0x4(%rsp), %r14
xorl %ebp, %ebp
cmpl 0x50(%rsp), %r12d
jae 0x1400
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1a4d
cmpl $0x7, 0x4(%rsp)
jne 0x13fb
movq %rbx, %rdi
callq 0x1090
movq %rax, %r15
movl 0xc(%rsp), %esi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
movq %rbx, %rdi
callq 0x17a8
movl %eax, %ebp
movq %rbx, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x10b0
incl %r12d
jmp 0x13b2
movl 0x54(%rsp), %esi
xorl %r14d, %r14d
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
leaq 0x4(%rsp), %r15
leaq 0x2c07(%rip), %r12      # 0x4024
cmpl 0x50(%rsp), %r14d
jae 0x14ea
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1a4d
movq %r15, %rdi
movl %r14d, %esi
callq 0x1b4f
movq %rbx, %rdi
callq 0x1090
movq %rax, %r13
movl 0xc(%rsp), %esi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
movl 0x4(%rsp), %eax
addl $-0x3, %eax
cmpl $0xe, %eax
ja 0x14d5
movslq (%r12,%rax,4), %rax
addq %r12, %rax
jmpq *%rax
movq %rbx, %rdi
movl %ebp, %esi
callq 0x1ba7
jmp 0x14d5
movq %rbx, %rdi
callq 0x29d8
jmp 0x14d5
movq %rbx, %rdi
leaq 0x10(%rsp), %rsi
callq 0x2edd
jmp 0x14d5
movq %rbx, %rdi
callq 0x26ad
jmp 0x14d5
movq %rbx, %rdi
callq 0x2fa0
jmp 0x14d5
movq %rbx, %rdi
callq 0x317e
jmp 0x14d5
movq %rbx, %rdi
callq 0x2c1f
jmp 0x14d5
movq %rbx, %rdi
callq 0x2d77
jmp 0x14d5
movq %rbx, %rdi
callq 0x3293
jmp 0x14d5
movq %rbx, %rdi
callq 0x2a57
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x10b0
incl %r14d
jmp 0x141d
pushq $0xa
popq %rdi
callq 0x1030
movq 0x18(%rsp), %rsi
testq %rsi, %rsi
je 0x1638
cmpq $0x0, 0x10(%rsp)
je 0x1562
movq 0x30(%rsp), %rdx
movq 0x38(%rsp), %rcx
leaq 0x2c15(%rip), %rdi      # 0x412e
xorl %eax, %eax
callq 0x1060
movq 0x18(%rsp), %r14
movq 0x20(%rsp), %r13
movzbl 0x40(%rsp), %eax
testq %r13, %r13
jne 0x153d
leaq (%r14,%rax), %r13
movq %r13, 0x20(%rsp)
subq %r14, %r13
movq 0x28(%rsp), %rcx
testq %rcx, %rcx
cmovneq %rcx, %r13
decb %al
cmpb $0x3, %al
ja 0x1575
movzbl %al, %eax
leaq 0x2d9c(%rip), %rcx      # 0x42f8
movq (%rcx,%rax,8), %rbp
jmp 0x1577
leaq 0x2b9a(%rip), %rdi      # 0x4103
xorl %eax, %eax
callq 0x1060
jmp 0x1638
xorl %ebp, %ebp
movq 0x10(%rsp), %rsi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
leaq 0x2a77(%rip), %r12      # 0x4004
xorl %r15d, %r15d
cmpq %r13, %r15
jae 0x162c
testq %rbp, %r15
jne 0x15af
leaq 0x2bab(%rip), %rdi      # 0x4150
movq %r14, %rsi
xorl %eax, %eax
callq 0x1060
movzbl 0x40(%rsp), %eax
decl %eax
cmpl $0x7, %eax
ja 0x161c
movslq (%r12,%rax,4), %rax
addq %r12, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x17c9
movzbl %al, %esi
leaq 0x2b82(%rip), %rdi      # 0x4158
jmp 0x15fa
movq %rbx, %rdi
callq 0x1766
leaq 0x2b7d(%rip), %rdi      # 0x4164
jmp 0x15f8
movq %rbx, %rdi
callq 0x17a8
leaq 0x2b66(%rip), %rdi      # 0x415e
movl %eax, %esi
xorl %eax, %eax
callq 0x1060
jmp 0x161c
movq %rbx, %rdi
callq 0x16cc
leaq 0x2b58(%rip), %rdi      # 0x416a
movq %rax, %rsi
xorl %eax, %eax
callq 0x1060
movzbl 0x40(%rsp), %eax
addq %rax, %r14
addq %rax, %r15
jmp 0x1590
leaq 0x2db4(%rip), %rdi      # 0x43e7
callq 0x1040
movq %rbx, %rdi
callq 0x1050
xorl %eax, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x2a63(%rip), %rdi      # 0x40bb
movq %r15, %rsi
jmp 0x16ab
leaq 0x2b89(%rip), %rdi      # 0x41ed
callq 0x1040
leaq 0x2ba4(%rip), %rdi      # 0x4214
callq 0x1040
leaq 0x2bd4(%rip), %rdi      # 0x4250
callq 0x1040
leaq 0x2c02(%rip), %rdi      # 0x428a
callq 0x1040
leaq 0x2c2b(%rip), %rdi      # 0x42bf
callq 0x1040
xorl %edi, %edi
callq 0x10e0
movq 0x8(%r14), %rsi
leaq 0x2a2d(%rip), %rdi      # 0x40d8
xorl %eax, %eax
callq 0x1060
pushq $0x1
popq %rdi
callq 0x10e0
leaq 0x29dd(%rip), %rdi      # 0x409e
xorl %eax, %eax
callq 0x1060
jmp 0x16b2
nop