changelog shortlog tags branches changeset files revisions annotate raw help

Mercurial > hg > plan9front / sys/src/libmach/7db.c

changeset 7220: f49283fe4c5f
parent: 4dd5e2428c1d
child: d98974bc6c16
author: cinap_lenrek@felloff.net
date: Thu, 09 May 2019 10:24:37 +0200
permissions: -rw-r--r--
description: libmach: support for MOVP instruction disassembly for arm64
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <mach.h>
5 
6 typedef struct Opcode Opcode;
7 struct Opcode
8 {
9  char *p;
10  char *o;
11  char *a;
12 };
13 
14 typedef struct Instr Instr;
15 struct Instr
16 {
17  Opcode *op;
18  Map *map;
19  uvlong addr;
20  ulong w;
21 
22  char *curr; /* fill point in buffer */
23  char *end; /* end of buffer */
24 };
25 
26 static void format(char*, Instr*, char*);
27 static char FRAMENAME[] = ".frame";
28 
29 /*
30  * Arm64-specific debugger interface
31  */
32 static char* arm64excep(Map*, Rgetter);
33 static int arm64foll(Map*, uvlong, Rgetter, uvlong*);
34 static int arm64inst(Map*, uvlong, char, char*, int);
35 static int arm64das(Map*, uvlong, char*, int);
36 static int arm64instlen(Map*, uvlong);
37 
38 /*
39  * Debugger interface
40  */
41 Machdata arm64mach =
42 {
43  {0x00, 0x00, 0x20, 0xD4}, /* break point 0xD4200000 */
44  4, /* break point size */
45  leswab, /* short to local byte order */
46  leswal, /* long to local byte order */
47  leswav, /* long to local byte order */
48  risctrace, /* C traceback */
49  riscframe, /* Frame finder */
50  arm64excep, /* print exception */
51  0, /* breakpoint fixup */
52  0, /* single precision float printer */
53  0, /* double precision float printer */
54  arm64foll, /* following addresses */
55  arm64inst, /* print instruction */
56  arm64das, /* dissembler */
57  arm64instlen, /* instruction size */
58 };
59 
60 static Opcode opcodes[] =
61 {
62  "0AA10000AAAAAAAAAAAAAAAAAAAddddd", "ADR", "$%A,R%d",
63  "1PP10000PPPPPPPPPPPPPPPPPPPddddd", "ADRP", "$%P,R%d",
64  "00011000lllllllllllllllllllddddd", "MOVWU", "%l,R%d",
65  "01011000LLLLLLLLLLLLLLLLLLLddddd", "MOV", "%L,R%d",
66  "10011000lllllllllllllllllllddddd", "MOVW", "%l,R%d",
67  "11011000lllllllllllllllllllddddd", "PRFM", "%l,$%d",
68  "1111100100uuuuuuuuuuuu11111ddddd", "MOV", "R%d,%u(SP)",
69  "1111100100uuuuuuuuuuuunnnnnddddd", "MOV", "R%d,%u(R%n)",
70  "WW11100100uuuuuuuuuuuu11111ddddd", "MOV%WU", "R%d,%u(SP)",
71  "WW11100100uuuuuuuuuuuunnnnnddddd", "MOV%WU", "R%d,%u(R%n)",
72  "1111100101uuuuuuuuuuuu11111ddddd", "MOV", "%u(SP),R%d",
73  "1111100101uuuuuuuuuuuunnnnnddddd", "MOV", "%u(R%n),R%d",
74  "WW11100101uuuuuuuuuuuu11111ddddd", "MOV%WU", "%u(SP),R%d",
75  "WW11100101uuuuuuuuuuuunnnnnddddd", "MOV%WU", "%u(R%n),R%d",
76  "WW11100110uuuuuuuuuuuu11111ddddd", "MOV%W", "%u(SP),R%d",
77  "WW11100110uuuuuuuuuuuunnnnnddddd", "MOV%W", "%u(R%n),R%d",
78  "11111000000ooooooooo0011111ddddd", "MOV", "R%d,%o(SP)",
79  "11111000000ooooooooo00nnnnnddddd", "MOV", "R%d,%o(R%n)",
80  "WW111000000ooooooooo0011111ddddd", "MOV%W", "R%d,%o(SP)",
81  "WW111000000ooooooooo00nnnnnddddd", "MOV%W", "R%d,%o(R%n)",
82  "11111000010ooooooooo0011111ddddd", "MOV", "%o(SP),R%d",
83  "11111000010ooooooooo00nnnnnddddd", "MOV", "%o(R%n),R%d",
84  "WW111000010ooooooooo0011111ddddd", "MOV%WU", "%o(SP),R%d",
85  "WW111000010ooooooooo00nnnnnddddd", "MOV%WU", "%o(R%n),R%d",
86  "WW111000100ooooooooo0011111ddddd", "MOV%W", "%o(SP),R%d",
87  "WW111000100ooooooooo00nnnnnddddd", "MOV%W", "%o(R%n),R%d",
88  "11111000000ooooooooo0111111ddddd", "MOV", "R%d,(SP)%o!",
89  "WW111000000ooooooooo0111111ddddd", "MOV%WU", "R%d,(SP)%o!",
90  "WW111000000ooooooooo01nnnnnddddd", "MOV%WU", "R%d,(R%n)%o!",
91  "11111000000ooooooooo1111111ddddd", "MOV", "R%d,%o(SP)!",
92  "WW111000000ooooooooo1111111ddddd", "MOV%WU", "R%d,%o(SP)!",
93  "WW111000000ooooooooo11nnnnnddddd", "MOV%WU", "R%d,%o(R%n)!",
94 
95  "11111000010ooooooooo0111111ddddd", "MOV", "(SP)%o!,R%d",
96  "11111000010ooooooooo01nnnnnddddd", "MOV", "(R%n)%o!,R%d",
97  "WW111000010ooooooooo0111111ddddd", "MOV%WU", "(SP)%o!,R%d",
98  "WW111000010ooooooooo01nnnnnddddd", "MOV%WU", "(R%n)%o!,R%d",
99  "WW111000100ooooooooo0111111ddddd", "MOV%W", "(SP)%o!,R%d",
100  "WW111000100ooooooooo01nnnnnddddd", "MOV%W", "(R%n)%o!,R%d",
101  "11111000010ooooooooo1111111ddddd", "MOV", "%o(SP)!,R%d",
102  "11111000010ooooooooo11nnnnnddddd", "MOV", "%o(R%n)!,R%d",
103  "WW111000010ooooooooo1111111ddddd", "MOV%WU", "%o(SP)!,R%d",
104  "WW111000010ooooooooo11nnnnnddddd", "MOV%WU", "%o(R%n)!,R%d",
105  "WW111000100ooooooooo1111111ddddd", "MOV%W", "%o(SP)!,R%d",
106  "WW111000100ooooooooo11nnnnnddddd", "MOV%W", "%o(R%n)!,R%d",
107  "11111000001mmmmmeeei10nnnnnddddd", "MOV", "R%d,(R%n)(R%m%e)",
108  "11111000111mmmmmeeei10nnnnnddddd", "MOV", "(R%n)(R%m%e),R%d",
109  "WW111000001mmmmmeeei10nnnnnddddd", "MOV%W", "R%d,(R%n)(R%m%e)",
110  "WW111000011mmmmmeeei10nnnnnddddd", "MOV%WU", "(R%n)(R%m%e),R%d",
111  "WW111000101mmmmmeeei10nnnnnddddd", "MOV%W", "(R%n)(R%m%e),R%d",
112  "WW111000111mmmmmeeei10nnnnnddddd", "MOV%WW", "(R%n)(R%m%e),R%d",
113  "W00100101ssKKKKKKKKKKKKKKKKddddd", "MOVN%W", "$%K,R%d",
114  "W10100101ssKKKKKKKKKKKKKKKKddddd", "MOVZ%W", "$%K,R%d",
115  "W11100101ssKKKKKKKKKKKKKKKKddddd", "MOVK%W", "$%K,R%d",
116  "W0010001--00000000000011111ddddd", "MOV%W", "SP,R%d",
117  "W0010001--000000000000nnnnn11111", "MOV%W", "R%n,SP",
118  "0110100011ooooooommmmm11111ddddd", "MOVPSW", "(SP)%o!,R%d,R%m",
119  "0110100011ooooooommmmmnnnnnddddd", "MOVPSW", "(R%n)%o!,R%d,R%m",
120  "0110100101ooooooommmmm11111ddddd", "MOVPSW", "%o(SP),R%d,R%m",
121  "0110100101ooooooommmmmnnnnnddddd", "MOVPSW", "%o(R%n),R%d,R%m",
122  "0110100111ooooooommmmm11111ddddd", "MOVPSW", "%o(SP)!,R%d,R%m",
123  "0110100111ooooooommmmmnnnnnddddd", "MOVPSW", "%o(R%n)!,R%d,R%m",
124  "W010100010ooooooommmmm11111ddddd", "MOVP%W", "R%d,R%m,(SP)%o!",
125  "W010100010ooooooommmmmnnnnnddddd", "MOVP%W", "R%d,R%m,(R%n)%o!",
126  "W010100100ooooooommmmm11111ddddd", "MOVP%W", "R%d,R%m,%o(SP)",
127  "W010100100ooooooommmmmnnnnnddddd", "MOVP%W", "R%d,R%m,%o(R%n)",
128  "W010100110ooooooommmmm11111ddddd", "MOVP%W", "R%d,R%m,%o(SP)!",
129  "W010100110ooooooommmmmnnnnnddddd", "MOVP%W", "R%d,R%m,%o(R%n)!",
130  "W010100011ooooooommmmm11111ddddd", "MOVP%W", "(SP)%o!,R%d,R%m",
131  "W010100011ooooooommmmmnnnnnddddd", "MOVP%W", "(R%n)%o!,R%d,R%m",
132  "W010100101ooooooommmmm11111ddddd", "MOVP%W", "%o(SP),R%d,R%m",
133  "W010100101ooooooommmmmnnnnnddddd", "MOVP%W", "%o(R%n),R%d,R%m",
134  "W010100111ooooooommmmm11111ddddd", "MOVP%W", "%o(SP)!,R%d,R%m",
135  "W010100111ooooooommmmmnnnnnddddd", "MOVP%W", "%o(R%n)!,R%d,R%m",
136  "W0010001ssIIIIIIIIIIII1111111111", "ADD%W", "$%I,SP,SP",
137  "W0010001ssIIIIIIIIIIII11111ddddd", "ADD%W", "$%I,SP,R%d",
138  "W0010001ssIIIIIIIIIIIInnnnn11111", "ADD%W", "$%I,R%n,SP",
139  "W0110001ssIIIIIIIIIIII1111111111", "ADDS%W", "$%I,SP,SP",
140  "W0110001ssIIIIIIIIIIII11111ddddd", "ADDS%W", "$%I,SP,R%d",
141  "W0110001ssIIIIIIIIIIIInnnnn11111", "ADDS%W", "$%I,R%n,SP",
142  "W1010001ssIIIIIIIIIIII1111111111", "SUB%W", "$%I,SP,SP",
143  "W1010001ssIIIIIIIIIIII11111ddddd", "SUB%W", "$%I,SP,R%d",
144  "W1010001ssIIIIIIIIIIIInnnnn11111", "SUB%W", "$%I,R%n,SP",
145  "W1110001ssIIIIIIIIIIII1111111111", "CMP%W", "$%I,SP",
146  "W1110001ssIIIIIIIIIIIInnnnn11111", "CMP%W", "$%I,R%n",
147  "W1110001ssIIIIIIIIIIII11111ddddd", "SUBS%W", "$%I,SP,R%d",
148  "W0010001ssIIIIIIIIIIIInnnnnddddd", "ADD%W", "$%I,R%n,R%d",
149  "W0110001ssIIIIIIIIIIIInnnnnddddd", "ADDS%W", "$%I,R%n,R%d",
150  "W1010001ssIIIIIIIIIIIInnnnnddddd", "SUB%W", "$%I,R%n,R%d",
151  "W1110001ssIIIIIIIIIIIInnnnnddddd", "SUBS%W", "$%I,R%n,R%d",
152  "W00100100MMMMMMMMMMMMMnnnnn11111", "AND%W", "$%M,R%n,SP",
153  "W01100100MMMMMMMMMMMMMnnnnn11111", "ORR%W", "$%M,R%n,SP",
154  "W10100100MMMMMMMMMMMMMnnnnn11111", "EOR%W", "$%M,R%n,SP",
155  "W11100100MMMMMMMMMMMMMnnnnn11111", "ANDS%W", "$%M,R%n,SP",
156  "W00100100MMMMMMMMMMMMMnnnnnddddd", "AND%W", "$%M,R%n,R%d",
157  "W01100100MMMMMMMMMMMMMnnnnnddddd", "ORR%W", "$%M,R%n,R%d",
158  "W10100100MMMMMMMMMMMMMnnnnnddddd", "EOR%W", "$%M,R%n,R%d",
159  "W11100100MMMMMMMMMMMMMnnnnnddddd", "ANDS%W", "$%M,R%n,R%d",
160  "1001001101000000011111nnnnnddddd", "SXTW", "R%n,R%d",
161  "0101001100iiiiii011111nnnnnddddd", "LSRW", "$%i,R%n,R%d",
162  "1101001101iiiiii111111nnnnnddddd", "LSR", "$%i,R%n,R%d",
163  "W00100110-iiiiiijjjjjjnnnnnddddd", "SBFM%W", "$%i,$%j,R%n,R%d",
164  "W01100110-iiiiiijjjjjjnnnnnddddd", "BFM%W", "$%i,$%j,R%n,R%d",
165  "W10100110-iiiiiijjjjjjnnnnnddddd", "UBFM%W", "$%i,$%j,R%n,R%d",
166  "W1011010000mmmmm00000011111ddddd", "NGC%W", "R%m,R%d",
167  "W1111010000mmmmm00000011111ddddd", "NGCS%W", "R%m,R%d",
168  "W0011010000mmmmm000000nnnnnddddd", "ADC%W", "R%m,R%n,R%d",
169  "W0111010000mmmmm000000nnnnnddddd", "ADCS%W", "R%m,R%n,R%d",
170  "W1011010000mmmmm000000nnnnnddddd", "SBC%W", "R%m,R%n,R%d",
171  "W1111010000mmmmm000000nnnnnddddd", "SBCS%W", "R%m,R%n,R%d",
172  "W0101011ss0mmmmmiiiiiinnnnn11111", "CMN%W", "R%m%s,R%n",
173  "W1101011ss0mmmmmiiiiiinnnnn11111", "CMP%W", "R%m%s,R%n",
174  "W1001011ss0mmmmmiiiiii11111ddddd", "NEG%W", "R%m%s,R%d",
175  "W1101011ss0mmmmmiiiiii11111ddddd", "NEGS%W", "R%m%s,R%d",
176  "W0001011ss0mmmmmiiiiiinnnnnddddd", "ADD%W", "R%m%s,R%n,R%d",
177  "W0101011ss0mmmmmiiiiiinnnnnddddd", "ADDS%W", "R%m%s,R%n,R%d",
178  "W1001011ss0mmmmmiiiiiinnnnnddddd", "SUB%W", "R%m%s,R%n,R%d",
179  "W1101011ss0mmmmmiiiiiinnnnnddddd", "SUBS%W", "R%m%s,R%n,R%d",
180  "W0001011001mmmmmeeeiii1111111111", "ADD%W", "R%m%e,SP,SP",
181  "W0001011001mmmmmeeeiii11111ddddd", "ADD%W", "R%m%e,SP,R%d",
182  "W0001011001mmmmmeeeiiinnnnn11111", "ADD%W", "R%m%e,R%n,SP",
183  "W0101011001mmmmmeeeiii1111111111", "ADDS%W", "R%m%e,SP,SP",
184  "W0101011001mmmmmeeeiii11111ddddd", "ADDS%W", "R%m%e,SP,R%d",
185  "W0101011001mmmmmeeeiiinnnnn11111", "ADDS%W", "R%m%e,R%n,SP",
186  "W1001011001mmmmmeeeiii1111111111", "SUB%W", "R%m%e,SP,SP",
187  "W1001011001mmmmmeeeiii11111ddddd", "SUB%W", "R%m%e,SP,R%d",
188  "W1001011001mmmmmeeeiiinnnnn11111", "SUB%W", "R%m%e,R%n,SP",
189  "W1101011001mmmmmeeeiii1111111111", "SUBS%W", "R%m%e,SP,SP",
190  "W1101011001mmmmmeeeiii11111ddddd", "SUBS%W", "R%m%e,SP,R%d",
191  "W1101011001mmmmmeeeiiinnnnn11111", "SUBS%W", "R%m%e,R%n,SP",
192  "W0001011001mmmmmeeeiiinnnnnddddd", "ADD%W", "R%m%e,R%n,R%d",
193  "W0101011001mmmmmeeeiiinnnnnddddd", "ADDS%W", "R%m%e,R%n,R%d",
194  "W1001011001mmmmmeeeiiinnnnnddddd", "SUB%W", "R%m%e,R%n,R%d",
195  "W1101011001mmmmmeeeiiinnnnnddddd", "SUBS%W", "R%m%e,R%n,R%d",
196  "W0101010000mmmmm-0000011111ddddd", "MOV%W", "R%m,R%d",
197  "W0101010ss1mmmmmiiiiii11111ddddd", "NVM%W", "R%m%s,R%d",
198  "W1101010ss0mmmmmiiiiiinnnnn11111", "TST%W", "R%m%s,R%n",
199  "W0001010ss0mmmmmiiiiiinnnnnddddd", "AND%W", "R%m%s,R%n,R%d",
200  "W1101010ss0mmmmmiiiiiinnnnnddddd", "ANDS%W", "R%m%s,R%n,R%d",
201  "W0001010ss1mmmmmiiiiiinnnnnddddd", "BIC%W", "R%m%s,R%n,R%d",
202  "W1101010ss1mmmmmiiiiiinnnnnddddd", "BICS%W", "R%m%s,R%n,R%d",
203  "W1001010ss0mmmmmiiiiiinnnnnddddd", "EOR%W", "R%m%s,R%n,R%d",
204  "W1001010ss1mmmmmiiiiiinnnnnddddd", "EON%W", "R%m%s,R%n,R%d",
205  "W0101010ss0mmmmmiiiiiinnnnnddddd", "ORR%W", "R%m%s,R%n,R%d",
206  "W0101010ss1mmmmmiiiiiinnnnnddddd", "ORN%W", "R%m%s,R%n,R%d",
207  "W0011010110mmmmm001000nnnnnddddd", "LSL%W", "R%m,R%n,R%d",
208  "W0011010110mmmmm001001nnnnnddddd", "LSR%W", "R%m,R%n,R%d",
209  "W0011010110mmmmm001010nnnnnddddd", "ASR%W", "R%m,R%n,R%d",
210  "W0011010110mmmmm001011nnnnnddddd", "ROR%W", "R%m,R%n,R%d",
211  "W0011010110mmmmm000010nnnnnddddd", "UDIV%W", "R%m,R%n,R%d",
212  "W0011010110mmmmm000011nnnnnddddd", "SDIV%W", "R%m,R%n,R%d",
213  "W0011011000mmmmm011111nnnnnddddd", "MUL%W", "R%m,R%n,R%d",
214  "W0011011000mmmmm111111nnnnnddddd", "MNEG%W", "R%m,R%n,R%d",
215  "W0011011000mmmmm0aaaaannnnnddddd", "MADD%W", "R%m,R%n,R%a,R%d",
216  "W0011011000mmmmm1aaaaannnnnddddd", "MSUB%W", "R%m,R%n,R%a,R%d",
217  "10011011001mmmmm011111nnnnnddddd", "SMULL", "R%m,R%n,R%d",
218  "10011011001mmmmm111111nnnnnddddd", "SMNEGL", "R%m,R%n,R%d",
219  "10011011001mmmmm0aaaaannnnnddddd", "SMADDL", "R%m,R%n,R%a,R%d",
220  "10011011001mmmmm1aaaaannnnnddddd", "SMSUBL", "R%m,R%n,R%a,R%d",
221  "10011011101mmmmm011111nnnnnddddd", "UMULL", "R%m,R%n,R%d",
222  "10011011101mmmmm111111nnnnnddddd", "UMNEGL", "R%m,R%n,R%d",
223  "10011011101mmmmm0aaaaannnnnddddd", "UMADDL", "R%m,R%n,R%a,R%d",
224  "10011011101mmmmm1aaaaannnnnddddd", "UMSUBL", "R%m,R%n,R%a,R%d",
225  "W0110100TTTTTTTTTTTTTTTTTTTddddd", "CBZ%W", "R%d,%T",
226  "W0110101TTTTTTTTTTTTTTTTTTTddddd", "CBNZ%W", "R%d,%T",
227  "01010100TTTTTTTTTTTTTTTTTTT0CCCC", "B%C", "%T",
228  "000101TTTTTTTTTTTTTTTTTTTTTTTTTT", "B", "%T",
229  "100101TTTTTTTTTTTTTTTTTTTTTTTTTT", "BL", "%T",
230  "1101011000011111000000nnnnn00000", "BR", "R%n",
231  "1101011000111111000000nnnnn00000", "BLR", "R%n",
232  "11010110010111110000001111000000", "RETURN", nil,
233  "1101011001011111000000nnnnn00000", "RET", "R%n",
234  "11010110100111110000001111100000", "ERET", nil,
235  "11010110101111110000001111100000", "DRPS", nil,
236  "11010100000iiiiiiiiiiiiiiii00001", "SVC", "$%i",
237  "11010100000iiiiiiiiiiiiiiii00010", "HVC", "$%i",
238  "11010100000iiiiiiiiiiiiiiii00011", "SMC", "$%i",
239  "11010100001iiiiiiiiiiiiiiii00000", "BRK", "$%i",
240  "11010100010iiiiiiiiiiiiiiii00000", "HLT", "$%i",
241  "11010100101iiiiiiiiiiiiiiii00001", "DCPS1", "$%i",
242  "11010100101iiiiiiiiiiiiiiii00010", "DCPS2", "$%i",
243  "11010100101iiiiiiiiiiiiiiii00011", "DCPS3", "$%i",
244  "11010101000000110010000000011111", "NOP", nil,
245  "11010101000000110010000000111111", "YIELD", nil,
246  "11010101000000110010000001011111", "WFE", nil,
247  "11010101000000110010000001111111", "WFI", nil,
248  "11010101000000110010000010011111", "SEV", nil,
249  "11010101000000110010000010111111", "SEVL", nil,
250  "11010101000000110011xxxx01011111", "CLREX", "$%x",
251  "11010101000000110011xxxx10011111", "DSB", "$%x",
252  "11010101000000110011xxxx10111111", "DMB", "$%x",
253  "11010101000000110011xxxx11011111", "ISB", "$%x",
254  "1101010100001YYYYYYYYYYYYYY11111", "SYS", "%Y",
255  "1101010100001YYYYYYYYYYYYYYddddd", "SYS", "R%d,%Y",
256  "1101010100101YYYYYYYYYYYYYYddddd", "SYSL", "%Y,R%d",
257  "11010101000000000100xxxx10111111", "MSR", "$%x,SP",
258  "11010101000000110100xxxx11011111", "MSR", "$%x,DAIFSet",
259  "11010101000000110100xxxx11111111", "MSR", "$%x,DAIFClr",
260  "11010101000YYYYYYYYYYYYYYYYddddd", "MSR", "R%d,%Y",
261  "11010101001YYYYYYYYYYYYYYYYddddd", "MRS", "%Y,R%d",
262  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "WORD", "$%x",
263 };
264 
265 #define SYSARG5(op0,op1,Cn,Cm,op2) ((op0)<<19|(op1)<<16|(Cn)<<12|(Cm)<<8|(op2)<<5)
266 
267 static ulong
268 smask(char *s, char c)
269 {
270  ulong m;
271  int i;
272 
273  m = 0;
274  for(i=0; i<32 && *s != '\0'; i++, s++)
275  m |= (*s == c)<<(31-i);
276  return m;
277 }
278 
279 static int
280 nbits(ulong v)
281 {
282  int n = 0;
283  while(v != 0){
284  v &= v-1;
285  n++;
286  }
287  return n;
288 }
289 
290 static int
291 nones(ulong v)
292 {
293  int n = 0;
294  while(v & 1){
295  v >>= 1;
296  n++;
297  }
298  return n;
299 }
300 
301 static int
302 nshift(ulong m)
303 {
304  if(m == 0 || m == ~0UL)
305  return 0;
306  return nones(~m);
307 }
308 
309 static ulong
310 unshift(ulong w, ulong m)
311 {
312  int s = nshift(m);
313  w >>= s, m >>= s;
314  if((m+1 & m) != 0){ // 0bxxx0000yyyyyy -> 0byyyyyyxxx
315  ulong b = (1UL<<nones(m))-1;
316  return ((w & b) << nbits(m & ~b)) | unshift(w, m & ~b);
317  }
318  return w & m;
319 }
320 
321 static long
322 sext(ulong u, int n)
323 {
324  long l = (long)u;
325  if(n > 0){
326  l <<= sizeof(l)*8 - n;
327  l >>= sizeof(l)*8 - n;
328  }
329  return l;
330 }
331 
332 static char*
333 arm64excep(Map *, Rgetter)
334 {
335 // uvlong c = (*rget)(map, "TYPE");
336  return "???";
337 }
338 
339 static int
340 decode(Map *map, uvlong pc, Instr *i)
341 {
342  static ulong tab[2*nelem(opcodes)];
343  static int once;
344  ulong w, j;
345 
346  if(!once){
347  Opcode *o;
348 
349  /* precalculate value/mask table */
350  for(j=0, o=opcodes; j<nelem(tab); j+=2, o++){
351  tab[j] = smask(o->p, '1');
352  tab[j|1] = tab[j] | smask(o->p, '0');
353  }
354 
355  once = 1;
356  }
357 
358  if(get4(map, pc, &w) < 0) {
359  werrstr("can't read instruction: %r");
360  return -1;
361  }
362  i->addr = pc;
363  i->map = map;
364  i->w = w;
365 
366  for(j=0; j<nelem(tab); j+=2){
367  if((w & tab[j|1]) == tab[j]){
368  i->op = &opcodes[j/2];
369  return 1;
370  }
371  }
372 
373  /* should not happen */
374  return 0;
375 }
376 
377 #pragma varargck argpos bprint 2
378 
379 static void
380 bprint(Instr *i, char *fmt, ...)
381 {
382  va_list arg;
383 
384  va_start(arg, fmt);
385  i->curr = vseprint(i->curr, i->end, fmt, arg);
386  va_end(arg);
387 }
388 
389 static
390 char* shtype[4] =
391 {
392  "<<", ">>", "->", "@>"
393 };
394 
395 static
396 char* rextype[8] =
397 {
398  "UB", "UH", "UW", "UX",
399  "SB", "SH", "SW", "SX"
400 };
401 
402 static
403 char* scond[16] =
404 {
405  "EQ", "NE", "HS", "LO",
406  "MI", "PL", "VS", "VC",
407  "HI", "LS", "GE", "LT",
408  "GT", "LE", "", "NV",
409 };
410 
411 static uvlong
412 decodebitmask(int n, int s, int r)
413 {
414  uvlong w;
415  int e;
416 
417  if(n)
418  n = 6;
419  else {
420  for(n = 5; n >= 1 && ((~s & 0x3F) & (1<<n)) == 0; n--)
421  ;
422  }
423  e = 1 << n;
424  s &= e-1;
425  r &= e-1;
426 
427  w = 1ULL << s;
428  w |= w-1;
429 
430  if(r != 0){
431  w = (w >> r) | (w << (e-r));
432  if(e < 64)
433  w &= (1ULL << e)-1;
434  }
435  while(e < 64){
436  w |= w << e;
437  e <<= 1;
438  }
439  return w;
440 }
441 
442 static void
443 format(char *mnemonic, Instr *i, char *f)
444 {
445  Symbol s;
446  uvlong v;
447  ulong w, u, m;
448 
449  if(mnemonic)
450  format(0, i, mnemonic);
451  if(f == 0)
452  return;
453  if(mnemonic)
454  if(i->curr < i->end)
455  *i->curr++ = '\t';
456  for ( ; *f && i->curr < i->end; f++) {
457  if(*f != '%') {
458  *i->curr++ = *f;
459  continue;
460  }
461  m = smask(i->op->p, *++f);
462  u = unshift(i->w, m);
463  switch (*f) {
464  case 'C': // Condition
465  bprint(i, "%s", scond[u & 15]);
466  break;
467 
468  case 'W': // Width
469  if(nbits(m) == 1) u += 2;
470  u &= 3;
471  if(u < 3)
472  *i->curr++ = "BHW"[u];
473  break;
474 
475  case 'd': // Register Numbers
476  case 'n':
477  case 'a':
478  case 'm':
479  bprint(i, "%lud", u);
480  break;
481 
482  case 's': // Register shift
483  w = unshift(i->w, smask(i->op->p, 'i'));
484  if(w != 0)
485  bprint(i, "%s%lud", shtype[u & 3], w);
486  break;
487 
488  case 'e': // Register extension
489  u &= 7;
490  bprint(i, ".%s", rextype[u]);
491  w = unshift(i->w, smask(i->op->p, 'i'));
492  if(w != 0 && u == 2+(i->w>>31))
493  bprint(i, "<<%lud", w);
494  break;
495 
496  case 'M': // Bitmask
497  v = decodebitmask((u>>12)&1, u&0x3F, (u>>6)&0x3F);
498  if((i->w & (1<<31)) == 0)
499  v &= 0xFFFFFFFF;
500  bprint(i, "%llux", v);
501  break;
502 
503  case 'I': // Shifted Immediate (12 bit)
504  case 'K': // Shifted Immediate (16 bit)
505  w = unshift(i->w, smask(i->op->p, 's'));
506  if(u != 0 && w != 0)
507  bprint(i, "(%lux<<%ld)", u, w*(*f == 'I' ? 12 : 16));
508  else
509  bprint(i, "%lud", u);
510  break;
511 
512  case 'o': // Signed byte offset
513  w = nbits(m);
514  bprint(i, "%ld", sext(u, w) << (w == 7 ? 2 + (i->w>>31) : 0));
515  break;
516  case 'u': // Unsigned offset
517  u <<= (i->w >> 30)&3;
518  /* wet floor */
519  case 'i': // Decimal
520  case 'j':
521  bprint(i, "%lud", u);
522  break;
523 
524  case 'x': // Hex
525  bprint(i, "%lux", u);
526  break;
527 
528  case 'l': // 32-bit Literal
529  if(get4(i->map, i->addr + sext(u, nbits(m))*4, &w) < 0)
530  goto Ptext;
531  bprint(i, "$%lux", w);
532  break;
533  case 'L': // 64-bit Literal
534  if(get8(i->map, i->addr + sext(u, nbits(m))*4, &v) < 0)
535  goto Ptext;
536  bprint(i, "$%llux", v);
537  break;
538  case 'T': // Text address (PC relative)
539  Ptext:
540  v = i->addr + sext(u, nbits(m))*4;
541  if(findsym(v, CTEXT, &s)){
542  bprint(i, "%s", s.name);
543  if(v < s.value)
544  bprint(i, "%llx", v - s.value);
545  else if(v > s.value)
546  bprint(i, "+%llx", v - s.value);
547  bprint(i, "(SB)");
548  break;
549  }
550  bprint(i, "%llux(SB)", v);
551  break;
552  case 'A': // Data address (PC relative)
553  v = i->addr + sext(u, nbits(m));
554  goto Pdata;
555  case 'P': // Page address (PC relative)
556  v = i->addr + ((vlong)sext(u, nbits(m)) << 12);
557  Pdata:
558  if(findsym(v, CANY, &s)){
559  bprint(i, "%s", s.name);
560  if(v < s.value)
561  bprint(i, "%llx", v - s.value);
562  else if(v > s.value)
563  bprint(i, "+%llx", v - s.value);
564  bprint(i, "(SB)");
565  break;
566  }
567  bprint(i, "%llux(SB)", v);
568  break;
569 
570  case 'Y':
571  if(nbits(m) == 14){ // SYS/SYSL operands
572  bprint(i, "%lud,%lud,%lud,%lud",
573  (u>>(4+4+3))&7, // op1
574  (u>>(4+3))&15, // CRn
575  (u>>3)&15, // CRm
576  (u)&7); // op2
577  break;
578  }
579  /* see /sys/src/cmd/7c/7.out.h */
580  switch(i->w & m){
581  case SYSARG5(3,3,4,2,1): bprint(i, "DAIF"); break;
582  case SYSARG5(3,3,4,2,0): bprint(i, "NZCV"); break;
583  case SYSARG5(3,3,4,4,1): bprint(i, "FPSR"); break;
584  case SYSARG5(3,3,4,4,0): bprint(i, "FPCR"); break;
585  case SYSARG5(3,0,4,0,0): bprint(i, "SPSR_EL1"); break;
586  case SYSARG5(3,0,4,0,1): bprint(i, "ELR_EL1"); break;
587  case SYSARG5(3,4,4,0,0): bprint(i, "SPSR_EL2"); break;
588  case SYSARG5(3,4,4,0,1): bprint(i, "ELR_EL2"); break;
589  case SYSARG5(3,0,4,2,2): bprint(i, "CurrentEL"); break;
590  case SYSARG5(3,0,4,1,0): bprint(i, "SP_EL0"); break;
591  case SYSARG5(3,0,4,2,0): bprint(i, "SPSel"); break;
592  default: bprint(i, "SPR(%lux)", i->w & m);
593  }
594  break;
595 
596  case '\0':
597  *i->curr++ = '%';
598  return;
599 
600  default:
601  bprint(i, "%%%c", *f);
602  break;
603  }
604  }
605  *i->curr = 0;
606 }
607 
608 static int
609 printins(Map *map, uvlong pc, char *buf, int n)
610 {
611  Instr i[1];
612 
613  i->curr = buf;
614  i->end = buf+n-1;
615  if(decode(map, pc, i) < 0)
616  return -1;
617  format(i->op->o, i, i->op->a);
618  return 4;
619 }
620 
621 static int
622 arm64inst(Map *map, uvlong pc, char modifier, char *buf, int n)
623 {
624  USED(modifier);
625  return printins(map, pc, buf, n);
626 }
627 
628 static int
629 arm64das(Map *map, uvlong pc, char *buf, int n)
630 {
631  Instr i[1];
632 
633  i->curr = buf;
634  i->end = buf+n;
635  if(decode(map, pc, i) < 0)
636  return -1;
637  if(i->end-i->curr > 8)
638  i->curr = _hexify(buf, i->w, 7);
639  *i->curr = 0;
640  return 4;
641 }
642 
643 static int
644 arm64instlen(Map*, uvlong)
645 {
646  return 4;
647 }
648 
649 static uvlong
650 readreg(Instr *i, Rgetter rget, int rc)
651 {
652  ulong m;
653  uvlong v;
654  char reg[4];
655  snprint(reg, sizeof(reg), "R%lud", unshift(i->w, smask(i->op->p, rc)));
656  v = (*rget)(i->map, reg);
657  m = smask(i->op->p, 'W');
658  if(m != 0 && unshift(i->w, m) == 0)
659  v &= 0xFFFFFFFFULL;
660  return v;
661 }
662 
663 static int
664 passcond(Instr *i, Rgetter rget)
665 {
666  uvlong psr;
667  uchar n;
668  uchar z;
669  uchar c;
670  uchar v;
671 
672  psr = (*rget)(i->map, "PSR");
673  n = (psr >> 31) & 1;
674  z = (psr >> 30) & 1;
675  c = (psr >> 29) & 1;
676  v = (psr >> 28) & 1;
677 
678  switch(unshift(i->w, smask(i->op->p, 'C'))) {
679  default:
680  case 0: return z;
681  case 1: return !z;
682  case 2: return c;
683  case 3: return !c;
684  case 4: return n;
685  case 5: return !n;
686  case 6: return v;
687  case 7: return !v;
688  case 8: return c && !z;
689  case 9: return !c || z;
690  case 10: return n == v;
691  case 11: return n != v;
692  case 12: return !z && (n == v);
693  case 13: return z || (n != v);
694  case 14: return 1;
695  case 15: return 0;
696  }
697 }
698 
699 static uvlong
700 jumptarg(Instr *i)
701 {
702  ulong m = smask(i->op->p, 'T');
703  return i->addr + sext(unshift(i->w, m), m)*4;
704 }
705 
706 static int
707 arm64foll(Map *map, uvlong pc, Rgetter rget, uvlong *foll)
708 {
709  Instr i[1];
710  char *o;
711 
712  if(decode(map, pc, i) < 0)
713  return -1;
714 
715  o = i->op->o;
716  if(strcmp(o, "ERET") == 0)
717  return -1;
718 
719  if(strcmp(o, "RET") == 0 || strcmp(o, "BR") == 0 || strcmp(o, "BLR") == 0){
720  foll[0] = readreg(i, rget, 'n');
721  return 1;
722  }
723  if(strcmp(o, "B") == 0 || strcmp(o, "BL") == 0){
724  foll[0] = jumptarg(i);
725  return 1;
726  }
727  if(strcmp(o, "B%C") == 0){
728  if(passcond(i, rget)){
729  foll[0] = jumptarg(i);
730  return 1;
731  }
732  }
733  if(strcmp(o, "CBZ%W") == 0){
734  if(readreg(i, rget, 'd') == 0){
735  foll[0] = jumptarg(i);
736  return 1;
737  }
738  }
739  if(strcmp(o, "CBNZ%W") == 0){
740  if(readreg(i, rget, 'd') != 0){
741  foll[0] = jumptarg(i);
742  return 1;
743  }
744  }
745 
746  foll[0] = i->addr+4;
747  return 1;
748 }