* [Qemu-devel] Instruction trace for ARM target @ 2008-04-02 19:28 Klaus Goffart 2008-04-03 14:13 ` Stuart Brady 0 siblings, 1 reply; 4+ messages in thread From: Klaus Goffart @ 2008-04-02 19:28 UTC (permalink / raw) To: qemu-devel Hi, I would like to generate an instruction trace for an ARM target. I applied the patch from Stuart Brady posted in this thread http://thread.gmane.org/gmane.comp.emulators.qemu/16604 to the corresponding "arm-target/*" files. It seems to work fine and generates a trace of pc values. But, I'm not sure if these are all pc values. I do not completely understand the way the helper_dump_pc() method is called, but it seems that it is triggered in the disas_insn() respectively the disas_arm_insn() method. But isn't each instruction just disassembled once and then cached for the next execution? Then the corresponding pc values would be missing. To get the instructions being executed I call the ldl_code() method with the actual pc value in the helper_dump_pc() method. It seems to work, but it would be great if anybody could just point out if this is correct. My next step is to mark those instructions that are not executed due to their condition codes and the memory accessed by executed instructions. But I have no idea where this information is available. Can anybody give me a clue? I appreciate any help! Thanks, Klaus ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Instruction trace for ARM target 2008-04-02 19:28 [Qemu-devel] Instruction trace for ARM target Klaus Goffart @ 2008-04-03 14:13 ` Stuart Brady 2008-04-04 15:10 ` Klaus Goffart 0 siblings, 1 reply; 4+ messages in thread From: Stuart Brady @ 2008-04-03 14:13 UTC (permalink / raw) To: qemu-devel On Wed, Apr 02, 2008 at 09:28:19PM +0200, Klaus Goffart wrote: > But, I'm not sure if these are all pc values. I do not completely > understand the way the helper_dump_pc() method is called, but it seems > that it is triggered in the disas_insn() respectively the > disas_arm_insn() method. But isn't each instruction just disassembled > once and then cached for the next execution? Then the corresponding pc > values would be missing. That's why disas_insn() should call gen_op_dump_pc(), instead of calling helper_dump_pc() directly. Calling gen_op_dump_pc() adds the code needed to call helper_dump_pc() to the translation block that is currently being generated. Actually, with the code in SVN, you'd probably want something like: tcg_gen_helper_0_1(helper_dump_pc, tcg_const_ptr(s->pc)); You would then no longer need op_dump_pc(). The program counter isn't updated after each instruction is executed for performance reasons, so it's passed as a parameter during translation, whenever it is needed. On the other hand, when the program counter is finally updated (e.g. after a conditional branch) you often can't determine its new value at translation time -- but where the instruction fetch occurs, this isn't a problem! > To get the instructions being executed I call the ldl_code() method with > the actual pc value in the helper_dump_pc() method. It seems to work, > but it would be great if anybody could just point out if this is > correct. If by 'actualy pc value', you mean the PC in the CPUState ('env'), then I'm very surprised that this would appear to produce correct output. > My next step is to mark those instructions that are not executed due to > their condition codes and the memory accessed by executed instructions. > But I have no idea where this information is available. Can anybody give > me a clue? Well, you'd certainly have to generate extra ops to mark instructions as executed, as instruction fetches occur at translation time. For memory access, you could modify the memory accessors to perform the marking... probably by adding helper calls in tcg-op.h. Cheers, -- Stuart Brady ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Instruction trace for ARM target 2008-04-03 14:13 ` Stuart Brady @ 2008-04-04 15:10 ` Klaus Goffart 2008-04-07 21:58 ` Stuart Brady 0 siblings, 1 reply; 4+ messages in thread From: Klaus Goffart @ 2008-04-04 15:10 UTC (permalink / raw) To: qemu-devel Hi, first of all, thanks for your help. Am Donnerstag, den 03.04.2008, 15:13 +0100 schrieb Stuart Brady: > On Wed, Apr 02, 2008 at 09:28:19PM +0200, Klaus Goffart wrote: > > But, I'm not sure if these are all pc values. I do not completely > > understand the way the helper_dump_pc() method is called, but it seems > > that it is triggered in the disas_insn() respectively the > > disas_arm_insn() method. But isn't each instruction just disassembled > > once and then cached for the next execution? Then the corresponding pc > > values would be missing. > > That's why disas_insn() should call gen_op_dump_pc(), instead of calling > helper_dump_pc() directly. OK. This was my first approach, so it missed pc values of reused code blocks. > Calling gen_op_dump_pc() adds the code > needed to call helper_dump_pc() to the translation block that is > currently being generated. Just to make sure I picked it up right. The call of gen_op_dump_pc() during translation adds the op_dump_pc() to the generated micro instruction stream of the translation block. When the TB is executed, the op_dump_pc() operation is called, calling helper_dump_pc() with PARAM1. PARAM1 in op_dump_pc() is the first parameter passed to gen_op_dump_pc(), i.e. s->pc. So the pc values to be traced are included into the micro instruction stream and printed at execution time, right? > The program counter isn't updated after each instruction is executed for > performance reasons, so it's passed as a parameter during translation, > whenever it is needed. On the other hand, when the program counter is > finally updated (e.g. after a conditional branch) you often can't > determine its new value at translation time -- but where the instruction > fetch occurs, this isn't a problem! > > > To get the instructions being executed I call the ldl_code() method with > > the actual pc value in the helper_dump_pc() method. It seems to work, > > but it would be great if anybody could just point out if this is > > correct. > > If by 'actualy pc value', you mean the PC in the CPUState ('env'), then > I'm very surprised that this would appear to produce correct output. No, my helper_dump_pc() looks like this: void helper_dump_pc(target_ulong pc) { if (logfile) { fputc('#', logfile); fwrite(&pc, sizeof(pc), 1, logfile); insn = ldl_code(pc); fwrite(&insn, sizeof(insn), 1, logfile); } } > > My next step is to mark those instructions that are not executed due to > > their condition codes and the memory accessed by executed instructions. > > But I have no idea where this information is available. Can anybody give > > me a clue? > > Well, you'd certainly have to generate extra ops to mark instructions as > executed, as instruction fetches occur at translation time. OK, so conditional instructions are skipped by a jump to the next instruction if the condition code fails. This is what I found in the documentation. In the code it looks like this jump is also a micro operation. Therefore, an op should be placed right after the jump_op that marks the last dumped instruction as executed. Is this what you meant? Thanks! Klaus ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [Qemu-devel] Instruction trace for ARM target 2008-04-04 15:10 ` Klaus Goffart @ 2008-04-07 21:58 ` Stuart Brady 0 siblings, 0 replies; 4+ messages in thread From: Stuart Brady @ 2008-04-07 21:58 UTC (permalink / raw) To: qemu-devel On Fri, Apr 04, 2008 at 05:10:51PM +0200, Klaus Goffart wrote: > Am Donnerstag, den 03.04.2008, 15:13 +0100 schrieb Stuart Brady: > > Calling gen_op_dump_pc() adds the code > > needed to call helper_dump_pc() to the translation block that is > > currently being generated. > > Just to make sure I picked it up right. The call of gen_op_dump_pc() > during translation adds the op_dump_pc() to the generated micro > instruction stream of the translation block. That's right. > When the TB is executed, the op_dump_pc() operation is called Well, op_dump_pc() is never called, as its code is instead copied into the generated TB, but I think that's what you meant anyway. > calling helper_dump_pc() with PARAM1. PARAM1 in op_dump_pc() is the > first parameter passed to gen_op_dump_pc(), i.e. s->pc. So the pc > values to be traced are included into the micro instruction stream > and printed at execution time, right? That's correct. It would be better to avoid an immediate load of the emulated PC for each instruction -- with dyngen, doing so would not be very practical, as we'd really prefer to hold the emulated PC in an extra register -- but with TCG, that shouldn't really be a problem. > > If by 'actual pc value', you mean the PC in the CPUState ('env'), then > > I'm very surprised that this would appear to produce correct output. > > No, my helper_dump_pc() looks like this: > > void helper_dump_pc(target_ulong pc) > { > if (logfile) > { > fputc('#', logfile); > fwrite(&pc, sizeof(pc), 1, logfile); > insn = ldl_code(pc); > fwrite(&insn, sizeof(insn), 1, logfile); > } > } Okay, that looks roughly correct -- although if you plan for anyone else to use that code, it would be preferable to produce the same output on big-endian and little-endian machines. > > Well, you'd certainly have to generate extra ops to mark instructions as > > executed, as instruction fetches occur at translation time. > > OK, so conditional instructions are skipped by a jump to the next > instruction if the condition code fails. This is what I found in the > documentation. In the code it looks like this jump is also a micro > operation. Therefore, an op should be placed right after the jump_op > that marks the last dumped instruction as executed. Is this what you > meant? Actually, I'd forgotten about ARM's conditional execution, and was talking about conditional branches. I expect that translated code can still be generated after a conditional branch, but never executed, as a result of that branch always (or perhaps never) being taken. What I meant was that you cannot mark instructions as executed by adding extra code to ldl_code(), but thanks to conditional execution, that was already rather more obvious than I had realised. Placing the dump_pc op after the jump op sounds correct, but you'll also need to deal with unconditional instructions, and conditional branches. Bear in mind that the program counter is incremented after ldl_code() is called, though. I wonder, does a branch count as 'executed' if and only if it is taken? What about branches with static 'taken' or 'not taken' prediction? Cheers, -- Stuart Brady ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2008-04-07 21:58 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-04-02 19:28 [Qemu-devel] Instruction trace for ARM target Klaus Goffart 2008-04-03 14:13 ` Stuart Brady 2008-04-04 15:10 ` Klaus Goffart 2008-04-07 21:58 ` Stuart Brady
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).