// File: /workspace/github_c_makefile_star2_O1/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, 0x20(%rsp)
movaps %xmm0, 0x10(%rsp)
movaps %xmm0, (%rsp)
movq $0x0, 0x30(%rsp)
movb $0x1, 0x30(%rsp)
leaq 0x2f3d(%rip), %rdi      # 0x4172
callq 0x1040
leaq 0x2f6e(%rip), %rdi      # 0x41af
callq 0x1040
cmpl $0x2, %ebx
jb 0x136b
movl $0x1, %r13d
xorl %ebp, %ebp
leaq 0x2e22(%rip), %r12      # 0x4080
movl %r13d, %eax
movq (%r14,%rax,8), %r15
cmpb $0x2d, (%r15)
jne 0x1300
movq %r15, %rdi
movq %r12, %rsi
callq 0x1070
testl %eax, %eax
je 0x1305
movq %r15, %rdi
leaq 0x2dfb(%rip), %rsi      # 0x4087
callq 0x1070
testl %eax, %eax
je 0x131c
movq %r15, %rdi
leaq 0x2de9(%rip), %rsi      # 0x408c
callq 0x1070
testl %eax, %eax
je 0x1333
movq %r15, %rdi
leaq 0x2dd9(%rip), %rsi      # 0x4093
callq 0x1070
testl %eax, %eax
jne 0x1677
incl %r13d
movq (%r14,%r13,8), %rdi
callq 0x10d0
movb %al, 0x30(%rsp)
movzbl %al, %esi
leal -0x8(%rsi), %eax
roll $0x1d, %eax
cmpl $0x7, %eax
ja 0x16e2
leaq 0x2d14(%rip), %rcx      # 0x4004
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movb $0x1, 0x30(%rsp)
jmp 0x135d
movq %r15, %rbp
jmp 0x135d
incl %r13d
movq (%r14,%r13,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x8(%rsp)
jmp 0x135d
incl %r13d
movq (%r14,%r13,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x10(%rsp)
jmp 0x135d
incl %r13d
movq (%r14,%r13,8), %rdi
xorl %esi, %esi
xorl %edx, %edx
callq 0x1080
movq %rax, 0x18(%rsp)
jmp 0x135d
movb $0x4, 0x30(%rsp)
jmp 0x135d
movb $0x8, 0x30(%rsp)
jmp 0x135d
movb $0x2, 0x30(%rsp)
incl %r13d
cmpl %ebx, %r13d
jb 0x125e
jmp 0x136d
xorl %ebp, %ebp
testq %rbp, %rbp
je 0x1683
leaq 0x2d58(%rip), %rsi      # 0x40d5
movq %rbp, %rdi
callq 0x10c0
testq %rax, %rax
je 0x16c6
movq %rax, %rbx
leaq 0x48(%rsp), %r14
movq %r14, %rdi
movq %rax, %rsi
callq 0x1a3c
movq %r14, %rdi
callq 0x1b17
movl 0xc(%r14), %esi
xorl %ebp, %ebp
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
cmpl $0x0, 0x8(%r14)
je 0x1416
xorl %ebp, %ebp
leaq 0x3c(%rsp), %r14
xorl %r12d, %r12d
movq %r14, %rdi
movq %rbx, %rsi
callq 0x1ab5
cmpl $0x7, 0x3c(%rsp)
jne 0x140c
movq %rbx, %rdi
callq 0x1090
movq %rax, %r15
movl 0x44(%rsp), %esi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
movq %rbx, %rdi
callq 0x17d0
movl %eax, %ebp
movq %rbx, %rdi
movq %r15, %rsi
xorl %edx, %edx
callq 0x10b0
incl %r12d
cmpl 0x50(%rsp), %r12d
jb 0x13ca
movl 0x54(%rsp), %esi
xorl %r14d, %r14d
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
cmpl $0x0, 0x50(%rsp)
je 0x1504
leaq 0x3c(%rsp), %r15
leaq 0x2be6(%rip), %r12      # 0x4024
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1ab5
movq %r15, %rdi
movl %r14d, %esi
callq 0x1bb7
movq %rbx, %rdi
callq 0x1090
movq %rax, %r13
movl 0x44(%rsp), %esi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
movl 0x3c(%rsp), %eax
addl $-0x3, %eax
cmpl $0xe, %eax
ja 0x14e9
movslq (%r12,%rax,4), %rax
addq %r12, %rax
jmpq *%rax
movq %rbx, %rdi
movl %ebp, %esi
callq 0x1c0f
jmp 0x14e9
movq %rbx, %rdi
callq 0x2a56
jmp 0x14e9
movq %rbx, %rdi
movq %rsp, %rsi
callq 0x2f62
jmp 0x14e9
movq %rbx, %rdi
callq 0x2713
jmp 0x14e9
movq %rbx, %rdi
callq 0x302d
jmp 0x14e9
movq %rbx, %rdi
callq 0x321e
jmp 0x14e9
movq %rbx, %rdi
callq 0x2ca0
jmp 0x14e9
movq %rbx, %rdi
callq 0x2dfa
jmp 0x14e9
movq %rbx, %rdi
callq 0x3335
jmp 0x14e9
movq %rbx, %rdi
callq 0x2ad5
movq %rbx, %rdi
movq %r13, %rsi
xorl %edx, %edx
callq 0x10b0
incl %r14d
cmpl 0x50(%rsp), %r14d
jb 0x143e
movl $0xa, %edi
callq 0x1030
movq 0x8(%rsp), %rsi
testq %rsi, %rsi
je 0x165e
cmpq $0x0, (%rsp)
je 0x1585
movq 0x20(%rsp), %rdx
movq 0x28(%rsp), %rcx
leaq 0x2bfa(%rip), %rdi      # 0x412e
xorl %eax, %eax
callq 0x1060
cmpq $0x0, 0x10(%rsp)
jne 0x1552
movzbl 0x30(%rsp), %eax
addq 0x8(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0x8(%rsp), %r14
movq 0x10(%rsp), %r13
subq %r14, %r13
movq 0x18(%rsp), %rax
testq %rax, %rax
cmovneq %rax, %r13
movb 0x30(%rsp), %al
decb %al
cmpb $0x3, %al
ja 0x1598
movzbl %al, %eax
leaq 0x2d79(%rip), %rcx      # 0x42f8
movq (%rcx,%rax,8), %rbp
jmp 0x159a
leaq 0x2b77(%rip), %rdi      # 0x4103
xorl %eax, %eax
callq 0x1060
jmp 0x165e
xorl %ebp, %ebp
movq (%rsp), %rsi
movq %rbx, %rdi
xorl %edx, %edx
callq 0x10b0
testq %r13, %r13
je 0x1652
leaq 0x2aa8(%rip), %r12      # 0x4060
xorl %r15d, %r15d
testq %rbp, %r15
jne 0x15d1
leaq 0x2b89(%rip), %rdi      # 0x4150
movq %r14, %rsi
xorl %eax, %eax
callq 0x1060
movzbl 0x30(%rsp), %eax
decl %eax
cmpl $0x7, %eax
ja 0x163e
movslq (%r12,%rax,4), %rax
addq %r12, %rax
jmpq *%rax
movq %rbx, %rdi
callq 0x17f1
movzbl %al, %esi
leaq 0x2b60(%rip), %rdi      # 0x4158
jmp 0x161c
movq %rbx, %rdi
callq 0x178e
leaq 0x2b5b(%rip), %rdi      # 0x4164
jmp 0x161a
movq %rbx, %rdi
callq 0x17d0
leaq 0x2b44(%rip), %rdi      # 0x415e
movl %eax, %esi
xorl %eax, %eax
callq 0x1060
jmp 0x163e
movq %rbx, %rdi
callq 0x16f4
leaq 0x2b36(%rip), %rdi      # 0x416a
movq %rax, %rsi
xorl %eax, %eax
callq 0x1060
movzbl 0x30(%rsp), %eax
addq %rax, %r14
addq %rax, %r15
cmpq %r13, %r15
jb 0x15bb
leaq 0x2d8e(%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 0x2a3d(%rip), %rdi      # 0x40bb
movq %r15, %rsi
jmp 0x16d1
leaq 0x2b63(%rip), %rdi      # 0x41ed
callq 0x1040
leaq 0x2b7e(%rip), %rdi      # 0x4214
callq 0x1040
leaq 0x2bae(%rip), %rdi      # 0x4250
callq 0x1040
leaq 0x2bdc(%rip), %rdi      # 0x428a
callq 0x1040
leaq 0x2c05(%rip), %rdi      # 0x42bf
callq 0x1040
xorl %edi, %edi
callq 0x10e0
movq 0x8(%r14), %rsi
leaq 0x2a07(%rip), %rdi      # 0x40d8
xorl %eax, %eax
callq 0x1060
movl $0x1, %edi
callq 0x10e0
leaq 0x29b5(%rip), %rdi      # 0x409e
xorl %eax, %eax
callq 0x1060
jmp 0x16d8
nop