blob: 87dc1765645be1d80612fb25cf693ae03b869e82 [file] [log] [blame]
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +08001/* Capstone Disassembler Engine */
2/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2013> */
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <capstone.h>
8
9#include "cs_priv.h"
10
11#include "MCRegisterInfo.h"
12
danghvu34d49d92013-12-19 12:10:24 -060013#include "arch.h"
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080014#include "utils.h"
15
Nguyen Anh Quynh36df4bb2013-12-10 13:31:20 +080016void cs_version(int *major, int *minor)
17{
18 *major = CS_API_MAJOR;
19 *minor = CS_API_MINOR;
20}
21
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080022cs_err cs_errno(csh handle)
23{
24 if (!handle)
25 return CS_ERR_CSH;
26
27 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
28
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +080029 return ud->errnum;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080030}
31
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080032cs_err cs_open(cs_arch arch, cs_mode mode, csh *handle)
33{
danghvu2b192962013-12-19 22:40:28 -060034 cs_struct *ud;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080035
danghvu2b192962013-12-19 22:40:28 -060036 ud = calloc(1, sizeof(*ud));
37 if (!ud) {
38 // memory insufficient
39 return CS_ERR_MEM;
40 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080041
danghvu2b192962013-12-19 22:40:28 -060042 ud->errnum = CS_ERR_OK;
43 ud->arch = arch;
44 ud->mode = mode;
45 ud->big_endian = mode & CS_MODE_BIG_ENDIAN;
46 ud->reg_name = NULL;
47 ud->detail = CS_OPT_ON; // by default break instruction into details
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080048
danghvu2b192962013-12-19 22:40:28 -060049 init_arch[ud->arch](ud);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080050
danghvu2b192962013-12-19 22:40:28 -060051 *handle = (uintptr_t)ud;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080052
danghvu2b192962013-12-19 22:40:28 -060053 return CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080054}
55
56cs_err cs_close(csh handle)
57{
58 if (!handle)
59 return CS_ERR_CSH;
60
61 cs_struct *ud = (cs_struct *)(uintptr_t)handle;
62
63 switch (ud->arch) {
64 case CS_ARCH_X86:
65 break;
66 case CS_ARCH_ARM:
67 case CS_ARCH_MIPS:
68 case CS_ARCH_ARM64:
69 free(ud->printer_info);
70 break;
71 default: // unsupported architecture
72 return CS_ERR_HANDLE;
73 }
74
75 memset(ud, 0, sizeof(*ud));
76 free(ud);
77
78 return CS_ERR_OK;
79}
80
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +080081#define MIN(x, y) ((x) < (y) ? (x) : (y))
82
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080083// fill insn with mnemonic & operands info
84static void fill_insn(cs_struct *handle, cs_insn *insn, char *buffer, MCInst *mci,
pancakef0e4eed2013-12-11 22:14:42 +010085 PostPrinter_t printer, const uint8_t *code)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080086{
Nguyen Anh Quynha209e672013-12-14 00:23:41 +080087 if (handle->detail) {
88 memcpy(insn, &mci->pub_insn, sizeof(*insn));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080089
Nguyen Anh Quynha209e672013-12-14 00:23:41 +080090 // fill the instruction bytes
91 memcpy(insn->bytes, code, MIN(sizeof(insn->bytes), insn->size));
Nguyen Anh Quynhad61c492013-11-30 16:23:31 +080092
Nguyen Anh Quynha209e672013-12-14 00:23:41 +080093 } else {
94 insn->address = mci->address;
95 insn->size = mci->insn_size;
96 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +080097
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +080098 // map internal instruction opcode to public insn ID
99 if (handle->insn_id)
100 handle->insn_id(insn, MCInst_getOpcode(mci), handle->detail);
101
102 // alias instruction might have ID saved in OpcodePub
103 if (MCInst_getOpcodePub(mci))
104 insn->id = MCInst_getOpcodePub(mci);
105
106 // post printer handles some corner cases (hacky)
107 if (printer)
108 printer((csh)handle, insn, buffer);
109
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800110 // fill in mnemonic & operands
Nguyen Anh Quynhdefb9bc2013-12-12 14:00:12 +0800111 // find first space or tab
112 char *sp = buffer;
113 for (sp = buffer; *sp; sp++)
114 if (*sp == ' '||*sp == '\t')
115 break;
116 if (*sp) {
117 *sp = '\0';
Nguyen Anh Quynh86dc3932013-12-12 14:43:39 +0800118 // find the next non-space char
119 sp++;
120 for (; ((*sp == ' ') || (*sp == '\t')); sp++);
121 strncpy(insn->op_str, sp, sizeof(insn->op_str) - 1);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800122 insn->op_str[sizeof(insn->op_str) - 1] = '\0';
123 } else
124 insn->op_str[0] = '\0';
125
126 strncpy(insn->mnemonic, buffer, sizeof(insn->mnemonic) - 1);
127 insn->mnemonic[sizeof(insn->mnemonic) - 1] = '\0';
128}
129
Nguyen Anh Quynhda8adad2013-12-04 09:44:07 +0800130cs_err cs_option(csh ud, cs_opt_type type, size_t value)
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800131{
danghvu2b192962013-12-19 22:40:28 -0600132 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
133 if (!handle)
134 return CS_ERR_CSH;
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800135
danghvu2b192962013-12-19 22:40:28 -0600136 switch(type) {
137 default:
138 break;
139 case CS_OPT_DETAIL:
140 handle->detail = value;
141 return CS_ERR_OK;
142 case CS_OPT_SYNTAX:
143 switch (handle->arch) {
144 default:
145 // only selected archs care about CS_OPT_SYNTAX
146 handle->errnum = CS_ERR_OPTION;
147 return CS_ERR_OPTION;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800148
danghvu34d49d92013-12-19 12:10:24 -0600149#ifdef CS_SUPPORT_X86
danghvu2b192962013-12-19 22:40:28 -0600150 case CS_ARCH_X86:
151 switch(value) {
152 default:
153 // wrong syntax value
154 handle->errnum = CS_ERR_OPTION;
155 return CS_ERR_OPTION;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800156
danghvu2b192962013-12-19 22:40:28 -0600157 case CS_OPT_SYNTAX_INTEL:
158 handle->printer = X86_Intel_printInst;
159 break;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800160
danghvu2b192962013-12-19 22:40:28 -0600161 case CS_OPT_SYNTAX_ATT:
162 handle->printer = X86_ATT_printInst;
163 break;
164 }
165 break;
danghvu34d49d92013-12-19 12:10:24 -0600166#endif
danghvu2b192962013-12-19 22:40:28 -0600167 }
168 break;
Nguyen Anh Quynh041e25d2013-12-06 00:37:32 +0800169
danghvu2b192962013-12-19 22:40:28 -0600170 case CS_OPT_MODE: // change engine's mode at run-time
171 handle->mode = value;
172 switch (handle->arch) {
173 default:
174 // only selected archs care about CS_OPT_SYNTAX
175 break;
danghvu34d49d92013-12-19 12:10:24 -0600176#ifdef CS_SUPPORT_ARM
danghvu2b192962013-12-19 22:40:28 -0600177 case CS_ARCH_ARM:
178 if (value & CS_MODE_THUMB)
179 handle->disasm = Thumb_getInstruction;
180 else
181 handle->disasm = ARM_getInstruction;
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800182
danghvu2b192962013-12-19 22:40:28 -0600183 handle->mode = value;
184 break;
danghvu34d49d92013-12-19 12:10:24 -0600185#endif
danghvu2b192962013-12-19 22:40:28 -0600186#ifdef CS_SUPPORT_AARCH64t
187 case CS_ARCH_MIPS:
188 if (value & CS_MODE_32)
189 handle->disasm = Mips_getInstruction;
190 else
191 handle->disasm = Mips64_getInstruction;
Nguyen Anh Quynh1bdb23a2013-12-20 00:04:26 +0800192
danghvu2b192962013-12-19 22:40:28 -0600193 handle->mode = value;
194 break;
danghvu34d49d92013-12-19 12:10:24 -0600195#endif
danghvu2b192962013-12-19 22:40:28 -0600196 }
197 break;
198 }
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800199
danghvu2b192962013-12-19 22:40:28 -0600200 return CS_ERR_OK;
Nguyen Anh Quynh01aba002013-12-03 21:00:09 +0800201}
202
pancakef0e4eed2013-12-11 22:14:42 +0100203size_t cs_disasm(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn *insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800204{
205 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
206 MCInst mci;
207 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800208 size_t c = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800209
210 if (!handle) {
211 // FIXME: handle this case?
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800212 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800213 return 0;
214 }
215
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800216 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800217 memset(insn, 0, count * sizeof(*insn));
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800218
219 while (size > 0) {
danghvu2b192962013-12-19 22:40:28 -0600220 MCInst_Init(&mci);
Nguyen Anh Quynh1f449282013-12-15 14:04:59 +0800221 mci.detail = handle->detail;
222 mci.mode = handle->mode;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800223
224 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
225 if (r) {
226 SStream ss;
227 SStream_Init(&ss);
228
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800229 // relative branches need to know the address & size of current insn
230 mci.insn_size = insn_size;
231 mci.address = offset;
232
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800233 if (handle->detail) {
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800234 // save all the information for non-detailed mode
235 mci.pub_insn.address = offset;
236 mci.pub_insn.size = insn_size;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800237 }
238
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800239 handle->printer(&mci, &ss, handle->printer_info);
240
Joxean114df0e2013-12-04 07:11:32 +0100241 fill_insn(handle, insn, ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800242
243 c++;
244 insn++;
245 buffer += insn_size;
246 size -= insn_size;
247 offset += insn_size;
248
Nguyen Anh Quynh9a0dbab2013-12-15 22:25:58 +0800249 if (c == count)
250 return c;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800251 } else
Nguyen Anh Quynh9a0dbab2013-12-15 22:25:58 +0800252 // face a broken instruction? then we stop here
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800253 return c;
254 }
255
256 return c;
257}
258
259// dynamicly allocate memory to contain disasm insn
260// NOTE: caller must free() the allocated memory itself to avoid memory leaking
pancakef0e4eed2013-12-11 22:14:42 +0100261size_t cs_disasm_dyn(csh ud, const uint8_t *buffer, size_t size, uint64_t offset, size_t count, cs_insn **insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800262{
263 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
264 MCInst mci;
265 uint16_t insn_size;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800266 size_t c = 0, f = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800267 cs_insn insn_cache[64];
268 void *total = NULL;
Nguyen Anh Quynhb42a6572013-11-29 17:40:07 +0800269 size_t total_size = 0;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800270
271 if (!handle) {
272 // FIXME: how to handle this case:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800273 // handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800274 return 0;
275 }
276
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800277 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800278
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800279 memset(insn_cache, 0, sizeof(insn_cache));
280
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800281 while (size > 0) {
danghvu2b192962013-12-19 22:40:28 -0600282 MCInst_Init(&mci);
Nguyen Anh Quynh1f449282013-12-15 14:04:59 +0800283 mci.detail = handle->detail;
284 mci.mode = handle->mode;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800285
286 bool r = handle->disasm(ud, buffer, size, &mci, &insn_size, offset, handle->getinsn_info);
287 if (r) {
288 SStream ss;
289 SStream_Init(&ss);
290
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800291 // relative branches need to know the address & size of current insn
292 mci.insn_size = insn_size;
293 mci.address = offset;
294
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800295 if (handle->detail) {
Nguyen Anh Quynh4d3e8522013-12-14 10:45:09 +0800296 // save all the information for non-detailed mode
297 mci.pub_insn.address = offset;
298 mci.pub_insn.size = insn_size;
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800299 }
300
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800301 handle->printer(&mci, &ss, handle->printer_info);
302
Joxean114df0e2013-12-04 07:11:32 +0100303 fill_insn(handle, &insn_cache[f], ss.buffer, &mci, handle->post_printer, buffer);
Nguyen Anh Quynha209e672013-12-14 00:23:41 +0800304
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800305 f++;
306
307 if (f == ARR_SIZE(insn_cache)) {
308 // resize total to contain newly disasm insns
309 total_size += sizeof(insn_cache);
310 void *tmp = realloc(total, total_size);
311 if (tmp == NULL) { // insufficient memory
312 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800313 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800314 return 0;
315 }
316
317 total = tmp;
318 memcpy(total + total_size - sizeof(insn_cache), insn_cache, sizeof(insn_cache));
319 // reset f back to 0
320 f = 0;
321 }
322
323 c++;
324 buffer += insn_size;
325 size -= insn_size;
326 offset += insn_size;
327
328 if (count > 0 && c == count)
329 break;
Nguyen Anh Quynh8f13f3c2013-12-04 22:57:04 +0800330 } else {
331 // encounter a broken instruction
332 // XXX: TODO: JOXEAN continue here
333 break;
334 }
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800335 }
336
337 if (f) {
338 // resize total to contain newly disasm insns
339 void *tmp = realloc(total, total_size + f * sizeof(insn_cache[0]));
340 if (tmp == NULL) { // insufficient memory
341 free(total);
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800342 handle->errnum = CS_ERR_MEM;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800343 return 0;
344 }
345
346 total = tmp;
347 memcpy(total + total_size, insn_cache, f * sizeof(insn_cache[0]));
348 }
349
350 *insn = total;
351
352 return c;
353}
354
355void cs_free(void *m)
356{
357 free(m);
358}
359
360// return friendly name of regiser in a string
pancakef0e4eed2013-12-11 22:14:42 +0100361const char *cs_reg_name(csh ud, unsigned int reg)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800362{
363 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
364
365 if (!handle || handle->reg_name == NULL) {
366 return NULL;
367 }
368
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800369 return handle->reg_name(ud, reg);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800370}
371
pancakef0e4eed2013-12-11 22:14:42 +0100372const char *cs_insn_name(csh ud, unsigned int insn)
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800373{
374 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
375
376 if (!handle || handle->insn_name == NULL) {
377 return NULL;
378 }
379
Nguyen Anh Quynha253c7a2013-12-09 10:26:18 +0800380 return handle->insn_name(ud, insn);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800381}
382
383static bool arr_exist(unsigned int *arr, int max, unsigned int id)
384{
385 int i;
386
387 for (i = 0; i < max; i++) {
388 if (arr[i] == id)
389 return true;
390 }
391
392 return false;
393}
394
395bool cs_insn_group(csh handle, cs_insn *insn, unsigned int group_id)
396{
397 if (!handle)
398 return false;
399
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800400 return arr_exist(insn->groups, insn->groups_count, group_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800401}
402
403bool cs_reg_read(csh handle, cs_insn *insn, unsigned int reg_id)
404{
405 if (!handle)
406 return false;
407
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800408 return arr_exist(insn->regs_read, insn->regs_read_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800409}
410
411bool cs_reg_write(csh handle, cs_insn *insn, unsigned int reg_id)
412{
413 if (!handle)
414 return false;
415
Nguyen Anh Quynhf35e2ad2013-12-03 11:10:26 +0800416 return arr_exist(insn->regs_write, insn->regs_write_count, reg_id);
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800417}
418
419int cs_op_count(csh ud, cs_insn *insn, unsigned int op_type)
420{
421 if (!ud)
422 return -1;
423
424 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
425 unsigned int count = 0, i;
426
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800427 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800428
429 switch (handle->arch) {
430 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800431 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800432 return -1;
433 case CS_ARCH_ARM:
434 for (i = 0; i < insn->arm.op_count; i++)
435 if (insn->arm.operands[i].type == op_type)
436 count++;
437 break;
438 case CS_ARCH_ARM64:
439 for (i = 0; i < insn->arm64.op_count; i++)
440 if (insn->arm64.operands[i].type == op_type)
441 count++;
442 break;
443 case CS_ARCH_X86:
444 for (i = 0; i < insn->x86.op_count; i++)
445 if (insn->x86.operands[i].type == op_type)
446 count++;
447 break;
448 case CS_ARCH_MIPS:
449 for (i = 0; i < insn->mips.op_count; i++)
450 if (insn->mips.operands[i].type == op_type)
451 count++;
452 break;
453 }
454
455 return count;
456}
457
458int cs_op_index(csh ud, cs_insn *insn, unsigned int op_type,
459 unsigned int post)
460{
461 if (!ud)
462 return -1;
463
464 cs_struct *handle = (cs_struct *)(uintptr_t)ud;
465 unsigned int count = 0, i;
466
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800467 handle->errnum = CS_ERR_OK;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800468
469 switch (handle->arch) {
470 default:
Nguyen Anh Quynh3eb9ac92013-11-27 15:24:47 +0800471 handle->errnum = CS_ERR_HANDLE;
Nguyen Anh Quynh26ee41a2013-11-27 12:11:31 +0800472 return -1;
473 case CS_ARCH_ARM:
474 for (i = 0; i < insn->arm.op_count; i++) {
475 if (insn->arm.operands[i].type == op_type)
476 count++;
477 if (count == post)
478 return i;
479 }
480 break;
481 case CS_ARCH_ARM64:
482 for (i = 0; i < insn->arm64.op_count; i++) {
483 if (insn->arm64.operands[i].type == op_type)
484 count++;
485 if (count == post)
486 return i;
487 }
488 break;
489 case CS_ARCH_X86:
490 for (i = 0; i < insn->x86.op_count; i++) {
491 if (insn->x86.operands[i].type == op_type)
492 count++;
493 if (count == post)
494 return i;
495 }
496 break;
497 case CS_ARCH_MIPS:
498 for (i = 0; i < insn->mips.op_count; i++) {
499 if (insn->mips.operands[i].type == op_type)
500 count++;
501 if (count == post)
502 return i;
503 }
504 break;
505 }
506
507 return -1;
508}