OLD | NEW |
---|---|
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <stdlib.h> | 5 #include <stdlib.h> |
6 #include <cmath> | 6 #include <cmath> |
7 #include <cstdarg> | 7 #include <cstdarg> |
8 #include "v8.h" | 8 #include "v8.h" |
9 | 9 |
10 #if V8_TARGET_ARCH_ARM64 | 10 #if V8_TARGET_ARCH_ARM64 |
(...skipping 3563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3574 ASSERT(pc_->ImmException() == kImmExceptionIsUnreachable); | 3574 ASSERT(pc_->ImmException() == kImmExceptionIsUnreachable); |
3575 // - Skip past the unreachable marker. | 3575 // - Skip past the unreachable marker. |
3576 set_pc(pc_->following()); | 3576 set_pc(pc_->following()); |
3577 | 3577 |
3578 // Check if the debugger should break. | 3578 // Check if the debugger should break. |
3579 if (parameters & BREAK) Debug(); | 3579 if (parameters & BREAK) Debug(); |
3580 | 3580 |
3581 } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) { | 3581 } else if (instr->ImmException() == kImmExceptionIsRedirectedCall) { |
3582 DoRuntimeCall(instr); | 3582 DoRuntimeCall(instr); |
3583 } else if (instr->ImmException() == kImmExceptionIsPrintf) { | 3583 } else if (instr->ImmException() == kImmExceptionIsPrintf) { |
3584 // Read the argument encoded inline in the instruction stream. | 3584 DoPrintf(instr); |
3585 uint32_t type; | |
3586 memcpy(&type, | |
3587 pc_->InstructionAtOffset(kPrintfTypeOffset), | |
3588 sizeof(type)); | |
3589 | |
3590 const char* format = reg<const char*>(0); | |
3591 | |
3592 // Pass all of the relevant PCS registers onto printf. It doesn't | |
3593 // matter if we pass too many as the extra ones won't be read. | |
3594 int result; | |
3595 fputs(clr_printf, stream_); | |
3596 if (type == CPURegister::kRegister) { | |
3597 result = fprintf(stream_, format, | |
3598 xreg(1), xreg(2), xreg(3), xreg(4), | |
3599 xreg(5), xreg(6), xreg(7)); | |
3600 } else if (type == CPURegister::kFPRegister) { | |
3601 result = fprintf(stream_, format, | |
3602 dreg(0), dreg(1), dreg(2), dreg(3), | |
3603 dreg(4), dreg(5), dreg(6), dreg(7)); | |
3604 } else { | |
3605 ASSERT(type == CPURegister::kNoRegister); | |
3606 result = fprintf(stream_, "%s", format); | |
3607 } | |
3608 fputs(clr_normal, stream_); | |
3609 | |
3610 #ifdef DEBUG | |
3611 CorruptAllCallerSavedCPURegisters(); | |
3612 #endif | |
3613 | |
3614 set_xreg(0, result); | |
3615 | |
3616 // The printf parameters are inlined in the code, so skip them. | |
3617 set_pc(pc_->InstructionAtOffset(kPrintfLength)); | |
3618 | |
3619 // Set LR as if we'd just called a native printf function. | |
3620 set_lr(pc()); | |
3621 | 3585 |
3622 } else if (instr->ImmException() == kImmExceptionIsUnreachable) { | 3586 } else if (instr->ImmException() == kImmExceptionIsUnreachable) { |
3623 fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n", | 3587 fprintf(stream_, "Hit UNREACHABLE marker at PC=%p.\n", |
3624 reinterpret_cast<void*>(pc_)); | 3588 reinterpret_cast<void*>(pc_)); |
3625 abort(); | 3589 abort(); |
3626 | 3590 |
3627 } else { | 3591 } else { |
3628 OS::DebugBreak(); | 3592 OS::DebugBreak(); |
3629 } | 3593 } |
3630 break; | 3594 break; |
3631 } | 3595 } |
3632 | 3596 |
3633 default: | 3597 default: |
3634 UNIMPLEMENTED(); | 3598 UNIMPLEMENTED(); |
3635 } | 3599 } |
3636 } | 3600 } |
3637 | 3601 |
3602 | |
3603 void Simulator::DoPrintf(Instruction* instr) { | |
3604 ASSERT((instr->Mask(ExceptionMask) == HLT) && | |
3605 (instr->ImmException() == kImmExceptionIsPrintf)); | |
3606 | |
3607 // Read the arguments encoded inline in the instruction stream. | |
3608 uint32_t arg_count; | |
3609 uint32_t arg_pattern_list; | |
3610 STATIC_ASSERT(sizeof(*instr) == 1); | |
3611 memcpy(&arg_count, | |
3612 instr + kPrintfArgCountOffset, | |
3613 sizeof(arg_count)); | |
3614 memcpy(&arg_pattern_list, | |
3615 instr + kPrintfArgPatternListOffset, | |
3616 sizeof(arg_pattern_list)); | |
3617 | |
3618 ASSERT(arg_count <= kPrintfMaxArgCount); | |
3619 ASSERT((arg_pattern_list >> (kPrintfArgPatternBits * arg_count)) == 0); | |
3620 | |
3621 // We need to call the host printf function with a set of arguments defined by | |
3622 // arg_pattern_list. Because we don't know the types and sizes of the | |
3623 // arguments, this is very difficult to do in a robust and portable way. To | |
3624 // work around the problem, we pick apart the format string, and print one | |
3625 // format placeholder at a time. | |
rmcilroy
2014/05/08 09:32:13
It's sad you need to go to all this bother since y
jbramley
2014/05/08 14:48:01
Yes, it is! I tried a few approaches and this was
| |
3626 | |
3627 // Allocate space for the format string. We take a copy, so we can modify it. | |
3628 // Leave enough space for one extra character per expected argument (plus the | |
3629 // '\0' termination). | |
3630 const char * format_base = reg<const char *>(0); | |
3631 ASSERT(format_base != NULL); | |
3632 size_t length = strlen(format_base) + 1; | |
3633 char * const format = new char[length + arg_count]; | |
3634 | |
3635 // A list of chunks, each with exactly one format placeholder. | |
3636 const char * chunks[kPrintfMaxArgCount]; | |
3637 | |
3638 // Copy the format string and search for format placeholders. | |
3639 uint32_t placeholder_count = 0; | |
3640 char * format_scratch = format; | |
3641 for (size_t i = 0; i < length; i++) { | |
3642 if (format_base[i] != '%') { | |
3643 *format_scratch++ = format_base[i]; | |
3644 } else { | |
3645 if (format_base[i + 1] == '%') { | |
3646 // Ignore explicit "%%" sequences. | |
3647 *format_scratch++ = format_base[i]; | |
3648 i++; | |
3649 // Chunks after the first are passed as format strings to printf, so we | |
3650 // need to escape '%' characters in those chunks. | |
3651 if (placeholder_count > 0) *format_scratch++ = format_base[i]; | |
rmcilroy
2014/05/08 09:32:13
Doesn't this mean you can overrun the size of the
jbramley
2014/05/08 14:48:01
- For the first chunk (which contains no format pl
rmcilroy
2014/05/08 15:38:32
Ahh I see - I missed the 'i++'. I think this is c
jbramley
2014/05/12 10:11:29
Done.
| |
3652 } else { | |
3653 CHECK(placeholder_count < arg_count); | |
3654 // Insert '\0' before placeholders, and store their locations. | |
3655 *format_scratch++ = '\0'; | |
3656 chunks[placeholder_count++] = format_scratch; | |
3657 *format_scratch++ = format_base[i]; | |
3658 } | |
3659 } | |
3660 } | |
3661 CHECK(placeholder_count == arg_count); | |
3662 | |
3663 // Finally, call printf with each chunk, passing the appropriate register | |
3664 // argument. Normally, printf returns the number of bytes transmitted, so we | |
3665 // can emulate a single printf call by adding the result from each chunk. If | |
3666 // any call returns a negative (error) value, though, just return that value. | |
3667 | |
3668 fprintf(stream_, "%s", clr_printf); | |
3669 | |
3670 // Because '\0' is inserted before each placeholder, the first string in | |
3671 // 'format' contains no format placeholders and should be printed literally. | |
3672 int result = fprintf(stream_, "%s", format); | |
3673 int pcs_r = 1; // Start at x1. x0 holds the format string. | |
3674 int pcs_f = 0; // Start at d0. | |
3675 if (result >= 0) { | |
3676 for (uint32_t i = 0; i < placeholder_count; i++) { | |
3677 int part_result = -1; | |
3678 | |
3679 uint32_t arg_pattern = arg_pattern_list >> (i * kPrintfArgPatternBits); | |
3680 arg_pattern &= (1 << kPrintfArgPatternBits) - 1; | |
3681 switch (arg_pattern) { | |
3682 case kPrintfArgW: | |
3683 part_result = fprintf(stream_, chunks[i], wreg(pcs_r++)); | |
3684 break; | |
3685 case kPrintfArgX: | |
3686 part_result = fprintf(stream_, chunks[i], xreg(pcs_r++)); | |
3687 break; | |
3688 case kPrintfArgD: | |
3689 part_result = fprintf(stream_, chunks[i], dreg(pcs_f++)); | |
3690 break; | |
3691 default: UNREACHABLE(); | |
3692 } | |
3693 | |
3694 if (part_result < 0) { | |
3695 // Handle error values. | |
3696 result = part_result; | |
3697 break; | |
3698 } | |
3699 | |
3700 result += part_result; | |
3701 } | |
3702 } | |
3703 | |
3704 fprintf(stream_, "%s", clr_normal); | |
3705 | |
3706 #ifdef DEBUG | |
3707 CorruptAllCallerSavedCPURegisters(); | |
3708 #endif | |
3709 | |
3710 // Printf returns its result in x0 (just like the C library's printf). | |
3711 set_xreg(0, result); | |
3712 | |
3713 // The printf parameters are inlined in the code, so skip them. | |
3714 set_pc(instr->InstructionAtOffset(kPrintfLength)); | |
3715 | |
3716 // Set LR as if we'd just called a native printf function. | |
3717 set_lr(pc()); | |
3718 | |
3719 delete[] format; | |
3720 } | |
3721 | |
3722 | |
3638 #endif // USE_SIMULATOR | 3723 #endif // USE_SIMULATOR |
3639 | 3724 |
3640 } } // namespace v8::internal | 3725 } } // namespace v8::internal |
3641 | 3726 |
3642 #endif // V8_TARGET_ARCH_ARM64 | 3727 #endif // V8_TARGET_ARCH_ARM64 |
OLD | NEW |