summaryrefslogtreecommitdiffstats
path: root/utils/disassembler/arm/main.c
blob: 812f80779f8d580fd877b05cbb851350ef802519 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>

#define ULONG  uint32_t
#define USHORT uint16_t
#define UCHAR  uint8_t

ULONG isdata[1000000]; /* each bit defines one byte as: code=0, data=1 */

extern void dis_asm(ULONG off, ULONG val, char *stg);

int main(int argc, char **argv)
{
  FILE   *in, *out;
  char   *ptr, stg[256];
  ULONG  pos, sz, val, loop;
  int    offset, offset1;
  USHORT regid;

  if(argc == 1 || strcmp(argv[1], "--help") == 0)
  { printf("Usage: arm_disass [input file]\n");
    printf(" disassembles input file to 'disasm.txt'\n");
    exit(-1);
  }

  in = fopen(argv[1], "rb");
  if(in == NULL)
  { printf("Cannot open %s", argv[1]);
    exit(-1);
  }

  out = fopen("disasm.txt", "w");
  if(out == NULL) exit(-1);

  fseek(in, 0, SEEK_END);
  sz = ftell(in);

  /* first loop only sets data/code tags */
  for(loop=0; loop<2; loop++)
  {
    for(pos=0; pos<sz; pos+=4)
    {
      /* clear disassembler string start */
      memset(stg, 0, 40);
      /* read next code dword */
      fseek(in, pos, SEEK_SET);
      fread(&val, 4, 1, in);

      /* check for data tag set: if 1 byte out of 4 is marked => assume data */
      if((isdata[pos>>5] & (0xf << (pos & 31))) || (val & 0xffff0000) == 0)
      {
        sprintf(stg, "%6x:	%08x", pos, val);
      }
      else
      {
        dis_asm(pos, val, stg);

        /* check for instant mov operation */
        if(memcmp(stg+17, "mov ", 4) == 0 && (ptr=strstr(stg, "0x")) != NULL)
        {
          regid = *(USHORT*)(stg+22);

          sscanf(ptr+2, "%x", &offset);
          if(ptr[-1] == '-')
            offset = -offset;
        }
        else
        /* check for add/sub operation */
        if((ptr=strstr(stg, "0x")) != NULL
         && (memcmp(stg+17, "add ", 4) == 0 || memcmp(stg+17, "sub ", 4) == 0))
        {
          if(regid == *(USHORT*)(stg+22) && regid == *(USHORT*)(stg+26))
          {
            sscanf(ptr+2, "%x", &offset1);
            if(ptr[-1] == '-')
              offset1 = -offset1;

            if(memcmp(stg+17, "add ", 4) == 0) offset += offset1;
            else                               offset -= offset1;

            /* add result to disassembler string */
            sprintf(stg+strlen(stg), " <- 0x%x", offset);
          }
          else
            regid = 0;
        }
        else
          regid = 0;

        /* check for const data */
        if(memcmp(stg+26, "[pc, ", 5) == 0 && (ptr=strstr(stg, "0x")) != NULL)
        {
          sscanf(ptr+2, "%x", &offset);
          if(ptr[-1] == '-')
            offset = -offset;

          /* add data tag */
          isdata[(pos+offset+8)>>5] |= 1 << ((pos+offset+8) & 31);

          /* add const data to disassembler string */
          fseek(in, pos+offset+8, SEEK_SET);
          fread(&offset, 4, 1, in);
          sprintf(stg+strlen(stg), " <- 0x%x", offset);
        }
      }
    
      /* remove trailing spaces */
      while(stg[strlen(stg)-1] == 32)
        stg[strlen(stg)-1] = 0;

      if(loop == 1)
        fprintf(out, "%s\n", stg);
    }
  }

  fclose(in);
  return 0;
}