ui/gtk: remove unused code
[qemu/ar7.git] / disas.c
blob45285d3f63fd62d68baf681d99c54887b6d6057c
1 /* General "disassemble this chunk" code. Used for debugging. */
2 #include "qemu/osdep.h"
3 #include "disas/dis-asm.h"
4 #include "elf.h"
5 #include "qemu/qemu-print.h"
7 #include "cpu.h"
8 #include "disas/disas.h"
9 #include "disas/capstone.h"
11 typedef struct CPUDebug {
12 struct disassemble_info info;
13 CPUState *cpu;
14 } CPUDebug;
16 /* Filled in by elfload.c. Simplistic, but will do for now. */
17 struct syminfo *syminfos = NULL;
19 /* Get LENGTH bytes from info's buffer, at target address memaddr.
20 Transfer them to myaddr. */
21 int
22 buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
23 struct disassemble_info *info)
25 if (memaddr < info->buffer_vma
26 || memaddr + length > info->buffer_vma + info->buffer_length)
27 /* Out of bounds. Use EIO because GDB uses it. */
28 return EIO;
29 memcpy (myaddr, info->buffer + (memaddr - info->buffer_vma), length);
30 return 0;
33 /* Get LENGTH bytes from info's buffer, at target address memaddr.
34 Transfer them to myaddr. */
35 static int
36 target_read_memory (bfd_vma memaddr,
37 bfd_byte *myaddr,
38 int length,
39 struct disassemble_info *info)
41 CPUDebug *s = container_of(info, CPUDebug, info);
43 cpu_memory_rw_debug(s->cpu, memaddr, myaddr, length, 0);
44 return 0;
47 /* Print an error message. We can assume that this is in response to
48 an error return from buffer_read_memory. */
49 void
50 perror_memory (int status, bfd_vma memaddr, struct disassemble_info *info)
52 if (status != EIO)
53 /* Can't happen. */
54 (*info->fprintf_func) (info->stream, "Unknown error %d\n", status);
55 else
56 /* Actually, address between memaddr and memaddr + len was
57 out of bounds. */
58 (*info->fprintf_func) (info->stream,
59 "Address 0x%" PRIx64 " is out of bounds.\n", memaddr);
62 /* This could be in a separate file, to save minuscule amounts of space
63 in statically linked executables. */
65 /* Just print the address is hex. This is included for completeness even
66 though both GDB and objdump provide their own (to print symbolic
67 addresses). */
69 void
70 generic_print_address (bfd_vma addr, struct disassemble_info *info)
72 (*info->fprintf_func) (info->stream, "0x%" PRIx64, addr);
75 /* Print address in hex, truncated to the width of a host virtual address. */
76 static void
77 generic_print_host_address(bfd_vma addr, struct disassemble_info *info)
79 uint64_t mask = ~0ULL >> (64 - (sizeof(void *) * 8));
80 generic_print_address(addr & mask, info);
83 /* Just return the given address. */
85 int
86 generic_symbol_at_address (bfd_vma addr, struct disassemble_info *info)
88 return 1;
91 bfd_vma bfd_getl64 (const bfd_byte *addr)
93 unsigned long long v;
95 v = (unsigned long long) addr[0];
96 v |= (unsigned long long) addr[1] << 8;
97 v |= (unsigned long long) addr[2] << 16;
98 v |= (unsigned long long) addr[3] << 24;
99 v |= (unsigned long long) addr[4] << 32;
100 v |= (unsigned long long) addr[5] << 40;
101 v |= (unsigned long long) addr[6] << 48;
102 v |= (unsigned long long) addr[7] << 56;
103 return (bfd_vma) v;
106 bfd_vma bfd_getl32 (const bfd_byte *addr)
108 unsigned long v;
110 v = (unsigned long) addr[0];
111 v |= (unsigned long) addr[1] << 8;
112 v |= (unsigned long) addr[2] << 16;
113 v |= (unsigned long) addr[3] << 24;
114 return (bfd_vma) v;
117 bfd_vma bfd_getb32 (const bfd_byte *addr)
119 unsigned long v;
121 v = (unsigned long) addr[0] << 24;
122 v |= (unsigned long) addr[1] << 16;
123 v |= (unsigned long) addr[2] << 8;
124 v |= (unsigned long) addr[3];
125 return (bfd_vma) v;
128 bfd_vma bfd_getl16 (const bfd_byte *addr)
130 unsigned long v;
132 v = (unsigned long) addr[0];
133 v |= (unsigned long) addr[1] << 8;
134 return (bfd_vma) v;
137 bfd_vma bfd_getb16 (const bfd_byte *addr)
139 unsigned long v;
141 v = (unsigned long) addr[0] << 24;
142 v |= (unsigned long) addr[1] << 16;
143 return (bfd_vma) v;
146 static int print_insn_objdump(bfd_vma pc, disassemble_info *info,
147 const char *prefix)
149 int i, n = info->buffer_length;
150 uint8_t *buf = g_malloc(n);
152 info->read_memory_func(pc, buf, n, info);
154 for (i = 0; i < n; ++i) {
155 if (i % 32 == 0) {
156 info->fprintf_func(info->stream, "\n%s: ", prefix);
158 info->fprintf_func(info->stream, "%02x", buf[i]);
161 g_free(buf);
162 return n;
165 static int print_insn_od_host(bfd_vma pc, disassemble_info *info)
167 return print_insn_objdump(pc, info, "OBJD-H");
170 static int print_insn_od_target(bfd_vma pc, disassemble_info *info)
172 return print_insn_objdump(pc, info, "OBJD-T");
175 #ifdef CONFIG_CAPSTONE
176 /* Temporary storage for the capstone library. This will be alloced via
177 malloc with a size private to the library; thus there's no reason not
178 to share this across calls and across host vs target disassembly. */
179 static __thread cs_insn *cap_insn;
181 /* Initialize the Capstone library. */
182 /* ??? It would be nice to cache this. We would need one handle for the
183 host and one for the target. For most targets we can reset specific
184 parameters via cs_option(CS_OPT_MODE, new_mode), but we cannot change
185 CS_ARCH_* in this way. Thus we would need to be able to close and
186 re-open the target handle with a different arch for the target in order
187 to handle AArch64 vs AArch32 mode switching. */
188 static cs_err cap_disas_start(disassemble_info *info, csh *handle)
190 cs_mode cap_mode = info->cap_mode;
191 cs_err err;
193 cap_mode += (info->endian == BFD_ENDIAN_BIG ? CS_MODE_BIG_ENDIAN
194 : CS_MODE_LITTLE_ENDIAN);
196 err = cs_open(info->cap_arch, cap_mode, handle);
197 if (err != CS_ERR_OK) {
198 return err;
201 /* ??? There probably ought to be a better place to put this. */
202 if (info->cap_arch == CS_ARCH_X86) {
203 /* We don't care about errors (if for some reason the library
204 is compiled without AT&T syntax); the user will just have
205 to deal with the Intel syntax. */
206 cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
209 /* "Disassemble" unknown insns as ".byte W,X,Y,Z". */
210 cs_option(*handle, CS_OPT_SKIPDATA, CS_OPT_ON);
212 /* Allocate temp space for cs_disasm_iter. */
213 if (cap_insn == NULL) {
214 cap_insn = cs_malloc(*handle);
215 if (cap_insn == NULL) {
216 cs_close(handle);
217 return CS_ERR_MEM;
220 return CS_ERR_OK;
223 static void cap_dump_insn_units(disassemble_info *info, cs_insn *insn,
224 int i, int n)
226 fprintf_function print = info->fprintf_func;
227 FILE *stream = info->stream;
229 switch (info->cap_insn_unit) {
230 case 4:
231 if (info->endian == BFD_ENDIAN_BIG) {
232 for (; i < n; i += 4) {
233 print(stream, " %08x", ldl_be_p(insn->bytes + i));
236 } else {
237 for (; i < n; i += 4) {
238 print(stream, " %08x", ldl_le_p(insn->bytes + i));
241 break;
243 case 2:
244 if (info->endian == BFD_ENDIAN_BIG) {
245 for (; i < n; i += 2) {
246 print(stream, " %04x", lduw_be_p(insn->bytes + i));
248 } else {
249 for (; i < n; i += 2) {
250 print(stream, " %04x", lduw_le_p(insn->bytes + i));
253 break;
255 default:
256 for (; i < n; i++) {
257 print(stream, " %02x", insn->bytes[i]);
259 break;
263 static void cap_dump_insn(disassemble_info *info, cs_insn *insn,
264 const char *note)
266 fprintf_function print = info->fprintf_func;
267 int i, n, split;
269 print(info->stream, "0x%08" PRIx64 ": ", insn->address);
271 n = insn->size;
272 split = info->cap_insn_split;
274 /* Dump the first SPLIT bytes of the instruction. */
275 cap_dump_insn_units(info, insn, 0, MIN(n, split));
277 /* Add padding up to SPLIT so that mnemonics line up. */
278 if (n < split) {
279 int width = (split - n) / info->cap_insn_unit;
280 width *= (2 * info->cap_insn_unit + 1);
281 print(info->stream, "%*s", width, "");
284 /* Print the actual instruction. */
285 print(info->stream, " %-8s %s", insn->mnemonic, insn->op_str);
286 if (note) {
287 print(info->stream, "\t\t%s", note);
289 print(info->stream, "\n");
291 /* Dump any remaining part of the insn on subsequent lines. */
292 for (i = split; i < n; i += split) {
293 print(info->stream, "0x%08" PRIx64 ": ", insn->address + i);
294 cap_dump_insn_units(info, insn, i, MIN(n, i + split));
295 print(info->stream, "\n");
299 /* Disassemble SIZE bytes at PC for the target. */
300 static bool cap_disas_target(disassemble_info *info, uint64_t pc, size_t size)
302 uint8_t cap_buf[1024];
303 csh handle;
304 cs_insn *insn;
305 size_t csize = 0;
307 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
308 return false;
310 insn = cap_insn;
312 while (1) {
313 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
314 const uint8_t *cbuf = cap_buf;
316 target_read_memory(pc + csize, cap_buf + csize, tsize, info);
317 csize += tsize;
318 size -= tsize;
320 while (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
321 cap_dump_insn(info, insn, NULL);
324 /* If the target memory is not consumed, go back for more... */
325 if (size != 0) {
326 /* ... taking care to move any remaining fractional insn
327 to the beginning of the buffer. */
328 if (csize != 0) {
329 memmove(cap_buf, cbuf, csize);
331 continue;
334 /* Since the target memory is consumed, we should not have
335 a remaining fractional insn. */
336 if (csize != 0) {
337 (*info->fprintf_func)(info->stream,
338 "Disassembler disagrees with translator "
339 "over instruction decoding\n"
340 "Please report this to qemu-devel@nongnu.org\n");
342 break;
345 cs_close(&handle);
346 return true;
349 /* Disassemble SIZE bytes at CODE for the host. */
350 static bool cap_disas_host(disassemble_info *info, void *code, size_t size,
351 const char *note)
353 csh handle;
354 const uint8_t *cbuf;
355 cs_insn *insn;
356 uint64_t pc;
358 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
359 return false;
361 insn = cap_insn;
363 cbuf = code;
364 pc = (uintptr_t)code;
366 while (cs_disasm_iter(handle, &cbuf, &size, &pc, insn)) {
367 cap_dump_insn(info, insn, note);
368 note = NULL;
370 if (size != 0) {
371 (*info->fprintf_func)(info->stream,
372 "Disassembler disagrees with TCG over instruction encoding\n"
373 "Please report this to qemu-devel@nongnu.org\n");
376 cs_close(&handle);
377 return true;
380 #if !defined(CONFIG_USER_ONLY)
381 /* Disassemble COUNT insns at PC for the target. */
382 static bool cap_disas_monitor(disassemble_info *info, uint64_t pc, int count)
384 uint8_t cap_buf[32];
385 csh handle;
386 cs_insn *insn;
387 size_t csize = 0;
389 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
390 return false;
392 insn = cap_insn;
394 while (1) {
395 /* We want to read memory for one insn, but generically we do not
396 know how much memory that is. We have a small buffer which is
397 known to be sufficient for all supported targets. Try to not
398 read beyond the page, Just In Case. For even more simplicity,
399 ignore the actual target page size and use a 1k boundary. If
400 that turns out to be insufficient, we'll come back around the
401 loop and read more. */
402 uint64_t epc = QEMU_ALIGN_UP(pc + csize + 1, 1024);
403 size_t tsize = MIN(sizeof(cap_buf) - csize, epc - pc);
404 const uint8_t *cbuf = cap_buf;
406 /* Make certain that we can make progress. */
407 assert(tsize != 0);
408 info->read_memory_func(pc, cap_buf + csize, tsize, info);
409 csize += tsize;
411 if (cs_disasm_iter(handle, &cbuf, &csize, &pc, insn)) {
412 cap_dump_insn(info, insn, NULL);
413 if (--count <= 0) {
414 break;
417 memmove(cap_buf, cbuf, csize);
420 cs_close(&handle);
421 return true;
423 #endif /* !CONFIG_USER_ONLY */
424 #else
425 # define cap_disas_target(i, p, s) false
426 # define cap_disas_host(i, p, s, n) false
427 # define cap_disas_monitor(i, p, c) false
428 # define cap_disas_plugin(i, p, c) false
429 #endif /* CONFIG_CAPSTONE */
431 /* Disassemble this for me please... (debugging). */
432 void target_disas(FILE *out, CPUState *cpu, target_ulong code,
433 target_ulong size)
435 CPUClass *cc = CPU_GET_CLASS(cpu);
436 target_ulong pc;
437 int count;
438 CPUDebug s;
440 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
442 s.cpu = cpu;
443 s.info.read_memory_func = target_read_memory;
444 s.info.buffer_vma = code;
445 s.info.buffer_length = size;
446 s.info.print_address_func = generic_print_address;
447 s.info.cap_arch = -1;
448 s.info.cap_mode = 0;
449 s.info.cap_insn_unit = 4;
450 s.info.cap_insn_split = 4;
452 #ifdef TARGET_WORDS_BIGENDIAN
453 s.info.endian = BFD_ENDIAN_BIG;
454 #else
455 s.info.endian = BFD_ENDIAN_LITTLE;
456 #endif
458 if (cc->disas_set_info) {
459 cc->disas_set_info(cpu, &s.info);
462 if (s.info.cap_arch >= 0 && cap_disas_target(&s.info, code, size)) {
463 return;
466 if (s.info.print_insn == NULL) {
467 s.info.print_insn = print_insn_od_target;
470 for (pc = code; size > 0; pc += count, size -= count) {
471 fprintf(out, "0x" TARGET_FMT_lx ": ", pc);
472 count = s.info.print_insn(pc, &s.info);
473 fprintf(out, "\n");
474 if (count < 0)
475 break;
476 if (size < count) {
477 fprintf(out,
478 "Disassembler disagrees with translator over instruction "
479 "decoding\n"
480 "Please report this to qemu-devel@nongnu.org\n");
481 break;
486 static __thread GString plugin_disas_output;
488 static int plugin_printf(FILE *stream, const char *fmt, ...)
490 va_list va;
491 GString *s = &plugin_disas_output;
492 int initial_len = s->len;
494 va_start(va, fmt);
495 g_string_append_vprintf(s, fmt, va);
496 va_end(va);
498 return s->len - initial_len;
501 static void plugin_print_address(bfd_vma addr, struct disassemble_info *info)
503 /* does nothing */
507 #ifdef CONFIG_CAPSTONE
508 /* Disassemble a single instruction directly into plugin output */
509 static
510 bool cap_disas_plugin(disassemble_info *info, uint64_t pc, size_t size)
512 uint8_t cap_buf[1024];
513 csh handle;
514 cs_insn *insn;
515 size_t csize = 0;
516 int count;
517 GString *s = &plugin_disas_output;
519 if (cap_disas_start(info, &handle) != CS_ERR_OK) {
520 return false;
522 insn = cap_insn;
524 size_t tsize = MIN(sizeof(cap_buf) - csize, size);
525 const uint8_t *cbuf = cap_buf;
526 target_read_memory(pc, cap_buf, tsize, info);
528 count = cs_disasm(handle, cbuf, size, 0, 1, &insn);
530 if (count) {
531 g_string_printf(s, "%s %s", insn->mnemonic, insn->op_str);
532 } else {
533 g_string_printf(s, "cs_disasm failed");
536 cs_close(&handle);
537 return true;
539 #endif
542 * We should only be dissembling one instruction at a time here. If
543 * there is left over it usually indicates the front end has read more
544 * bytes than it needed.
546 char *plugin_disas(CPUState *cpu, uint64_t addr, size_t size)
548 CPUClass *cc = CPU_GET_CLASS(cpu);
549 int count;
550 CPUDebug s;
551 GString *ds = g_string_set_size(&plugin_disas_output, 0);
553 g_assert(ds == &plugin_disas_output);
555 INIT_DISASSEMBLE_INFO(s.info, NULL, plugin_printf);
557 s.cpu = cpu;
558 s.info.read_memory_func = target_read_memory;
559 s.info.buffer_vma = addr;
560 s.info.buffer_length = size;
561 s.info.print_address_func = plugin_print_address;
562 s.info.cap_arch = -1;
563 s.info.cap_mode = 0;
564 s.info.cap_insn_unit = 4;
565 s.info.cap_insn_split = 4;
567 #ifdef TARGET_WORDS_BIGENDIAN
568 s.info.endian = BFD_ENDIAN_BIG;
569 #else
570 s.info.endian = BFD_ENDIAN_LITTLE;
571 #endif
573 if (cc->disas_set_info) {
574 cc->disas_set_info(cpu, &s.info);
577 if (s.info.cap_arch >= 0 && cap_disas_plugin(&s.info, addr, size)) {
578 return g_strdup(ds->str);
581 if (s.info.print_insn == NULL) {
582 s.info.print_insn = print_insn_od_target;
585 count = s.info.print_insn(addr, &s.info);
587 /* The decoder probably read more than it needed it's not critical */
588 if (count < size) {
589 warn_report("%s: %zu bytes left over", __func__, size - count);
592 return g_strdup(ds->str);
595 /* Disassemble this for me please... (debugging). */
596 void disas(FILE *out, void *code, unsigned long size, const char *note)
598 uintptr_t pc;
599 int count;
600 CPUDebug s;
601 int (*print_insn)(bfd_vma pc, disassemble_info *info) = NULL;
603 INIT_DISASSEMBLE_INFO(s.info, out, fprintf);
604 s.info.print_address_func = generic_print_host_address;
606 s.info.buffer = code;
607 s.info.buffer_vma = (uintptr_t)code;
608 s.info.buffer_length = size;
609 s.info.cap_arch = -1;
610 s.info.cap_mode = 0;
611 s.info.cap_insn_unit = 4;
612 s.info.cap_insn_split = 4;
614 #ifdef HOST_WORDS_BIGENDIAN
615 s.info.endian = BFD_ENDIAN_BIG;
616 #else
617 s.info.endian = BFD_ENDIAN_LITTLE;
618 #endif
619 #if defined(CONFIG_TCG_INTERPRETER)
620 print_insn = print_insn_tci;
621 #elif defined(__i386__)
622 s.info.mach = bfd_mach_i386_i386;
623 print_insn = print_insn_i386;
624 s.info.cap_arch = CS_ARCH_X86;
625 s.info.cap_mode = CS_MODE_32;
626 s.info.cap_insn_unit = 1;
627 s.info.cap_insn_split = 8;
628 #elif defined(__x86_64__)
629 s.info.mach = bfd_mach_x86_64;
630 print_insn = print_insn_i386;
631 s.info.cap_arch = CS_ARCH_X86;
632 s.info.cap_mode = CS_MODE_64;
633 s.info.cap_insn_unit = 1;
634 s.info.cap_insn_split = 8;
635 #elif defined(_ARCH_PPC)
636 s.info.disassembler_options = (char *)"any";
637 print_insn = print_insn_ppc;
638 s.info.cap_arch = CS_ARCH_PPC;
639 # ifdef _ARCH_PPC64
640 s.info.cap_mode = CS_MODE_64;
641 # endif
642 #elif defined(__riscv) && defined(CONFIG_RISCV_DIS)
643 #if defined(_ILP32) || (__riscv_xlen == 32)
644 print_insn = print_insn_riscv32;
645 #elif defined(_LP64)
646 print_insn = print_insn_riscv64;
647 #else
648 #error unsupported RISC-V ABI
649 #endif
650 #elif defined(__aarch64__) && defined(CONFIG_ARM_A64_DIS)
651 print_insn = print_insn_arm_a64;
652 s.info.cap_arch = CS_ARCH_ARM64;
653 #elif defined(__alpha__)
654 print_insn = print_insn_alpha;
655 #elif defined(__sparc__)
656 print_insn = print_insn_sparc;
657 s.info.mach = bfd_mach_sparc_v9b;
658 #elif defined(__arm__)
659 print_insn = print_insn_arm;
660 s.info.cap_arch = CS_ARCH_ARM;
661 /* TCG only generates code for arm mode. */
662 #elif defined(__MIPSEB__)
663 print_insn = print_insn_big_mips;
664 #elif defined(__MIPSEL__)
665 print_insn = print_insn_little_mips;
666 #elif defined(__m68k__)
667 print_insn = print_insn_m68k;
668 #elif defined(__s390__)
669 print_insn = print_insn_s390;
670 #elif defined(__hppa__)
671 print_insn = print_insn_hppa;
672 #endif
674 if (s.info.cap_arch >= 0 && cap_disas_host(&s.info, code, size, note)) {
675 return;
678 if (print_insn == NULL) {
679 print_insn = print_insn_od_host;
681 for (pc = (uintptr_t)code; size > 0; pc += count, size -= count) {
682 fprintf(out, "0x%08" PRIxPTR ": ", pc);
683 count = print_insn(pc, &s.info);
684 if (note) {
685 fprintf(out, "\t\t%s", note);
686 note = NULL;
688 fprintf(out, "\n");
689 if (count < 0) {
690 break;
696 /* Look up symbol for debugging purpose. Returns "" if unknown. */
697 const char *lookup_symbol(target_ulong orig_addr)
699 const char *symbol = "";
700 struct syminfo *s;
702 for (s = syminfos; s; s = s->next) {
703 symbol = s->lookup_symbol(s, orig_addr);
704 if (symbol[0] != '\0') {
705 break;
709 return symbol;
712 #if !defined(CONFIG_USER_ONLY)
714 #include "monitor/monitor.h"
716 static int
717 physical_read_memory(bfd_vma memaddr, bfd_byte *myaddr, int length,
718 struct disassemble_info *info)
720 CPUDebug *s = container_of(info, CPUDebug, info);
722 address_space_read(s->cpu->as, memaddr, MEMTXATTRS_UNSPECIFIED,
723 myaddr, length);
724 return 0;
727 /* Disassembler for the monitor. */
728 void monitor_disas(Monitor *mon, CPUState *cpu,
729 target_ulong pc, int nb_insn, int is_physical)
731 CPUClass *cc = CPU_GET_CLASS(cpu);
732 int count, i;
733 CPUDebug s;
735 INIT_DISASSEMBLE_INFO(s.info, NULL, qemu_fprintf);
737 s.cpu = cpu;
738 s.info.read_memory_func
739 = (is_physical ? physical_read_memory : target_read_memory);
740 s.info.print_address_func = generic_print_address;
741 s.info.buffer_vma = pc;
742 s.info.cap_arch = -1;
743 s.info.cap_mode = 0;
744 s.info.cap_insn_unit = 4;
745 s.info.cap_insn_split = 4;
747 #ifdef TARGET_WORDS_BIGENDIAN
748 s.info.endian = BFD_ENDIAN_BIG;
749 #else
750 s.info.endian = BFD_ENDIAN_LITTLE;
751 #endif
753 if (cc->disas_set_info) {
754 cc->disas_set_info(cpu, &s.info);
757 if (s.info.cap_arch >= 0 && cap_disas_monitor(&s.info, pc, nb_insn)) {
758 return;
761 if (!s.info.print_insn) {
762 monitor_printf(mon, "0x" TARGET_FMT_lx
763 ": Asm output not supported on this arch\n", pc);
764 return;
767 for(i = 0; i < nb_insn; i++) {
768 monitor_printf(mon, "0x" TARGET_FMT_lx ": ", pc);
769 count = s.info.print_insn(pc, &s.info);
770 monitor_printf(mon, "\n");
771 if (count < 0)
772 break;
773 pc += count;
776 #endif