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