[Qemu-devel] Starting KVM/VMX guest with non-exiting RDTSC instruction

2018-06-04 Thread Lluís Vilanova
Hi,

Is there some way to start a KVM-accelerated VM with QEMU (on an Intel/VMX
host) that is configured so that RDTSC/RDTSCP instructions won't cause a
VM-exit?

According to Intel's manual, it seems I should disable the "RDTSC exiting"
bit on the MSR that Linux identifies as MSR_IA32_VMX_PROCBASED_CTLS (in its
KVM code).

I've checked the vmxcap script from qemu:

$ sudo /tmp/vmvm-vilanova/vmxcap.py | grep -i rdtsc
  RDTSC exitingyes
  Enable RDTSCPyes

So, can I somehow curbe QEMU+KVM to disable RDTSC exiting?

Thanks,
Lluis


Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-10-21 Thread Lluís Vilanova
Peter Maydell writes:

> On 15 October 2017 at 17:30, Lluís Vilanova  wrote:
>> Thinking about it, shouldn't this always be the same given QEMU's TLB/page 
>> table
>> consistency assurances?

> What TLB/page table consistency assurances? For ARM at least
> we will only update (ie flush) the TLB when the guest next
> executes a relevant TLB maintenance instruction. So a
> misbehaving guest can set things up so the page table
> is completely different from what's in QEMU's TLB if it
> wants. This all falls in the realms of architecturally
> unpredictable behaviour for the guest -- whether you
> want the instrumentation to be confused as well is a
> different question...

I meant that if the contents of a virtual memory page change while QEMU is
translating an instruction, it must be able to detect that and act accordingly
for correctness.

Having that in mind, the same should hold true when an instrumentor reads a
page's contents during translation (e.g., to gather information on opcodes).


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-10-15 Thread Lluís Vilanova
Emilio G Cota writes:

> On Fri, Oct 06, 2017 at 18:07:16 +0300, Lluís Vilanova wrote:
>> Emilio G Cota writes:
>> > On Thu, Oct 05, 2017 at 02:28:12 +0300, Lluís Vilanova wrote:
>> >> The API takes care of telling you if the access could be performed
>> >> successfully. If you access the instruction's memory representation at
>> >> translation time, it should be able to perform the access, since QEMU's
>> >> translation loop just had to do so in order to access that instruction (I 
>> >> should
>> >> check what happens in the corner case where another guest CPU changes the 
>> >> page
>> >> table, since I'm not sure if the address translation functions I'm using 
>> >> in QEMU
>> >> will use the per-vCPU TLB cache or always traverse the page table).
>> 
>> > That was my concern, I'd rather just perform the read once, that is, the 
>> > read(s)
>> > done by ops->insn_translate.
>> 
>> If your concern is on performance, that should not be an issue, since you'd 
>> be
>> using the memory peek functions at translation-time. Furthermore, since 
>> others
>> suggested having memory peek anyway, that's a nicer way (to me) to compose 
>> APIs
>> (and is less complex to implement).

> My concern was the same as yours, correctness -- what happens if something
> changes between the two reads? Because the two reads should always return
> the same thing.

Thinking about it, shouldn't this always be the same given QEMU's TLB/page table
consistency assurances? Otherwise, QEMU could read bytes from different physical
pages while translating an instruction from the same virtual page.

Therefore, this leads me to believe it is safe to use the memory read operations
during translation to let instrumentation libraries know what exactly they are
dealing with.



>> > I see. I implemented what I suggested above, i.e. tb_trans_cb
>> > (i.e. post_trans) passes an opaque descriptor of the TB (which can
>> > be iterated over insn by insn) and the return value (void *) of this
>> > cb will be passed by tb_exec_cb (i.e. pre_exec).  Perf-wise this
>> > is pretty OK, turns out even if we don't end up caring about the
>> > TB, the additional per-TB helper (which might not end up calling
>> > a callback) does not introduce significant overhead at execution time.
>> 
>> So you build this structure after translating the whole TB, and the user can
>> iterate it to check the translated instructions. This is closer to other
>> existing tools: you iterate the structure and then decide which/how to
>> instrument instructions, memory accesses, etc within it.

> Correct. I suspect they went with this design because it makes sense to
> do this preprocessing once, instead of having each plugin do it
> themselves. I'm not sure how much we should care about supporting multiple
> plugins, but the impression I get from DynamoRIO is that it seems important
> to users.

If that can be built into a "helper" instrumentation library / header that
others can use, I would rather keep this functionality outside QEMU.


>> My only concern is that this is much more complex than the simpler API I 
>> propose
>> (you must build the informational structures, generate calls to every 
>> possible
>> instrumentation call, which will be optimized-out by TCG if the user decides 
>> not
>> to use them, and overall pay in performance for any unused functionality),
>> whereas your approach can be implemented on top of it.

> It's pretty simple; tr_ops->translate_insn has to copy each insn.
> For instance, on aarch64 (disas_a64 is called from tr_translate_insn):

> -static void disas_a64_insn(CPUARMState *env, DisasContext *s)
> +static void disas_a64_insn(CPUARMState *env, DisasContext *s, struct 
> qemu_plugin_insn *q_insn)
>  {
>  uint32_t insn;

>  insn = arm_ldl_code(env, s->pc, s->sctlr_b);
> +if (q_insn) {
> +qemu_plugin_insn_append(q_insn, &insn, sizeof(insn));
> +}

> It takes some memory though (we duplicate the guest code), but perf-wise this
> isn't a big deal (an empty callback on every TB execution incurs only a 10-15%
> perf slowdown).

> I don't understand the part where you say that the instrumentation call can
> be optimized out. Is there a special value of a "TCG promise" (at 
> tb_trans_post
> time) that removes the previously generated callback (at tb_trans_pre time)?
> Otherwise I don't see how selective TB instrumentation can work at 
> tb_trans_pre
> time.

With the approach

Re: [Qemu-devel] [PATCH] tcg: Initialize cpu_env generically

2017-10-12 Thread Lluís Vilanova
Richard Henderson writes:

> On 10/11/2017 11:43 PM, Lluís Vilanova wrote:
>>> /* Track which vCPU triggers events */
>>> CPUState *cpu;  /* *_trans */
>>> -TCGv_env tcg_env;   /* *_exec  */
>> 
>> I would rather keep it here instead of making a new global variable, since 
>> that
>> should make it easier in the future to have multiple translation contexts.

> Why do you believe this prevents it?  The variable is literally identical for
> *all* targets.

If someone decides to make tcg_ctx thread-local or have one per target
architecture (supporting multiple target archs concurrently), having all that
info on the tcg_ctx object is easier to track and modify, compared to having
multiple global variables.


> r~

> PS: Everyone, please trim context that you don't care about.  If you just add
> two lines in the middle of 1000, I'll not always find it.

So true; I just went with the flow of the list, sorry.


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH] tcg: Initialize cpu_env generically

2017-10-11 Thread Lluís Vilanova
Richard Henderson writes:

> This is identical for each target.  So, move the initialization to
> common code.  Move the variable itself out of tcg_ctx and name it
> cpu_env to minimize changes within targets.

> This also means we can remove tcg_global_reg_new_{ptr,i32,i64},
> since there are no longer global-register temps created by targets.

> Signed-off-by: Richard Henderson 
> ---
>  include/exec/gen-icount.h |  8 
>  target/arm/translate.h|  1 -
>  tcg/tcg.h |  9 +
>  target/alpha/translate.c  |  4 
>  target/arm/translate.c|  4 
>  target/cris/translate.c   |  3 ---
>  target/cris/translate_v10.c   |  2 --
>  target/hppa/translate.c   |  4 
>  target/i386/translate.c   |  3 ---
>  target/lm32/translate.c   |  4 
>  target/m68k/translate.c   |  5 -
>  target/microblaze/translate.c |  4 
>  target/mips/translate.c   |  4 
>  target/moxie/translate.c  |  7 ++-
>  target/nios2/translate.c  |  3 ---
>  target/openrisc/translate.c   |  3 ---
>  target/ppc/translate.c| 10 +++---
>  target/s390x/translate.c  |  6 --
>  target/sh4/translate.c|  7 +--
>  target/sparc/translate.c  |  4 
>  target/tilegx/translate.c |  3 ---
>  target/tricore/translate.c|  6 ++
>  target/unicore32/translate.c  |  4 
>  target/xtensa/translate.c |  3 ---
>  tcg/tcg-op.c  | 30 +++---
>  tcg/tcg.c | 31 +++
>  26 files changed, 35 insertions(+), 137 deletions(-)

> diff --git a/include/exec/gen-icount.h b/include/exec/gen-icount.h
> index 9b3cb14dfa..de52a67ee8 100644
> --- a/include/exec/gen-icount.h
> +++ b/include/exec/gen-icount.h
> @@ -19,7 +19,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
>  count = tcg_temp_new_i32();
>  }
 
> -tcg_gen_ld_i32(count, tcg_ctx.tcg_env,
> +tcg_gen_ld_i32(count, cpu_env,
> -ENV_OFFSET + offsetof(CPUState, icount_decr.u32));
 
>  if (tb->cflags & CF_USE_ICOUNT) {
> @@ -37,7 +37,7 @@ static inline void gen_tb_start(TranslationBlock *tb)
>  tcg_gen_brcondi_i32(TCG_COND_LT, count, 0, exitreq_label);
 
>  if (tb->cflags & CF_USE_ICOUNT) {
> -tcg_gen_st16_i32(count, tcg_ctx.tcg_env,
> +tcg_gen_st16_i32(count, cpu_env,
>   -ENV_OFFSET + offsetof(CPUState, 
> icount_decr.u16.low));
>  }
 
> @@ -62,7 +62,7 @@ static inline void gen_tb_end(TranslationBlock *tb, int 
> num_insns)
>  static inline void gen_io_start(void)
>  {
>  TCGv_i32 tmp = tcg_const_i32(1);
> -tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
> +tcg_gen_st_i32(tmp, cpu_env,
> -ENV_OFFSET + offsetof(CPUState, can_do_io));
>  tcg_temp_free_i32(tmp);
>  }
> @@ -70,7 +70,7 @@ static inline void gen_io_start(void)
>  static inline void gen_io_end(void)
>  {
>  TCGv_i32 tmp = tcg_const_i32(0);
> -tcg_gen_st_i32(tmp, tcg_ctx.tcg_env,
> +tcg_gen_st_i32(tmp, cpu_env,
> -ENV_OFFSET + offsetof(CPUState, can_do_io));
>  tcg_temp_free_i32(tmp);
>  }
> diff --git a/target/arm/translate.h b/target/arm/translate.h
> index 3c96aec956..410ba79c0d 100644
> --- a/target/arm/translate.h
> +++ b/target/arm/translate.h
> @@ -80,7 +80,6 @@ typedef struct DisasCompare {
>  } DisasCompare;
 
>  /* Share the TCG temporaries common between 32 and 64 bit modes.  */
> -extern TCGv_env cpu_env;
>  extern TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
>  extern TCGv_i64 cpu_exclusive_addr;
>  extern TCGv_i64 cpu_exclusive_val;
> diff --git a/tcg/tcg.h b/tcg/tcg.h
> index b2d42e3136..da1fefd6f1 100644
> --- a/tcg/tcg.h
> +++ b/tcg/tcg.h
> @@ -702,7 +702,6 @@ struct TCGContext {
 
>  /* Track which vCPU triggers events */
>  CPUState *cpu;  /* *_trans */
> -TCGv_env tcg_env;   /* *_exec  */

I would rather keep it here instead of making a new global variable, since that
should make it easier in the future to have multiple translation contexts.


Thanks,
  Lluis

 
>  /* These structures are private to tcg-target.inc.c.  */
>  #ifdef TCG_TARGET_NEED_LDST_LABELS
> @@ -727,6 +726,7 @@ struct TCGContext {
>  };
 
>  extern TCGContext tcg_ctx;
> +extern TCGv_env cpu_env;
>  extern bool parallel_cpus;
 
>  static inline void tcg_set_insn_param(int op_idx, int arg, TCGArg v)
> @@ -783,9 +783,6 @@ void tcg_set_frame(TCGContext *s, TCGReg reg, intptr_t 
> start, intptr_t size);
 
>  int tcg_global_mem_new_internal(TCGType, TCGv_ptr, intptr_t, const char *);
 
> -TCGv_i32 tcg_global_reg_new_i32(TCGReg reg, const char *name);
> -TCGv_i64 tcg_global_reg_new_i64(TCGReg reg, const char *name);
> -
>  TCGv_i32 tcg_temp_new_internal_i32(int temp_local);
>  TCGv_i64 tcg_temp_new_internal_i64(int temp_local);
 
> @@ -904,8 +901,6 @@ do {\
>  #define TCGV_PTR_TO_NAT(n) MAKE_TCGV_I32(GET_TCGV_PTR(n))
 
>  #define

Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-10-06 Thread Lluís Vilanova
Emilio G Cota writes:

> On Thu, Oct 05, 2017 at 02:28:12 +0300, Lluís Vilanova wrote:
>> Emilio G Cota writes:
>> > I see some potential problems with this:
>> > 1. Instrumenters' accesses could generate exceptions. I presume we'd want 
>> > to avoid
>> >this, or leave it as a debug-only kind of option.
>> 
>> The API takes care of telling you if the access could be performed
>> successfully. If you access the instruction's memory representation at
>> translation time, it should be able to perform the access, since QEMU's
>> translation loop just had to do so in order to access that instruction (I 
>> should
>> check what happens in the corner case where another guest CPU changes the 
>> page
>> table, since I'm not sure if the address translation functions I'm using in 
>> QEMU
>> will use the per-vCPU TLB cache or always traverse the page table).

> That was my concern, I'd rather just perform the read once, that is, the 
> read(s)
> done by ops->insn_translate.

If your concern is on performance, that should not be an issue, since you'd be
using the memory peek functions at translation-time. Furthermore, since others
suggested having memory peek anyway, that's a nicer way (to me) to compose APIs
(and is less complex to implement).


>> > 2. Instrumenters won't know where the end of an instruction (for 
>> > variable-length
>> >   ISAs) or of a TB is (TB != basic block). For instructions one could have 
>> > a loop
>> >   where we read byte-by-byte and pass it to the decoder, something similar 
>> > to
>> >   what we have in the capstone code recently posted to the list (v4). For 
>> > TBs,
>> >   we really should have a way to delimit the length of the TB. This is 
>> > further
>> >   complicated if we want instrumentation to be inserted *before* a TB is
>> >   translated.
>> 
>> > Some thoughts on the latter problem: if we want a tb_trans_pre callback, 
>> > like
>> > Pin/DynamoRIO provide, instead of doing two passes (one to delimit the TB 
>> > and
>> > call the tb_trans_pre callback, to then generate the translated TB), we 
>> > could:
>> >   - have a tb_trans_pre callback. This callback inserts an exec-time 
>> > callback
>> > with a user-defined pointer (let's call it **tb_info). The callback has
>> > no arguments, perhaps just the pc.
>> >   - have a tb_trans_post callback. This one passes a copy of the guest
>> > instructions. The instrumenter then can allocate whatever data 
>> > structure
>> > to represent the TB (*tb_info), and copies this pointer to **tb_info, 
>> > so
>> > that at execution time, we can obtain tb_info _before_ the TB is 
>> > executed.
>> > After the callback returns, the copy of the guest instructions can be 
>> > freed.
>> >   This has two disadvantages:
>> >   - We have an extra dereference to find tb_info
>> >   - If it turns out that the TB should not be instrumented, we have 
>> > generated
>> > a callback for nothing.
>> 
>> That's precisely one of the reasons why I proposed adding instrumentation 
>> points
>> before and after events happen (e.g., instrument right after translating an
>> instruction, where you know its size).
>> 
>> What you propose is actually a broader issue, how to allow instrumentors to 
>> pass
>> their own data to execution-time functions "after the fact". For this, I
>> implemented "promises", a kind of generalization of what gen_icount() does 
>> (you
>> pass a value to the execution-time callback that is computed later during
>> translation-time).

> I see. I implemented what I suggested above, i.e. tb_trans_cb
> (i.e. post_trans) passes an opaque descriptor of the TB (which can
> be iterated over insn by insn) and the return value (void *) of this
> cb will be passed by tb_exec_cb (i.e. pre_exec).  Perf-wise this
> is pretty OK, turns out even if we don't end up caring about the
> TB, the additional per-TB helper (which might not end up calling
> a callback) does not introduce significant overhead at execution time.

So you build this structure after translating the whole TB, and the user can
iterate it to check the translated instructions. This is closer to other
existing tools: you iterate the structure and then decide which/how to
instrument instructions, memory accesses, etc within it.

My only concern is that this is much more complex than the simpler API I propose
(yo

Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-10-04 Thread Lluís Vilanova
Emilio G Cota writes:

> On Sat, Sep 30, 2017 at 00:46:33 +0300, Lluís Vilanova wrote:
>> Emilio G Cota writes:
>> > I'm not sure I understand this concept of filtering. Are you saying that in
>> > the first case, all memory accesses are instrumented, and then in the
>> > "access helper" we only call the user's callback if it's a memory write?
>> > And in the second case, we simply just generate a "write helper" instead
>> > of an "access helper". Am I understanding this correctly?
>> 
>> In the previous case (no filtering), the user callback is always called when 
>> a
>> memory access is *executed*, and the user then checks if the access mode is a
>> write to decide whether to increment a counter.
>> 
>> In this case (with filtering), a user callback is called when a memory 
>> access is
>> *translated*, and if the access mode is a write, the user generates a call 
>> to a
>> second callback that is executed every time a memory access is executed (only
>> that it is only generated for memory writes, the ones we care about).
>> 
>> Is this clearer?

> I get it now, thanks!

>> > FWIW my experiments so far show similar numbers for instrumenting each
>> > instruction (haven't done the per-tb yet). The difference is that I'm
>> > exposing to instrumenters a copy of the guest instructions (const void 
>> > *data,
>> > size_t size). These copies are kept around until TB's are flushed.
>> > Luckily there seems to be very little overhead in keeping these around,
>> > apart from the memory overhead -- but in terms of performance, the
>> > necessary allocations do not induce significant overhead.
>> 
>> To keep this use-case simpler, I added the memory access API I posted in this
>> series, where instrumenters can read guest memory (more general than passing 
>> a
>> copy of the current instruction).

> I see some potential problems with this:
> 1. Instrumenters' accesses could generate exceptions. I presume we'd want to 
> avoid
>this, or leave it as a debug-only kind of option.

The API takes care of telling you if the access could be performed
successfully. If you access the instruction's memory representation at
translation time, it should be able to perform the access, since QEMU's
translation loop just had to do so in order to access that instruction (I should
check what happens in the corner case where another guest CPU changes the page
table, since I'm not sure if the address translation functions I'm using in QEMU
will use the per-vCPU TLB cache or always traverse the page table).


> 2. Instrumenters won't know where the end of an instruction (for 
> variable-length
>   ISAs) or of a TB is (TB != basic block). For instructions one could have a 
> loop
>   where we read byte-by-byte and pass it to the decoder, something similar to
>   what we have in the capstone code recently posted to the list (v4). For TBs,
>   we really should have a way to delimit the length of the TB. This is further
>   complicated if we want instrumentation to be inserted *before* a TB is
>   translated.

> Some thoughts on the latter problem: if we want a tb_trans_pre callback, like
> Pin/DynamoRIO provide, instead of doing two passes (one to delimit the TB and
> call the tb_trans_pre callback, to then generate the translated TB), we could:
>   - have a tb_trans_pre callback. This callback inserts an exec-time callback
> with a user-defined pointer (let's call it **tb_info). The callback has
> no arguments, perhaps just the pc.
>   - have a tb_trans_post callback. This one passes a copy of the guest
> instructions. The instrumenter then can allocate whatever data structure
> to represent the TB (*tb_info), and copies this pointer to **tb_info, so
> that at execution time, we can obtain tb_info _before_ the TB is executed.
> After the callback returns, the copy of the guest instructions can be 
> freed.
>   This has two disadvantages:
>   - We have an extra dereference to find tb_info
>   - If it turns out that the TB should not be instrumented, we have generated
> a callback for nothing.

That's precisely one of the reasons why I proposed adding instrumentation points
before and after events happen (e.g., instrument right after translating an
instruction, where you know its size).

What you propose is actually a broader issue, how to allow instrumentors to pass
their own data to execution-time functions "after the fact". For this, I
implemented "promises", a kind of generalization of what gen_icount() does (you
pass a value to the execution-time callback that is computed later during
translation-time).


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-09-26 Thread Lluís Vilanova
Emilio G Cota writes:

> On Mon, Sep 25, 2017 at 21:03:39 +0300, Lluís Vilanova wrote:
>> I know it's not exactly the same we're discussing, but the plot in [1] 
>> compares
>> a few different ways to trace memory accesses on SPEC benchmarks:
>> 
>> * First bar is using a Intel's tool called PIN [2].
>> * Second is calling into an instrumentation function on every executed memory
>> access in QEMU.
>> * Third is embedding the hot path of writing the memory access info to an 
>> array
>> into the TCG opcode stream (more or less equivalent to supporting filtering;
>> when the array is full, a user's callback is called - cold path -)
>> * Fourth bar can be ignored.
>> 
>> This was working on a much older version of instrumentation for QEMU, but I 
>> can
>> implement something that does the first use-case point above and some 
>> filtering
>> example (second use-case point) to see what's the performance difference.
>> 
>> [1] https://filetea.me/n3wy9WwyCCZR72E9OWXHArHDw

> Interesting! Unfortunately, this URL gives me a 404.

Ok, I've uploade it somewhere else:

  https://people.gso.ac.upc.edu/vilanova/mtrace.pdf

There's also another one that simply counts the number of memory accesses, using
the same three approaches:

  https://people.gso.ac.upc.edu/vilanova/mcount.pdf

Cheers,
  Lluis



Re: [Qemu-devel] [PATCH 4/7] tcg: Add support for "inlining" regions of code

2017-09-26 Thread Lluís Vilanova
Lluís Vilanova writes:

> Richard Henderson writes:
>> On 09/14/2017 08:20 AM, Lluís Vilanova wrote:
>>> Richard Henderson writes:
>>> 
>>>> On 09/10/2017 09:27 AM, Lluís Vilanova wrote:
>>>>> TCG BBLs and instructions have multiple exit points from where to raise
>>>>> tracing events, but some of the necessary information in the generic
>>>>> disassembly infrastructure is not available until after generating these
>>>>> exit points.
>>>>> 
>>>>> This patch adds support for "inline points" (where the tracing code will
>>>>> be placed), and "inline regions" (which identify the TCG code that must
>>>>> be inlined). The TCG compiler will basically copy each inline region to
>>>>> any inline points that reference it.
>>> 
>>>> I am not keen on this.
>>> 
>>>> Is there a reason you can't just emit the tracing code at the appropriate 
>>>> place
>>>> to begin with?  Perhaps I have to wait to see how this is used...
>>> 
>>> As I tried to briefly explain on next patch, the main problem without 
>>> inlining
>>> is that we will see guest_tb_after_trans twice on the trace for each TB in
>>> conditional instructions on the guest, since they have two exit points 
>>> (which we
>>> capture when emitting goto_tb in TCG).

>> Without seeing the code, I suspect this is because you didn't examine the
>> argument to tcg_gen_exit_tb.  You can tell when goto_tb must have been 
>> emitted
>> and avoid logging twice.

> The generated tracing code for 'guest_*_after' must be right before the
> "goto_tb" opcode at the end of a TB (AFAIU generated by
> tcg_gen_lookup_and_goto_ptr()), and we have two of those when decoding a guest
> conditional jump.

> If we couple this with the semantics of the trace_*_tcg functions (trace the
> event at translation time, and generate TCG code to trace the event at 
> execution
> time), we get the case I described (we don't want to call trace_tb_after_tcg()
> or trace_insn_after_tcg() twice for the same TB or instruction).

> That is, unless I've missed something.


> The only alternative I can think of is changing tracetool to offer an 
> additional
> API that provides separate functions for translation-time tracing and
> execution-time generation. So from this:

>   static inline void trace_event_tcg(CPUState *cpu, TCGv_env env, ...)
>   {
>   trace_event_trans(cpu, ...);
>   if (trace_event_get_vcpu_state(cpu, EVENT_EXEC)) {
>   gen_helper_trace_event_exec(env, ...);
>   }
>   }

> We can extend it into this:

>   static inline void gen_trace_event_exec(TCGv_env env, ...)
>   if (trace_event_get_vcpu_state(cpu, EVENT_EXEC)) {
>   gen_helper_trace_event_exec(env, ...);
>   }
>   }
>   static inline void trace_event_tcg(CPUState *cpu, TCGv_env env, ...)
>   {
>   trace_event_trans(cpu, ...);
>   gen_trace_event_exec(env, ...);
>   }

Richard, do you prefer to keep the "TCG inline" feature or switch the internal
tracing API to this second approach?


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH v6 00/22] instrument: Add basic event instrumentation

2017-09-26 Thread Lluís Vilanova
Emilio G Cota writes:

> On Mon, Sep 25, 2017 at 21:07:45 +0300, Lluís Vilanova wrote:
>> You're doing it right, and I've checked that the branch is properly pushed. 
>> Can
>> you compile with V=1 to show me the failing cmdline?

> $ make V=1
> (cd /data/src/qemu2; printf '#define QEMU_PKGVERSION '; if test -n ""; then
> printf '""\n'; else if test -d .git; then printf '" ('; git describe --match
> 'v*' 2>/dev/null | tr -d '\n'; if ! git diff-index --quiet HEAD &>/dev/null;
> then printf -- '-dirty'; fi; printf ')"\n'; else printf '""\n'; fi; fi) >
> qemu-version.h.tmp
> if ! cmp -s qemu-version.h qemu-version.h.tmp; then mv qemu-version.h.tmp 
> qemu-version.h; else rm qemu-version.h.tmp; fi
> make -I/data/src/qemu2/dtc VPATH=/data/src/qemu2/dtc -C dtc V="1"
> LIBFDT_srcdir=/data/src/qemu2/dtc/libfdt CPPFLAGS="-I/data/src/qemu2/build/dtc
> -I/data/src/qemu2/dtc -I/data/src/qemu2/dtc/libfdt" CFLAGS="-O2
> -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g -fvisibility=hidden
> -I/usr/include/pixman-1 -I/data/src/qemu2/dtc/libfdt -Werror -pthread
> -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -fPIE 
> -DPIE
> -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
> -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings
> -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels
> -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security
> -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration
> -Wold-style-definition -Wtype-limits -fstack-protector-strong
> -I/usr/include/libpng12 -I/data/src/qemu2/tests" LDFLAGS="-rdynamic
> -Wl,--warn-common -Wl,-z,relro -Wl,-z,now -pie -m64 -g " ARFLAGS="rv" CC="cc"
> AR="ar" LD="ld" BUILD_DIR=/data/src/qemu2/build libfdt/libfdt.a
> make[1]: Entering directory '/data/src/qemu2/build/dtc'
> make[1]: 'libfdt/libfdt.a' is up to date.
> make[1]: Leaving directory '/data/src/qemu2/build/dtc'
> make  BUILD_DIR=/data/src/qemu2/build -C x86_64-linux-user V="1" 
> TARGET_DIR="x86_64-linux-user/" all
> make[1]: Entering directory '/data/src/qemu2/build/x86_64-linux-user'
> cc -I/data/src/qemu2/build/. -I. -I/data/src/qemu2/tcg
> -I/data/src/qemu2/tcg/i386 -I/data/src/qemu2/instrument
> -I/data/src/qemu2/linux-headers -I/data/src/qemu2/build/linux-headers
> -I. -I/data/src/qemu2 -I/data/src/qemu2/accel/tcg -I/data/src/qemu2/include
> -fvisibility=hidden -I/usr/include/pixman-1 -I/data/src/qemu2/dtc/libfdt 
> -Werror
> -pthread -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
> -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 
> -D_LARGEFILE_SOURCE
> -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings
> -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels
> -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security
> -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration
> -Wold-style-definition -Wtype-limits -fstack-protector-strong
> -I/usr/include/libpng12 -I../linux-headers -I.. -I/data/src/qemu2/target/i386
> -DNEED_CPU_H -I/data/src/qemu2/include -I/data/src/qemu2/linux-user/x86_64
> -I/data/src/qemu2/linux-user/host/x86_64 -I/data/src/qemu2/linux-user -MMD -MP
> -MT gdbstub-xml.o -MF ./gdbstub-xml.d -O2 -U_FORTIFY_SOURCE 
> -D_FORTIFY_SOURCE=2
> -g -DQEMU_TARGET_BUILD=1 -c -o gdbstub-xml.o gdbstub-xml.c
> cc -I/data/src/qemu2/build/instrument -Iinstrument -I/data/src/qemu2/tcg
> -I/data/src/qemu2/tcg/i386 -I/data/src/qemu2/instrument
> -I/data/src/qemu2/linux-headers -I/data/src/qemu2/build/linux-headers
> -I. -I/data/src/qemu2 -I/data/src/qemu2/accel/tcg -I/data/src/qemu2/include
> -fvisibility=hidden -I/usr/include/pixman-1 -I/data/src/qemu2/dtc/libfdt 
> -Werror
> -pthread -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
> -fPIE -DPIE -m64 -mcx16 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 
> -D_LARGEFILE_SOURCE
> -Wstrict-prototypes -Wredundant-decls -Wall -Wundef -Wwrite-strings
> -Wmissing-prototypes -fno-strict-aliasing -fno-common -fwrapv -Wendif-labels
> -Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security
> -Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration
> -Wold-style-definition -Wtype-limits -fstack-protector-strong
> -I/usr/include/libpng12 -I../linux-headers -I.. -I/data/src/qemu2/target/i386
> -DNEED_CPU_H -I/data/src/qemu2/include -I/data/src/qemu2/linux-user/x86_64
> -I/data/src/qemu2/linux-user/host/x86_64 -I/data/src

Re: [Qemu-devel] [RFC 0/6] initial plugin support

2017-09-25 Thread Lluís Vilanova
Stefan Hajnoczi writes:

> On Mon, Sep 18, 2017 at 04:05:31PM +0100, Peter Maydell wrote:
>> On 18 September 2017 at 15:59, Stefan Hajnoczi  wrote:
>> > Thanks for sending this!  Could you and Lluís collaborate on a single
>> > instrumentation plugin API?
>> >
>> > Let's have a discussion with Lluís, Peter, myself, and potentially
>> > others then we can use the QEMU Developer Conference Call that is
>> > scheduled every 2 weeks.
>> >
>> > The next call time slot is Tue 26 Sept at 13:00 UTC:
>> > https://www.timeanddate.com/worldclock/fixedtime.html?iso=20170926T14&p1=136
>> 
>> I can't make that, I'm afraid, it's Linaro Connect that week.
>> 
>> From my point of view, it would be helpful to start with
>> just designing the API that we're trying to implement.
>> I care a lot that we get that API correct, I don't care much
>> at all about the implementation...

> That sounds good to me.

> An RFC patch with just the header files would be enough for mailing list
> discussion.  No implementation is needed yet.

I can send a stripped down version of this series only with the docs and public
headers.

But first I would like to know how to handle the translate/execute
differentiation first (if it is indeed needed).


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH v6 00/22] instrument: Add basic event instrumentation

2017-09-25 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 13, 2017 at 12:53:43 +0300, Lluís Vilanova wrote:
>> The instrumentation code is dynamically loaded as a library into QEMU either
>> when it starts or later using its remote control interfaces. The loaded code
>> only has access to function explicitly exported through the QI_VPUBLIC macro.
>> 
>> This series is branch 'devel-instrument' in
>> https://code.gso.ac.upc.edu/git/qemu-dbi.

> Is this up to date? That tree doesn't build for me with --enable-instrument; I
> get the same error I got in v4:

>   CC  x86_64-linux-user/instrument/state.o
> /data/src/qemu2/instrument/trace.c:13:30: fatal error: qemu-instr/trace.h: No 
> such file or directory
> compilation terminated.
> /data/src/qemu2/rules.mak:66: recipe for target 'instrument/trace.o' failed

> Or maybe I'm doing something wrong?
> I'm configuring with `configure --target-list=x86_64-linux-user 
> --enable-instrument'.

You're doing it right, and I've checked that the branch is properly pushed. Can
you compile with V=1 to show me the failing cmdline?

Thanks,
  Lluis



Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-09-25 Thread Lluís Vilanova
First, sorry for the late response; I was away for a few days.


Peter Maydell writes:

> On 18 September 2017 at 18:09, Lluís Vilanova  wrote:
>> Peter Maydell writes:
>>> It's also exposing internal QEMU implementation detail.
>>> What if in future we decide to switch from our current
>>> setup to always interpreting guest instructions as a
>>> first pass with JITting done only in the background for
>>> hot code?
>> 
>> TCI still has a separation of translation-time (translate.c) and 
>> execution-time
>> (interpreting the TCG opcodes), and I don't think that's gonna go away 
>> anytime
>> soon.

> I didn't mean TCI, which is nothing like what you'd use for
> this if you did it (TCI is slower than just JITting.)

My point is that even on the cold path you need to decode a guest instruction
(equivalent to translating) and emulate it on the spot (equivalent to
executing).


>> Even if it did, I think there still will be a translation/execution 
>> separation
>> easy enough to hook into (even if it's a "fake" one for the cold-path
>> interpreted instructions).

> But what would it mean? You don't have basic blocks any more.

Every instruction emulated on the spot can be seen as a newly translated block
(of one instruction only), which is executed immediately after.


>>> Sticking to instrumentation events that correspond exactly to guest
>>> execution events means they won't break or expose internals.
>> 
>> It also means we won't be able to "conditionally" instrument instructions 
>> (e.g.,
>> based on their opcode, address range, etc.).

> You can still do that, it's just less efficient (your
> condition-check happens in the callout to the instrumentation
> plugin). We can add "filter" options later if we need them
> (which I would rather do than have translate-time callbacks).

Before answering, a short summary of when knowing about translate/execute makes
a difference:

* Record some information only once when an instruction is translated, instead
  of recording it on every executed instruction (e.g., a study of opcode
  distribution, which you can get from a file of per-TB opcodes - generated at
  translation time - and a list of executed TBs - generated at execution time
  -). The translate/execute separation makes this run faster *and* produces much
  smaller files with the recorded info.

  Other typical examples that benefit from this are writing a simulator that
  feeds off a stream of instruction information (a common reason why people want
  to trace memory accesses and information of executed instructions).

* Conditionally instrumenting instructions.

Adding filtering to the instrumentation API would only solve the second point,
but not the first one.

Now, do we need/want to support the first point?


>> Of course we can add the translation/execution differentiation later if we 
>> find
>> it necessary for performance, but I would rather avoid leaving "historical"
>> instrumentation points behind on the API.
>> 
>> What are the use-cases you're aiming for?

> * I want to be able to point the small stream of people who come
> into qemu-devel asking "how do I trace all my guest's memory
> accesses" at a clean API for it.

> * I want to be able to have less ugly and confusing tracing
> than our current -d output (and perhaps emit tracing in formats
> that other analysis tools want as input)

> * I want to keep this initial tracing API simple enough that
> we can agree on it and get a first working useful version.

Fair enough.

I know it's not exactly the same we're discussing, but the plot in [1] compares
a few different ways to trace memory accesses on SPEC benchmarks:

* First bar is using a Intel's tool called PIN [2].
* Second is calling into an instrumentation function on every executed memory
  access in QEMU.
* Third is embedding the hot path of writing the memory access info to an array
  into the TCG opcode stream (more or less equivalent to supporting filtering;
  when the array is full, a user's callback is called - cold path -)
* Fourth bar can be ignored.

This was working on a much older version of instrumentation for QEMU, but I can
implement something that does the first use-case point above and some filtering
example (second use-case point) to see what's the performance difference.

[1] https://filetea.me/n3wy9WwyCCZR72E9OWXHArHDw
[2] 
https://software.intel.com/en-us/articles/pin-a-dynamic-binary-instrumentation-tool


Thanks!
  Lluis



Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-09-18 Thread Lluís Vilanova
Peter Maydell writes:

> On 15 September 2017 at 14:39, Lluís Vilanova  wrote:
>> Peter Maydell writes:
>>> This looks like it's exposing too much implementation detail.
>>> We should just provide an API for "hook to be called for
>>> memory writes" which gets all the information when it
>>> is called. I don't think we should expose any kind of
>>> "this hook is called at translation time" at all.
>> 
>> The differentiation between translation-time and execution-time is key to
>> perform certain analysis efficiently.

> It's also exposing internal QEMU implementation detail.
> What if in future we decide to switch from our current
> setup to always interpreting guest instructions as a
> first pass with JITting done only in the background for
> hot code?

TCI still has a separation of translation-time (translate.c) and execution-time
(interpreting the TCG opcodes), and I don't think that's gonna go away anytime
soon.

Even if it did, I think there still will be a translation/execution separation
easy enough to hook into (even if it's a "fake" one for the cold-path
interpreted instructions).


> Sticking to instrumentation events that correspond exactly to guest
> execution events means they won't break or expose internals.

It also means we won't be able to "conditionally" instrument instructions (e.g.,
based on their opcode, address range, etc.).

Of course we can add the translation/execution differentiation later if we find
it necessary for performance, but I would rather avoid leaving "historical"
instrumentation points behind on the API.

What are the use-cases you're aiming for?


Cheers!
  Lluis



Re: [Qemu-devel] [PATCH v5 00/22] instrument: Add basic event instrumentation

2017-09-15 Thread Lluís Vilanova
Peter Maydell writes:

> On 12 September 2017 at 22:01, Lluís Vilanova  wrote:
>> This series adds an API to add instrumentation events.
>> 
>> It also provides additional APIs for:
>> * Controlling tracing events.
>> * Peek/poke guest memory.

>> Future APIs (for later series):
>> * Peek/poke guest registers.
>> * Add breakpoints to trigger instrumentation functions.
>> * Trigger instrumentation functions from guest code (former hypertrace).
>> * Add events for guest code translation/execution (once the respective 
>> tracing
>> events are accepted upstream).
>> * Add events for exceptions/syscalls.
>> * Add events for TB invalidation (necessary for libraries to deallocate any 
>> data
>> they might have allocated for the TBs they instrumented).
>> 
>> The instrumentation code is dynamically loaded as a library into QEMU either
>> when it starts or later using its remote control interfaces. The loaded code
>> only has access to function explicitly exported through the QI_VPUBLIC macro.
>> 
>> This series is branch 'devel-instrument' in
>> https://code.gso.ac.upc.edu/git/qemu-dbi.

> To parallel the comment I sent on Emilio's series: I think the
> first thing we should do here is work out the API we want to
> present to the instrumentation plugin, because that's permanent
> and we want to get it right. Then we can figure out the
> implementation details later.

> Particular notes:
>  * putting things in the instrumentation plugin API that basically
>parallel some existing trace points is something I'm wary of,
>because a lot of our existing tracing is "output something at
>a point and in a way that's convenient for our internal
>implementation", rather than "what is the right clean interface
>to provide this sort of information". I'd rather we started
>with a blank piece of paper and designed an API, and then
>implemented it.

Do you have an opinion on specific trace points, or an observation in general?

I wanted to have the following events:

* cpu hotplug/hotunplug
* cpu reset
* memory access translation/execution
* BBL/TB translation/execution
* instruction translation/execution
* exceptions / syscalls


>  * I definitely don't think we should expose to the instrumentation
>the distinction between translate time and execute time

Please see my response to your email in v6.

Also, I forgot an even simpler case, like instrumenting a subset of memory
accesses (e.g., only writes).


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-09-15 Thread Lluís Vilanova
Peter Maydell writes:

> On 13 September 2017 at 10:57, Lluís Vilanova  wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> MAINTAINERS |6 ++
>> docs/instrument.txt |  173 
>> +++
>> 2 files changed, 179 insertions(+)
>> create mode 100644 docs/instrument.txt
>> 
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 36eeb42d19..fb0eaee06a 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1486,6 +1486,12 @@ F: scripts/tracetool/
>> F: docs/tracing.txt
>> T: git git://github.com/stefanha/qemu.git tracing
>> 
>> +Event instrumentation
>> +M: Lluís Vilanova 
>> +M: Stefan Hajnoczi 
>> +S: Maintained
>> +F: docs/instrument.txt
>> +
>> TPM
>> S: Orphan
>> F: tpm.c
>> diff --git a/docs/instrument.txt b/docs/instrument.txt
>> new file mode 100644
>> index 00..24a0d21fc7
>> --- /dev/null
>> +++ b/docs/instrument.txt
>> @@ -0,0 +1,173 @@
>> += Event instrumentation =
>> +
>> +== Introduction ==
>> +
>> +Event instrumentation allows users to execute their own host-native code on 
>> a
>> +set of pre-defined events provided by QEMU. QEMU also exposes other
>> +functionality to peek/poke at the guest state (e.g., memory or registers), 
>> as
>> +well as interacting with tracing events. For those familiar with the term, 
>> this
>> +provides dynamic binary instrumentation, works on all QEMU-supported
>> +architectures, as well as works in both 'user' (standalone application) and
>> +'system' (full-system emulation) modes.
>> +
>> +Look at the headers installed by QEMU on the "qemu-instr" directory for 
>> further
>> +information beyond this document.
>> +
>> +
>> +== Loading an instrumentation library ==
>> +
>> +Instrumentation code can be bundled into a dynamic library, which can be 
>> later
>> +loaded into QEMU:
>> +
>> +* Using the command-line "-instr" argument.
>> +
>> +* Using the "instr-load" and "instr-unload" commands in the HMP and QMP
>> +  interfaces.
>> +
>> +
>> +== Example ==
>> +
>> +1. Configure QEMU with event instrumentation:
>> +
>> +# instrument guest_cpu_enter and guest_mem_before
>> +mkdir -p /path/to/qemu-build
>> +cd /path/to/qemu-build
>> +/path/to/qemu-source/configure \
>> +  --enable-instrument \
>> +  --prefix=/path/to/qemu-install

> Ideally instrumentation should be cost-free in the case where
> we're not using it, so we can default it to enabled.

I wasn't sure if everyone would want it enabled by default on the first release,
but I can easily change that.


>> +
>> +2. Build and install QEMU:
>> +
>> +make install
>> +
>> +3. Create the "Makefile" to build the instrumentation library:
>> +
>> +mkdir -p /tmp/my-instrument
>> +
>> +cat > /tmp/my-instrument/Makefile <> +QEMU_PATH=/tmp/qemu-install/
>> +
>> +CFLAGS += -g
>> +CFLAGS += -O3
>> +CFLAGS += -Werror -Wall
>> +CFLAGS += -I$(QEMU_PATH)/include

> Plugins shouldn't have or need access to all of the QEMU source
> tree or its include files. We want to be able to provide them
> with one header file which defines all they need (and all they
> get), under a suitably non-restrictive license like 2-clause-BSD.

Variable QEMU_PATH refers to the *installation* path of QEMU.

I can change the API headers to use some other license.


>> +
>> +all: libtrace-instrument.la
>> +
>> +libtrace-instrument.la: instrument.lo
>> +libtool --mode=link --tag=CC $(CC) -module -rpath 
>> /usr/local/lib -o $@ $^

> -rpath ?

I couldn't make libtool to generate a .so file without it. I can change the
example to directly use gcc instead of libtool.


>> +
>> +%.lo: %.c
>> +libtool --mode=compile --tag=CC $(CC) $(CFLAGS) -c $^
>> +
>> +clean:
>> +$(RM) -f *.o *.so *.lo
>> +$(RM) -Rf .libs
>> +EOF
>> +
>> +4. Write your instrumentation library:
>> +
>> +cat > /tmp/my-instrument/instrument.c <> +#include 
>> +#include 
>> +
>> +#include  /* manipulate events */
>> +#include/* manipulate tracing */
>> +
>> +/* the address for the memory access is not known at translation time */
>> +void guest_mem_before_trans(QICPU vcpu_trans, 

Re: [Qemu-devel] [PATCH 4/7] tcg: Add support for "inlining" regions of code

2017-09-15 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/14/2017 08:20 AM, Lluís Vilanova wrote:
>> Richard Henderson writes:
>> 
>>> On 09/10/2017 09:27 AM, Lluís Vilanova wrote:
>>>> TCG BBLs and instructions have multiple exit points from where to raise
>>>> tracing events, but some of the necessary information in the generic
>>>> disassembly infrastructure is not available until after generating these
>>>> exit points.
>>>> 
>>>> This patch adds support for "inline points" (where the tracing code will
>>>> be placed), and "inline regions" (which identify the TCG code that must
>>>> be inlined). The TCG compiler will basically copy each inline region to
>>>> any inline points that reference it.
>> 
>>> I am not keen on this.
>> 
>>> Is there a reason you can't just emit the tracing code at the appropriate 
>>> place
>>> to begin with?  Perhaps I have to wait to see how this is used...
>> 
>> As I tried to briefly explain on next patch, the main problem without 
>> inlining
>> is that we will see guest_tb_after_trans twice on the trace for each TB in
>> conditional instructions on the guest, since they have two exit points 
>> (which we
>> capture when emitting goto_tb in TCG).

> Without seeing the code, I suspect this is because you didn't examine the
> argument to tcg_gen_exit_tb.  You can tell when goto_tb must have been emitted
> and avoid logging twice.

The generated tracing code for 'guest_*_after' must be right before the
"goto_tb" opcode at the end of a TB (AFAIU generated by
tcg_gen_lookup_and_goto_ptr()), and we have two of those when decoding a guest
conditional jump.

If we couple this with the semantics of the trace_*_tcg functions (trace the
event at translation time, and generate TCG code to trace the event at execution
time), we get the case I described (we don't want to call trace_tb_after_tcg()
or trace_insn_after_tcg() twice for the same TB or instruction).

That is, unless I've missed something.


The only alternative I can think of is changing tracetool to offer an additional
API that provides separate functions for translation-time tracing and
execution-time generation. So from this:

  static inline void trace_event_tcg(CPUState *cpu, TCGv_env env, ...)
  {
  trace_event_trans(cpu, ...);
  if (trace_event_get_vcpu_state(cpu, EVENT_EXEC)) {
  gen_helper_trace_event_exec(env, ...);
  }
  }

We can extend it into this:

  static inline void gen_trace_event_exec(TCGv_env env, ...)
  if (trace_event_get_vcpu_state(cpu, EVENT_EXEC)) {
  gen_helper_trace_event_exec(env, ...);
  }
  }
  static inline void trace_event_tcg(CPUState *cpu, TCGv_env env, ...)
  {
  trace_event_trans(cpu, ...);
  gen_trace_event_exec(env, ...);
  }


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH 6/7] trace: Add event "guest_inst_after"

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:35 AM, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> accel/tcg/translator.c |   23 ++-
>> trace-events   |8 
>> 2 files changed, 26 insertions(+), 5 deletions(-)
>> 
>> diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
>> index d66d601c89..c010aeee45 100644
>> --- a/accel/tcg/translator.c
>> +++ b/accel/tcg/translator.c
>> @@ -35,7 +35,8 @@ void translator_loop_temp_check(DisasContextBase *db)
>> void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
>> CPUState *cpu, TranslationBlock *tb)
>> {
>> -target_ulong pc_bbl;
>> +target_ulong pc_bbl, pc_insn = 0;
>> +bool translated_insn = false;
>> int max_insns;
>> 
>> /* Initialize DisasContext */
>> @@ -75,10 +76,15 @@ void translator_loop(const TranslatorOps *ops, 
>> DisasContextBase *db,
>> tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
>> 
>> while (true) {
>> -target_ulong pc_insn = db->pc_next;
>> TCGv_i32 insn_size_tcg = 0;
>> int insn_size_opcode_idx;
>> 
>> +/* Tracing after (previous instruction) */
>> +if (db->num_insns > 0) {
>> +trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
>> +}

> How does this differ from "guest_inst"?  Why would you need two trace points?

I assume you mean how it differs from guest_inst_before. The two main ideas are:

* To be able to get a trace an execution-time event only after the instruction
  or TB have finished executing successfully (i.e., there could be an 
exception).
* Some values are only known *after* the instruction is translated (like the
  instruction size, or other extra information we might add in the future), so
  an efficient way to collect that is to trace guest_bbl_* and guest_insn_after
  at translation time (to build a TB "dictionary" as some call it), and trace
  guest_bbl_before at execution time (and use the detailed info above that you
  got at translation time).


> Why are you placing this at the beginning of the while loop rather than the 
> end?

Yeah, that'll be much clearer.


>> @@ -164,6 +172,9 @@ void translator_loop(const TranslatorOps *ops, 
>> DisasContextBase *db,
>> 
>> gen_set_inline_region_begin(tcg_ctx.disas.inline_label);
>> 
>> +if (TRACE_GUEST_INST_AFTER_ENABLED && translated_insn) {
>> +trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
>> +}
>> if (TRACE_GUEST_BBL_AFTER_ENABLED) {
>> trace_guest_bbl_after_tcg(cpu, tcg_ctx.tcg_env, pc_bbl);
>> }

> I think I'm finally beginning to understand what you're after with your
> inlining.  But I still think this should be doable in the appropriate opcode
> generating functions.

I'm not sure we can if we want to avoid having the duplicate translation-time
events I said in a previous response (since TB can have two exit points and
we're detecting them through goto_tb).


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH 5/7] trace: Add event "guest_bbl_after"

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:31 AM, Lluís Vilanova wrote:
>> +void translator__gen_goto_tb(TCGContext *ctx)
>> +{
>> +if (ctx->disas.in_guest_code &&
>> +(TRACE_GUEST_BBL_AFTER_ENABLED)) {
>> +if (ctx->disas.inline_label == NULL) {
>> +ctx->disas.inline_label = gen_new_inline_label();
>> +}
>> +gen_set_inline_point(ctx->disas.inline_label);
>> +/* disable next exit_tb */
>> +ctx->disas.seen_goto_tb = true;
>> +}
>> +}
>> +
>> +void translator__gen_exit_tb(TCGContext *ctx)
>> +{
>> +if (ctx->disas.in_guest_code && !ctx->disas.seen_goto_tb &&
>> +(TRACE_GUEST_BBL_AFTER_ENABLED)) {
>> +if (ctx->disas.inline_label == NULL) {
>> +ctx->disas.inline_label = gen_new_inline_label();
>> +}
>> +gen_set_inline_point(ctx->disas.inline_label);
>> +/* enable next exit_tb */
>> +ctx->disas.seen_goto_tb = false;
>> +}
>> +}

> I don't understand why you wouldn't just modify tcg_gen_goto_tb and
> tcg_gen_exit_tb instead.

I prefer to keep all generic translation-related tracing on a single file, where
it is easier to reason about.

Cheers,
  Lluis



Re: [Qemu-devel] [PATCH 4/7] tcg: Add support for "inlining" regions of code

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:27 AM, Lluís Vilanova wrote:
>> TCG BBLs and instructions have multiple exit points from where to raise
>> tracing events, but some of the necessary information in the generic
>> disassembly infrastructure is not available until after generating these
>> exit points.
>> 
>> This patch adds support for "inline points" (where the tracing code will
>> be placed), and "inline regions" (which identify the TCG code that must
>> be inlined). The TCG compiler will basically copy each inline region to
>> any inline points that reference it.

> I am not keen on this.

> Is there a reason you can't just emit the tracing code at the appropriate 
> place
> to begin with?  Perhaps I have to wait to see how this is used...

As I tried to briefly explain on next patch, the main problem without inlining
is that we will see guest_tb_after_trans twice on the trace for each TB in
conditional instructions on the guest, since they have two exit points (which we
capture when emitting goto_tb in TCG).

We cannot instead emit it only once by overloading the brcond opcode in TCG,
since that can be used internally in the guest instruction emulation without
necessarily ending a TB (or we could have more than one brcond for a single
instruction).

I hope it's clearer now.


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH 3/7] trace: Add event "guest_inst_info_before"

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:23 AM, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> accel/tcg/translator.c |   18 ++
>> trace-events   |9 +
>> 2 files changed, 27 insertions(+)
>> 
>> diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
>> index 287d27b4f7..6598931171 100644
>> --- a/accel/tcg/translator.c
>> +++ b/accel/tcg/translator.c
>> @@ -70,6 +70,8 @@ void translator_loop(const TranslatorOps *ops, 
>> DisasContextBase *db,
>> 
>> while (true) {
>> target_ulong pc_insn = db->pc_next;
>> +TCGv_i32 insn_size_tcg = 0;
>> +int insn_size_opcode_idx;

> Initializing a TCGv_i32 is wrong.
> And surely insn_size_opcode is surely uninitialized?

>> +if (TRACE_GUEST_INST_INFO_BEFORE_EXEC_ENABLED) {
>> +insn_size_tcg = tcg_temp_new_i32();
>> +insn_size_opcode_idx = tcg_op_buf_count();
>> +tcg_gen_movi_i32(insn_size_tcg, 0xdeadbeef);
>> +
>> +trace_guest_inst_info_before_tcg(
>> +cpu, tcg_ctx.tcg_env, pc_insn, insn_size_tcg);
>> +
>> +tcg_temp_free_i32(insn_size_tcg);

> There's no reason you can't declare insn_size_tcg right here and avoid the
> incorrect initialization above.

Yes, I guess I did not move the declaration here by error after refactoring the
code.


> Is there a reason to have both "guest_insn" and "guest_insn_info"?

I initially wanted to have a bare-bones event with simple information, and an
*_info variant with more detailed information like register usage and physical
 addresses (which would be disabled by default to avoid performance impact).

We had a discussion long time ago that led to decide that register usage
information as I implemented it was only partial (it did not capture register
usage helpers), and thus was not worth adding.

Since physical address information is not gonna be added in this series (if at
all), what do you say about hoisting instruction length info into
guest_insn_before/after and dropping the *_info variants?


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH 2/7] trace: Add event "guest_inst_before"

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:19 AM, Lluís Vilanova wrote:
>> while (true) {
>> +target_ulong pc_insn = db->pc_next;

> Why not just "pc"?

>> +
db-> num_insns++;
ops-> insn_start(db, cpu);
>> tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
>> @@ -96,6 +98,7 @@ void translator_loop(const TranslatorOps *ops, 
>> DisasContextBase *db,
>> if (db->num_insns == 1) {
>> trace_guest_bbl_before_tcg(cpu, tcg_ctx.tcg_env, db->pc_first);
>> }
>> +trace_guest_inst_before_tcg(cpu, tcg_ctx.tcg_env, pc_insn);

> I prefer "insn" over "inst".  There are enough other words that begin with
> "inst" (e.g. instance) to possibly be confusing.  Either that or it's my 20
> years working on gcc that ingrained "insn".  ;-)

Both work for me, so no problem in switching to pc and insn.

Thanks,
  Lluis



Re: [Qemu-devel] [PATCH 1/7] trace: Add event "guest_bbl_before"

2017-09-14 Thread Lluís Vilanova
Richard Henderson writes:

> On 09/10/2017 09:15 AM, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> accel/tcg/translator.c |6 ++
>> trace-events   |   11 +++
>> 2 files changed, 17 insertions(+)
>> 
>> diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
>> index afa3af478a..91b3b0da32 100644
>> --- a/accel/tcg/translator.c
>> +++ b/accel/tcg/translator.c
>> @@ -13,6 +13,7 @@
>> #include "cpu.h"
>> #include "tcg/tcg.h"
>> #include "tcg/tcg-op.h"
>> +#include "trace-tcg.h"
>> #include "exec/exec-all.h"
>> #include "exec/gen-icount.h"
>> #include "exec/log.h"
>> @@ -91,6 +92,11 @@ void translator_loop(const TranslatorOps *ops, 
>> DisasContextBase *db,
>> }
>> }
>> 
>> +/* Tracing before */
>> +if (db->num_insns == 1) {
>> +trace_guest_bbl_before_tcg(cpu, tcg_ctx.tcg_env, db->pc_first);
>> +}

> Why not place this before the loop, so that you don't
> have to check num_insns == 1?

In case the translation hits a breakpoint. I do not want the BBL/TB to appear
once before breaking, and then again after continuing.


>> +vcpu tcg guest_bbl_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
>> "vaddr=0x%016"PRIx64

> You're really going to print both ENV and PC tagged with "vaddr"?
> That just seems confusing.

I'm not sure I follow. The ENV/CPUState is automatically added to the print
format (due to the "vcpu" property). The two format strings are necessary due to
the "tcg" property (translation-time format and execution-time format, since
TCGv arguments are not passed to the tracing function at translation time).

I'm not sure if this addresses your issue.


> Also, terminology.  A "basic block" ("bb" by preference, not "bbl"), has a
> specific meaning (https://en.wikipedia.org/wiki/Basic_block).  What we're
> generating here is a TranslationBlock (which may consist of many basic 
> blocks),
> and oft contracted within the source as "tb".

Yes, I got carried away by the naming used by some binary analysis tools like
pin. I will change it to TB and that will probably make it clearer.


Thanks,
  Lluis



[Qemu-devel] [PATCH v6 22/22] instrument: Add API to manipulate guest memory

2017-09-13 Thread Lluís Vilanova
It includes access to the guest's memory and vCPU registers.

Signed-off-by: Lluís Vilanova 
---
 instrument/Makefile.objs  |1 
 instrument/qemu-instr/state.h |  104 +
 instrument/state.c|   73 +
 3 files changed, 178 insertions(+)
 create mode 100644 instrument/qemu-instr/state.h
 create mode 100644 instrument/state.c

diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index d7e6c760c3..ee482bdb45 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -5,3 +5,4 @@ target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
 target-obj-$(CONFIG_INSTRUMENT) += control.o
 target-obj-$(CONFIG_INSTRUMENT) += trace.o
+target-obj-$(CONFIG_INSTRUMENT) += state.o
diff --git a/instrument/qemu-instr/state.h b/instrument/qemu-instr/state.h
new file mode 100644
index 00..0ae6255fe5
--- /dev/null
+++ b/instrument/qemu-instr/state.h
@@ -0,0 +1,104 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__STATE_H
+#define QI__STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include 
+
+
+/**
+ * qi_mem_read_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to read could be translated.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ *
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to write could be 
translated.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_virt_to_phys:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Virtual address to translate.
+ * @paddr: Pointer to output physical address.
+ *
+ * Translate a virtual address into a physical address.
+ *
+ * Returns: Whether the address could be translated.
+ */
+bool qi_mem_virt_to_phys(QICPU vcpu, uint64_t vaddr, uint64_t *paddr);
+
+/**
+ * qi_mem_read_phys:
+ * @paddr: Starting physical address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from physical memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_phys(uint64_t paddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_phys:
+ * @paddr: Starting physical address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ *
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_phys(uint64_t paddr, size_t size, void *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__STATE_H */
diff --git a/instrument/state.c b/instrument/state.c
new file mode 100644
index 00..e76fd5fbcd
--- /dev/null
+++ b/instrument/state.c
@@ -0,0 +1,73 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/compiler.h"
+#include "cpu.h"
+#include "exec/cpu-all.h"
+#include "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/qemu-instr/state.h"
+
+
+SYM_PUBLIC bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr,
+ size_t size, void *buf)
+{
+CPUState *vcpu_ = instr_cpu_from_qicpu(vcpu);
+ERROR_IF_RET(!instr_get_state(), false, "called outside instrumentation");
+ERROR_IF_RET(!vcpu_, false, "invalid Q

[Qemu-devel] [PATCH v6 18/22] instrument: Add event 'guest_mem_before_trans'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 Makefile.target |1 +
 instrument/control.c|   15 +
 instrument/control.h|   36 +-
 instrument/control.inc.h|   16 +++---
 instrument/events.h |   21 +
 instrument/events.inc.h |   20 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   16 ++
 instrument/qemu-instr/types.h   |   64 +++
 stubs/instrument.c  |4 ++
 tcg/tcg-op.c|5 +++
 trace/control.h |   23 ++
 trace/mem.h |   23 --
 13 files changed, 214 insertions(+), 31 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 7f42c45db8..6997b921c9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -196,6 +196,7 @@ $(QEMU_PROG_BUILD): config-devices.mak
 COMMON_LDADDS = ../libqemuutil.a ../libqemustub.a
 
 # build either PROG or PROGW
+$(QEMU_PROG_BUILD): CFLAGS += -DQEMU_TARGET_BUILD=1
 $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
$(call LINK, $(filter-out %.mak, $^))
 ifdef CONFIG_DARWIN
diff --git a/instrument/control.c b/instrument/control.c
index cb397639ce..2e910f963b 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -17,7 +17,7 @@
 #include "qom/cpu.h"
 
 
-__thread InstrState instr_cur_state;
+__thread InstrInfo instr_cur_info;
 
 
 unsigned int instr_cpus_count;
@@ -143,3 +143,16 @@ SYM_PUBLIC void qi_event_set_guest_cpu_reset(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_reset, fn);
 }
+
+
+void (*instr_event__guest_mem_before_trans)(
+QICPU vcpu_trans, QITCGv_cpu vcpu_exec, QITCGv vaddr, QIMemInfo info);
+
+SYM_PUBLIC void qi_event_set_guest_mem_before_trans(
+void (*fn)(QICPU vcpu_trans, QITCGv_cpu vcpu_exec,
+   QITCGv vaddr, QIMemInfo info))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+instr_set_event(guest_mem_before_trans, fn);
+}
diff --git a/instrument/control.h b/instrument/control.h
index 03e87b2b8f..3e44702f75 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -86,12 +86,21 @@ typedef enum {
 INSTR_STATE_ENABLE,
 } InstrState;
 
+#define INSTR_MAX_TCG_REGS 16
+
+typedef struct InstrInfo {
+InstrState state;
+unsigned int max;
+void *tcg_regs[INSTR_MAX_TCG_REGS];
+} InstrInfo;
+
 /**
  * instr_set_state:
  *
- * Set the instrumentation state of the current host thread.
+ * Set the instrumentation state of the current host thread, and return its
+ * #InstrInfo.
  */
-static inline void instr_set_state(InstrState state);
+static inline InstrInfo *instr_set_state(InstrState state);
 
 /**
  * instr_get_state:
@@ -100,6 +109,29 @@ static inline void instr_set_state(InstrState state);
  */
 static inline InstrState instr_get_state(void);
 
+/**
+ * instr_tcg_to_qitcg:
+ * @info: Pointer to #InstrInfo.
+ * @num: Number of TCG register used by instrumentation.
+ * @arg: TCG register.
+ *
+ * Get a suitable QITCGv* from a TCGv* value.
+ */
+#define instr_tcg_to_qitcg(info, num, arg) \
+({\
+info->tcg_regs[num] = arg;\
+(void *)num;  \
+})
+
+/**
+ * instr_tcg_count:
+ * @info: Pointer to #InstrInfo.
+ * @count: Number of TCG registers used by instrumentation.
+ *
+ * Set the number of TCG registers used by instrumentation.
+ */
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count);
+
 
 #include "instrument/control.inc.h"
 
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 6d65b23ead..3eba9b7c85 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -46,14 +46,22 @@ static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu)
 }
 
 
-extern __thread InstrState instr_cur_state;
+extern __thread InstrInfo instr_cur_info;
 
-static inline void instr_set_state(InstrState state)
+static inline InstrInfo *instr_set_state(InstrState state)
 {
-atomic_store_release(&instr_cur_state, state);
+InstrInfo *info = &instr_cur_info;
+atomic_store_release(&info->state, state);
+return info;
 }
 
 static inline InstrState instr_get_state(void)
 {
-return atomic_load_acquire(&instr_cur_state);
+return atomic_load_acquire(&instr_cur_info.state);
+}
+
+
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count)
+{
+info->max = count;
 }
diff --git a/instrument/events.h b/instrument/events.h
index 4a0560490a..1cc4dbb052 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -12,6 +12,8 @@
 
 #include "instrument/qemu-instr/control.h"
 #include "instrument/qemu-instr/types.h"
+#include "trace/control.

[Qemu-devel] [PATCH v6 21/22] instrument: Add event 'guest_user_syscall_ret'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |3 +++
 instrument/control.c|   15 +++
 instrument/events.h |5 +
 instrument/events.inc.h |   13 +
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   13 +
 linux-user/syscall.c|1 +
 stubs/instrument.c  |2 ++
 8 files changed, 53 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0d92eaf8c4..fb468c0574 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -407,6 +407,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_freebsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -485,6 +486,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #endif
 if (do_strace)
 print_netbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -563,6 +565,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_openbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
diff --git a/instrument/control.c b/instrument/control.c
index 45efeef7ac..e58a38b7db 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -211,3 +211,18 @@ SYM_PUBLIC void qi_event_set_guest_user_syscall(
 #endif
 instr_set_event(guest_user_syscall, fn);
 }
+
+
+void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+
+SYM_PUBLIC void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+#if !defined(CONFIG_USER_ONLY)
+ERROR_IF(true, "called in full-system mode");
+#endif
+instr_set_event(guest_user_syscall_ret, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 8c944e1f91..6197ece466 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -75,6 +75,11 @@ static inline void instr_guest_user_syscall(
 CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
 uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
 
+extern void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index e2f4315fb0..d31dec54b8 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -94,3 +94,16 @@ static inline void instr_guest_user_syscall(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t ret)
+= instr_get_event(guest_user_syscall_ret);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+(*cb)(vcpu_, num, ret);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index a76f76e1d1..be13a90286 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -165,6 +165,7 @@ InstrUnloadError instr_unload(const char *id)
 instr_set_event(guest_mem_before_trans, NULL);
 instr_set_event(guest_mem_before_exec, NULL);
 instr_set_event(guest_user_syscall, NULL);
+instr_set_event(guest_user_syscall_ret, NULL);
 
 instr_cpu_stop_all_end(&info);
 cpu_list_unlock();
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index 136058af4f..bc4e49bef1 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -157,6 +157,19 @@ void qi_event_set_guest_user_syscall(
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
uint64_t arg7, uint64_t arg8));
 
+/*
+ * Finish executing a guest system call in syscall emulation mode.
+ *
+ * @num: System call number.
+ * @ret: System call result value.
+ *
+ * Mode: user
+ * Targets: TCG(all)
+ * Time: exec
+ */
+void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c9f0b9fa56..44b91e3c52 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -12398,6 +12398,7 @@ fail:
 #endif
 if(do_strace)
 print_syscall_ret(num, ret);
+  

[Qemu-devel] [PATCH v6 20/22] instrument: Add event 'guest_user_syscall'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |6 ++
 instrument/control.c|   18 ++
 instrument/events.h |7 +++
 instrument/events.inc.h |   16 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   15 +++
 linux-user/syscall.c|2 ++
 stubs/instrument.c  |3 +++
 8 files changed, 68 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 3230f722f3..0d92eaf8c4 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -324,6 +324,8 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("freebsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 
arg7, arg8);
 if(do_strace)
 print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -423,6 +425,8 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #ifdef DEBUG
 gemu_log("netbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -499,6 +503,8 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("openbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
diff --git a/instrument/control.c b/instrument/control.c
index 3fcacb2853..45efeef7ac 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -193,3 +193,21 @@ SYM_PUBLIC void qi_event_set_guest_mem_before_exec(
 ERROR_IF(!tcg_enabled(), "called without TCG");
 instr_set_event(guest_mem_before_exec, fn);
 }
+
+
+void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
+SYM_PUBLIC void qi_event_set_guest_user_syscall(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+#if !defined(CONFIG_USER_ONLY)
+ERROR_IF(true, "called in full-system mode");
+#endif
+instr_set_event(guest_user_syscall, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 6507b26867..8c944e1f91 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -68,6 +68,13 @@ extern void (*instr_event__guest_mem_before_exec)(
 static inline void instr_guest_mem_before_exec(
 CPUState *vcpu, uint64_t vaddr, TraceMemInfo info);
 
+extern void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index ebc8020715..e2f4315fb0 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -78,3 +78,19 @@ static inline void instr_guest_mem_before_exec(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8)
+= instr_get_event(guest_user_syscall);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+(*cb)(vcpu_, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index f1d769b92d..a76f76e1d1 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -164,6 +164,7 @@ InstrUnl

[Qemu-devel] [PATCH v6 19/22] instrument: Add event 'guest_mem_before_exec'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |4 +++
 include/exec/cpu_ldst_useronly_template.h |4 +++
 include/exec/helper-gen.h |1 +
 include/exec/helper-proto.h   |1 +
 include/exec/helper-tcg.h |1 +
 instrument/control.c  |   37 +
 instrument/control.h  |   15 
 instrument/events.h   |5 
 instrument/events.inc.h   |   18 +-
 instrument/helpers.h  |2 ++
 instrument/load.c |1 +
 instrument/qemu-instr/control.h   |   21 
 stubs/instrument.c|   21 
 13 files changed, 129 insertions(+), 2 deletions(-)
 create mode 100644 instrument/helpers.h

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index debbabcfb2..8018e8b16a 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -28,6 +28,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -89,6 +90,7 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -126,6 +128,7 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -167,6 +170,7 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index b0b3fc1b8d..c36c50ae41 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -27,6 +27,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -62,6 +63,7 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
@@ -81,6 +83,7 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
@@ -102,6 +105,7 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
index 8239ffc77c..f351c3d050 100644
--- a/include/exec/helper-gen.h
+++ b/include/exec/helper-gen.h
@@ -57,6 +57,7 @@ static inline void glue(gen_helper_, 
name)(dh_retvar_decl(ret)  \
 }
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "trace/generated-helpers-wrappers.h"
 #include "tcg-runtime.h"
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
index 954bef85ce..8fdd02c132 100644
--- a/include/exec/helper-proto.h
+++ b/include/exec/helper-proto.h
@@ -27,6 +27,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), 
dh_ctype(t3), \
 dh_ctype(t4), dh_ctype(t5));
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "tcg-runtime.h"
 
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index b0c5bafa99..255e73c3e6 100644
--- a/include/exec/helper-tcg.h
+

[Qemu-devel] [PATCH v6 17/22] trace: Introduce a proper structure to describe memory accesses

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |   15 ++
 include/exec/cpu_ldst_useronly_template.h |   15 ++
 tcg/tcg-op.c  |   22 +
 trace/mem-internal.h  |   22 -
 trace/mem.h   |   31 +
 5 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index 4db2302962..debbabcfb2 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -88,9 +88,8 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -126,9 +125,8 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -168,9 +166,8 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index 7b8c7c506e..b0b3fc1b8d 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -61,9 +61,8 @@ static inline RES_TYPE
 glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
 }
@@ -81,9 +80,8 @@ static inline int
 glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
 }
@@ -103,9 +101,8 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
   RES_TYPE v)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
 }
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 688d91755b..6edf70bdfc 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2676,24 +2676,28 @@ static void tcg_gen_req_mo(TCGBar type)
 
 void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
 memop = tcg_canonicalize_memop(memop, 0, 0);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 0));
+meminfo = trace_mem_get_info(memop, 0);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
 memop = tcg_canonicalize_memop(memop, 0, 1);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 1));
+meminfo = trace_mem_get_info(memop, 1);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_ld_i64(TCGv_i64 val

[Qemu-devel] [PATCH v6 16/22] instrument: Add event 'guest_cpu_reset'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |9 +
 qom/cpu.c   |2 ++
 stubs/instrument.c  |1 +
 7 files changed, 36 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 7ed4bf3505..cb397639ce 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -134,3 +134,12 @@ SYM_PUBLIC void qi_event_set_guest_cpu_exit(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_exit, fn);
 }
+
+
+void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_reset, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index c743cb8180..4a0560490a 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -39,6 +39,9 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu);
 extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
 static inline void instr_guest_cpu_exit(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+static inline void instr_guest_cpu_reset(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index c88df7e42f..a126ba5ae6 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -31,3 +31,14 @@ static inline void instr_guest_cpu_exit(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_reset(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_reset);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 6808d361b5..8c15a73a8c 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -161,6 +161,7 @@ InstrUnloadError instr_unload(const char *id)
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
 instr_set_event(guest_cpu_exit, NULL);
+instr_set_event(guest_cpu_reset, NULL);
 
 instr_cpu_stop_all_end(&info);
 cpu_list_unlock();
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index 107ee8afe0..322009100d 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -96,6 +96,15 @@ void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
  */
 void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
 
+/*
+ * Reset the state of a virtual (guest) CPU.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/qom/cpu.c b/qom/cpu.c
index dc5392dbeb..6336d63f66 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -19,6 +19,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "qom/cpu.h"
@@ -275,6 +276,7 @@ void cpu_reset(CPUState *cpu)
 (*klass->reset)(cpu);
 }
 
+instr_guest_cpu_reset(cpu);
 trace_guest_cpu_reset(cpu);
 }
 
diff --git a/stubs/instrument.c b/stubs/instrument.c
index e7adea1aad..752c66e3a4 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -44,3 +44,4 @@ void qmp_instr_unload(const char *id, Error **errp)
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
 void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
+void (*instr_event__guest_cpu_reset)(QICPU *vcpu);




[Qemu-devel] [PATCH v6 15/22] instrument: Add event 'guest_cpu_exit'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |   17 +
 instrument/qemu-instr/control.h |   11 +++
 stubs/instrument.c  |1 +
 trace/control.c |4 +++-
 7 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/instrument/control.c b/instrument/control.c
index 4f9c138ccf..7ed4bf3505 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -125,3 +125,12 @@ SYM_PUBLIC void qi_event_set_guest_cpu_enter(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_enter, fn);
 }
+
+
+void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_exit, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 947f120aa9..c743cb8180 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -36,6 +36,9 @@ extern void *instr_event__fini_data;
 extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
 static inline void instr_guest_cpu_enter(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+static inline void instr_guest_cpu_exit(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index e3f8024716..c88df7e42f 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -20,3 +20,14 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_exit(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_exit);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 218bca74b2..6808d361b5 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -11,7 +11,9 @@
 #include "qemu-common.h"
 
 #include 
+#include "cpu.h"
 #include "exec/cpu-common.h"
+#include "exec/exec-all.h"
 #include "instrument/control.h"
 #include "instrument/events.h"
 #include "instrument/load.h"
@@ -127,6 +129,13 @@ out:
 return res;
 }
 
+
+static void instr_unload__cb(CPUState *cpu, void *data)
+{
+tb_flush_sync(cpu);
+instr_guest_cpu_exit(cpu);
+}
+
 InstrUnloadError instr_unload(const char *id)
 {
 InstrUnloadError res;
@@ -139,6 +148,10 @@ InstrUnloadError instr_unload(const char *id)
 goto out;
 }
 
+InstrCPUStop info;
+cpu_list_lock();
+instr_cpu_stop_all_begin(&info, instr_unload__cb, NULL);
+
 qi_fini_fn fini_fn = instr_get_event(fini_fn);
 if (fini_fn) {
 void *fini_data = instr_get_event(fini_data);
@@ -147,6 +160,10 @@ InstrUnloadError instr_unload(const char *id)
 
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
+instr_set_event(guest_cpu_exit, NULL);
+
+instr_cpu_stop_all_end(&info);
+cpu_list_unlock();
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index f61e7a2b6e..107ee8afe0 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -85,6 +85,17 @@ void qi_set_fini(qi_fini_fn fn, void *data);
  */
 void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
 
+/*
+ * Hot-unplug a virtual (guest) CPU.
+ *
+ * Also triggered on each CPU when an instrumentation library is unloaded.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/stubs/instrument.c b/stubs/instrument.c
index abed583a56..e7adea1aad 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -43,3 +43,4 @@ void qmp_instr_unload(const char *id, Error **errp)
 
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
+void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
diff --git a/trace/control.c b/trace/control.c
index 82d8989c4d..946a0af818 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -1,13 +1,14 @@
 /*
  * Interface for configuring and controlling the state of tracing events.
  *
- * Copyright (C) 2011-2016 Lluís Vilanova 
+ * Copyright (C) 2011-2017 Lluís Vilanova 
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #includ

[Qemu-devel] [PATCH v6 14/22] exec: Add function to synchronously flush TB on a stopped vCPU

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/stubs/tcg-stub.c|3 +++
 accel/tcg/translate-all.c |7 +++
 include/exec/exec-all.h   |1 +
 3 files changed, 11 insertions(+)

diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c
index 5dd480b1a2..5226c4a8a4 100644
--- a/accel/stubs/tcg-stub.c
+++ b/accel/stubs/tcg-stub.c
@@ -20,3 +20,6 @@
 void tb_flush(CPUState *cpu)
 {
 }
+void tb_flush_sync(CPUState *cpu)
+{
+}
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 2d1ed06065..a334ac4ccb 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -929,6 +929,13 @@ done:
 tb_unlock();
 }
 
+void tb_flush_sync(CPUState *cpu)
+{
+unsigned tb_flush_count = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
+assert(cpu == current_cpu);
+do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count));
+}
+
 void tb_flush(CPUState *cpu)
 {
 if (tcg_enabled()) {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 673fc066d0..3f38186a5e 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -358,6 +358,7 @@ struct TranslationBlock {
 
 void tb_free(TranslationBlock *tb);
 void tb_flush(CPUState *cpu);
+void tb_flush_sync(CPUState *cpu);
 void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
 TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
target_ulong cs_base, uint32_t flags);




[Qemu-devel] [PATCH v6 13/22] instrument: Support synchronous modification of vCPU state

2017-09-13 Thread Lluís Vilanova
Stops all vCPUs to allow performing management operations like TB
invalidations. These are later necessary to ensure translated code does not
reference unloaded instrumentation libraries.

Signed-off-by: Lluís Vilanova 
---
 instrument/control.c |   67 ++
 instrument/control.h |   26 ++
 instrument/control.inc.h |   11 
 3 files changed, 104 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index c4b3ca0440..4f9c138ccf 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,6 +13,7 @@
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "qemu/compiler.h"
+#include "qemu/main-loop.h"
 #include "qom/cpu.h"
 
 
@@ -40,6 +41,72 @@ void instr_cpu_remove(CPUState *vcpu)
 }
 
 
+static void instr_cpu_stop_all__cb(CPUState *cpu, run_on_cpu_data data)
+{
+InstrCPUStop *info = data.host_ptr;
+/* run posted function */
+if (info->fun) {
+info->fun(cpu, info->data);
+}
+#if !defined(CONFIG_USER_ONLY)
+/* signal we're out of the main vCPU loop */
+unsigned int count = atomic_load_acquire(&info->count);
+atomic_store_release(&info->count, count + 1);
+atomic_store_release(&info->stopped, true);
+/* wait until we're good to go again */
+qemu_cond_wait(&info->cond, &info->mutex);
+count = atomic_load_acquire(&info->count);
+atomic_store_release(&info->count, count - 1);
+qemu_mutex_unlock(&info->mutex);
+#endif
+}
+
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+  instr_cpu_stop_fun fun, void *data)
+{
+CPUState *cpu;
+
+info->fun = fun;
+info->data = data;
+
+#if !defined(CONFIG_USER_ONLY)
+info->count = 0;
+qemu_cond_init(&info->cond);
+qemu_mutex_init(&info->mutex);
+
+/* main dispatch loop and run_on_cpu() lock the BQL */
+qemu_mutex_unlock_iothread();
+#endif
+
+CPU_FOREACH(cpu) {
+#if !defined(CONFIG_USER_ONLY)
+atomic_store_release(&info->stopped, false);
+qemu_mutex_lock(&info->mutex);
+async_run_on_cpu(cpu, instr_cpu_stop_all__cb,
+ RUN_ON_CPU_HOST_PTR(info));
+while (!atomic_load_acquire(&info->stopped)) {
+/* wait for vCPU to signal it's stopped */
+}
+#else
+instr_cpu_stop_all__cb(cpu, RUN_ON_CPU_HOST_PTR(info));
+#endif
+}
+}
+
+void instr_cpu_stop_all_end(InstrCPUStop *info)
+{
+#if !defined(CONFIG_USER_ONLY)
+qemu_cond_broadcast(&info->cond);
+while (atomic_load_acquire(&info->count)) {
+/* wait for all vCPUs to continue before we can destroy info */
+}
+qemu_cond_destroy(&info->cond);
+qemu_mutex_destroy(&info->mutex);
+qemu_mutex_lock_iothread();
+#endif
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index 57cea07fa7..03e87b2b8f 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -46,6 +46,32 @@ static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
  */
 static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
 
+typedef struct InstrCPUStop InstrCPUStop;
+typedef void (*instr_cpu_stop_fun)(CPUState *cpu, void *data);
+
+/**
+ * instr_cpu_stop_all_begin:
+ * @info: Opaque structure describing the operation.
+ * @fun: Function to run on the context of each vCPU once stopped.
+ * @data: Pointer to pass to @fun.
+ *
+ * Ensure all vCPUs stop executing guest code, and execute @fun on their 
context
+ * in turn. Returns with all vCPUs still stopped.
+ *
+ * Assumes cpu_list_lock() and that the QBL is locked before calling.
+ */
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+  instr_cpu_stop_fun fun, void *data);
+
+/**
+ * instr_cpu_stop_all_end:
+ * @info: Opaque structure passed to a previous instr_cpu_stop_all_begin()
+ * call.
+ *
+ * Resume execution on all vCPUs stopped by instr_cpu_stop_all_begin().
+ */
+void instr_cpu_stop_all_end(InstrCPUStop *info);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 45daae7d1d..6d65b23ead 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -15,6 +15,17 @@
 #include 
 
 
+struct InstrCPUStop {
+instr_cpu_stop_fun fun;
+void *data;
+#if !defined(CONFIG_USER_ONLY)
+bool stopped;
+unsigned int count;
+QemuCond cond;
+QemuMutex mutex;
+#endif
+};
+
 extern unsigned int instr_cpus_count;
 extern CPUState **instr_cpus;
 




[Qemu-devel] [PATCH v6 12/22] instrument: Add event 'guest_cpu_enter'

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 
 instrument/events.h |5 
 instrument/events.inc.h |   11 +
 instrument/load.c   |9 
 instrument/qemu-instr/control.h |   46 +++
 stubs/instrument.c  |1 +
 trace/control-target.c  |2 ++
 7 files changed, 83 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 8cf2b4f967..c4b3ca0440 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -49,3 +49,12 @@ SYM_PUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
 instr_set_event(fini_fn, fn);
 instr_set_event(fini_data, data);
 }
+
+
+void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_enter, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 82ad0bd827..947f120aa9 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -11,6 +11,7 @@
 #define INSTRUMENT__EVENTS_H
 
 #include "instrument/qemu-instr/control.h"
+#include "instrument/qemu-instr/types.h"
 
 /**
  * instr_get_event:
@@ -32,6 +33,10 @@
 extern qi_fini_fn instr_event__fini_fn;
 extern void *instr_event__fini_data;
 
+extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+static inline void instr_guest_cpu_enter(CPUState *vcpu);
+
+
 #include "instrument/events.inc.h"
 
 #endif  /* INSTRUMENT__EVENTS_H */
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index 8b1ce7fcb2..e3f8024716 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -7,5 +7,16 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "instrument/control.h"
 
 
+static inline void instr_guest_cpu_enter(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_enter);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index a01d66a4d4..218bca74b2 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -11,6 +11,7 @@
 #include "qemu-common.h"
 
 #include 
+#include "exec/cpu-common.h"
 #include "instrument/control.h"
 #include "instrument/events.h"
 #include "instrument/load.h"
@@ -109,6 +110,13 @@ InstrLoadError instr_load(const char *path, int argc, 
const char **argv,
 goto err;
 }
 
+cpu_list_lock();
+CPUState *cpu;
+CPU_FOREACH(cpu) {
+instr_guest_cpu_enter(cpu);
+}
+cpu_list_unlock();
+
 res = INSTR_LOAD_OK;
 goto out;
 
@@ -138,6 +146,7 @@ InstrUnloadError instr_unload(const char *id)
 }
 
 instr_set_event(fini_fn, NULL);
+instr_set_event(guest_cpu_enter, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index b841afaa31..f61e7a2b6e 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -16,6 +16,7 @@ extern "C" {
 
 #include 
 #include 
+#include 
 
 
 /**
@@ -39,6 +40,51 @@ typedef void (*qi_fini_fn)(void *arg);
  */
 void qi_set_fini(qi_fini_fn fn, void *data);
 
+
+/*
+ * Set callbacks for available events. Each event has a short description and
+ * various indicators of when it can be triggered:
+ *
+ * - Mode :: user
+ *   Triggered in QEMU user application emulation (e.g., linux-user).
+ *
+ * - Mode :: softmmy
+ *   Triggered in QEMU full-system emulation.
+ *
+ *
+ * - Targets :: all
+ *   Triggered on all targets, both using TCG or native hardware virtualization
+ *   (e.g., KVM).
+ *
+ * - Targets :: TCG()
+ *   Triggered on the given guest target architectures when executing with TCG
+ *   (no native hardware virtualization).
+ *
+ *
+ * - Time :: exec
+ *   Triggered when the guest executes the described operation.
+ *
+ * - Time :: trans
+ *   Triggered when QEMU translates a guest operation. This is only available
+ *   when executing with TCG. Guest instructions are decompiled and translated
+ *   into the intermediate TCG language (when "Time: trans" events are
+ *   triggered). Then, the TCG compiler translates TCG code into the native 
host
+ *   code that QEMU will execute to emulate the guest (when "Time: exec" events
+ *   are triggered). As QEMU uses a cache of translated code, the same
+ *   instruction might be translated more than once (when the cache overflows).
+ */
+
+/*
+ * Hot-plug a new virtual (guest) CPU.
+ *
+ * Also triggered on each CPU when an instrumentation library is loaded.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_c

[Qemu-devel] [PATCH v6 11/22] instrument: Track vCPUs

2017-09-13 Thread Lluís Vilanova
Keep a translation between instrumentation's QICPU and CPUState objects to avoid
exposing QEMU's internals to instrumentation clients.

Signed-off-by: Lluís Vilanova 
---
 cpus-common.c|9 +
 instrument/control.c |   23 +++
 instrument/control.h |   36 
 instrument/control.inc.h |   23 +++
 4 files changed, 91 insertions(+)

diff --git a/cpus-common.c b/cpus-common.c
index 59f751ecf9..ec5f46cc3d 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -22,6 +22,9 @@
 #include "exec/cpu-common.h"
 #include "qom/cpu.h"
 #include "sysemu/cpus.h"
+#if defined(CONFIG_INSTRUMENT)
+#include "instrument/control.h"
+#endif
 
 static QemuMutex qemu_cpu_list_lock;
 static QemuCond exclusive_cond;
@@ -84,6 +87,9 @@ void cpu_list_add(CPUState *cpu)
 } else {
 assert(!cpu_index_auto_assigned);
 }
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_add(cpu);
+#endif
 QTAILQ_INSERT_TAIL(&cpus, cpu, node);
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 
@@ -102,6 +108,9 @@ void cpu_list_remove(CPUState *cpu)
 assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
 
 QTAILQ_REMOVE(&cpus, cpu, node);
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_remove(cpu);
+#endif
 cpu->cpu_index = UNASSIGNED_CPU_INDEX;
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 }
diff --git a/instrument/control.c b/instrument/control.c
index 3630d6b3be..8cf2b4f967 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,10 +13,33 @@
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "qemu/compiler.h"
+#include "qom/cpu.h"
+
 
 __thread InstrState instr_cur_state;
 
 
+unsigned int instr_cpus_count;
+CPUState **instr_cpus;
+
+void instr_cpu_add(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+if (idx >= instr_cpus_count) {
+instr_cpus_count = idx + 1;
+instr_cpus = realloc(instr_cpus,
+ sizeof(*instr_cpus) * instr_cpus_count);
+}
+instr_cpus[idx] = vcpu;
+}
+
+void instr_cpu_remove(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+instr_cpus[idx] = NULL;
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index f2b085f69b..57cea07fa7 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -10,6 +10,42 @@
 #ifndef INSTRUMENT__CONTROL_H
 #define INSTRUMENT__CONTROL_H
 
+#include "qemu/typedefs.h"
+#include "instrument/qemu-instr/types.h"
+
+
+/**
+ * instr_cpu_add:
+ *
+ * Make @vcpu available to instrumentation clients.
+ *
+ * Precondition: cpu_list_lock().
+ */
+void instr_cpu_add(CPUState *vcpu);
+
+/**
+ * instr_cpu_remove:
+ *
+ * Make @vcpu unavailable to instrumentation clients.
+ *
+ * Precondition: cpu_list_lock().
+ */
+void instr_cpu_remove(CPUState *vcpu);
+
+/**
+ * instr_cpu_to_qicpu:
+ *
+ * Get the #QICPU corresponding to the given #CPUState.
+ */
+static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
+
+/**
+ * instr_cpu_from_qicpu:
+ *
+ * Get the #CPUState corresponding to the given #QICPU.
+ */
+static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 0f649f4caa..45daae7d1d 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -7,9 +7,32 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "qemu/osdep.h"
 #include "qemu/atomic.h"
 #include "qemu/compiler.h"
+#include "qom/cpu.h"
 #include 
+#include 
+
+
+extern unsigned int instr_cpus_count;
+extern CPUState **instr_cpus;
+
+static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu)
+{
+uintptr_t idx = vcpu->cpu_index;
+return (QICPU)idx;
+}
+
+static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu)
+{
+unsigned int idx = (uintptr_t)vcpu;
+if (idx >= instr_cpus_count) {
+return NULL;
+} else {
+return instr_cpus[idx];
+}
+}
 
 
 extern __thread InstrState instr_cur_state;




[Qemu-devel] [PATCH v6 10/22] instrument: Add support for tracing events

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 .gitignore|1 
 Makefile  |3 +
 instrument/Makefile.objs  |1 
 instrument/error.h|6 ++
 instrument/qemu-instr/types.h |   51 +++
 instrument/qemu-instr/types.inc.h |   15 
 instrument/trace.c|  125 +
 trace/control.h   |1 
 8 files changed, 203 insertions(+)
 create mode 100644 instrument/qemu-instr/types.h
 create mode 100644 instrument/qemu-instr/types.inc.h
 create mode 100644 instrument/trace.c

diff --git a/.gitignore b/.gitignore
index cf65316863..5ffcb9a091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -134,3 +134,4 @@ trace-dtrace-root.h
 trace-dtrace-root.dtrace
 trace-ust-all.h
 trace-ust-all.c
+!/instrument/*
diff --git a/Makefile b/Makefile
index c3d9a4bcd9..646fe2f327 100644
--- a/Makefile
+++ b/Makefile
@@ -602,6 +602,9 @@ endif
 ifdef CONFIG_INSTRUMENT
$(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
$(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/trace.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.inc.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
 endif
 
 install-datadir:
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index ec76b2080b..d7e6c760c3 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -4,3 +4,4 @@ target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
 target-obj-$(CONFIG_INSTRUMENT) += control.o
+target-obj-$(CONFIG_INSTRUMENT) += trace.o
diff --git a/instrument/error.h b/instrument/error.h
index f8d1dd4b16..7a51d62fdb 100644
--- a/instrument/error.h
+++ b/instrument/error.h
@@ -25,4 +25,10 @@
 return;  \
 }
 
+#define ERROR_IF_RET(cond, ret, msg, args...)   \
+if (unlikely(cond)) {   \
+_ERROR(msg, ##args);\
+return ret; \
+}   \
+
 #endif  /* INSTRUMENT_ERROR_H */
diff --git a/instrument/qemu-instr/types.h b/instrument/qemu-instr/types.h
new file mode 100644
index 00..ea3a032b4f
--- /dev/null
+++ b/instrument/qemu-instr/types.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__TYPES_H
+#define QI__TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION: types
+ * @section_id: qi-types
+ * @title: Common types
+ */
+
+/**
+ * QITraceEvent:
+ *
+ * Opaque structure defining a tracing event.
+ */
+typedef struct QITraceEvent QITraceEvent;
+
+/**
+ * QITraceEventIter:
+ *
+ * Opaque structure defining a tracing event iterator.
+ */
+typedef struct QITraceEventIter QITraceEventIter;
+
+/**
+ * QICPU:
+ *
+ * Opaque guest CPU pointer.
+ */
+typedef struct QICPU_d *QICPU;
+
+
+#include 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__TYPES_H */
diff --git a/instrument/qemu-instr/types.inc.h 
b/instrument/qemu-instr/types.inc.h
new file mode 100644
index 00..0d99ea59a2
--- /dev/null
+++ b/instrument/qemu-instr/types.inc.h
@@ -0,0 +1,15 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include 
+
+
+struct QITraceEventIter {
+char buffer[(sizeof(size_t) * 2) + sizeof(char *)];
+};
diff --git a/instrument/trace.c b/instrument/trace.c
new file mode 100644
index 00..6a437039b4
--- /dev/null
+++ b/instrument/trace.c
@@ -0,0 +1,125 @@
+/*
+ * API for QEMU's tracing events.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "instrument/error.h"
+#include "qemu/compiler.h"
+#include "qemu-instr/trace.h"
+#include "trace/control.h"
+
+
+SYM_PUBLIC
+QITraceEvent *qi_trace_event_name(const char *name)
+{
+ERROR_IF_RET(!name, NULL, "must provide a name");
+return (QITraceEvent *)trace_event_name(name);
+}
+
+SYM_PUBLIC
+void qi_trace_event_iter_init(QITraceEventIter *iter, const char *pattern)
+{
+TraceEventIter *iter_ = (TraceEventIter *)iter;

[Qemu-devel] [PATCH v6 09/22] instrument: Add basic control interface

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 Makefile|4 +++
 configure   |1 +
 include/qemu/compiler.h |   19 
 instrument/Makefile.objs|1 +
 instrument/control.c|   28 
 instrument/control.h|   44 +
 instrument/control.inc.h|   25 +
 instrument/error.h  |   28 
 instrument/events.h |   37 +++
 instrument/events.inc.h |   11 +
 instrument/load.c   |   13 +++
 instrument/qemu-instr/control.h |   46 +++
 stubs/instrument.c  |4 +++
 13 files changed, 261 insertions(+)
 create mode 100644 instrument/control.c
 create mode 100644 instrument/control.h
 create mode 100644 instrument/control.inc.h
 create mode 100644 instrument/error.h
 create mode 100644 instrument/events.h
 create mode 100644 instrument/events.inc.h
 create mode 100644 instrument/qemu-instr/control.h

diff --git a/Makefile b/Makefile
index 3861b3f49c..c3d9a4bcd9 100644
--- a/Makefile
+++ b/Makefile
@@ -599,6 +599,10 @@ ifdef CONFIG_VIRTFS
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
 endif
+ifdef CONFIG_INSTRUMENT
+   $(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+endif
 
 install-datadir:
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
diff --git a/configure b/configure
index 5175151317..18810eae84 100755
--- a/configure
+++ b/configure
@@ -6030,6 +6030,7 @@ if test "$instrument" = "yes"; then
   LIBS="-ldl $LIBS"
   echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
 fi
+QEMU_INCLUDES="-I\$(SRC_PATH)/instrument $QEMU_INCLUDES"
 
 if test "$rdma" = "yes" ; then
   echo "CONFIG_RDMA=y" >> $config_host_mak
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 340e5fdc09..e86bd34e2c 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -111,4 +111,23 @@
 #define GCC_FMT_ATTR(n, m)
 #endif
 
+/*
+ * Export symbol to dlopen()'ed libraries'.
+ *
+ * This code is taken from http://gcc.gnu.org/wiki/Visibility.
+ */
+#if defined _WIN32 || defined __CYGWIN__
+  #ifdef __GNUC__
+#define SYM_PUBLIC __attribute__ ((dllimport))
+  #else
+#define SYM_PUBLIC __declspec(dllimport)
+  #endif
+#else
+  #if __GNUC__ >= 4
+#define SYM_PUBLIC __attribute__ ((visibility("default")))
+  #else
+#define SYM_PUBLIC
+  #endif
+#endif
+
 #endif /* COMPILER_H */
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 7bf4e27e3c..ec76b2080b 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -3,3 +3,4 @@
 target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
+target-obj-$(CONFIG_INSTRUMENT) += control.o
diff --git a/instrument/control.c b/instrument/control.c
new file mode 100644
index 00..3630d6b3be
--- /dev/null
+++ b/instrument/control.c
@@ -0,0 +1,28 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/events.h"
+#include "instrument/load.h"
+#include "instrument/qemu-instr/control.h"
+#include "qemu/compiler.h"
+
+__thread InstrState instr_cur_state;
+
+
+qi_fini_fn instr_event__fini_fn;
+void *instr_event__fini_data;
+
+SYM_PUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(fini_fn, fn);
+instr_set_event(fini_data, data);
+}
diff --git a/instrument/control.h b/instrument/control.h
new file mode 100644
index 00..f2b085f69b
--- /dev/null
+++ b/instrument/control.h
@@ -0,0 +1,44 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef INSTRUMENT__CONTROL_H
+#define INSTRUMENT__CONTROL_H
+
+
+/**
+ * InstrState:
+ * @INSTR_STATE_DISABLE: Intrumentation API not available.
+ * @INSTR_STATE_ENABLE: Intrumentation API available.
+ *
+ * Instrumentation state of current host thread. Used to ensure instrumentation
+ * clients use QEMU&#

[Qemu-devel] [PATCH v6 08/22] instrument: [hmp] Add library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 hmp-commands.hx |   32 
 monitor.c   |   39 +++
 2 files changed, 71 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 1941e19932..2e8ebe8422 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1858,6 +1858,38 @@ ETEXI
 .sub_table  = info_cmds,
 },
 
+#ifdef CONFIG_INSTRUMENT
+{
+.name   = "instr-load",
+.args_type  = "path:F,id:s?,arg:s?",
+.params = "path [id] [arg]",
+.help   = "load an instrumentation library",
+.cmd= hmp_instr_load,
+},
+#endif
+
+STEXI
+@item instr-load @var{path} [@var{id}] [@var{arg}]
+@findex instr-load
+Load an instrumentation library.
+ETEXI
+
+#ifdef CONFIG_INSTRUMENT
+{
+.name   = "instr-unload",
+.args_type  = "id:s",
+.params = "id",
+.help   = "unload an instrumentation library",
+.cmd= hmp_instr_unload,
+},
+#endif
+
+STEXI
+@item instr-unload
+@findex instr-unload
+Unload an instrumentation library.
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/monitor.c b/monitor.c
index e031aa2687..7b80d5351f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2323,6 +2323,45 @@ int monitor_fd_param(Monitor *mon, const char *fdname, 
Error **errp)
 return fd;
 }
 
+#ifdef CONFIG_INSTRUMENT
+static void hmp_instr_load(Monitor *mon, const QDict *qdict)
+{
+Error *err = NULL;
+const char *path = qdict_get_str(qdict, "path");
+const char *id = qdict_get_try_str(qdict, "id");
+const char *str = qdict_get_try_str(qdict, "arg");
+strList args;
+
+args.value = (char *)str;
+args.next = NULL;
+
+InstrLoadResult *res = qmp_instr_load(path,
+  id != NULL, id,
+  args.value != NULL, &args,
+  &err);
+if (err) {
+error_report_err(err);
+} else {
+monitor_printf(mon, "Handle: %s\n", res->id);
+monitor_printf(mon, "OK\n");
+}
+qapi_free_InstrLoadResult(res);
+}
+
+static void hmp_instr_unload(Monitor *mon, const QDict *qdict)
+{
+Error *err = NULL;
+const char *id = qdict_get_str(qdict, "id");
+
+qmp_instr_unload(id, &err);
+if (err) {
+error_report_err(err);
+} else {
+monitor_printf(mon, "OK\n");
+}
+}
+#endif
+
 /* Please update hmp-commands.hx when adding or changing commands */
 static mon_cmd_t info_cmds[] = {
 #include "hmp-commands-info.h"




[Qemu-devel] [PATCH v6 07/22] instrument: [qapi] Add library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS  |1 +
 Makefile |1 +
 instrument/Makefile.objs |1 +
 instrument/qmp.c |   82 ++
 monitor.c|4 ++
 qapi-schema.json |3 ++
 qapi/instrument.json |   49 +++
 stubs/instrument.c   |   22 
 8 files changed, 163 insertions(+)
 create mode 100644 instrument/qmp.c
 create mode 100644 qapi/instrument.json

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c0b12a69a..edddab0502 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1492,6 +1492,7 @@ M: Stefan Hajnoczi 
 S: Maintained
 F: docs/instrument.txt
 F: instrument/
+F: qapi/instrument.json
 
 TPM
 S: Orphan
diff --git a/Makefile b/Makefile
index 337a1f6f9b..3861b3f49c 100644
--- a/Makefile
+++ b/Makefile
@@ -412,6 +412,7 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json 
$(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
$(SRC_PATH)/qapi/char.json \
$(SRC_PATH)/qapi/crypto.json \
+   $(SRC_PATH)/qapi/instrument.json \
$(SRC_PATH)/qapi/introspect.json \
$(SRC_PATH)/qapi/migration.json \
$(SRC_PATH)/qapi/net.json \
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 71994a4c85..7bf4e27e3c 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -2,3 +2,4 @@
 
 target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
+target-obj-$(CONFIG_INSTRUMENT) += qmp.o
diff --git a/instrument/qmp.c b/instrument/qmp.c
new file mode 100644
index 00..e4464aa5eb
--- /dev/null
+++ b/instrument/qmp.c
@@ -0,0 +1,82 @@
+/*
+ * QMP interface for instrumentation control commands.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include 
+
+#include "instrument/load.h"
+#include "qemu-common.h"
+#include "qapi/qmp/qerror.h"
+#include "qmp-commands.h"
+
+
+InstrLoadResult *qmp_instr_load(const char *path,
+bool has_id, const char *id,
+bool have_args, strList *args,
+Error **errp)
+{
+InstrLoadResult *res = g_malloc0(sizeof(*res));
+int argc = 0;
+const char **argv = NULL;
+InstrLoadError code;
+
+if (!has_id) {
+id = NULL;
+}
+
+strList *entry = have_args ? args : NULL;
+while (entry != NULL) {
+argv = realloc(argv, sizeof(*argv) * (argc + 1));
+argv[argc] = entry->value;
+argc++;
+entry = entry->next;
+}
+
+code = instr_load(path, argc, argv, &id);
+switch (code) {
+case INSTR_LOAD_OK:
+res->id = g_strdup(id);
+break;
+case INSTR_LOAD_ID_EXISTS:
+error_setg(errp, "Library ID exists");
+break;
+case INSTR_LOAD_TOO_MANY:
+error_setg(errp, "Tried to load too many libraries");
+break;
+case INSTR_LOAD_ERROR:
+error_setg(errp, "Library initialization returned non-zero");
+break;
+case INSTR_LOAD_DLERROR:
+error_setg(errp, "Error loading library: %s",
+   dlerror());
+break;
+}
+
+if (*errp) {
+g_free(res);
+res = NULL;
+}
+
+return res;
+}
+
+void qmp_instr_unload(const char *id, Error **errp)
+{
+InstrUnloadError code = instr_unload(id);
+switch (code) {
+case INSTR_UNLOAD_OK:
+break;
+case INSTR_UNLOAD_INVALID:
+error_setg(errp, "Unknown library ID");
+break;
+case INSTR_UNLOAD_DLERROR:
+error_setg(errp, "Error unloading library: %s", dlerror());
+break;
+}
+}
diff --git a/monitor.c b/monitor.c
index 9239f7adde..e031aa2687 100644
--- a/monitor.c
+++ b/monitor.c
@@ -978,6 +978,10 @@ static void qmp_unregister_commands_hack(void)
 qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
 qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
 #endif
+#ifndef CONFIG_INSTRUMENT
+qmp_unregister_command(&qmp_commands, "instr-load");
+qmp_unregister_command(&qmp_commands, "instr-unload");
+#endif
 #ifndef TARGET_I386
 qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index f3af2cb851..706c64659f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -93,6 +93,9 @@
 { 'include': 'qapi/trace.json' }
 { 'include': 'qapi/introspect.json' }
 
+# Instrumentation commands
+{ 'include&#

[Qemu-devel] [PATCH v6 06/22] instrument: [softmmu] Add command line library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 qemu-options.hx |   19 +++
 vl.c|   15 +++
 2 files changed, 34 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 9f6e2adfff..6947388aab 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4077,6 +4077,25 @@ HXCOMM HX does not support conditional compilation of 
text.
 @findex -trace
 @include qemu-option-trace.texi
 ETEXI
+#if defined(CONFIG_INSTRUMENT)
+DEF("instr", HAS_ARG, QEMU_OPTION_instr,
+"-instr [file=][,arg=]\n"
+"load an instrumentation library\n",
+QEMU_ARCH_ALL)
+#endif
+STEXI
+@item -instr file=@var{file}[,arg=@var{string}]
+@findex -instr
+
+Load a dynamic trace instrumentation library.
+
+@table @option
+@item file=@var{file}
+Load the given dynamic trace instrumentation library.
+@item arg=@var{string}
+String argument passed as to the library's @code{qi_init} routine (can be 
given multiple times).
+@end table
+ETEXI
 
 HXCOMM Internal use
 DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index fb1f05b937..aea05ed4cc 100644
--- a/vl.c
+++ b/vl.c
@@ -118,6 +118,7 @@ int main(int argc, char **argv)
 
 #include "trace-root.h"
 #include "trace/control.h"
+#include "instrument/cmdline.h"
 #include "qemu/queue.h"
 #include "sysemu/arch_init.h"
 
@@ -3037,6 +3038,9 @@ int main(int argc, char **argv, char **envp)
 } BlockdevOptions_queue;
 QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue
 = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
+char *instrument_path = NULL;
+int instrument_argc = 0;
+const char **instrument_argv = NULL;
 
 module_call_init(MODULE_INIT_TRACE);
 
@@ -3064,6 +3068,9 @@ int main(int argc, char **argv, char **envp)
 qemu_add_opts(&qemu_global_opts);
 qemu_add_opts(&qemu_mon_opts);
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 qemu_add_opts(&qemu_option_rom_opts);
 qemu_add_opts(&qemu_machine_opts);
 qemu_add_opts(&qemu_accel_opts);
@@ -4009,6 +4016,12 @@ int main(int argc, char **argv, char **envp)
 g_free(trace_file);
 trace_file = trace_opt_parse(optarg);
 break;
+#if defined(CONFIG_INSTRUMENT)
+case QEMU_OPTION_instr:
+instr_opt_parse(optarg, &instrument_path,
+&instrument_argc, &instrument_argv);
+break;
+#endif
 case QEMU_OPTION_readconfig:
 {
 int ret = qemu_read_config_file(optarg);
@@ -4196,6 +4209,8 @@ int main(int argc, char **argv, char **envp)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Open the logfile at this point and set the log mask if necessary.
  */
 if (log_file) {




[Qemu-devel] [PATCH v6 05/22] instrument: [bsd-user] Add command line library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/main.c|   17 +
 bsd-user/syscall.c |5 +
 2 files changed, 22 insertions(+)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 8a6706a1c8..104844edfc 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -33,6 +33,7 @@
 #include "exec/log.h"
 #include "trace/control.h"
 #include "glib-compat.h"
+#include "instrument/cmdline.h"
 
 int singlestep;
 unsigned long mmap_min_addr;
@@ -667,6 +668,11 @@ static void usage(void)
"-B addressset guest_base address to address\n"
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD 
(default)\n"
"\n"
+#if defined(CONFIG_INSTRUMENT)
+   "-instr [file=][,arg=]\n"
+   "  load an instrumentation library\n"
+   "\n"
+#endif
"Debug options:\n"
"-d item1[,...]enable logging of specified items\n"
"  (use '-d help' for a list of log items)\n"
@@ -738,6 +744,9 @@ int main(int argc, char **argv)
 envlist_t *envlist = NULL;
 char *trace_file = NULL;
 bsd_type = target_openbsd;
+char *instrument_path = NULL;
+int instrument_argc = 0;
+const char **instrument_argv = NULL;
 
 if (argc <= 1)
 usage();
@@ -756,6 +765,9 @@ int main(int argc, char **argv)
 cpu_model = NULL;
 
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 
 optind = 1;
 for (;;) {
@@ -843,6 +855,9 @@ int main(int argc, char **argv)
 } else if (!strcmp(r, "trace")) {
 g_free(trace_file);
 trace_file = trace_opt_parse(optarg);
+} else if (!strcmp(r, "instr")) {
+instr_opt_parse(optarg, &instrument_path,
+&instrument_argc, &instrument_argv);
 } else {
 usage();
 }
@@ -872,6 +887,8 @@ int main(int argc, char **argv)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Zero out regs */
 memset(regs, 0, sizeof(struct target_pt_regs));
 
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 66492aaf5d..3230f722f3 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -26,6 +26,8 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
+#include "instrument/cmdline.h"
+
 
 //#define DEBUG
 
@@ -332,6 +334,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */
@@ -430,6 +433,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */
@@ -505,6 +509,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */




[Qemu-devel] [PATCH v6 04/22] instrument: [linux-user] Add command line library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 linux-user/main.c|   21 +
 linux-user/syscall.c |4 
 2 files changed, 25 insertions(+)

diff --git a/linux-user/main.c b/linux-user/main.c
index 03666ef657..ac5c30c1fb 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -36,6 +36,7 @@
 #include "exec/log.h"
 #include "trace/control.h"
 #include "glib-compat.h"
+#include "instrument/cmdline.h"
 
 char *exec_path;
 
@@ -4017,6 +4018,17 @@ static void handle_arg_trace(const char *arg)
 trace_file = trace_opt_parse(arg);
 }
 
+static char *instrument_path;
+static int instrument_argc;
+static const char **instrument_argv;
+#if defined(CONFIG_INSTRUMENT)
+static void handle_arg_instrument(const char *arg)
+{
+instr_opt_parse(arg, &instrument_path,
+&instrument_argc, &instrument_argv);
+}
+#endif
+
 struct qemu_argument {
 const char *argv;
 const char *env;
@@ -4066,6 +4078,10 @@ static const struct qemu_argument arg_table[] = {
  "",   "Seed for pseudo-random number generator"},
 {"trace",  "QEMU_TRACE",   true,  handle_arg_trace,
  "",   "[[enable=]][,events=][,file=]"},
+#if defined(CONFIG_INSTRUMENT)
+{"instr",  "QEMU_INSTR",   true,  handle_arg_instrument,
+ "",   "[file=][,arg=]"},
+#endif
 {"version","QEMU_VERSION", false, handle_arg_version,
  "",   "display version information and exit"},
 {NULL, NULL, false, NULL, NULL, NULL}
@@ -4257,6 +4273,9 @@ int main(int argc, char **argv, char **envp)
 srand(time(NULL));
 
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 
 optind = parse_args(argc, argv);
 
@@ -4265,6 +4284,8 @@ int main(int argc, char **argv, char **envp)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Zero out regs */
 memset(regs, 0, sizeof(struct target_pt_regs));
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9b6364a266..e73a07fa6f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -115,6 +115,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include "uname.h"
 
 #include "qemu.h"
+#include "instrument/cmdline.h"
+
 
 #ifndef CLONE_IO
 #define CLONE_IO0x8000  /* Clone io context */
@@ -7765,6 +7767,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 _exit(arg1);
 ret = 0; /* avoid warning */
 break;
@@ -9821,6 +9824,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 ret = get_errno(exit_group(arg1));
 break;
 #endif




[Qemu-devel] [PATCH v6 03/22] instrument: Add generic library loader

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS  |1 
 Makefile.objs|4 +
 configure|3 +
 instrument/Makefile.objs |4 +
 instrument/cmdline.c |  128 +++
 instrument/cmdline.h |   51 ++
 instrument/load.c|  166 ++
 instrument/load.h|   88 
 stubs/Makefile.objs  |1 
 stubs/instrument.c   |   18 +
 10 files changed, 464 insertions(+)
 create mode 100644 instrument/Makefile.objs
 create mode 100644 instrument/cmdline.c
 create mode 100644 instrument/cmdline.h
 create mode 100644 instrument/load.c
 create mode 100644 instrument/load.h
 create mode 100644 stubs/instrument.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fb0eaee06a..6c0b12a69a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1491,6 +1491,7 @@ M: Lluís Vilanova 
 M: Stefan Hajnoczi 
 S: Maintained
 F: docs/instrument.txt
+F: instrument/
 
 TPM
 S: Orphan
diff --git a/Makefile.objs b/Makefile.objs
index 24a4ea08b8..81a9218e14 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -97,6 +97,10 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
 util-obj-y +=  trace/
 target-obj-y += trace/
 
+##
+# instrument
+target-obj-y += instrument/
+
 ##
 # guest agent
 
diff --git a/configure b/configure
index a21d1bceb9..5175151317 100755
--- a/configure
+++ b/configure
@@ -6025,6 +6025,9 @@ fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
 if test "$instrument" = "yes"; then
+  LDFLAGS="-rdynamic $LDFLAGS"  # limit symbols available to clients
+  QEMU_CFLAGS="-fvisibility=hidden $QEMU_CFLAGS"
+  LIBS="-ldl $LIBS"
   echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
 fi
 
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
new file mode 100644
index 00..71994a4c85
--- /dev/null
+++ b/instrument/Makefile.objs
@@ -0,0 +1,4 @@
+# -*- mode: makefile -*-
+
+target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
+target-obj-$(CONFIG_INSTRUMENT) += load.o
diff --git a/instrument/cmdline.c b/instrument/cmdline.c
new file mode 100644
index 00..da7a7cbceb
--- /dev/null
+++ b/instrument/cmdline.c
@@ -0,0 +1,128 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include 
+#include "instrument/cmdline.h"
+#include "instrument/load.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+
+
+QemuOptsList qemu_instr_opts = {
+.name = "instrument",
+.implied_opt_name = "file",
+.merge_lists = true,
+.head = QTAILQ_HEAD_INITIALIZER(qemu_instr_opts.head),
+.desc = {
+{
+.name = "file",
+.type = QEMU_OPT_STRING,
+},{
+.name = "arg",
+.type = QEMU_OPT_STRING,
+},
+{ /* end of list */ }
+},
+};
+
+void instr_opt_parse(const char *optarg, char **path,
+ int *argc, const char ***argv)
+{
+const char *arg;
+QemuOptsIter iter;
+QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("instrument"),
+ optarg, true);
+if (!opts) {
+exit(1);
+} else {
+#if !defined(CONFIG_INSTRUMENT)
+error_report("instrumentation not enabled on this build");
+exit(1);
+#endif
+}
+
+
+arg = qemu_opt_get(opts, "file");
+if (arg != NULL) {
+g_free(*path);
+*path = g_strdup(arg);
+}
+
+qemu_opt_iter_init(&iter, opts, "arg");
+while ((arg = qemu_opt_iter_next(&iter)) != NULL) {
+*argv = realloc(*argv, sizeof(**argv) * (*argc + 1));
+(*argv)[*argc] = g_strdup(arg);
+(*argc)++;
+}
+
+qemu_opts_del(opts);
+}
+
+void instr_init(const char *path, int argc, const char **argv)
+{
+#if defined(CONFIG_INSTRUMENT)
+InstrLoadError err;
+
+if (path == NULL) {
+return;
+}
+
+if (atexit(instr_fini) != 0) {
+fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+abort();
+}
+
+const char *id = "cmdline";
+err = instr_load(path, argc, argv, &id);
+switch (err) {
+case INSTR_LOAD_OK:
+error_report("instrument: loaded library with ID '%s'", id);
+return;
+case INSTR_LOAD_TOO_MANY:
+error_report("instrument: tried to load too many libraries");
+break;
+case INSTR_

[Qemu-devel] [PATCH v6 02/22] instrument: Add configure-time flag

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 configure |9 +
 1 file changed, 9 insertions(+)

diff --git a/configure b/configure
index fd7e3a5e81..a21d1bceb9 100755
--- a/configure
+++ b/configure
@@ -356,6 +356,7 @@ pie=""
 qom_cast_debug="yes"
 trace_backends="log"
 trace_file="trace"
+instrument="no"
 spice=""
 rbd=""
 smartcard=""
@@ -886,6 +887,8 @@ for opt do
   ;;
   --with-trace-file=*) trace_file="$optarg"
   ;;
+  --enable-instrument) instrument="yes"
+  ;;
   --enable-gprof) gprof="yes"
   ;;
   --enable-gcov) gcov="yes"
@@ -1436,6 +1439,7 @@ Advanced options (experts only):
Available backends: $trace_backend_list
   --with-trace-file=NAME   Full PATH,NAME of file to store traces
Default:trace-
+  --enable-instrument  enable event instrumentation
   --disable-slirp  disable SLIRP userspace network connectivity
   --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)
   --oss-libpath to OSS library
@@ -5366,6 +5370,7 @@ echo "Trace backends$trace_backends"
 if have_backend "simple"; then
 echo "Trace output file $trace_file-"
 fi
+echo "instrumentation   $instrument"
 echo "spice support $spice $(echo_version $spice 
$spice_protocol_version/$spice_server_version)"
 echo "rbd support   $rbd"
 echo "xfsctl support$xfs"
@@ -6019,6 +6024,10 @@ if have_backend "syslog"; then
 fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
+if test "$instrument" = "yes"; then
+  echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
+fi
+
 if test "$rdma" = "yes" ; then
   echo "CONFIG_RDMA=y" >> $config_host_mak
 fi




[Qemu-devel] [PATCH v6 01/22] instrument: Add documentation

2017-09-13 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS |6 ++
 docs/instrument.txt |  173 +++
 2 files changed, 179 insertions(+)
 create mode 100644 docs/instrument.txt

diff --git a/MAINTAINERS b/MAINTAINERS
index 36eeb42d19..fb0eaee06a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1486,6 +1486,12 @@ F: scripts/tracetool/
 F: docs/tracing.txt
 T: git git://github.com/stefanha/qemu.git tracing
 
+Event instrumentation
+M: Lluís Vilanova 
+M: Stefan Hajnoczi 
+S: Maintained
+F: docs/instrument.txt
+
 TPM
 S: Orphan
 F: tpm.c
diff --git a/docs/instrument.txt b/docs/instrument.txt
new file mode 100644
index 00..24a0d21fc7
--- /dev/null
+++ b/docs/instrument.txt
@@ -0,0 +1,173 @@
+= Event instrumentation =
+
+== Introduction ==
+
+Event instrumentation allows users to execute their own host-native code on a
+set of pre-defined events provided by QEMU. QEMU also exposes other
+functionality to peek/poke at the guest state (e.g., memory or registers), as
+well as interacting with tracing events. For those familiar with the term, this
+provides dynamic binary instrumentation, works on all QEMU-supported
+architectures, as well as works in both 'user' (standalone application) and
+'system' (full-system emulation) modes.
+
+Look at the headers installed by QEMU on the "qemu-instr" directory for further
+information beyond this document.
+
+
+== Loading an instrumentation library ==
+
+Instrumentation code can be bundled into a dynamic library, which can be later
+loaded into QEMU:
+
+* Using the command-line "-instr" argument.
+
+* Using the "instr-load" and "instr-unload" commands in the HMP and QMP
+  interfaces.
+
+
+== Example ==
+
+1. Configure QEMU with event instrumentation:
+
+# instrument guest_cpu_enter and guest_mem_before
+mkdir -p /path/to/qemu-build
+cd /path/to/qemu-build
+/path/to/qemu-source/configure \
+  --enable-instrument \
+  --prefix=/path/to/qemu-install
+
+2. Build and install QEMU:
+
+make install
+
+3. Create the "Makefile" to build the instrumentation library:
+
+mkdir -p /tmp/my-instrument
+
+cat > /tmp/my-instrument/Makefile < /tmp/my-instrument/instrument.c <
+#include 
+
+#include  /* manipulate events */
+#include/* manipulate tracing */
+
+/* the address for the memory access is not known at translation time */
+void guest_mem_before_trans(QICPU vcpu_trans, QITCGv_cpu vcpu_exec,
+QITCGv vaddr, QIMemInfo info)
+{
+printf("%s: %p %p %p %d %d %d %d\n", __func__, vcpu_trans, vcpu_exec, 
vaddr,
+   1 << info.size_shift, info.sign_extend, info.endianness, 
info.store);
+if (info.store) {
+/* generate at execution time only for memory writes */
+qi_event_gen_guest_mem_before_exec(vcpu_exec, vaddr, info);
+}
+}
+
+/* called when QEMU executes a memory access */
+void guest_mem_before_exec(QICPU vcpu, uint64_t vaddr, QIMemInfo info)
+{
+if (info.store) {
+/* if called by TCG code, we'll only get writes (see above) */
+printf("%s: %p %lx %d %d %d %d\n", __func__, vcpu, vaddr,
+   1 << info.size_shift, info.sign_extend, info.endianness, 
info.store);
+}
+}
+
+/* called every time QEMU hotplugs a CPU */
+void guest_cpu_enter(QICPU vcpu)
+{
+printf("%s: %p\n", __func__, vcpu);
+
+/* disable instrumentation and tracing after the first call */
+static bool found = false;
+if (found) {
+qi_event_set_guest_cpu_enter(NULL);
+QITraceEvent *ev = qi_trace_event_name("guest_cpu_enter");
+assert(ev);
+qi_trace_event_set_state_dynamic(ev, true);
+} else {
+found = true;
+}
+}
+
+static void fini(void *data)
+{
+/* diable all tracing events */
+QITraceEventIter iter;
+qi_trace_event_iter_init(&iter, NULL);
+QITraceEvent *ev;
+while ((ev = qi_trace_event_iter_next(&iter)) != NULL) {
+if (qi_trace_event_get_state_static(ev)) {
+qi_trace_event_set_state_dynamic(ev, false);
+}
+}
+
+/* instrumentation callbacks are automatically reset by QEMU */
+}
+
+/* mandatory initialization function */
+int main(int argc, const char **argv)
+{
+int i;
+printf("init!\n");
+printf("argc :: %d\n", argc);
+for (i = 0; i < argc; i++) {
+printf("-> %s\n", argv[i]);
+}
+
+qi_set_fini(fini, NULL);
+
+/* instrument and trace events */
+QITraceEvent *ev;
+
+

[Qemu-devel] [PATCH v6 00/22] instrument: Add basic event instrumentation

2017-09-13 Thread Lluís Vilanova
This series adds an API to add instrumentation events.

It also provides additional APIs for:
* Controlling tracing events.
* Peek/poke guest memory.

TODO:
* Replace qi_event_gen_* with generating calls to arbitrary functions (e.g.,
  qi_event_gen_call(num_args, va_list)).
* Flush all TBs when an execution-time event is unset (to ensure it won't be
  called in the future).
* Flush all TBs when a translation-time event is set (to ensure no future events
  will be lost).

Undecided:
* Alternatively to the two last points above, provide an API to request a TB
  flush (much more flexible and can be more efficient, but requires instrumentor
  to clearly know differences between translation and execution).
* Pass a user-provided pointer to events (i.e., to avoid using global
  variables).
* Provide something like tracing's per-vCPU trace states (i.e., so that each
  vCPU can have different instrumentation code). Useful mainly for sampling
  (enable/disable instrumentation multiple times without re-translating guest
  code) and more complex use cases like tracing a guest process in softmmu mode.
  It's still not clear to me if we should extend the per-vCPU bitmap with
  instrumentation events, or otherwise somehow reuse the bits in tracing events
  (since they're currently limited).
* Allow multiple callbacks per event (both to support multiple callbacks
  installed by a library, and multiple libraries at the same time).
* Allow instr libraries to iterate on the list of guest CPUs (info is already
  available through guest_cpu_enter/guest_cpu_exit, but forces libs to be
  prepared for hot-plugging guest CPUs).

Future APIs (for later series):
* Peek/poke guest registers.
* Add breakpoints to trigger instrumentation functions.
* Trigger instrumentation functions from guest code (former hypertrace).
* Add events for guest code translation/execution (once the respective tracing
  events are accepted upstream).
* Add events for exceptions/syscalls.
* Add events for TB invalidation (necessary for libraries to deallocate any data
  they might have allocated for the TBs they instrumented).

The instrumentation code is dynamically loaded as a library into QEMU either
when it starts or later using its remote control interfaces. The loaded code
only has access to function explicitly exported through the QI_VPUBLIC macro.

This series is branch 'devel-instrument' in
https://code.gso.ac.upc.edu/git/qemu-dbi.

Signed-off-by: Lluís Vilanova 
---

Changes in v6
=

* Fix a minor style warning.
* Fix a minor compilation error.


Changes in v5
=

* Rebase on fcea73709b.
* Minor changes to pass checkpatch.
* Fix symbol availability to external libraries by adding missing default symbol
  visibility flag.
* Use a string to identify instrumentation handles [Markus Armbruster].
* Use stubs for command line initialization.
* Use stubs to signal unsupported QAPI commands [Markus Armbruster].
* Use error messages instead of codes in QAPI commands [Markus Armbruster].
* Move symbol visibility macros to internal "qemu/compiler.h" header.
* Trigger event 'guest_cpu_enter' when library is loaded.
* Trigger event 'guest_cpu_exit' and flush TBs when library is unloaded.
* Rename instr_cpu_get/instr_cpu_set into clearer
  instr_cpu_to_qicpu/instr_cpu_from_qicpu.
* Rename handle_get/handle_put to clearer handle_new/handle_destroy.
* Ensure qi_event_set_* are called only on the proper mode and targets.


Changes in v4
=

* Add missing stub function.


Changes in v3
=

* Use a separate event set for instrumentation (i.e., do not instrument tracing
  events) [Stefan Hajnoczi].
* Add API for peek/poke guest memory.


Changes in v2
=

* Update QEMU version in QAPI [Eric Blake].
* Clarify 'msg' result in QAPI is for humans only.
* Make 'msg' and 'handle' results optional in QAPI.
* Use a list of 'str' in 'instr-load' QAPI command.
* Update MAINTAINERS.
* Add macros for error-reporting in API.


Lluís Vilanova (22):
  instrument: Add documentation
  instrument: Add configure-time flag
  instrument: Add generic library loader
  instrument: [linux-user] Add command line library loader
  instrument: [bsd-user] Add command line library loader
  instrument: [softmmu] Add command line library loader
  instrument: [qapi] Add library loader
  instrument: [hmp] Add library loader
  instrument: Add basic control interface
  instrument: Add support for tracing events
  instrument: Track vCPUs
  instrument: Add event 'guest_cpu_enter'
  instrument: Support synchronous modification of vCPU state
  exec: Add function to synchronously flush TB on a stopped vCPU
  instrument: Add event 'guest_cpu_exit'
  instrument: Add event 'guest_cpu_reset'
  trace: Introduce a proper structure to describe memory a

Re: [Qemu-devel] [PATCH v5 00/22] instrument: Add basic event instrumentation

2017-09-13 Thread Lluís Vilanova
no-reply  writes:

> Hi,
> This series failed automatic build test. Please find the testing commands and
> their output below. If you have docker installed, you can probably reproduce 
> it
> locally.

> Subject: [Qemu-devel] [PATCH v5 00/22] instrument: Add basic event 
> instrumentation
> Message-id: 150525010239.15988.8172586618197849619.st...@frigg.lan
> Type: series

> === TEST SCRIPT BEGIN ===
> #!/bin/bash
> set -e
> git submodule update --init dtc
> # Let docker tests dump environment info
> export SHOW_ENV=1
> export J=8
> time make docker-test-quick@centos6
> time make docker-test-build@min-glib
> time make docker-test-mingw@fedora
> === TEST SCRIPT END ===

> Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
> Switched to a new branch 'test'
> 1ab48ae9b7 instrument: Add API to manipulate guest memory
> 7e0bd2cad7 instrument: Add event 'guest_user_syscall_ret'
> 334caef899 instrument: Add event 'guest_user_syscall'
> 09a1773791 instrument: Add event 'guest_mem_before_exec'
> 2bd64563d3 instrument: Add event 'guest_mem_before_trans'
> 5b344ec1c3 trace: Introduce a proper structure to describe memory accesses
> 04e5b883b1 instrument: Add event 'guest_cpu_reset'
> 7971d0f2a4 instrument: Add event 'guest_cpu_exit'
> 53dbc9ad88 exec: Add function to synchronously flush TB on a stopped vCPU
> d8b51515d2 instrument: Support synchronous modification of vCPU state
> 08d492e35f instrument: Add event 'guest_cpu_enter'
> 0be52b1bbd instrument: Track vCPUs
> 7ab01f20f5 instrument: Add support for tracing events
> 78676cff2d instrument: Add basic control interface
> 00172972ae instrument: [hmp] Add library loader
> 34ccf831e6 instrument: [qapi] Add library loader
> d1ab648b00 instrument: [softmmu] Add command line library loader
> 150ad4a651 instrument: [bsd-user] Add command line library loader
> a064b1621a instrument: [linux-user] Add command line library loader
> aa78ee9f5a instrument: Add generic library loader
> f10357e313 instrument: Add configure-time flag
> 4d324ad619 instrument: Add documentation

> === OUTPUT BEGIN ===
> Submodule 'dtc' (git://git.qemu-project.org/dtc.git) registered for path 'dtc'
> Cloning into '/var/tmp/patchew-tester-tmp-lf5qg9x6/src/dtc'...
> Submodule path 'dtc': checked out '558cd81bdd432769b59bff01240c44f82cfb1a9d'
>   BUILD   centos6
> make[1]: Entering directory '/var/tmp/patchew-tester-tmp-lf5qg9x6/src'
>   ARCHIVE qemu.tgz
>   ARCHIVE dtc.tgz
>   COPYRUNNER
> RUN test-quick in qemu:centos6 
> Packages installed:
> SDL-devel-1.2.14-7.el6_7.1.x86_64
> bison-2.4.1-5.el6.x86_64
> bzip2-devel-1.0.5-7.el6_0.x86_64
> ccache-3.1.6-2.el6.x86_64
> csnappy-devel-0-6.20150729gitd7bc683.el6.x86_64
> flex-2.5.35-9.el6.x86_64
> gcc-4.4.7-18.el6.x86_64
> git-1.7.1-8.el6.x86_64
> glib2-devel-2.28.8-9.el6.x86_64
> libepoxy-devel-1.2-3.el6.x86_64
> libfdt-devel-1.4.0-1.el6.x86_64
> librdmacm-devel-1.0.21-0.el6.x86_64
> lzo-devel-2.03-3.1.el6_5.1.x86_64
> make-3.81-23.el6.x86_64
> mesa-libEGL-devel-11.0.7-4.el6.x86_64
> mesa-libgbm-devel-11.0.7-4.el6.x86_64
> package g++ is not installed
> pixman-devel-0.32.8-1.el6.x86_64
> spice-glib-devel-0.26-8.el6.x86_64
> spice-server-devel-0.12.4-16.el6.x86_64
> tar-1.23-15.el6_8.x86_64
> vte-devel-0.25.1-9.el6.x86_64
> xen-devel-4.6.3-15.el6.x86_64
> zlib-devel-1.2.3-29.el6.x86_64

> Environment variables:
> PACKAGES=bison bzip2-devel ccache csnappy-devel flex g++  
>gcc git glib2-devel libepoxy-devel libfdt-devel 
> librdmacm-devel lzo-devel make mesa-libEGL-devel 
> mesa-libgbm-devel pixman-devel SDL-devel spice-glib-devel 
> spice-server-devel tar vte-devel xen-devel zlib-devel
> HOSTNAME=fd698ce7a83b
> TERM=xterm
> MAKEFLAGS= -j8
> HISTSIZE=1000
> J=8
> USER=root
> LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*

Re: [Qemu-devel] [PATCH v5 00/22] instrument: Add basic event instrumentation

2017-09-13 Thread Lluís Vilanova
no-reply  writes:

> Hi,
> This series seems to have some coding style problems. See output below for
> more information:

> Subject: [Qemu-devel] [PATCH v5 00/22] instrument: Add basic event 
> instrumentation
> Message-id: 150525010239.15988.8172586618197849619.st...@frigg.lan
> Type: series

> === TEST SCRIPT BEGIN ===
> #!/bin/bash

> BASE=base
> n=1
> total=$(git log --oneline $BASE.. | wc -l)
> failed=0

> git config --local diff.renamelimit 0
> git config --local diff.renames True

> commits="$(git log --format=%H --reverse $BASE..)"
> for c in $commits; do
> echo "Checking PATCH $n/$total: $(git log -n 1 --format=%s $c)..."
> if ! git show $c --format=email | ./scripts/checkpatch.pl --mailback -; 
> then
> failed=1
> echo
> fi
> n=$((n+1))
> done

> exit $failed
> === TEST SCRIPT END ===

> Updating 3c8cf5a9c21ff8782164d1def7f44bd888713384
> From https://github.com/patchew-project/qemu
>  * [new tag]   
> patchew/150525010239.15988.8172586618197849619.st...@frigg.lan -> 
> patchew/150525010239.15988.8172586618197849619.st...@frigg.lan
>  t [tag update]patchew/20170912144459.11359-1-pbonz...@redhat.com 
> -> patchew/20170912144459.11359-1-pbonz...@redhat.com
> Switched to a new branch 'test'
> 1ab48ae9b7 instrument: Add API to manipulate guest memory
> 7e0bd2cad7 instrument: Add event 'guest_user_syscall_ret'
> 334caef899 instrument: Add event 'guest_user_syscall'
> 09a1773791 instrument: Add event 'guest_mem_before_exec'
> 2bd64563d3 instrument: Add event 'guest_mem_before_trans'
> 5b344ec1c3 trace: Introduce a proper structure to describe memory accesses
> 04e5b883b1 instrument: Add event 'guest_cpu_reset'
> 7971d0f2a4 instrument: Add event 'guest_cpu_exit'
> 53dbc9ad88 exec: Add function to synchronously flush TB on a stopped vCPU
> d8b51515d2 instrument: Support synchronous modification of vCPU state
> 08d492e35f instrument: Add event 'guest_cpu_enter'
> 0be52b1bbd instrument: Track vCPUs
> 7ab01f20f5 instrument: Add support for tracing events
> 78676cff2d instrument: Add basic control interface
> 00172972ae instrument: [hmp] Add library loader
> 34ccf831e6 instrument: [qapi] Add library loader
> d1ab648b00 instrument: [softmmu] Add command line library loader
> 150ad4a651 instrument: [bsd-user] Add command line library loader
> a064b1621a instrument: [linux-user] Add command line library loader
> aa78ee9f5a instrument: Add generic library loader
> f10357e313 instrument: Add configure-time flag
> 4d324ad619 instrument: Add documentation

> === OUTPUT BEGIN ===
> Checking PATCH 1/22: instrument: Add documentation...
> Checking PATCH 2/22: instrument: Add configure-time flag...
> Checking PATCH 3/22: instrument: Add generic library loader...
> Checking PATCH 4/22: instrument: [linux-user] Add command line library 
> loader...
> Checking PATCH 5/22: instrument: [bsd-user] Add command line library loader...
> Checking PATCH 6/22: instrument: [softmmu] Add command line library loader...
> Checking PATCH 7/22: instrument: [qapi] Add library loader...
> ERROR: externs should be avoided in .c files
> #254: FILE: stubs/instrument.c:40:
> +void qmp_instr_unload(const char *id, Error **errp);

> total: 1 errors, 0 warnings, 204 lines checked

> Your patch has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.

> Checking PATCH 8/22: instrument: [hmp] Add library loader...
> Checking PATCH 9/22: instrument: Add basic control interface...
> WARNING: architecture specific defines should be avoided
> #52: FILE: include/qemu/compiler.h:119:
> +#if defined _WIN32 || defined __CYGWIN__

> WARNING: architecture specific defines should be avoided
> #53: FILE: include/qemu/compiler.h:120:
> +  #ifdef __GNUC__

> WARNING: architecture specific defines should be avoided
> #59: FILE: include/qemu/compiler.h:126:
> +  #if __GNUC__ >= 4

> WARNING: architecture specific defines should be avoided
> #343: FILE: instrument/qemu-instr/control.h:13:
> +#ifdef __cplusplus

> WARNING: architecture specific defines should be avoided
> #372: FILE: instrument/qemu-instr/control.h:42:
> +#ifdef __cplusplus

> total: 0 errors, 5 warnings, 309 lines checked

> Your patch has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
> Checking PATCH 10/22: instrument: Add support for tracing events...
> WARNING: architecture specific defines should be avoided
> #77: FILE: instrument/qemu-instr/types.h:13:
> +#ifdef __cplusplus

> WARNING: architecture specific defines should be avoided
> #111: FILE: instrument/qemu-instr/types.h:47:
> +#ifdef __cplusplus

> total: 0 errors, 2 warnings, 225 lines checked

> Your patch has style problems, please review.  If any of these errors
> are false positives report them to the maintainer, see
> CHECKPATCH in MAINTAINERS.
> Checking PATCH 11/22: instrument: Track vCPUs...

[Qemu-devel] [PATCH v2] trace: Immediately apply per-vCPU state changes if a vCPU is being created

2017-09-12 Thread Lluís Vilanova
Right now, function trace_event_set_vcpu_state_dynamic() asynchronously enables
events in the case a vCPU is executing TCG code. If the vCPU is being created
this makes some events like "guest_cpu_enter" to not be traced.

Signed-off-by: Lluís Vilanova 
Reviewed-by: Emilio G. Cota 
---

Changes in v2
=

* Use RUN_ON_CPU_NULL [Emilio G. Cota].
* Rebase on fcea73709b.
---
 trace/control-target.c |   18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/trace/control-target.c b/trace/control-target.c
index 4e36101997..706b2cee9d 100644
--- a/trace/control-target.c
+++ b/trace/control-target.c
@@ -88,13 +88,17 @@ void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
 clear_bit(vcpu_id, vcpu->trace_dstate_delayed);
 (*ev->dstate)--;
 }
-/*
- * Delay changes until next TB; we want all TBs to be built from a
- * single set of dstate values to ensure consistency of generated
- * tracing code.
- */
-async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic,
- RUN_ON_CPU_NULL);
+if (vcpu->created) {
+/*
+ * Delay changes until next TB; we want all TBs to be built from a
+ * single set of dstate values to ensure consistency of generated
+ * tracing code.
+ */
+async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic,
+ RUN_ON_CPU_NULL);
+} else {
+trace_event_synchronize_vcpu_state_dynamic(vcpu, RUN_ON_CPU_NULL);
+}
 }
 }
 




[Qemu-devel] [PATCH v5 22/22] instrument: Add API to manipulate guest memory

2017-09-12 Thread Lluís Vilanova
It includes access to the guest's memory and vCPU registers.

Signed-off-by: Lluís Vilanova 
---
 instrument/Makefile.objs  |1 
 instrument/qemu-instr/state.h |  104 +
 instrument/state.c|   73 +
 3 files changed, 178 insertions(+)
 create mode 100644 instrument/qemu-instr/state.h
 create mode 100644 instrument/state.c

diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index d7e6c760c3..ee482bdb45 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -5,3 +5,4 @@ target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
 target-obj-$(CONFIG_INSTRUMENT) += control.o
 target-obj-$(CONFIG_INSTRUMENT) += trace.o
+target-obj-$(CONFIG_INSTRUMENT) += state.o
diff --git a/instrument/qemu-instr/state.h b/instrument/qemu-instr/state.h
new file mode 100644
index 00..0ae6255fe5
--- /dev/null
+++ b/instrument/qemu-instr/state.h
@@ -0,0 +1,104 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__STATE_H
+#define QI__STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include 
+
+
+/**
+ * qi_mem_read_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to read could be translated.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ *
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to write could be 
translated.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_virt_to_phys:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Virtual address to translate.
+ * @paddr: Pointer to output physical address.
+ *
+ * Translate a virtual address into a physical address.
+ *
+ * Returns: Whether the address could be translated.
+ */
+bool qi_mem_virt_to_phys(QICPU vcpu, uint64_t vaddr, uint64_t *paddr);
+
+/**
+ * qi_mem_read_phys:
+ * @paddr: Starting physical address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from physical memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_phys(uint64_t paddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_phys:
+ * @paddr: Starting physical address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ *
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_phys(uint64_t paddr, size_t size, void *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__STATE_H */
diff --git a/instrument/state.c b/instrument/state.c
new file mode 100644
index 00..e76fd5fbcd
--- /dev/null
+++ b/instrument/state.c
@@ -0,0 +1,73 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qemu/compiler.h"
+#include "cpu.h"
+#include "exec/cpu-all.h"
+#include "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/qemu-instr/state.h"
+
+
+SYM_PUBLIC bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr,
+ size_t size, void *buf)
+{
+CPUState *vcpu_ = instr_cpu_from_qicpu(vcpu);
+ERROR_IF_RET(!instr_get_state(), false, "called outside instrumentation");
+ERROR_IF_RET(!vcpu_, false, "invalid Q

[Qemu-devel] [PATCH v5 21/22] instrument: Add event 'guest_user_syscall_ret'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |3 +++
 instrument/control.c|   15 +++
 instrument/events.h |5 +
 instrument/events.inc.h |   13 +
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   13 +
 linux-user/syscall.c|1 +
 stubs/instrument.c  |2 ++
 8 files changed, 53 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 0d92eaf8c4..fb468c0574 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -407,6 +407,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_freebsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -485,6 +486,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #endif
 if (do_strace)
 print_netbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -563,6 +565,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_openbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
diff --git a/instrument/control.c b/instrument/control.c
index b3ef03798e..b5b1e0503d 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -210,3 +210,18 @@ SYM_PUBLIC void qi_event_set_guest_user_syscall(
 #endif
 instr_set_event(guest_user_syscall, fn);
 }
+
+
+void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+
+SYM_PUBLIC void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+#if !defined(CONFIG_USER_ONLY)
+ERROR_IF(true, "called in full-system mode");
+#endif
+instr_set_event(guest_user_syscall_ret, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 8c944e1f91..6197ece466 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -75,6 +75,11 @@ static inline void instr_guest_user_syscall(
 CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
 uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
 
+extern void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index e2f4315fb0..d31dec54b8 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -94,3 +94,16 @@ static inline void instr_guest_user_syscall(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t ret)
+= instr_get_event(guest_user_syscall_ret);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+(*cb)(vcpu_, num, ret);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index a76f76e1d1..be13a90286 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -165,6 +165,7 @@ InstrUnloadError instr_unload(const char *id)
 instr_set_event(guest_mem_before_trans, NULL);
 instr_set_event(guest_mem_before_exec, NULL);
 instr_set_event(guest_user_syscall, NULL);
+instr_set_event(guest_user_syscall_ret, NULL);
 
 instr_cpu_stop_all_end(&info);
 cpu_list_unlock();
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index 136058af4f..bc4e49bef1 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -157,6 +157,19 @@ void qi_event_set_guest_user_syscall(
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
uint64_t arg7, uint64_t arg8));
 
+/*
+ * Finish executing a guest system call in syscall emulation mode.
+ *
+ * @num: System call number.
+ * @ret: System call result value.
+ *
+ * Mode: user
+ * Targets: TCG(all)
+ * Time: exec
+ */
+void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c9f0b9fa56..44b91e3c52 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -12398,6 +12398,7 @@ fail:
 #endif
 if(do_strace)
 print_syscall_ret(num, ret);
+  

[Qemu-devel] [PATCH v5 20/22] instrument: Add event 'guest_user_syscall'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |6 ++
 instrument/control.c|   18 ++
 instrument/events.h |7 +++
 instrument/events.inc.h |   16 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   15 +++
 linux-user/syscall.c|2 ++
 stubs/instrument.c  |3 +++
 8 files changed, 68 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 3230f722f3..0d92eaf8c4 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -324,6 +324,8 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("freebsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 
arg7, arg8);
 if(do_strace)
 print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -423,6 +425,8 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #ifdef DEBUG
 gemu_log("netbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -499,6 +503,8 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("openbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num,
+ arg1, arg2, arg3, arg4, arg5, arg6, 0, 0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
diff --git a/instrument/control.c b/instrument/control.c
index 4181e030f6..b3ef03798e 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -192,3 +192,21 @@ SYM_PUBLIC void qi_event_set_guest_mem_before_exec(
 ERROR_IF(!tcg_enabled(), "called without TCG");
 instr_set_event(guest_mem_before_exec, fn);
 }
+
+
+void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
+SYM_PUBLIC void qi_event_set_guest_user_syscall(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+#if !defined(CONFIG_USER_ONLY)
+ERROR_IF(true, "called in full-system mode");
+#endif
+instr_set_event(guest_user_syscall, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 6507b26867..8c944e1f91 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -68,6 +68,13 @@ extern void (*instr_event__guest_mem_before_exec)(
 static inline void instr_guest_mem_before_exec(
 CPUState *vcpu, uint64_t vaddr, TraceMemInfo info);
 
+extern void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index ebc8020715..e2f4315fb0 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -78,3 +78,19 @@ static inline void instr_guest_mem_before_exec(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8)
+= instr_get_event(guest_user_syscall);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+(*cb)(vcpu_, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index f1d769b92d..a76f76e1d1 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -164,6 +164,7 @@ InstrUnl

[Qemu-devel] [PATCH v5 19/22] instrument: Add event 'guest_mem_before_exec'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |4 +++
 include/exec/cpu_ldst_useronly_template.h |4 +++
 include/exec/helper-gen.h |1 +
 include/exec/helper-proto.h   |1 +
 include/exec/helper-tcg.h |1 +
 instrument/control.c  |   37 +
 instrument/control.h  |   15 
 instrument/events.h   |5 
 instrument/events.inc.h   |   18 +-
 instrument/helpers.h  |2 ++
 instrument/load.c |1 +
 instrument/qemu-instr/control.h   |   21 
 stubs/instrument.c|   19 ++-
 13 files changed, 127 insertions(+), 2 deletions(-)
 create mode 100644 instrument/helpers.h

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index debbabcfb2..8018e8b16a 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -28,6 +28,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -89,6 +90,7 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -126,6 +128,7 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -167,6 +170,7 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index b0b3fc1b8d..c36c50ae41 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -27,6 +27,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -62,6 +63,7 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
@@ -81,6 +83,7 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
@@ -102,6 +105,7 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
index 8239ffc77c..f351c3d050 100644
--- a/include/exec/helper-gen.h
+++ b/include/exec/helper-gen.h
@@ -57,6 +57,7 @@ static inline void glue(gen_helper_, 
name)(dh_retvar_decl(ret)  \
 }
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "trace/generated-helpers-wrappers.h"
 #include "tcg-runtime.h"
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
index 954bef85ce..8fdd02c132 100644
--- a/include/exec/helper-proto.h
+++ b/include/exec/helper-proto.h
@@ -27,6 +27,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), 
dh_ctype(t3), \
 dh_ctype(t4), dh_ctype(t5));
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "tcg-runtime.h"
 
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index b0c5bafa99..255e73c3e6 100644
--- a/include/exec/helper-tcg.h
+

[Qemu-devel] [PATCH v5 18/22] instrument: Add event 'guest_mem_before_trans'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 Makefile.target |1 +
 instrument/control.c|   15 +
 instrument/control.h|   36 +-
 instrument/control.inc.h|   16 +++---
 instrument/events.h |   21 +
 instrument/events.inc.h |   20 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   16 ++
 instrument/qemu-instr/types.h   |   64 +++
 stubs/instrument.c  |4 ++
 tcg/tcg-op.c|5 +++
 trace/control.h |   23 ++
 trace/mem.h |   23 --
 13 files changed, 214 insertions(+), 31 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 7f42c45db8..6997b921c9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -196,6 +196,7 @@ $(QEMU_PROG_BUILD): config-devices.mak
 COMMON_LDADDS = ../libqemuutil.a ../libqemustub.a
 
 # build either PROG or PROGW
+$(QEMU_PROG_BUILD): CFLAGS += -DQEMU_TARGET_BUILD=1
 $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
$(call LINK, $(filter-out %.mak, $^))
 ifdef CONFIG_DARWIN
diff --git a/instrument/control.c b/instrument/control.c
index 401189db2e..0424dd57ab 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -17,7 +17,7 @@
 #include "qom/cpu.h"
 
 
-__thread InstrState instr_cur_state;
+__thread InstrInfo instr_cur_info;
 
 
 unsigned int instr_cpus_count;
@@ -142,3 +142,16 @@ SYM_PUBLIC void qi_event_set_guest_cpu_reset(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_reset, fn);
 }
+
+
+void (*instr_event__guest_mem_before_trans)(
+QICPU vcpu_trans, QITCGv_cpu vcpu_exec, QITCGv vaddr, QIMemInfo info);
+
+SYM_PUBLIC void qi_event_set_guest_mem_before_trans(
+void (*fn)(QICPU vcpu_trans, QITCGv_cpu vcpu_exec,
+   QITCGv vaddr, QIMemInfo info))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+ERROR_IF(!tcg_enabled(), "called without TCG");
+instr_set_event(guest_mem_before_trans, fn);
+}
diff --git a/instrument/control.h b/instrument/control.h
index 03e87b2b8f..3e44702f75 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -86,12 +86,21 @@ typedef enum {
 INSTR_STATE_ENABLE,
 } InstrState;
 
+#define INSTR_MAX_TCG_REGS 16
+
+typedef struct InstrInfo {
+InstrState state;
+unsigned int max;
+void *tcg_regs[INSTR_MAX_TCG_REGS];
+} InstrInfo;
+
 /**
  * instr_set_state:
  *
- * Set the instrumentation state of the current host thread.
+ * Set the instrumentation state of the current host thread, and return its
+ * #InstrInfo.
  */
-static inline void instr_set_state(InstrState state);
+static inline InstrInfo *instr_set_state(InstrState state);
 
 /**
  * instr_get_state:
@@ -100,6 +109,29 @@ static inline void instr_set_state(InstrState state);
  */
 static inline InstrState instr_get_state(void);
 
+/**
+ * instr_tcg_to_qitcg:
+ * @info: Pointer to #InstrInfo.
+ * @num: Number of TCG register used by instrumentation.
+ * @arg: TCG register.
+ *
+ * Get a suitable QITCGv* from a TCGv* value.
+ */
+#define instr_tcg_to_qitcg(info, num, arg) \
+({\
+info->tcg_regs[num] = arg;\
+(void *)num;  \
+})
+
+/**
+ * instr_tcg_count:
+ * @info: Pointer to #InstrInfo.
+ * @count: Number of TCG registers used by instrumentation.
+ *
+ * Set the number of TCG registers used by instrumentation.
+ */
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count);
+
 
 #include "instrument/control.inc.h"
 
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 6d65b23ead..3eba9b7c85 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -46,14 +46,22 @@ static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu)
 }
 
 
-extern __thread InstrState instr_cur_state;
+extern __thread InstrInfo instr_cur_info;
 
-static inline void instr_set_state(InstrState state)
+static inline InstrInfo *instr_set_state(InstrState state)
 {
-atomic_store_release(&instr_cur_state, state);
+InstrInfo *info = &instr_cur_info;
+atomic_store_release(&info->state, state);
+return info;
 }
 
 static inline InstrState instr_get_state(void)
 {
-return atomic_load_acquire(&instr_cur_state);
+return atomic_load_acquire(&instr_cur_info.state);
+}
+
+
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count)
+{
+info->max = count;
 }
diff --git a/instrument/events.h b/instrument/events.h
index 4a0560490a..1cc4dbb052 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -12,6 +12,8 @@
 
 #include "instrument/qemu-instr/control.h"
 #include "instrument/qemu-instr/types.h"
+#include "trace/control.

[Qemu-devel] [PATCH v5 17/22] trace: Introduce a proper structure to describe memory accesses

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |   15 ++
 include/exec/cpu_ldst_useronly_template.h |   15 ++
 tcg/tcg-op.c  |   22 +
 trace/mem-internal.h  |   22 -
 trace/mem.h   |   31 +
 5 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index 4db2302962..debbabcfb2 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -88,9 +88,8 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -126,9 +125,8 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -168,9 +166,8 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index 7b8c7c506e..b0b3fc1b8d 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -61,9 +61,8 @@ static inline RES_TYPE
 glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
 }
@@ -81,9 +80,8 @@ static inline int
 glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
 }
@@ -103,9 +101,8 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
   RES_TYPE v)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
 }
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 688d91755b..6edf70bdfc 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2676,24 +2676,28 @@ static void tcg_gen_req_mo(TCGBar type)
 
 void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 tcg_gen_req_mo(TCG_MO_LD_LD | TCG_MO_ST_LD);
 memop = tcg_canonicalize_memop(memop, 0, 0);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 0));
+meminfo = trace_mem_get_info(memop, 0);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 tcg_gen_req_mo(TCG_MO_LD_ST | TCG_MO_ST_ST);
 memop = tcg_canonicalize_memop(memop, 0, 1);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 1));
+meminfo = trace_mem_get_info(memop, 1);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_ld_i64(TCGv_i64 val

[Qemu-devel] [PATCH v5 16/22] instrument: Add event 'guest_cpu_reset'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |9 +
 qom/cpu.c   |2 ++
 stubs/instrument.c  |1 +
 7 files changed, 36 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 0be8065409..401189db2e 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -133,3 +133,12 @@ SYM_PUBLIC void qi_event_set_guest_cpu_exit(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_exit, fn);
 }
+
+
+void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_reset, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index c743cb8180..4a0560490a 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -39,6 +39,9 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu);
 extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
 static inline void instr_guest_cpu_exit(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+static inline void instr_guest_cpu_reset(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index c88df7e42f..a126ba5ae6 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -31,3 +31,14 @@ static inline void instr_guest_cpu_exit(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_reset(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_reset);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 6808d361b5..8c15a73a8c 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -161,6 +161,7 @@ InstrUnloadError instr_unload(const char *id)
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
 instr_set_event(guest_cpu_exit, NULL);
+instr_set_event(guest_cpu_reset, NULL);
 
 instr_cpu_stop_all_end(&info);
 cpu_list_unlock();
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index 107ee8afe0..322009100d 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -96,6 +96,15 @@ void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
  */
 void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
 
+/*
+ * Reset the state of a virtual (guest) CPU.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/qom/cpu.c b/qom/cpu.c
index dc5392dbeb..6336d63f66 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -19,6 +19,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "qom/cpu.h"
@@ -275,6 +276,7 @@ void cpu_reset(CPUState *cpu)
 (*klass->reset)(cpu);
 }
 
+instr_guest_cpu_reset(cpu);
 trace_guest_cpu_reset(cpu);
 }
 
diff --git a/stubs/instrument.c b/stubs/instrument.c
index c4b1c791d9..dda2ae88c5 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -48,3 +48,4 @@ void qmp_instr_unload(const char *id, Error **errp)
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
 void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
+void (*instr_event__guest_cpu_reset)(QICPU *vcpu);




[Qemu-devel] [PATCH v5 15/22] instrument: Add event 'guest_cpu_exit'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |   17 +
 instrument/qemu-instr/control.h |   11 +++
 stubs/instrument.c  |1 +
 trace/control.c |4 +++-
 7 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/instrument/control.c b/instrument/control.c
index 20ddffdc28..0be8065409 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -124,3 +124,12 @@ SYM_PUBLIC void qi_event_set_guest_cpu_enter(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_enter, fn);
 }
+
+
+void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_exit, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 947f120aa9..c743cb8180 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -36,6 +36,9 @@ extern void *instr_event__fini_data;
 extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
 static inline void instr_guest_cpu_enter(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+static inline void instr_guest_cpu_exit(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index e3f8024716..c88df7e42f 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -20,3 +20,14 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_exit(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_exit);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 218bca74b2..6808d361b5 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -11,7 +11,9 @@
 #include "qemu-common.h"
 
 #include 
+#include "cpu.h"
 #include "exec/cpu-common.h"
+#include "exec/exec-all.h"
 #include "instrument/control.h"
 #include "instrument/events.h"
 #include "instrument/load.h"
@@ -127,6 +129,13 @@ out:
 return res;
 }
 
+
+static void instr_unload__cb(CPUState *cpu, void *data)
+{
+tb_flush_sync(cpu);
+instr_guest_cpu_exit(cpu);
+}
+
 InstrUnloadError instr_unload(const char *id)
 {
 InstrUnloadError res;
@@ -139,6 +148,10 @@ InstrUnloadError instr_unload(const char *id)
 goto out;
 }
 
+InstrCPUStop info;
+cpu_list_lock();
+instr_cpu_stop_all_begin(&info, instr_unload__cb, NULL);
+
 qi_fini_fn fini_fn = instr_get_event(fini_fn);
 if (fini_fn) {
 void *fini_data = instr_get_event(fini_data);
@@ -147,6 +160,10 @@ InstrUnloadError instr_unload(const char *id)
 
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
+instr_set_event(guest_cpu_exit, NULL);
+
+instr_cpu_stop_all_end(&info);
+cpu_list_unlock();
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index f61e7a2b6e..107ee8afe0 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -85,6 +85,17 @@ void qi_set_fini(qi_fini_fn fn, void *data);
  */
 void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
 
+/*
+ * Hot-unplug a virtual (guest) CPU.
+ *
+ * Also triggered on each CPU when an instrumentation library is unloaded.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/stubs/instrument.c b/stubs/instrument.c
index 6b59ba9a7a..c4b1c791d9 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -47,3 +47,4 @@ void qmp_instr_unload(const char *id, Error **errp)
 
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
+void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
diff --git a/trace/control.c b/trace/control.c
index 82d8989c4d..946a0af818 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -1,13 +1,14 @@
 /*
  * Interface for configuring and controlling the state of tracing events.
  *
- * Copyright (C) 2011-2016 Lluís Vilanova 
+ * Copyright (C) 2011-2017 Lluís Vilanova 
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #includ

[Qemu-devel] [PATCH v5 14/22] exec: Add function to synchronously flush TB on a stopped vCPU

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/stubs/tcg-stub.c|3 +++
 accel/tcg/translate-all.c |7 +++
 include/exec/exec-all.h   |1 +
 3 files changed, 11 insertions(+)

diff --git a/accel/stubs/tcg-stub.c b/accel/stubs/tcg-stub.c
index 5dd480b1a2..5226c4a8a4 100644
--- a/accel/stubs/tcg-stub.c
+++ b/accel/stubs/tcg-stub.c
@@ -20,3 +20,6 @@
 void tb_flush(CPUState *cpu)
 {
 }
+void tb_flush_sync(CPUState *cpu)
+{
+}
diff --git a/accel/tcg/translate-all.c b/accel/tcg/translate-all.c
index 2d1ed06065..a334ac4ccb 100644
--- a/accel/tcg/translate-all.c
+++ b/accel/tcg/translate-all.c
@@ -929,6 +929,13 @@ done:
 tb_unlock();
 }
 
+void tb_flush_sync(CPUState *cpu)
+{
+unsigned tb_flush_count = atomic_mb_read(&tcg_ctx.tb_ctx.tb_flush_count);
+assert(cpu == current_cpu);
+do_tb_flush(cpu, RUN_ON_CPU_HOST_INT(tb_flush_count));
+}
+
 void tb_flush(CPUState *cpu)
 {
 if (tcg_enabled()) {
diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h
index 673fc066d0..3f38186a5e 100644
--- a/include/exec/exec-all.h
+++ b/include/exec/exec-all.h
@@ -358,6 +358,7 @@ struct TranslationBlock {
 
 void tb_free(TranslationBlock *tb);
 void tb_flush(CPUState *cpu);
+void tb_flush_sync(CPUState *cpu);
 void tb_phys_invalidate(TranslationBlock *tb, tb_page_addr_t page_addr);
 TranslationBlock *tb_htable_lookup(CPUState *cpu, target_ulong pc,
target_ulong cs_base, uint32_t flags);




[Qemu-devel] [PATCH v5 13/22] instrument: Support synchronous modification of vCPU state

2017-09-12 Thread Lluís Vilanova
Stops all vCPUs to allow performing management operations like TB
invalidations. These are later necessary to ensure translated code does not
reference unloaded instrumentation libraries.

Signed-off-by: Lluís Vilanova 
---
 instrument/control.c |   66 ++
 instrument/control.h |   26 ++
 instrument/control.inc.h |   11 
 3 files changed, 103 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index c4b3ca0440..20ddffdc28 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,6 +13,7 @@
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "qemu/compiler.h"
+#include "qemu/main-loop.h"
 #include "qom/cpu.h"
 
 
@@ -40,6 +41,71 @@ void instr_cpu_remove(CPUState *vcpu)
 }
 
 
+static void instr_cpu_stop_all__cb(CPUState *cpu, run_on_cpu_data data)
+{
+InstrCPUStop *info = data.host_ptr;
+/* run posted function */
+if (info->fun) {
+info->fun(cpu, info->data);
+}
+#if !defined(CONFIG_USER_ONLY)
+/* signal we're out of the main vCPU loop */
+unsigned int count = atomic_load_acquire(&info->count);
+atomic_store_release(&info->count, count + 1);
+atomic_store_release(&info->stopped, true);
+/* wait until we're good to go again */
+qemu_cond_wait(&info->cond, &info->mutex);
+count = atomic_load_acquire(&info->count);
+atomic_store_release(&info->count, count - 1);
+qemu_mutex_unlock(&info->mutex);
+#endif
+}
+
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+  instr_cpu_stop_fun fun, void *data)
+{
+CPUState *cpu;
+
+info->fun = fun;
+info->data = data;
+
+#if !defined(CONFIG_USER_ONLY)
+info->count = 0;
+qemu_cond_init(&info->cond);
+qemu_mutex_init(&info->mutex);
+
+/* main dispatch loop and run_on_cpu() lock the BQL */
+qemu_mutex_unlock_iothread();
+#endif
+
+CPU_FOREACH(cpu) {
+#if !defined(CONFIG_USER_ONLY)
+atomic_store_release(&info->stopped, false);
+qemu_mutex_lock(&info->mutex);
+async_run_on_cpu(cpu, instr_cpu_stop_all__cb, 
RUN_ON_CPU_HOST_PTR(info));
+while (!atomic_load_acquire(&info->stopped)) {
+/* wait for vCPU to signal it's stopped */
+}
+#else
+instr_cpu_stop_all__cb(cpu, RUN_ON_CPU_HOST_PTR(info));
+#endif
+}
+}
+
+void instr_cpu_stop_all_end(InstrCPUStop *info)
+{
+#if !defined(CONFIG_USER_ONLY)
+qemu_cond_broadcast(&info->cond);
+while (atomic_load_acquire(&info->count)) {
+/* wait for all vCPUs to continue before we can destroy info */
+}
+qemu_cond_destroy(&info->cond);
+qemu_mutex_destroy(&info->mutex);
+qemu_mutex_lock_iothread();
+#endif
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index 57cea07fa7..03e87b2b8f 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -46,6 +46,32 @@ static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
  */
 static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
 
+typedef struct InstrCPUStop InstrCPUStop;
+typedef void (*instr_cpu_stop_fun)(CPUState *cpu, void *data);
+
+/**
+ * instr_cpu_stop_all_begin:
+ * @info: Opaque structure describing the operation.
+ * @fun: Function to run on the context of each vCPU once stopped.
+ * @data: Pointer to pass to @fun.
+ *
+ * Ensure all vCPUs stop executing guest code, and execute @fun on their 
context
+ * in turn. Returns with all vCPUs still stopped.
+ *
+ * Assumes cpu_list_lock() and that the QBL is locked before calling.
+ */
+void instr_cpu_stop_all_begin(InstrCPUStop *info,
+  instr_cpu_stop_fun fun, void *data);
+
+/**
+ * instr_cpu_stop_all_end:
+ * @info: Opaque structure passed to a previous instr_cpu_stop_all_begin()
+ * call.
+ *
+ * Resume execution on all vCPUs stopped by instr_cpu_stop_all_begin().
+ */
+void instr_cpu_stop_all_end(InstrCPUStop *info);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 45daae7d1d..6d65b23ead 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -15,6 +15,17 @@
 #include 
 
 
+struct InstrCPUStop {
+instr_cpu_stop_fun fun;
+void *data;
+#if !defined(CONFIG_USER_ONLY)
+bool stopped;
+unsigned int count;
+QemuCond cond;
+QemuMutex mutex;
+#endif
+};
+
 extern unsigned int instr_cpus_count;
 extern CPUState **instr_cpus;
 




[Qemu-devel] [PATCH v5 12/22] instrument: Add event 'guest_cpu_enter'

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 
 instrument/events.h |5 
 instrument/events.inc.h |   11 +
 instrument/load.c   |9 
 instrument/qemu-instr/control.h |   46 +++
 stubs/instrument.c  |1 +
 trace/control-target.c  |2 ++
 7 files changed, 83 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 8cf2b4f967..c4b3ca0440 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -49,3 +49,12 @@ SYM_PUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
 instr_set_event(fini_fn, fn);
 instr_set_event(fini_data, data);
 }
+
+
+void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+
+SYM_PUBLIC void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_enter, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 82ad0bd827..947f120aa9 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -11,6 +11,7 @@
 #define INSTRUMENT__EVENTS_H
 
 #include "instrument/qemu-instr/control.h"
+#include "instrument/qemu-instr/types.h"
 
 /**
  * instr_get_event:
@@ -32,6 +33,10 @@
 extern qi_fini_fn instr_event__fini_fn;
 extern void *instr_event__fini_data;
 
+extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+static inline void instr_guest_cpu_enter(CPUState *vcpu);
+
+
 #include "instrument/events.inc.h"
 
 #endif  /* INSTRUMENT__EVENTS_H */
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index 8b1ce7fcb2..e3f8024716 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -7,5 +7,16 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "instrument/control.h"
 
 
+static inline void instr_guest_cpu_enter(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_enter);
+if (cb) {
+QICPU vcpu_ = instr_cpu_to_qicpu(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index a01d66a4d4..218bca74b2 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -11,6 +11,7 @@
 #include "qemu-common.h"
 
 #include 
+#include "exec/cpu-common.h"
 #include "instrument/control.h"
 #include "instrument/events.h"
 #include "instrument/load.h"
@@ -109,6 +110,13 @@ InstrLoadError instr_load(const char *path, int argc, 
const char **argv,
 goto err;
 }
 
+cpu_list_lock();
+CPUState *cpu;
+CPU_FOREACH(cpu) {
+instr_guest_cpu_enter(cpu);
+}
+cpu_list_unlock();
+
 res = INSTR_LOAD_OK;
 goto out;
 
@@ -138,6 +146,7 @@ InstrUnloadError instr_unload(const char *id)
 }
 
 instr_set_event(fini_fn, NULL);
+instr_set_event(guest_cpu_enter, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index b841afaa31..f61e7a2b6e 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -16,6 +16,7 @@ extern "C" {
 
 #include 
 #include 
+#include 
 
 
 /**
@@ -39,6 +40,51 @@ typedef void (*qi_fini_fn)(void *arg);
  */
 void qi_set_fini(qi_fini_fn fn, void *data);
 
+
+/*
+ * Set callbacks for available events. Each event has a short description and
+ * various indicators of when it can be triggered:
+ *
+ * - Mode :: user
+ *   Triggered in QEMU user application emulation (e.g., linux-user).
+ *
+ * - Mode :: softmmy
+ *   Triggered in QEMU full-system emulation.
+ *
+ *
+ * - Targets :: all
+ *   Triggered on all targets, both using TCG or native hardware virtualization
+ *   (e.g., KVM).
+ *
+ * - Targets :: TCG()
+ *   Triggered on the given guest target architectures when executing with TCG
+ *   (no native hardware virtualization).
+ *
+ *
+ * - Time :: exec
+ *   Triggered when the guest executes the described operation.
+ *
+ * - Time :: trans
+ *   Triggered when QEMU translates a guest operation. This is only available
+ *   when executing with TCG. Guest instructions are decompiled and translated
+ *   into the intermediate TCG language (when "Time: trans" events are
+ *   triggered). Then, the TCG compiler translates TCG code into the native 
host
+ *   code that QEMU will execute to emulate the guest (when "Time: exec" events
+ *   are triggered). As QEMU uses a cache of translated code, the same
+ *   instruction might be translated more than once (when the cache overflows).
+ */
+
+/*
+ * Hot-plug a new virtual (guest) CPU.
+ *
+ * Also triggered on each CPU when an instrumentation library is loaded.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_c

[Qemu-devel] [PATCH v5 11/22] instrument: Track vCPUs

2017-09-12 Thread Lluís Vilanova
Keep a translation between instrumentation's QICPU and CPUState objects to avoid
exposing QEMU's internals to instrumentation clients.

Signed-off-by: Lluís Vilanova 
---
 cpus-common.c|9 +
 instrument/control.c |   23 +++
 instrument/control.h |   36 
 instrument/control.inc.h |   23 +++
 4 files changed, 91 insertions(+)

diff --git a/cpus-common.c b/cpus-common.c
index 59f751ecf9..ec5f46cc3d 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -22,6 +22,9 @@
 #include "exec/cpu-common.h"
 #include "qom/cpu.h"
 #include "sysemu/cpus.h"
+#if defined(CONFIG_INSTRUMENT)
+#include "instrument/control.h"
+#endif
 
 static QemuMutex qemu_cpu_list_lock;
 static QemuCond exclusive_cond;
@@ -84,6 +87,9 @@ void cpu_list_add(CPUState *cpu)
 } else {
 assert(!cpu_index_auto_assigned);
 }
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_add(cpu);
+#endif
 QTAILQ_INSERT_TAIL(&cpus, cpu, node);
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 
@@ -102,6 +108,9 @@ void cpu_list_remove(CPUState *cpu)
 assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
 
 QTAILQ_REMOVE(&cpus, cpu, node);
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_remove(cpu);
+#endif
 cpu->cpu_index = UNASSIGNED_CPU_INDEX;
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 }
diff --git a/instrument/control.c b/instrument/control.c
index 3630d6b3be..8cf2b4f967 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,10 +13,33 @@
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "qemu/compiler.h"
+#include "qom/cpu.h"
+
 
 __thread InstrState instr_cur_state;
 
 
+unsigned int instr_cpus_count;
+CPUState **instr_cpus;
+
+void instr_cpu_add(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+if (idx >= instr_cpus_count) {
+instr_cpus_count = idx + 1;
+instr_cpus = realloc(instr_cpus,
+ sizeof(*instr_cpus) * instr_cpus_count);
+}
+instr_cpus[idx] = vcpu;
+}
+
+void instr_cpu_remove(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+instr_cpus[idx] = NULL;
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index f2b085f69b..57cea07fa7 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -10,6 +10,42 @@
 #ifndef INSTRUMENT__CONTROL_H
 #define INSTRUMENT__CONTROL_H
 
+#include "qemu/typedefs.h"
+#include "instrument/qemu-instr/types.h"
+
+
+/**
+ * instr_cpu_add:
+ *
+ * Make @vcpu available to instrumentation clients.
+ *
+ * Precondition: cpu_list_lock().
+ */
+void instr_cpu_add(CPUState *vcpu);
+
+/**
+ * instr_cpu_remove:
+ *
+ * Make @vcpu unavailable to instrumentation clients.
+ *
+ * Precondition: cpu_list_lock().
+ */
+void instr_cpu_remove(CPUState *vcpu);
+
+/**
+ * instr_cpu_to_qicpu:
+ *
+ * Get the #QICPU corresponding to the given #CPUState.
+ */
+static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu);
+
+/**
+ * instr_cpu_from_qicpu:
+ *
+ * Get the #CPUState corresponding to the given #QICPU.
+ */
+static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 0f649f4caa..45daae7d1d 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -7,9 +7,32 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "qemu/osdep.h"
 #include "qemu/atomic.h"
 #include "qemu/compiler.h"
+#include "qom/cpu.h"
 #include 
+#include 
+
+
+extern unsigned int instr_cpus_count;
+extern CPUState **instr_cpus;
+
+static inline QICPU instr_cpu_to_qicpu(CPUState *vcpu)
+{
+uintptr_t idx = vcpu->cpu_index;
+return (QICPU)idx;
+}
+
+static inline CPUState *instr_cpu_from_qicpu(QICPU vcpu)
+{
+unsigned int idx = (uintptr_t)vcpu;
+if (idx >= instr_cpus_count) {
+return NULL;
+} else {
+return instr_cpus[idx];
+}
+}
 
 
 extern __thread InstrState instr_cur_state;




[Qemu-devel] [PATCH v5 10/22] instrument: Add support for tracing events

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 .gitignore|1 
 Makefile  |3 +
 instrument/Makefile.objs  |1 
 instrument/error.h|6 ++
 instrument/qemu-instr/types.h |   51 +++
 instrument/qemu-instr/types.inc.h |   15 
 instrument/trace.c|  125 +
 trace/control.h   |1 
 8 files changed, 203 insertions(+)
 create mode 100644 instrument/qemu-instr/types.h
 create mode 100644 instrument/qemu-instr/types.inc.h
 create mode 100644 instrument/trace.c

diff --git a/.gitignore b/.gitignore
index cf65316863..5ffcb9a091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -134,3 +134,4 @@ trace-dtrace-root.h
 trace-dtrace-root.dtrace
 trace-ust-all.h
 trace-ust-all.c
+!/instrument/*
diff --git a/Makefile b/Makefile
index c3d9a4bcd9..646fe2f327 100644
--- a/Makefile
+++ b/Makefile
@@ -602,6 +602,9 @@ endif
 ifdef CONFIG_INSTRUMENT
$(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
$(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/trace.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.inc.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
 endif
 
 install-datadir:
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index ec76b2080b..d7e6c760c3 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -4,3 +4,4 @@ target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
 target-obj-$(CONFIG_INSTRUMENT) += control.o
+target-obj-$(CONFIG_INSTRUMENT) += trace.o
diff --git a/instrument/error.h b/instrument/error.h
index f8d1dd4b16..7a51d62fdb 100644
--- a/instrument/error.h
+++ b/instrument/error.h
@@ -25,4 +25,10 @@
 return;  \
 }
 
+#define ERROR_IF_RET(cond, ret, msg, args...)   \
+if (unlikely(cond)) {   \
+_ERROR(msg, ##args);\
+return ret; \
+}   \
+
 #endif  /* INSTRUMENT_ERROR_H */
diff --git a/instrument/qemu-instr/types.h b/instrument/qemu-instr/types.h
new file mode 100644
index 00..ea3a032b4f
--- /dev/null
+++ b/instrument/qemu-instr/types.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__TYPES_H
+#define QI__TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION: types
+ * @section_id: qi-types
+ * @title: Common types
+ */
+
+/**
+ * QITraceEvent:
+ *
+ * Opaque structure defining a tracing event.
+ */
+typedef struct QITraceEvent QITraceEvent;
+
+/**
+ * QITraceEventIter:
+ *
+ * Opaque structure defining a tracing event iterator.
+ */
+typedef struct QITraceEventIter QITraceEventIter;
+
+/**
+ * QICPU:
+ *
+ * Opaque guest CPU pointer.
+ */
+typedef struct QICPU_d *QICPU;
+
+
+#include 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__TYPES_H */
diff --git a/instrument/qemu-instr/types.inc.h 
b/instrument/qemu-instr/types.inc.h
new file mode 100644
index 00..0d99ea59a2
--- /dev/null
+++ b/instrument/qemu-instr/types.inc.h
@@ -0,0 +1,15 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include 
+
+
+struct QITraceEventIter {
+char buffer[(sizeof(size_t) * 2) + sizeof(char *)];
+};
diff --git a/instrument/trace.c b/instrument/trace.c
new file mode 100644
index 00..6a437039b4
--- /dev/null
+++ b/instrument/trace.c
@@ -0,0 +1,125 @@
+/*
+ * API for QEMU's tracing events.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "instrument/error.h"
+#include "qemu/compiler.h"
+#include "qemu-instr/trace.h"
+#include "trace/control.h"
+
+
+SYM_PUBLIC
+QITraceEvent *qi_trace_event_name(const char *name)
+{
+ERROR_IF_RET(!name, NULL, "must provide a name");
+return (QITraceEvent *)trace_event_name(name);
+}
+
+SYM_PUBLIC
+void qi_trace_event_iter_init(QITraceEventIter *iter, const char *pattern)
+{
+TraceEventIter *iter_ = (TraceEventIter *)iter;

[Qemu-devel] [PATCH v5 09/22] instrument: Add basic control interface

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 Makefile|4 +++
 configure   |1 +
 include/qemu/compiler.h |   19 
 instrument/Makefile.objs|1 +
 instrument/control.c|   28 
 instrument/control.h|   44 +
 instrument/control.inc.h|   25 +
 instrument/error.h  |   28 
 instrument/events.h |   37 +++
 instrument/events.inc.h |   11 +
 instrument/load.c   |   13 +++
 instrument/qemu-instr/control.h |   46 +++
 stubs/instrument.c  |4 +++
 13 files changed, 261 insertions(+)
 create mode 100644 instrument/control.c
 create mode 100644 instrument/control.h
 create mode 100644 instrument/control.inc.h
 create mode 100644 instrument/error.h
 create mode 100644 instrument/events.h
 create mode 100644 instrument/events.inc.h
 create mode 100644 instrument/qemu-instr/control.h

diff --git a/Makefile b/Makefile
index 3861b3f49c..c3d9a4bcd9 100644
--- a/Makefile
+++ b/Makefile
@@ -599,6 +599,10 @@ ifdef CONFIG_VIRTFS
$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1"
$(INSTALL_DATA) fsdev/virtfs-proxy-helper.1 "$(DESTDIR)$(mandir)/man1"
 endif
+ifdef CONFIG_INSTRUMENT
+   $(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+endif
 
 install-datadir:
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)"
diff --git a/configure b/configure
index 5175151317..18810eae84 100755
--- a/configure
+++ b/configure
@@ -6030,6 +6030,7 @@ if test "$instrument" = "yes"; then
   LIBS="-ldl $LIBS"
   echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
 fi
+QEMU_INCLUDES="-I\$(SRC_PATH)/instrument $QEMU_INCLUDES"
 
 if test "$rdma" = "yes" ; then
   echo "CONFIG_RDMA=y" >> $config_host_mak
diff --git a/include/qemu/compiler.h b/include/qemu/compiler.h
index 340e5fdc09..e86bd34e2c 100644
--- a/include/qemu/compiler.h
+++ b/include/qemu/compiler.h
@@ -111,4 +111,23 @@
 #define GCC_FMT_ATTR(n, m)
 #endif
 
+/*
+ * Export symbol to dlopen()'ed libraries'.
+ *
+ * This code is taken from http://gcc.gnu.org/wiki/Visibility.
+ */
+#if defined _WIN32 || defined __CYGWIN__
+  #ifdef __GNUC__
+#define SYM_PUBLIC __attribute__ ((dllimport))
+  #else
+#define SYM_PUBLIC __declspec(dllimport)
+  #endif
+#else
+  #if __GNUC__ >= 4
+#define SYM_PUBLIC __attribute__ ((visibility("default")))
+  #else
+#define SYM_PUBLIC
+  #endif
+#endif
+
 #endif /* COMPILER_H */
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 7bf4e27e3c..ec76b2080b 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -3,3 +3,4 @@
 target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-$(CONFIG_INSTRUMENT) += qmp.o
+target-obj-$(CONFIG_INSTRUMENT) += control.o
diff --git a/instrument/control.c b/instrument/control.c
new file mode 100644
index 00..3630d6b3be
--- /dev/null
+++ b/instrument/control.c
@@ -0,0 +1,28 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/events.h"
+#include "instrument/load.h"
+#include "instrument/qemu-instr/control.h"
+#include "qemu/compiler.h"
+
+__thread InstrState instr_cur_state;
+
+
+qi_fini_fn instr_event__fini_fn;
+void *instr_event__fini_data;
+
+SYM_PUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(fini_fn, fn);
+instr_set_event(fini_data, data);
+}
diff --git a/instrument/control.h b/instrument/control.h
new file mode 100644
index 00..f2b085f69b
--- /dev/null
+++ b/instrument/control.h
@@ -0,0 +1,44 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef INSTRUMENT__CONTROL_H
+#define INSTRUMENT__CONTROL_H
+
+
+/**
+ * InstrState:
+ * @INSTR_STATE_DISABLE: Intrumentation API not available.
+ * @INSTR_STATE_ENABLE: Intrumentation API available.
+ *
+ * Instrumentation state of current host thread. Used to ensure instrumentation
+ * clients use QEMU&#

[Qemu-devel] [PATCH v5 08/22] instrument: [hmp] Add library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 hmp-commands.hx |   32 
 monitor.c   |   39 +++
 2 files changed, 71 insertions(+)

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 1941e19932..2e8ebe8422 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1858,6 +1858,38 @@ ETEXI
 .sub_table  = info_cmds,
 },
 
+#ifdef CONFIG_INSTRUMENT
+{
+.name   = "instr-load",
+.args_type  = "path:F,id:s?,arg:s?",
+.params = "path [id] [arg]",
+.help   = "load an instrumentation library",
+.cmd= hmp_instr_load,
+},
+#endif
+
+STEXI
+@item instr-load @var{path} [@var{id}] [@var{arg}]
+@findex instr-load
+Load an instrumentation library.
+ETEXI
+
+#ifdef CONFIG_INSTRUMENT
+{
+.name   = "instr-unload",
+.args_type  = "id:s",
+.params = "id",
+.help   = "unload an instrumentation library",
+.cmd= hmp_instr_unload,
+},
+#endif
+
+STEXI
+@item instr-unload
+@findex instr-unload
+Unload an instrumentation library.
+ETEXI
+
 STEXI
 @end table
 ETEXI
diff --git a/monitor.c b/monitor.c
index e031aa2687..7b80d5351f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2323,6 +2323,45 @@ int monitor_fd_param(Monitor *mon, const char *fdname, 
Error **errp)
 return fd;
 }
 
+#ifdef CONFIG_INSTRUMENT
+static void hmp_instr_load(Monitor *mon, const QDict *qdict)
+{
+Error *err = NULL;
+const char *path = qdict_get_str(qdict, "path");
+const char *id = qdict_get_try_str(qdict, "id");
+const char *str = qdict_get_try_str(qdict, "arg");
+strList args;
+
+args.value = (char *)str;
+args.next = NULL;
+
+InstrLoadResult *res = qmp_instr_load(path,
+  id != NULL, id,
+  args.value != NULL, &args,
+  &err);
+if (err) {
+error_report_err(err);
+} else {
+monitor_printf(mon, "Handle: %s\n", res->id);
+monitor_printf(mon, "OK\n");
+}
+qapi_free_InstrLoadResult(res);
+}
+
+static void hmp_instr_unload(Monitor *mon, const QDict *qdict)
+{
+Error *err = NULL;
+const char *id = qdict_get_str(qdict, "id");
+
+qmp_instr_unload(id, &err);
+if (err) {
+error_report_err(err);
+} else {
+monitor_printf(mon, "OK\n");
+}
+}
+#endif
+
 /* Please update hmp-commands.hx when adding or changing commands */
 static mon_cmd_t info_cmds[] = {
 #include "hmp-commands-info.h"




[Qemu-devel] [PATCH v5 07/22] instrument: [qapi] Add library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS  |1 +
 Makefile |1 +
 instrument/Makefile.objs |1 +
 instrument/qmp.c |   82 ++
 monitor.c|4 ++
 qapi-schema.json |3 ++
 qapi/instrument.json |   49 +++
 stubs/instrument.c   |   26 +++
 8 files changed, 167 insertions(+)
 create mode 100644 instrument/qmp.c
 create mode 100644 qapi/instrument.json

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c0b12a69a..edddab0502 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1492,6 +1492,7 @@ M: Stefan Hajnoczi 
 S: Maintained
 F: docs/instrument.txt
 F: instrument/
+F: qapi/instrument.json
 
 TPM
 S: Orphan
diff --git a/Makefile b/Makefile
index 337a1f6f9b..3861b3f49c 100644
--- a/Makefile
+++ b/Makefile
@@ -412,6 +412,7 @@ qapi-modules = $(SRC_PATH)/qapi-schema.json 
$(SRC_PATH)/qapi/common.json \
$(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \
$(SRC_PATH)/qapi/char.json \
$(SRC_PATH)/qapi/crypto.json \
+   $(SRC_PATH)/qapi/instrument.json \
$(SRC_PATH)/qapi/introspect.json \
$(SRC_PATH)/qapi/migration.json \
$(SRC_PATH)/qapi/net.json \
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 71994a4c85..7bf4e27e3c 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -2,3 +2,4 @@
 
 target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
 target-obj-$(CONFIG_INSTRUMENT) += load.o
+target-obj-$(CONFIG_INSTRUMENT) += qmp.o
diff --git a/instrument/qmp.c b/instrument/qmp.c
new file mode 100644
index 00..e4464aa5eb
--- /dev/null
+++ b/instrument/qmp.c
@@ -0,0 +1,82 @@
+/*
+ * QMP interface for instrumentation control commands.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include 
+
+#include "instrument/load.h"
+#include "qemu-common.h"
+#include "qapi/qmp/qerror.h"
+#include "qmp-commands.h"
+
+
+InstrLoadResult *qmp_instr_load(const char *path,
+bool has_id, const char *id,
+bool have_args, strList *args,
+Error **errp)
+{
+InstrLoadResult *res = g_malloc0(sizeof(*res));
+int argc = 0;
+const char **argv = NULL;
+InstrLoadError code;
+
+if (!has_id) {
+id = NULL;
+}
+
+strList *entry = have_args ? args : NULL;
+while (entry != NULL) {
+argv = realloc(argv, sizeof(*argv) * (argc + 1));
+argv[argc] = entry->value;
+argc++;
+entry = entry->next;
+}
+
+code = instr_load(path, argc, argv, &id);
+switch (code) {
+case INSTR_LOAD_OK:
+res->id = g_strdup(id);
+break;
+case INSTR_LOAD_ID_EXISTS:
+error_setg(errp, "Library ID exists");
+break;
+case INSTR_LOAD_TOO_MANY:
+error_setg(errp, "Tried to load too many libraries");
+break;
+case INSTR_LOAD_ERROR:
+error_setg(errp, "Library initialization returned non-zero");
+break;
+case INSTR_LOAD_DLERROR:
+error_setg(errp, "Error loading library: %s",
+   dlerror());
+break;
+}
+
+if (*errp) {
+g_free(res);
+res = NULL;
+}
+
+return res;
+}
+
+void qmp_instr_unload(const char *id, Error **errp)
+{
+InstrUnloadError code = instr_unload(id);
+switch (code) {
+case INSTR_UNLOAD_OK:
+break;
+case INSTR_UNLOAD_INVALID:
+error_setg(errp, "Unknown library ID");
+break;
+case INSTR_UNLOAD_DLERROR:
+error_setg(errp, "Error unloading library: %s", dlerror());
+break;
+}
+}
diff --git a/monitor.c b/monitor.c
index 9239f7adde..e031aa2687 100644
--- a/monitor.c
+++ b/monitor.c
@@ -978,6 +978,10 @@ static void qmp_unregister_commands_hack(void)
 qmp_unregister_command(&qmp_commands, "query-xen-replication-status");
 qmp_unregister_command(&qmp_commands, "xen-colo-do-checkpoint");
 #endif
+#ifndef CONFIG_INSTRUMENT
+qmp_unregister_command(&qmp_commands, "instr-load");
+qmp_unregister_command(&qmp_commands, "instr-unload");
+#endif
 #ifndef TARGET_I386
 qmp_unregister_command(&qmp_commands, "rtc-reset-reinjection");
 #endif
diff --git a/qapi-schema.json b/qapi-schema.json
index f3af2cb851..706c64659f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -93,6 +93,9 @@
 { 'include': 'qapi/trace.json' }
 { 'include': 'qapi/introspect.json' }
 
+# Instrumentation commands
+{ 'i

[Qemu-devel] [PATCH v5 06/22] instrument: [softmmu] Add command line library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 qemu-options.hx |   19 +++
 vl.c|   15 +++
 2 files changed, 34 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 9f6e2adfff..6947388aab 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -4077,6 +4077,25 @@ HXCOMM HX does not support conditional compilation of 
text.
 @findex -trace
 @include qemu-option-trace.texi
 ETEXI
+#if defined(CONFIG_INSTRUMENT)
+DEF("instr", HAS_ARG, QEMU_OPTION_instr,
+"-instr [file=][,arg=]\n"
+"load an instrumentation library\n",
+QEMU_ARCH_ALL)
+#endif
+STEXI
+@item -instr file=@var{file}[,arg=@var{string}]
+@findex -instr
+
+Load a dynamic trace instrumentation library.
+
+@table @option
+@item file=@var{file}
+Load the given dynamic trace instrumentation library.
+@item arg=@var{string}
+String argument passed as to the library's @code{qi_init} routine (can be 
given multiple times).
+@end table
+ETEXI
 
 HXCOMM Internal use
 DEF("qtest", HAS_ARG, QEMU_OPTION_qtest, "", QEMU_ARCH_ALL)
diff --git a/vl.c b/vl.c
index fb1f05b937..aea05ed4cc 100644
--- a/vl.c
+++ b/vl.c
@@ -118,6 +118,7 @@ int main(int argc, char **argv)
 
 #include "trace-root.h"
 #include "trace/control.h"
+#include "instrument/cmdline.h"
 #include "qemu/queue.h"
 #include "sysemu/arch_init.h"
 
@@ -3037,6 +3038,9 @@ int main(int argc, char **argv, char **envp)
 } BlockdevOptions_queue;
 QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue
 = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
+char *instrument_path = NULL;
+int instrument_argc = 0;
+const char **instrument_argv = NULL;
 
 module_call_init(MODULE_INIT_TRACE);
 
@@ -3064,6 +3068,9 @@ int main(int argc, char **argv, char **envp)
 qemu_add_opts(&qemu_global_opts);
 qemu_add_opts(&qemu_mon_opts);
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 qemu_add_opts(&qemu_option_rom_opts);
 qemu_add_opts(&qemu_machine_opts);
 qemu_add_opts(&qemu_accel_opts);
@@ -4009,6 +4016,12 @@ int main(int argc, char **argv, char **envp)
 g_free(trace_file);
 trace_file = trace_opt_parse(optarg);
 break;
+#if defined(CONFIG_INSTRUMENT)
+case QEMU_OPTION_instr:
+instr_opt_parse(optarg, &instrument_path,
+&instrument_argc, &instrument_argv);
+break;
+#endif
 case QEMU_OPTION_readconfig:
 {
 int ret = qemu_read_config_file(optarg);
@@ -4196,6 +4209,8 @@ int main(int argc, char **argv, char **envp)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Open the logfile at this point and set the log mask if necessary.
  */
 if (log_file) {




[Qemu-devel] [PATCH v5 05/22] instrument: [bsd-user] Add command line library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/main.c|   17 +
 bsd-user/syscall.c |5 +
 2 files changed, 22 insertions(+)

diff --git a/bsd-user/main.c b/bsd-user/main.c
index 8a6706a1c8..104844edfc 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -33,6 +33,7 @@
 #include "exec/log.h"
 #include "trace/control.h"
 #include "glib-compat.h"
+#include "instrument/cmdline.h"
 
 int singlestep;
 unsigned long mmap_min_addr;
@@ -667,6 +668,11 @@ static void usage(void)
"-B addressset guest_base address to address\n"
"-bsd type select emulated BSD type FreeBSD/NetBSD/OpenBSD 
(default)\n"
"\n"
+#if defined(CONFIG_INSTRUMENT)
+   "-instr [file=][,arg=]\n"
+   "  load an instrumentation library\n"
+   "\n"
+#endif
"Debug options:\n"
"-d item1[,...]enable logging of specified items\n"
"  (use '-d help' for a list of log items)\n"
@@ -738,6 +744,9 @@ int main(int argc, char **argv)
 envlist_t *envlist = NULL;
 char *trace_file = NULL;
 bsd_type = target_openbsd;
+char *instrument_path = NULL;
+int instrument_argc = 0;
+const char **instrument_argv = NULL;
 
 if (argc <= 1)
 usage();
@@ -756,6 +765,9 @@ int main(int argc, char **argv)
 cpu_model = NULL;
 
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 
 optind = 1;
 for (;;) {
@@ -843,6 +855,9 @@ int main(int argc, char **argv)
 } else if (!strcmp(r, "trace")) {
 g_free(trace_file);
 trace_file = trace_opt_parse(optarg);
+} else if (!strcmp(r, "instr")) {
+instr_opt_parse(optarg, &instrument_path,
+&instrument_argc, &instrument_argv);
 } else {
 usage();
 }
@@ -872,6 +887,8 @@ int main(int argc, char **argv)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Zero out regs */
 memset(regs, 0, sizeof(struct target_pt_regs));
 
diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 66492aaf5d..3230f722f3 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -26,6 +26,8 @@
 
 #include "qemu.h"
 #include "qemu-common.h"
+#include "instrument/cmdline.h"
+
 
 //#define DEBUG
 
@@ -332,6 +334,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */
@@ -430,6 +433,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */
@@ -505,6 +509,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 /* XXX: should free thread stack and CPU env */
 _exit(arg1);
 ret = 0; /* avoid warning */




[Qemu-devel] [PATCH v5 04/22] instrument: [linux-user] Add command line library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 linux-user/main.c|   21 +
 linux-user/syscall.c |4 
 2 files changed, 25 insertions(+)

diff --git a/linux-user/main.c b/linux-user/main.c
index 03666ef657..ac5c30c1fb 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -36,6 +36,7 @@
 #include "exec/log.h"
 #include "trace/control.h"
 #include "glib-compat.h"
+#include "instrument/cmdline.h"
 
 char *exec_path;
 
@@ -4017,6 +4018,17 @@ static void handle_arg_trace(const char *arg)
 trace_file = trace_opt_parse(arg);
 }
 
+static char *instrument_path;
+static int instrument_argc;
+static const char **instrument_argv;
+#if defined(CONFIG_INSTRUMENT)
+static void handle_arg_instrument(const char *arg)
+{
+instr_opt_parse(arg, &instrument_path,
+&instrument_argc, &instrument_argv);
+}
+#endif
+
 struct qemu_argument {
 const char *argv;
 const char *env;
@@ -4066,6 +4078,10 @@ static const struct qemu_argument arg_table[] = {
  "",   "Seed for pseudo-random number generator"},
 {"trace",  "QEMU_TRACE",   true,  handle_arg_trace,
  "",   "[[enable=]][,events=][,file=]"},
+#if defined(CONFIG_INSTRUMENT)
+{"instr",  "QEMU_INSTR",   true,  handle_arg_instrument,
+ "",   "[file=][,arg=]"},
+#endif
 {"version","QEMU_VERSION", false, handle_arg_version,
  "",   "display version information and exit"},
 {NULL, NULL, false, NULL, NULL, NULL}
@@ -4257,6 +4273,9 @@ int main(int argc, char **argv, char **envp)
 srand(time(NULL));
 
 qemu_add_opts(&qemu_trace_opts);
+#if defined(CONFIG_INSTRUMENT)
+qemu_add_opts(&qemu_instr_opts);
+#endif
 
 optind = parse_args(argc, argv);
 
@@ -4265,6 +4284,8 @@ int main(int argc, char **argv, char **envp)
 }
 trace_init_file(trace_file);
 
+instr_init(instrument_path, instrument_argc, instrument_argv);
+
 /* Zero out regs */
 memset(regs, 0, sizeof(struct target_pt_regs));
 
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 9b6364a266..e73a07fa6f 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -115,6 +115,8 @@ int __clone2(int (*fn)(void *), void *child_stack_base,
 #include "uname.h"
 
 #include "qemu.h"
+#include "instrument/cmdline.h"
+
 
 #ifndef CLONE_IO
 #define CLONE_IO0x8000  /* Clone io context */
@@ -7765,6 +7767,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 _exit(arg1);
 ret = 0; /* avoid warning */
 break;
@@ -9821,6 +9824,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
 _mcleanup();
 #endif
 gdb_exit(cpu_env, arg1);
+instr_fini();
 ret = get_errno(exit_group(arg1));
 break;
 #endif




[Qemu-devel] [PATCH v5 03/22] instrument: Add generic library loader

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS  |1 
 Makefile.objs|4 +
 configure|3 +
 instrument/Makefile.objs |4 +
 instrument/cmdline.c |  128 +++
 instrument/cmdline.h |   51 ++
 instrument/load.c|  166 ++
 instrument/load.h|   88 
 stubs/Makefile.objs  |1 
 stubs/instrument.c   |   18 +
 10 files changed, 464 insertions(+)
 create mode 100644 instrument/Makefile.objs
 create mode 100644 instrument/cmdline.c
 create mode 100644 instrument/cmdline.h
 create mode 100644 instrument/load.c
 create mode 100644 instrument/load.h
 create mode 100644 stubs/instrument.c

diff --git a/MAINTAINERS b/MAINTAINERS
index fb0eaee06a..6c0b12a69a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1491,6 +1491,7 @@ M: Lluís Vilanova 
 M: Stefan Hajnoczi 
 S: Maintained
 F: docs/instrument.txt
+F: instrument/
 
 TPM
 S: Orphan
diff --git a/Makefile.objs b/Makefile.objs
index 24a4ea08b8..81a9218e14 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -97,6 +97,10 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
 util-obj-y +=  trace/
 target-obj-y += trace/
 
+##
+# instrument
+target-obj-y += instrument/
+
 ##
 # guest agent
 
diff --git a/configure b/configure
index a21d1bceb9..5175151317 100755
--- a/configure
+++ b/configure
@@ -6025,6 +6025,9 @@ fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
 if test "$instrument" = "yes"; then
+  LDFLAGS="-rdynamic $LDFLAGS"  # limit symbols available to clients
+  QEMU_CFLAGS="-fvisibility=hidden $QEMU_CFLAGS"
+  LIBS="-ldl $LIBS"
   echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
 fi
 
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
new file mode 100644
index 00..71994a4c85
--- /dev/null
+++ b/instrument/Makefile.objs
@@ -0,0 +1,4 @@
+# -*- mode: makefile -*-
+
+target-obj-$(CONFIG_INSTRUMENT) += cmdline.o
+target-obj-$(CONFIG_INSTRUMENT) += load.o
diff --git a/instrument/cmdline.c b/instrument/cmdline.c
new file mode 100644
index 00..da7a7cbceb
--- /dev/null
+++ b/instrument/cmdline.c
@@ -0,0 +1,128 @@
+/*
+ * Control instrumentation during program (de)initialization.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include 
+#include "instrument/cmdline.h"
+#include "instrument/load.h"
+#include "qemu/config-file.h"
+#include "qemu/error-report.h"
+
+
+QemuOptsList qemu_instr_opts = {
+.name = "instrument",
+.implied_opt_name = "file",
+.merge_lists = true,
+.head = QTAILQ_HEAD_INITIALIZER(qemu_instr_opts.head),
+.desc = {
+{
+.name = "file",
+.type = QEMU_OPT_STRING,
+},{
+.name = "arg",
+.type = QEMU_OPT_STRING,
+},
+{ /* end of list */ }
+},
+};
+
+void instr_opt_parse(const char *optarg, char **path,
+ int *argc, const char ***argv)
+{
+const char *arg;
+QemuOptsIter iter;
+QemuOpts *opts = qemu_opts_parse_noisily(qemu_find_opts("instrument"),
+ optarg, true);
+if (!opts) {
+exit(1);
+} else {
+#if !defined(CONFIG_INSTRUMENT)
+error_report("instrumentation not enabled on this build");
+exit(1);
+#endif
+}
+
+
+arg = qemu_opt_get(opts, "file");
+if (arg != NULL) {
+g_free(*path);
+*path = g_strdup(arg);
+}
+
+qemu_opt_iter_init(&iter, opts, "arg");
+while ((arg = qemu_opt_iter_next(&iter)) != NULL) {
+*argv = realloc(*argv, sizeof(**argv) * (*argc + 1));
+(*argv)[*argc] = g_strdup(arg);
+(*argc)++;
+}
+
+qemu_opts_del(opts);
+}
+
+void instr_init(const char *path, int argc, const char **argv)
+{
+#if defined(CONFIG_INSTRUMENT)
+InstrLoadError err;
+
+if (path == NULL) {
+return;
+}
+
+if (atexit(instr_fini) != 0) {
+fprintf(stderr, "error: atexit: %s\n", strerror(errno));
+abort();
+}
+
+const char *id = "cmdline";
+err = instr_load(path, argc, argv, &id);
+switch (err) {
+case INSTR_LOAD_OK:
+error_report("instrument: loaded library with ID '%s'", id);
+return;
+case INSTR_LOAD_TOO_MANY:
+error_report("instrument: tried to load too many libraries");
+break;
+case INSTR_

[Qemu-devel] [PATCH v5 02/22] instrument: Add configure-time flag

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 configure |9 +
 1 file changed, 9 insertions(+)

diff --git a/configure b/configure
index fd7e3a5e81..a21d1bceb9 100755
--- a/configure
+++ b/configure
@@ -356,6 +356,7 @@ pie=""
 qom_cast_debug="yes"
 trace_backends="log"
 trace_file="trace"
+instrument="no"
 spice=""
 rbd=""
 smartcard=""
@@ -886,6 +887,8 @@ for opt do
   ;;
   --with-trace-file=*) trace_file="$optarg"
   ;;
+  --enable-instrument) instrument="yes"
+  ;;
   --enable-gprof) gprof="yes"
   ;;
   --enable-gcov) gcov="yes"
@@ -1436,6 +1439,7 @@ Advanced options (experts only):
Available backends: $trace_backend_list
   --with-trace-file=NAME   Full PATH,NAME of file to store traces
Default:trace-
+  --enable-instrument  enable event instrumentation
   --disable-slirp  disable SLIRP userspace network connectivity
   --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)
   --oss-libpath to OSS library
@@ -5366,6 +5370,7 @@ echo "Trace backends$trace_backends"
 if have_backend "simple"; then
 echo "Trace output file $trace_file-"
 fi
+echo "instrumentation   $instrument"
 echo "spice support $spice $(echo_version $spice 
$spice_protocol_version/$spice_server_version)"
 echo "rbd support   $rbd"
 echo "xfsctl support$xfs"
@@ -6019,6 +6024,10 @@ if have_backend "syslog"; then
 fi
 echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
 
+if test "$instrument" = "yes"; then
+  echo "CONFIG_INSTRUMENT=y" >> $config_host_mak
+fi
+
 if test "$rdma" = "yes" ; then
   echo "CONFIG_RDMA=y" >> $config_host_mak
 fi




[Qemu-devel] [PATCH v5 01/22] instrument: Add documentation

2017-09-12 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 MAINTAINERS |6 ++
 docs/instrument.txt |  173 +++
 2 files changed, 179 insertions(+)
 create mode 100644 docs/instrument.txt

diff --git a/MAINTAINERS b/MAINTAINERS
index 36eeb42d19..fb0eaee06a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1486,6 +1486,12 @@ F: scripts/tracetool/
 F: docs/tracing.txt
 T: git git://github.com/stefanha/qemu.git tracing
 
+Event instrumentation
+M: Lluís Vilanova 
+M: Stefan Hajnoczi 
+S: Maintained
+F: docs/instrument.txt
+
 TPM
 S: Orphan
 F: tpm.c
diff --git a/docs/instrument.txt b/docs/instrument.txt
new file mode 100644
index 00..24a0d21fc7
--- /dev/null
+++ b/docs/instrument.txt
@@ -0,0 +1,173 @@
+= Event instrumentation =
+
+== Introduction ==
+
+Event instrumentation allows users to execute their own host-native code on a
+set of pre-defined events provided by QEMU. QEMU also exposes other
+functionality to peek/poke at the guest state (e.g., memory or registers), as
+well as interacting with tracing events. For those familiar with the term, this
+provides dynamic binary instrumentation, works on all QEMU-supported
+architectures, as well as works in both 'user' (standalone application) and
+'system' (full-system emulation) modes.
+
+Look at the headers installed by QEMU on the "qemu-instr" directory for further
+information beyond this document.
+
+
+== Loading an instrumentation library ==
+
+Instrumentation code can be bundled into a dynamic library, which can be later
+loaded into QEMU:
+
+* Using the command-line "-instr" argument.
+
+* Using the "instr-load" and "instr-unload" commands in the HMP and QMP
+  interfaces.
+
+
+== Example ==
+
+1. Configure QEMU with event instrumentation:
+
+# instrument guest_cpu_enter and guest_mem_before
+mkdir -p /path/to/qemu-build
+cd /path/to/qemu-build
+/path/to/qemu-source/configure \
+  --enable-instrument \
+  --prefix=/path/to/qemu-install
+
+2. Build and install QEMU:
+
+make install
+
+3. Create the "Makefile" to build the instrumentation library:
+
+mkdir -p /tmp/my-instrument
+
+cat > /tmp/my-instrument/Makefile < /tmp/my-instrument/instrument.c <
+#include 
+
+#include  /* manipulate events */
+#include/* manipulate tracing */
+
+/* the address for the memory access is not known at translation time */
+void guest_mem_before_trans(QICPU vcpu_trans, QITCGv_cpu vcpu_exec,
+QITCGv vaddr, QIMemInfo info)
+{
+printf("%s: %p %p %p %d %d %d %d\n", __func__, vcpu_trans, vcpu_exec, 
vaddr,
+   1 << info.size_shift, info.sign_extend, info.endianness, 
info.store);
+if (info.store) {
+/* generate at execution time only for memory writes */
+qi_event_gen_guest_mem_before_exec(vcpu_exec, vaddr, info);
+}
+}
+
+/* called when QEMU executes a memory access */
+void guest_mem_before_exec(QICPU vcpu, uint64_t vaddr, QIMemInfo info)
+{
+if (info.store) {
+/* if called by TCG code, we'll only get writes (see above) */
+printf("%s: %p %lx %d %d %d %d\n", __func__, vcpu, vaddr,
+   1 << info.size_shift, info.sign_extend, info.endianness, 
info.store);
+}
+}
+
+/* called every time QEMU hotplugs a CPU */
+void guest_cpu_enter(QICPU vcpu)
+{
+printf("%s: %p\n", __func__, vcpu);
+
+/* disable instrumentation and tracing after the first call */
+static bool found = false;
+if (found) {
+qi_event_set_guest_cpu_enter(NULL);
+QITraceEvent *ev = qi_trace_event_name("guest_cpu_enter");
+assert(ev);
+qi_trace_event_set_state_dynamic(ev, true);
+} else {
+found = true;
+}
+}
+
+static void fini(void *data)
+{
+/* diable all tracing events */
+QITraceEventIter iter;
+qi_trace_event_iter_init(&iter, NULL);
+QITraceEvent *ev;
+while ((ev = qi_trace_event_iter_next(&iter)) != NULL) {
+if (qi_trace_event_get_state_static(ev)) {
+qi_trace_event_set_state_dynamic(ev, false);
+}
+}
+
+/* instrumentation callbacks are automatically reset by QEMU */
+}
+
+/* mandatory initialization function */
+int main(int argc, const char **argv)
+{
+int i;
+printf("init!\n");
+printf("argc :: %d\n", argc);
+for (i = 0; i < argc; i++) {
+printf("-> %s\n", argv[i]);
+}
+
+qi_set_fini(fini, NULL);
+
+/* instrument and trace events */
+QITraceEvent *ev;
+
+

[Qemu-devel] [PATCH v5 00/22] instrument: Add basic event instrumentation

2017-09-12 Thread Lluís Vilanova
This series adds an API to add instrumentation events.

It also provides additional APIs for:
* Controlling tracing events.
* Peek/poke guest memory.

TODO:
* Replace qi_event_gen_* with generating calls to arbitrary functions (e.g.,
  qi_event_gen_call(num_args, va_list)).
* Flush all TBs when an execution-time event is unset (to ensure it won't be
  called in the future).
* Flush all TBs when a translation-time event is set (to ensure no future events
  will be lost).

Undecided:
* Alternatively to the two last points above, provide an API to request a TB
  flush (much more flexible and can be more efficient, but requires instrumentor
  to clearly know differences between translation and execution).
* Pass a user-provided pointer to events (i.e., to avoid using global
  variables).
* Provide something like tracing's per-vCPU trace states (i.e., so that each
  vCPU can have different instrumentation code). Useful mainly for sampling
  (enable/disable instrumentation multiple times without re-translating guest
  code) and more complex use cases like tracing a guest process in softmmu mode.
  It's still not clear to me if we should extend the per-vCPU bitmap with
  instrumentation events, or otherwise somehow reuse the bits in tracing events
  (since they're currently limited).
* Allow multiple callbacks per event (both to support multiple callbacks
  installed by a library, and multiple libraries at the same time).
* Allow instr libraries to iterate on the list of guest CPUs (info is already
  available through guest_cpu_enter/guest_cpu_exit, but forces libs to be
  prepared for hot-plugging guest CPUs).

Future APIs (for later series):
* Peek/poke guest registers.
* Add breakpoints to trigger instrumentation functions.
* Trigger instrumentation functions from guest code (former hypertrace).
* Add events for guest code translation/execution (once the respective tracing
  events are accepted upstream).
* Add events for exceptions/syscalls.
* Add events for TB invalidation (necessary for libraries to deallocate any data
  they might have allocated for the TBs they instrumented).

The instrumentation code is dynamically loaded as a library into QEMU either
when it starts or later using its remote control interfaces. The loaded code
only has access to function explicitly exported through the QI_VPUBLIC macro.

This series is branch 'devel-instrument' in
https://code.gso.ac.upc.edu/git/qemu-dbi.

Signed-off-by: Lluís Vilanova 
---

Changes in v5
=

* Rebase on fcea73709b.
* Minor changes to pass checkpatch.
* Fix symbol availability to external libraries by adding missing default symbol
  visibility flag.
* Use a string to identify instrumentation handles [Markus Armbruster].
* Use stubs for command line initialization.
* Use stubs to signal unsupported QAPI commands [Markus Armbruster].
* Use error messages instead of codes in QAPI commands [Markus Armbruster].
* Move symbol visibility macros to internal "qemu/compiler.h" header.
* Trigger event 'guest_cpu_enter' when library is loaded.
* Trigger event 'guest_cpu_exit' and flush TBs when library is unloaded.
* Rename instr_cpu_get/instr_cpu_set into clearer
  instr_cpu_to_qicpu/instr_cpu_from_qicpu.
* Rename handle_get/handle_put to clearer handle_new/handle_destroy.
* Ensure qi_event_set_* are called only on the proper mode and targets.


Changes in v4
=

* Add missing stub function.


Changes in v3
=

* Use a separate event set for instrumentation (i.e., do not instrument tracing
  events) [Stefan Hajnoczi].
* Add API for peek/poke guest memory.


Changes in v2
=

* Update QEMU version in QAPI [Eric Blake].
* Clarify 'msg' result in QAPI is for humans only.
* Make 'msg' and 'handle' results optional in QAPI.
* Use a list of 'str' in 'instr-load' QAPI command.
* Update MAINTAINERS.
* Add macros for error-reporting in API.


Lluís Vilanova (22):
  instrument: Add documentation
  instrument: Add configure-time flag
  instrument: Add generic library loader
  instrument: [linux-user] Add command line library loader
  instrument: [bsd-user] Add command line library loader
  instrument: [softmmu] Add command line library loader
  instrument: [qapi] Add library loader
  instrument: [hmp] Add library loader
  instrument: Add basic control interface
  instrument: Add support for tracing events
  instrument: Track vCPUs
  instrument: Add event 'guest_cpu_enter'
  instrument: Support synchronous modification of vCPU state
  exec: Add function to synchronously flush TB on a stopped vCPU
  instrument: Add event 'guest_cpu_exit'
  instrument: Add event 'guest_cpu_reset'
  trace: Introduce a proper structure to describe memory accesses
  instrument: Add event 'guest_mem_before_trans'
  instrument: Ad

Re: [Qemu-devel] [PATCH v4 00/20] instrument: Add basic event instrumentation

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 06, 2017 at 20:22:41 +0300, Lluís Vilanova wrote:
>> This series adds an API to add instrumentation events.
>> 
>> It also provides additional APIs for:
>> * Controlling tracing events

> hmm didn't Stefan say that tracing should be decoupled from this?

I understood decoupling instr from the tracing infrastructure (since tracing
events are defined as not stable, and instr must be stable by definition).


>> * Peek/poke guest memory
>> 
>> There's still missing APIs for (can be added in later series?):
>> * Provide something like tracing's per-vCPU trace states (i.e., so that each
>> vCPU can have different instrumentation code). It's still not clear to me if
>> we should extend the per-vCPU bitmap with instrumentation events, or 
>> otherwise
>> somehow reuse the bits in tracing events (since they're currently limited).

> As I said in the description of my alternative implementation [*], I don't see
> much value in having per-vCPU events, as most instrumenters just care about
> the guest application/system. I can only think of cases where the instrumenter
> is only interested in a guest process (in system-mode), but that'd be ugly
> anyway (would need to change both QEMU and the guest kernel to track the pid).

> If the need ever arises, we could add __vcpu(cpu_index) registration 
> functions.

> [*] https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg01446.html

Sorry, your series slipped my radar. I'll take a look at it.


Thanks,
  Lluis



Re: [Qemu-devel] [PATCH v4 09/20] instrument: Add basic control interface

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 06, 2017 at 20:59:02 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
> (snip)
>> +QI_VPUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
>> +{
>> +ERROR_IF(!instr_get_state(), "called outside instrumentation");
>> +instr_set_event(fini_fn, fn);
>> +instr_set_event(fini_data, data);
>> +}

> Why are these QI_VPUBLIC attributes here? Those are useful for DSO's, not
> for executables --by using -rdynamic, all non-static symbols in the
> executable are already visible.

That's because I'm using -rdynamic, -fvisibility=hidden and these attributes all
together to limit what symbols are available to dlopen()'ed libs (new series
version will have the visibility compiler flag I forgot to send).


>> diff --git a/instrument/control.h b/instrument/control.h
>> new file mode 100644
>> index 00..f2b085f69b
>> --- /dev/null
>> +++ b/instrument/control.h
> (snip)
>> + * Instrumentation state of current host thread. Used to ensure 
>> instrumentation
>> + * clients use QEMU's API only in expected points.
>> + */
>> +typedef enum {
>> +INSTR_STATE_DISABLE,
>> +INSTR_STATE_ENABLE,
>> +} InstrState;

> I find this unnecessarily ugly for the little gain we get, i.e. asserts 
> against
> calling API code from QEMU.. seems unlikely to me (although admittedly I think
> the qemu-internal API is unnecessarily complex/verbose, so maybe
> you're better off with these checks).

It ensures only QEMU's threads now calling a library function are allowed to use
the public API. In a later patch, it also ensures that TCG-generating functions
(e.g., qi_event_gen_guest_mem_before_exec) can only be called from
translation-time library functions.


> (snip)
>> +/**
>> + * instr_get_event:
>> + *
>> + * Get value set by instrumentation library.
>> + */
>> +#define instr_get_event(name)   \
>> +atomic_load_acquire(&instr_event__ ## name)
>> +
>> +/**
>> + * instr_get_event:
>> + *
>> + * Set value from instrumentation library.
>> + */
>> +#define instr_set_event(name, fn)   \
>> +atomic_store_release(&instr_event__ ## name, fn)

> This isn't enough to decide whether to call instrumentation, especially for
> TCG. We need TB's to know what to call, and update that mask with async
> work, just like we do with tracing. Check out my alternative patchset.

What do you mean by TB's need to know what to call?

> Also, a single function pointer cannot work for more than one plugin. But
> I see you have an XXX when there's more than one plugin, so it's OK for now.
> I used RCU lists for this, which at least gives you a time in the future
> at which things become visible/invisible by other threads -- this is important
> when unloading an instrumenter, since you don't want to clear important stuff
> (e.g. dlclose) before you're sure no further callbacks to it are possible.
> [no, the atomic_acquire/release isn't enough!]

In principle, this together with the API checks above and kicking all vCPUs to
flush TBs before unloading a library (I'm still looking at last bit) should
ensure libs can be safely unloaded. This should work for guest code events, but
I still need to look at other events like vCPU hotplug (is it asynchronous?), or
other events we might want triggered outside the vCPU loops.

Flushing all TBs is also on my todo to support immediate event availability when
loading a library and setting a translation-time callback.

Also, I'm not sure if we should support the complexity and performance penalty
of more than one library at a time. Right now, the QAPI commands expose support
for more than one just for future-proofing (as suggested by Richard Henderson,
if I remember correctly).



> (snip)
>> diff --git a/instrument/load.c b/instrument/load.c
>> index a57401102a..e180f03429 100644
>> --- a/instrument/load.c
>> +++ b/instrument/load.c
>> @@ -11,6 +11,8 @@
>> #include "qemu-common.h"
>> 
>> #include 
>> +#include "instrument/control.h"
>> +#include "instrument/events.h"
>> #include "instrument/load.h"
>> #include "qemu/config-file.h"
>> #include "qemu/error-report.h"
>> @@ -105,8 +107,11 @@ InstrLoadError instr_load(const char * path, int argc, 
>> const char ** argv,
>> res = INSTR_LOAD_DLERROR;
>> goto err;
>> }
>> +instr_set_event(fini_fn, NULL);
>> 
>> +instr_set_state(INSTR_STATE_ENABLE);
>> main_res = main_cb(argc, argv);
>> +ins

Re: [Qemu-devel] [PATCH v4 09/20] instrument: Add basic control interface

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 06, 2017 at 20:59:02 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> Makefile   |5 +++
>> configure  |1 +
>> instrument/Makefile.objs   |2 +
>> instrument/control.c   |   28 +
>> instrument/control.h   |   44 +++
>> instrument/control.inc.h   |   25 
>> instrument/error.h |   28 +
>> instrument/events.h|   37 +++
>> instrument/events.inc.h|   11 +++

> Am I the only one who finds this control vs. events division confusing?

Control is only for controlling instrumentation, and the header is used mainly
inside the instrumentation directory. Wheread the events header is later going
to be included in every file that needs to trigger an instrumentation event.

> Also, do we need all these many files, even for the public API?

The only other header, error.h, is later used in many other files.


> And why the .inc's?

To keep tidy headers with documentation, and the implementation details stashed
away on a separate file (like in the case of trace/).


> Thanks,
>   E.


Cheers,
  Lluis



Re: [Qemu-devel] [PATCH v4 08/20] instrument: [hmp] Add library loader

2017-09-10 Thread Lluís Vilanova
Markus Armbruster writes:

> Lluís Vilanova  writes:
>> Signed-off-by: Lluís Vilanova 
>> ---
>> hmp-commands.hx |   28 ++
>> monitor.c   |   60 
>> +++
>> 2 files changed, 88 insertions(+)
>> 
>> diff --git a/hmp-commands.hx b/hmp-commands.hx
>> index 1941e19932..703d7262f5 100644
>> --- a/hmp-commands.hx
>> +++ b/hmp-commands.hx
>> @@ -1858,6 +1858,34 @@ ETEXI
>> .sub_table  = info_cmds,
>> },
>> 
>> +{
>> +.name   = "instr-load",
>> +.args_type  = "path:F,args:s?",
>> +.params = "path [arg]",
>> +.help   = "load an instrumentation library",
>> +.cmd= hmp_instr_load,
>> +},
>> +
>> +STEXI
>> +@item instr-load @var{path} [args=value[,...]]
>> +@findex instr-load
>> +Load an instrumentation library.
>> +ETEXI
>> +
>> +{
>> +.name   = "instr-unload",
>> +.args_type  = "handle:i",
>> +.params = "handle",
>> +.help   = "unload an instrumentation library",
>> +.cmd= hmp_instr_unload,
>> +},
>> +
>> +STEXI
>> +@item instr-unload
>> +@findex instr-unload
>> +Unload an instrumentation library.
>> +ETEXI
>> +
>> STEXI
>> @end table
>> ETEXI

> Want #ifdef CONFIG_INSTRUMENT, see my review of the previous patch.

> See also my remark there on returning handles vs. passing in IDs.

>> diff --git a/monitor.c b/monitor.c
>> index e0f880107f..8a7684f860 100644
>> --- a/monitor.c
>> +++ b/monitor.c
>> @@ -2319,6 +2319,66 @@ int monitor_fd_param(Monitor *mon, const char 
>> *fdname, Error **errp)
>> return fd;
>> }
>> 
>> +static void hmp_instr_load(Monitor *mon, const QDict *qdict)
>> +{
>> +const char *path = qdict_get_str(qdict, "path");
>> +const char *str = qdict_get_try_str(qdict, "args");
>> +strList args;

> Blank line between last declaration and first statement, please.

>> +args.value = (str == NULL) ? NULL : (char *)str;

> What's wrong with

>args.value = (char *)str;

> ?

>> +args.next = NULL;
>> +InstrLoadResult *res = qmp_instr_load(path, args.value != NULL,
>> +  args.value != NULL ? &args : NULL,
>> +  NULL);
>> +switch (res->code) {
>> +case INSTR_LOAD_CODE_OK:
>> +monitor_printf(mon, "Handle: %"PRId64"\n", res->handle);
>> +monitor_printf(mon, "OK\n");
>> +break;
>> +case INSTR_LOAD_CODE_TOO_MANY:
>> +monitor_printf(mon, "Too many instrumentation libraries already 
>> loaded\n");
>> +break;
>> +case INSTR_LOAD_CODE_ERROR:
>> +monitor_printf(mon, "Instrumentation library returned a non-zero 
>> value during initialization");
>> +break;
>> +case INSTR_LOAD_CODE_DLERROR:
>> +monitor_printf(mon, "Error loading library: %s\n", res->msg);
>> +break;
>> +case INSTR_LOAD_CODE_UNAVAILABLE:
>> +monitor_printf(mon, "Service not available\n");
>> +break;
>> +default:
>> +fprintf(stderr, "Unknown instrumentation load code: %d", res->code);
>> +exit(1);

> Impossible conditions should be assertion failures, but it's a moot point
> because...

>> +break;
>> +}
>> +qapi_free_InstrLoadResult(res);
>> +}

> With qmp_instr_load() fixed to set an error on failure, this becomes
> something like

>InstrLoadResult *res = qmp_instr_load(path, args.value != NULL,
>  args.value != NULL ? &args : 
> NULL,
>  &err);
>if (err) {
>error_report_err(err);
>} else {
>monitor_printf(mon, "Handle: %"PRId64"\n", res->handle);
>monitor_printf(mon, "OK\n");
>}
>qapi_free_InstrLoadResult(res);

>> +
>> +static void hmp_instr_unload(Monitor *mon, const QDict *qdict)
>> +{
>> +int64_t handle = qdict_get_int(qdict, "handle");
>> +InstrUnloadResult *res = qmp_instr_unload(handle, NULL);
>> +switch (res->code) {
>> +case INSTR_UNLOAD_CODE_OK:
>> +monitor_printf(mon, "OK\n");
>> +break;
>> +case INSTR_UNLOAD_CODE_INVALID:
>> +monitor_printf(mon, "Invalid handle\n");
>> +break;
>> +case INSTR_UNLOAD_CODE_DLERROR:
>> +monitor_printf(mon, "Error unloading library: %s\n", res->msg);
>> +break;
>> +case INSTR_UNLOAD_CODE_UNAVAILABLE:
>> +monitor_printf(mon, "Service not available\n");
>> +break;
>> +default:
>> +fprintf(stderr, "Unknown instrumentation unload code: %d", 
>> res->code);
>> +exit(1);
>> +break;
>> +}
>> +qapi_free_InstrUnloadResult(res);
>> +}
>> +
>> /* Please update hmp-commands.hx when adding or changing commands */
>> static mon_cmd_t info_cmds[] = {
>> #include "hmp-commands-info.h"

> Likewise.

Done, thanks!

Lluis



Re: [Qemu-devel] [PATCH v4 07/20] instrument: [qapi] Add library loader

2017-09-10 Thread Lluís Vilanova
Markus Armbruster writes:

> I missed prior versions of this series.  Please cc: qapi-schema
> maintainers on all non-trivial schema patches.
> scripts/get_maintainer.pl points to them for this patch.

> Marc-André, semantic conflict with your QAPI conditionals series.  Just
> a heads-up, there's nothing for you to do about it right now.

> Lluís Vilanova  writes:

[...]
>> diff --git a/instrument/load.h b/instrument/load.h
>> index 2ddb2c6c19..f8a02e6849 100644
>> --- a/instrument/load.h
>> +++ b/instrument/load.h
>> @@ -25,6 +25,8 @@
>> * @INSTR_LOAD_DLERROR: Error with libdl (see dlerror).
>> *
>> * Error codes for instr_load().
>> + *
>> + * NOTE: Keep in sync with QAPI's #InstrLoadCode.
>> */
>> typedef enum {
>> INSTR_LOAD_OK,
>> @@ -40,6 +42,8 @@ typedef enum {
>> * @INSTR_UNLOAD_DLERROR: Error with libdl (see dlerror).
>> *
>> * Error codes for instr_unload().
>> + *
>> + * NOTE: Keep in sync with QAPI's #InstrUnloadCode.
>> */
>> typedef enum {
>> INSTR_UNLOAD_OK,

> Any particular reason why you can't simply use the QAPI-generated enum
> types?

Silly me, just missed that "optimization" :) But after reading your later
comments, I'll keep these and remove the QAPI-generated enums.


[...]
>> diff --git a/instrument/qmp.c b/instrument/qmp.c
>> new file mode 100644
>> index 00..c36960c12f
>> --- /dev/null
>> +++ b/instrument/qmp.c
>> @@ -0,0 +1,88 @@
>> +/*
>> + * QMP interface for instrumentation control commands.
>> + *
>> + * Copyright (C) 2012-2017 Lluís Vilanova 
>> + *
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#include "qemu/osdep.h"
>> +#include "qemu-common.h"
>> +#include "qapi/qmp/qerror.h"
>> +#include "qmp-commands.h"
>> +
>> +#include 

> System headers go right after "qemu/osdep.h".

>> +
>> +#include "instrument/load.h"
>> +
>> +
>> +

> Fewer blank lines would do.

>> +InstrLoadResult *qmp_instr_load(const char * path,
>> +bool have_args, strList * args,

> checkpatch ERROR: "foo * bar" should be "foo *bar"

> Please feed it all your patches, and carefully consider which of its
> complaints you should address.

>> +Error **errp)
>> +{
>> +InstrLoadResult *res = g_malloc0(sizeof(*res));
>> +
>> +#if defined(CONFIG_INSTRUMENT)
>> +int argc = 0;
>> +const char **argv = NULL;
>> +
>> +strList *entry = have_args ? args : NULL;
>> +while (entry != NULL) {
>> +argv = realloc(argv, sizeof(*argv) * (argc + 1));
>> +argv[argc] = entry->value;
>> +argc++;
>> +entry = entry->next;
>> +}
>> +
>> +InstrLoadError code = instr_load(path, argc, argv, &res->handle);
>> +switch (code) {
>> +case INSTR_LOAD_OK:
>> +res->code = INSTR_LOAD_CODE_OK;
>> +res->has_handle = true;
>> +break;
>> +case INSTR_LOAD_TOO_MANY:
>> +res->code = INSTR_LOAD_CODE_TOO_MANY;
>> +break;
>> +case INSTR_LOAD_ERROR:
>> +res->code = INSTR_LOAD_CODE_ERROR;
>> +break;
>> +case INSTR_LOAD_DLERROR:
>> +res->has_msg = true;
>> +res->msg = dlerror();
>> +res->code = INSTR_LOAD_CODE_DLERROR;
>> +break;
>> +}
>> +#else
>> +res->code = INSTR_LOAD_CODE_UNAVAILABLE;
>> +#endif
>> +
>> +return res;
>> +}
>> +
>> +InstrUnloadResult *qmp_instr_unload(int64_t handle, Error **errp)
>> +{
>> +InstrUnloadResult *res = g_malloc0(sizeof(*res));
>> +
>> +#if defined(CONFIG_INSTRUMENT)
>> +InstrUnloadError code = instr_unload(handle);
>> +switch (code) {
>> +case INSTR_UNLOAD_OK:
>> +res->code = INSTR_UNLOAD_CODE_OK;
>> +break;
>> +case INSTR_UNLOAD_INVALID:
>> +res->code = INSTR_UNLOAD_CODE_INVALID;
>> +break;
>> +case INSTR_UNLOAD_DLERROR:
>> +res->has_msg = true;
>> +res->msg = dlerror();
>> +break;
>> +res->code = INSTR_UNLOAD_CODE_DLERROR;
>> +}
>> +#else
>> +res->code = INSTR_UNLOAD_CODE_UNAVAILABLE;
>> +#endif
&

Re: [Qemu-devel] [PATCH v4 03/20] instrument: Add generic library loader

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 06, 2017 at 20:34:48 +0300, Lluís Vilanova wrote:
>> Signed-off-by: Lluís Vilanova 
>> ---
> (snip)
>> diff --git a/configure b/configure
>> index 80dcc91c98..05bd7b1950 100755
>> --- a/configure
>> +++ b/configure
>> @@ -6034,6 +6034,8 @@ fi
>> echo "CONFIG_TRACE_FILE=$trace_file" >> $config_host_mak
>> 
>> if test "$instrument" = "yes"; then
>> +  LDFLAGS="-rdynamic $LDFLAGS"  # limit symbols available to clients

> -rdynamic exports all objects to the instrumenters, not the other way around.
> You can see it with nm(1).

I'll send a minor fix for this in next version.


> BTW I'm using ebf447b5b from your qemu-dbi repo. Is that the same as this
> patchset? It doesn't compile with --enable-instrument:
> $ make
>   CC  x86_64-linux-user/instrument/trace.o
> /data/src/qemu2/instrument/trace.c:12:30: fatal error: qemu-instr/trace.h: No 
> such file or directory
> compilation terminated.
> /data/src/qemu2/rules.mak:66: recipe for target 'instrument/trace.o' failed
> make[1]: *** [instrument/trace.o] Error 1
> Makefile:326: recipe for target 'subdir-x86_64-linux-user' failed
> make: *** [subdir-x86_64-linux-user] Error 2

No, I started using a separate branch to keep the old patches around in the
meantime.


>   Emilio


Lluis



Re: [Qemu-devel] [PATCH v4 00/20] instrument: Add basic event instrumentation

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Wed, Sep 06, 2017 at 20:22:41 +0300, Lluís Vilanova wrote:
>> This series adds an API to add instrumentation events.
>> 
>> It also provides additional APIs for:
>> * Controlling tracing events

> hmm didn't Stefan say that tracing should be decoupled from this?

>> * Peek/poke guest memory
>> 
>> There's still missing APIs for (can be added in later series?):
>> * Provide something like tracing's per-vCPU trace states (i.e., so that each
>> vCPU can have different instrumentation code). It's still not clear to me if
>> we should extend the per-vCPU bitmap with instrumentation events, or 
>> otherwise
>> somehow reuse the bits in tracing events (since they're currently limited).

> As I said in the description of my alternative implementation [*], I don't see
> much value in having per-vCPU events, as most instrumenters just care about
> the guest application/system. I can only think of cases where the instrumenter
> is only interested in a guest process (in system-mode), but that'd be ugly
> anyway (would need to change both QEMU and the guest kernel to track the pid).

Yes, that's exactly what I was using it for (track guest processes in softmmu
mode).


> If the need ever arises, we could add __vcpu(cpu_index) registration 
> functions.

You still need the functionality I cited if you're using
"qi_event_gen_guest_mem_before_exec" or similar.


> [*] https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg01446.html

>   E.

Cheers,
  Lluis



Re: [Qemu-devel] [PATCH v4 00/20] instrument: Add basic event instrumentation

2017-09-10 Thread Lluís Vilanova
Emilio G Cota writes:

> On Thu, Sep 07, 2017 at 12:58:05 +0200, Markus Armbruster wrote:
>> Lluís Vilanova  writes:
>> 
>> > This series adds an API to add instrumentation events.
>> >
>> > It also provides additional APIs for:
>> > * Controlling tracing events
>> > * Peek/poke guest memory
>> >
>> > There's still missing APIs for (can be added in later series?):
>> > * Provide something like tracing's per-vCPU trace states (i.e., so that 
>> > each
>> >   vCPU can have different instrumentation code). It's still not clear to 
>> > me if
>> >   we should extend the per-vCPU bitmap with instrumentation events, or 
>> > otherwise
>> >   somehow reuse the bits in tracing events (since they're currently 
>> > limited).
>> > * Peek/poke guest registers
>> >
>> > The instrumentation code is dynamically loaded as a library into QEMU 
>> > either
>> > when it starts or later using its remote control interfaces.
>> >
>> > Signed-off-by: Lluís Vilanova 
>> 
>> Taking a step back.
>> 
>> This looks like a way to dynamically load arbitrary code.  What
>> interfaces can this code use?  Your cover letter should answer this.
>> 
>> As long as the answer is "everything the dynamic linker is willing to
>> resolve", this series heading nowhere.  We can talk about an interface
>> for plugins, but "anything goes" is not on the menu.

> A simple solution to this is to only export the API symbols by passing
> --dynamic-file to the linker -- see patch 2 of the following series for an
> example (ELF-only, although I'm pretty sure this can be achieved on Windows
> as well):
>   https://lists.gnu.org/archive/html/qemu-devel/2017-09/msg01446.html

Sorry, I adapted the instr series in a rush and missed your series. I'm now
preparing a new version that fixes this without the flags you mention (missed to
add a line in this series).


Thanks,
  Lluis



[Qemu-devel] [PATCH v2] trace: Immediately apply per-vCPU state changes if a vCPU is being created

2017-09-10 Thread Lluís Vilanova
Right now, function trace_event_set_vcpu_state_dynamic() asynchronously enables
events in the case a vCPU is executing TCG code. If the vCPU is being created
this makes some events like "guest_cpu_enter" to not be traced.

Signed-off-by: Lluís Vilanova 
Reviewed-by: Emilio G. Cora 
---

Changes in v2
=

* Use RUN_ON_CPU_NULL [Emilio G. Cota].
* Rebase on fcea73709b.
---
 trace/control-target.c |   18 +++---
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/trace/control-target.c b/trace/control-target.c
index 4e36101997..706b2cee9d 100644
--- a/trace/control-target.c
+++ b/trace/control-target.c
@@ -88,13 +88,17 @@ void trace_event_set_vcpu_state_dynamic(CPUState *vcpu,
 clear_bit(vcpu_id, vcpu->trace_dstate_delayed);
 (*ev->dstate)--;
 }
-/*
- * Delay changes until next TB; we want all TBs to be built from a
- * single set of dstate values to ensure consistency of generated
- * tracing code.
- */
-async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic,
- RUN_ON_CPU_NULL);
+if (vcpu->created) {
+/*
+ * Delay changes until next TB; we want all TBs to be built from a
+ * single set of dstate values to ensure consistency of generated
+ * tracing code.
+ */
+async_run_on_cpu(vcpu, trace_event_synchronize_vcpu_state_dynamic,
+ RUN_ON_CPU_NULL);
+} else {
+trace_event_synchronize_vcpu_state_dynamic(vcpu, RUN_ON_CPU_NULL);
+}
 }
 }
 




[Qemu-devel] [PATCH 7/7] trace: Add event "guest_inst_info_after"

2017-09-10 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c |   18 ++
 trace-events   |8 
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index c010aeee45..d3039e7fd2 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -36,6 +36,7 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
  CPUState *cpu, TranslationBlock *tb)
 {
 target_ulong pc_bbl, pc_insn = 0;
+unsigned int insn_size = 0;
 bool translated_insn = false;
 int max_insns;
 
@@ -82,6 +83,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 /* Tracing after (previous instruction) */
 if (db->num_insns > 0) {
 trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
+trace_guest_inst_info_after_tcg(
+cpu, tcg_ctx.tcg_env, pc_insn, insn_size);
 }
 pc_insn = db->pc_next;
 
@@ -145,7 +148,7 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 translated_insn = true;
 /* Tracing after (patched values) */
 if (TRACE_GUEST_INST_INFO_BEFORE_EXEC_ENABLED) {
-unsigned int insn_size = db->pc_next - pc_insn;
+insn_size = db->pc_next - pc_insn;
 tcg_set_insn_param(insn_size_opcode_idx, 1, insn_size);
 }
 
@@ -164,7 +167,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 
 /* Tracing after */
 if (TRACE_GUEST_BBL_AFTER_ENABLED ||
-TRACE_GUEST_INST_AFTER_ENABLED) {
+TRACE_GUEST_INST_AFTER_ENABLED ||
+TRACE_GUEST_INST_INFO_AFTER_ENABLED) {
 tcg_ctx.disas.in_guest_code = false;
 if (tcg_ctx.disas.inline_label == NULL) {
 tcg_ctx.disas.inline_label = gen_new_inline_label();
@@ -175,6 +179,10 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 if (TRACE_GUEST_INST_AFTER_ENABLED && translated_insn) {
 trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
 }
+if (TRACE_GUEST_INST_INFO_AFTER_ENABLED && translated_insn) {
+trace_guest_inst_info_after_tcg(
+cpu, tcg_ctx.tcg_env, pc_insn, insn_size);
+}
 if (TRACE_GUEST_BBL_AFTER_ENABLED) {
 trace_guest_bbl_after_tcg(cpu, tcg_ctx.tcg_env, pc_bbl);
 }
@@ -207,7 +215,8 @@ void translator__gen_goto_tb(TCGContext *ctx)
 {
 if (ctx->disas.in_guest_code &&
 (TRACE_GUEST_BBL_AFTER_ENABLED ||
- TRACE_GUEST_INST_AFTER_ENABLED)) {
+ TRACE_GUEST_INST_AFTER_ENABLED ||
+ TRACE_GUEST_INST_INFO_AFTER_ENABLED)) {
 if (ctx->disas.inline_label == NULL) {
 ctx->disas.inline_label = gen_new_inline_label();
 }
@@ -221,7 +230,8 @@ void translator__gen_exit_tb(TCGContext *ctx)
 {
 if (ctx->disas.in_guest_code && !ctx->disas.seen_goto_tb &&
 (TRACE_GUEST_BBL_AFTER_ENABLED ||
- TRACE_GUEST_INST_AFTER_ENABLED)) {
+ TRACE_GUEST_INST_AFTER_ENABLED ||
+ TRACE_GUEST_INST_INFO_AFTER_ENABLED)) {
 if (ctx->disas.inline_label == NULL) {
 ctx->disas.inline_label = gen_new_inline_label();
 }
diff --git a/trace-events b/trace-events
index c477302d8d..73d797cb48 100644
--- a/trace-events
+++ b/trace-events
@@ -135,6 +135,14 @@ vcpu tcg guest_inst_after(uint64_t vaddr) 
"vaddr=0x%016"PRIx64, "vaddr=0x%016"PR
 # Targets: TCG(all)
 disable vcpu tcg guest_inst_info_before(uint64_t vaddr, TCGv_i32 size) 
"vaddr=0x%016"PRIx64, "vaddr=0x%016"PRIx64" size=%d"
 
+# @vaddr: Instruction's virtual address
+# @size: Instruction's size in bytes
+#
+# Same as 'guest_inst_after', with additional information.
+#
+# Targets: TCG(all)
+disable vcpu tcg guest_inst_info_after(uint64_t vaddr, uint32_t size) 
"vaddr=0x%016"PRIx64" size=%d", "vaddr=0x%016"PRIx64" size=%d"
+
 # @vaddr: Access' virtual address.
 # @info : Access' information (see below).
 #




[Qemu-devel] [PATCH 6/7] trace: Add event "guest_inst_after"

2017-09-10 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c |   23 ++-
 trace-events   |8 
 2 files changed, 26 insertions(+), 5 deletions(-)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index d66d601c89..c010aeee45 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -35,7 +35,8 @@ void translator_loop_temp_check(DisasContextBase *db)
 void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
  CPUState *cpu, TranslationBlock *tb)
 {
-target_ulong pc_bbl;
+target_ulong pc_bbl, pc_insn = 0;
+bool translated_insn = false;
 int max_insns;
 
 /* Initialize DisasContext */
@@ -75,10 +76,15 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
 while (true) {
-target_ulong pc_insn = db->pc_next;
 TCGv_i32 insn_size_tcg = 0;
 int insn_size_opcode_idx;
 
+/* Tracing after (previous instruction) */
+if (db->num_insns > 0) {
+trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
+}
+pc_insn = db->pc_next;
+
 db->num_insns++;
 if (db->num_insns == 1) {
 tcg_ctx.disas.in_guest_code = true;
@@ -136,6 +142,7 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 ops->translate_insn(db, cpu);
 }
 
+translated_insn = true;
 /* Tracing after (patched values) */
 if (TRACE_GUEST_INST_INFO_BEFORE_EXEC_ENABLED) {
 unsigned int insn_size = db->pc_next - pc_insn;
@@ -156,7 +163,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 }
 
 /* Tracing after */
-if (TRACE_GUEST_BBL_AFTER_ENABLED) {
+if (TRACE_GUEST_BBL_AFTER_ENABLED ||
+TRACE_GUEST_INST_AFTER_ENABLED) {
 tcg_ctx.disas.in_guest_code = false;
 if (tcg_ctx.disas.inline_label == NULL) {
 tcg_ctx.disas.inline_label = gen_new_inline_label();
@@ -164,6 +172,9 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 
 gen_set_inline_region_begin(tcg_ctx.disas.inline_label);
 
+if (TRACE_GUEST_INST_AFTER_ENABLED && translated_insn) {
+trace_guest_inst_after_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
+}
 if (TRACE_GUEST_BBL_AFTER_ENABLED) {
 trace_guest_bbl_after_tcg(cpu, tcg_ctx.tcg_env, pc_bbl);
 }
@@ -195,7 +206,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 void translator__gen_goto_tb(TCGContext *ctx)
 {
 if (ctx->disas.in_guest_code &&
-(TRACE_GUEST_BBL_AFTER_ENABLED)) {
+(TRACE_GUEST_BBL_AFTER_ENABLED ||
+ TRACE_GUEST_INST_AFTER_ENABLED)) {
 if (ctx->disas.inline_label == NULL) {
 ctx->disas.inline_label = gen_new_inline_label();
 }
@@ -208,7 +220,8 @@ void translator__gen_goto_tb(TCGContext *ctx)
 void translator__gen_exit_tb(TCGContext *ctx)
 {
 if (ctx->disas.in_guest_code && !ctx->disas.seen_goto_tb &&
-(TRACE_GUEST_BBL_AFTER_ENABLED)) {
+(TRACE_GUEST_BBL_AFTER_ENABLED ||
+ TRACE_GUEST_INST_AFTER_ENABLED)) {
 if (ctx->disas.inline_label == NULL) {
 ctx->disas.inline_label = gen_new_inline_label();
 }
diff --git a/trace-events b/trace-events
index ce54bb4993..c477302d8d 100644
--- a/trace-events
+++ b/trace-events
@@ -118,6 +118,14 @@ vcpu tcg guest_bbl_after(uint64_t vaddr) 
"vaddr=0x%016"PRIx64, "vaddr=0x%016"PRI
 # Targets: TCG(all)
 vcpu tcg guest_inst_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
 
+# @vaddr: Instruction's virtual address
+#
+# Mark end of instruction execution (after its operations have taken effect).
+#
+# Mode: user, softmmu
+# Targets: TCG(all)
+vcpu tcg guest_inst_after(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
+
 # @vaddr: Instruction's virtual address
 # @size: Instruction's size in bytes
 #




[Qemu-devel] [PATCH 5/7] trace: Add event "guest_bbl_after"

2017-09-10 Thread Lluís Vilanova
Need to use "TCG inlining" to avoid showing a trace entry for each exit
point (up to two per BBL).

Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c|   54 +
 include/exec/translator.h |   22 ++
 tcg/tcg-op.c  |2 ++
 tcg/tcg-op.h  |1 +
 tcg/tcg.h |5 
 trace-events  |   11 +
 6 files changed, 94 insertions(+), 1 deletion(-)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 6598931171..d66d601c89 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -35,6 +35,7 @@ void translator_loop_temp_check(DisasContextBase *db)
 void translator_loop(const TranslatorOps *ops, DisasContextBase *db,
  CPUState *cpu, TranslationBlock *tb)
 {
+target_ulong pc_bbl;
 int max_insns;
 
 /* Initialize DisasContext */
@@ -63,6 +64,11 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 /* Reset the temp count so that we can identify leaks */
 tcg_clear_temp_count();
 
+/* Tracking gen_goto_tb / gen_exit_tb */
+pc_bbl = db->pc_first;
+tcg_ctx.disas.seen_goto_tb = false;
+tcg_ctx.disas.in_guest_code = false;
+
 /* Start translating.  */
 gen_tb_start(db->tb);
 ops->tb_start(db, cpu);
@@ -74,6 +80,11 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 int insn_size_opcode_idx;
 
 db->num_insns++;
+if (db->num_insns == 1) {
+tcg_ctx.disas.in_guest_code = true;
+tcg_ctx.disas.inline_label = NULL;
+}
+
 ops->insn_start(db, cpu);
 tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
@@ -144,6 +155,22 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 }
 }
 
+/* Tracing after */
+if (TRACE_GUEST_BBL_AFTER_ENABLED) {
+tcg_ctx.disas.in_guest_code = false;
+if (tcg_ctx.disas.inline_label == NULL) {
+tcg_ctx.disas.inline_label = gen_new_inline_label();
+}
+
+gen_set_inline_region_begin(tcg_ctx.disas.inline_label);
+
+if (TRACE_GUEST_BBL_AFTER_ENABLED) {
+trace_guest_bbl_after_tcg(cpu, tcg_ctx.tcg_env, pc_bbl);
+}
+
+gen_set_inline_region_end(tcg_ctx.disas.inline_label);
+}
+
 /* Emit code to exit the TB, as indicated by db->is_jmp.  */
 ops->tb_stop(db, cpu);
 gen_tb_end(db->tb, db->num_insns);
@@ -163,3 +190,30 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 }
 #endif
 }
+
+
+void translator__gen_goto_tb(TCGContext *ctx)
+{
+if (ctx->disas.in_guest_code &&
+(TRACE_GUEST_BBL_AFTER_ENABLED)) {
+if (ctx->disas.inline_label == NULL) {
+ctx->disas.inline_label = gen_new_inline_label();
+}
+gen_set_inline_point(ctx->disas.inline_label);
+/* disable next exit_tb */
+ctx->disas.seen_goto_tb = true;
+}
+}
+
+void translator__gen_exit_tb(TCGContext *ctx)
+{
+if (ctx->disas.in_guest_code && !ctx->disas.seen_goto_tb &&
+(TRACE_GUEST_BBL_AFTER_ENABLED)) {
+if (ctx->disas.inline_label == NULL) {
+ctx->disas.inline_label = gen_new_inline_label();
+}
+gen_set_inline_point(ctx->disas.inline_label);
+/* enable next exit_tb */
+ctx->disas.seen_goto_tb = false;
+}
+}
diff --git a/include/exec/translator.h b/include/exec/translator.h
index e2dc2a04ae..83aeea59a1 100644
--- a/include/exec/translator.h
+++ b/include/exec/translator.h
@@ -20,7 +20,6 @@
 
 
 #include "exec/exec-all.h"
-#include "tcg/tcg.h"
 
 
 /**
@@ -71,6 +70,21 @@ typedef struct DisasContextBase {
 bool singlestep_enabled;
 } DisasContextBase;
 
+/**
+ * TCGContextDisas:
+ * @seen_goto_tb: Whether we've seen a call to tcg_gen_goto_tb().
+ * @in_guest_code: Whether we're generating guest code (or supporting
+ * boilerplate otherwise).
+ * @inline_label: Inline label.
+ *
+ * Extensions to #TCGContext specific to the generic translation framework.
+ */
+typedef struct TCGContextDisas {
+bool seen_goto_tb;
+bool in_guest_code;
+TCGInlineLabel *inline_label;
+} TCGContextDisas;
+
 /**
  * TranslatorOps:
  * @init_disas_context:
@@ -117,6 +131,8 @@ typedef struct TranslatorOps {
 void (*disas_log)(const DisasContextBase *db, CPUState *cpu);
 } TranslatorOps;
 
+#include "tcg/tcg.h"
+
 /**
  * translator_loop:
  * @ops: Target-specific operations.
@@ -141,4 +157,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 
 void translator_loop_temp_check(DisasContextBase *db);
 
+/* Internal functions to hook tracing into */
+void translator__gen_goto_tb(TCGContext *ctx);
+void translator__gen_exit_tb(TCGContext *ctx);
+
 #endif  /* EXEC__T

[Qemu-devel] [PATCH 4/7] tcg: Add support for "inlining" regions of code

2017-09-10 Thread Lluís Vilanova
TCG BBLs and instructions have multiple exit points from where to raise
tracing events, but some of the necessary information in the generic
disassembly infrastructure is not available until after generating these
exit points.

This patch adds support for "inline points" (where the tracing code will
be placed), and "inline regions" (which identify the TCG code that must
be inlined). The TCG compiler will basically copy each inline region to
any inline points that reference it.

Signed-off-by: Lluís Vilanova 
---
 include/qemu/log.h  |1 
 include/qemu/typedefs.h |1 
 tcg/tcg-op.h|   39 +++
 tcg/tcg-opc.h   |3 +
 tcg/tcg.c   |  166 +++
 tcg/tcg.h   |   18 +
 util/log.c  |2 +
 7 files changed, 230 insertions(+)

diff --git a/include/qemu/log.h b/include/qemu/log.h
index a50e994c21..23acc63c73 100644
--- a/include/qemu/log.h
+++ b/include/qemu/log.h
@@ -43,6 +43,7 @@ static inline bool qemu_log_separate(void)
 #define CPU_LOG_PAGE   (1 << 14)
 #define LOG_TRACE  (1 << 15)
 #define CPU_LOG_TB_OP_IND  (1 << 16)
+#define CPU_LOG_TB_OP_INLINE (1 << 17)
 
 /* Returns true if a bit is set in the current loglevel mask
  */
diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h
index 39bc8351a3..2fb5670af3 100644
--- a/include/qemu/typedefs.h
+++ b/include/qemu/typedefs.h
@@ -96,6 +96,7 @@ typedef struct SerialState SerialState;
 typedef struct SHPCDevice SHPCDevice;
 typedef struct SMBusDevice SMBusDevice;
 typedef struct SSIBus SSIBus;
+typedef struct TCGInlineLabel TCGInlineLabel;
 typedef struct uWireSlave uWireSlave;
 typedef struct VirtIODevice VirtIODevice;
 typedef struct Visitor Visitor;
diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h
index 5d3278f243..da3784f8f2 100644
--- a/tcg/tcg-op.h
+++ b/tcg/tcg-op.h
@@ -326,6 +326,45 @@ void tcg_gen_ext16u_i32(TCGv_i32 ret, TCGv_i32 arg);
 void tcg_gen_bswap16_i32(TCGv_i32 ret, TCGv_i32 arg);
 void tcg_gen_bswap32_i32(TCGv_i32 ret, TCGv_i32 arg);
 
+static inline int _get_inline_index(TCGInlineLabel *l)
+{
+TCGContext *s = &tcg_ctx;
+return l - s->inline_labels;
+}
+
+static inline void gen_set_inline_point(TCGInlineLabel *l)
+{
+TCGContext *s = &tcg_ctx;
+TCGInlinePoint *p = tcg_malloc(sizeof(TCGInlinePoint));
+p->op_idx = s->gen_next_op_idx;
+p->next_point = l->first_point;
+l->first_point = p;
+tcg_gen_op1i(INDEX_op_set_inline_point,
+ _get_inline_index(l));
+}
+
+static inline void gen_set_inline_region_begin(TCGInlineLabel *l)
+{
+TCGContext *s = &tcg_ctx;
+if (l->begin_op_idx != -1) {
+tcg_abort();
+}
+l->begin_op_idx = s->gen_next_op_idx;
+tcg_gen_op1i(INDEX_op_set_inline_region_begin,
+ _get_inline_index(l));
+}
+
+static inline void gen_set_inline_region_end(TCGInlineLabel *l)
+{
+TCGContext *s = &tcg_ctx;
+if (l->begin_op_idx == -1) {
+tcg_abort();
+}
+l->end_op_idx = s->gen_next_op_idx;
+tcg_gen_op1i(INDEX_op_set_inline_region_end,
+ _get_inline_index(l));
+}
+
 static inline void tcg_gen_discard_i32(TCGv_i32 arg)
 {
 tcg_gen_op1_i32(INDEX_op_discard, arg);
diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h
index 956fb1e9f3..279ac0dc1f 100644
--- a/tcg/tcg-opc.h
+++ b/tcg/tcg-opc.h
@@ -29,6 +29,9 @@
 /* predefined ops */
 DEF(discard, 1, 0, 0, TCG_OPF_NOT_PRESENT)
 DEF(set_label, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_NOT_PRESENT)
+DEF(set_inline_point, 0, 0, 1, TCG_OPF_NOT_PRESENT)
+DEF(set_inline_region_begin, 0, 0, 1, TCG_OPF_NOT_PRESENT)
+DEF(set_inline_region_end, 0, 0, 1, TCG_OPF_NOT_PRESENT)
 
 /* variable number of parameters */
 DEF(call, 0, 0, 3, TCG_OPF_CALL_CLOBBER | TCG_OPF_NOT_PRESENT)
diff --git a/tcg/tcg.c b/tcg/tcg.c
index fd8a3dfe93..b48196da27 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -251,6 +251,23 @@ TCGLabel *gen_new_label(void)
 return l;
 }
 
+TCGInlineLabel *gen_new_inline_label(void)
+{
+TCGContext *s = &tcg_ctx;
+int idx;
+TCGInlineLabel *l;
+
+if (s->nb_inline_labels >= TCG_MAX_INLINE_LABELS) {
+tcg_abort();
+}
+idx = s->nb_inline_labels++;
+l = &s->inline_labels[idx];
+l->first_point = NULL;
+l->begin_op_idx = -1;
+l->end_op_idx = -1;
+return l;
+}
+
 #include "tcg-target.inc.c"
 
 /* pool based memory allocation */
@@ -462,6 +479,10 @@ void tcg_func_start(TCGContext *s)
 s->nb_labels = 0;
 s->current_frame_offset = s->frame_start;
 
+s->inline_labels = tcg_malloc(sizeof(TCGInlineLabel) *
+  TCG_MAX_INLINE_LABELS);
+s->nb_inline_labels = 0;
+
 #ifdef CONFIG_DEBUG_TCG
 s->goto_tb_issue_mask = 0;
 #endif
@@ -1423,6 +1444,139 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t 
*temp_state)
 }

[Qemu-devel] [PATCH 3/7] trace: Add event "guest_inst_info_before"

2017-09-10 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c |   18 ++
 trace-events   |9 +
 2 files changed, 27 insertions(+)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 287d27b4f7..6598931171 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -70,6 +70,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 
 while (true) {
 target_ulong pc_insn = db->pc_next;
+TCGv_i32 insn_size_tcg = 0;
+int insn_size_opcode_idx;
 
 db->num_insns++;
 ops->insn_start(db, cpu);
@@ -99,6 +101,16 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 trace_guest_bbl_before_tcg(cpu, tcg_ctx.tcg_env, db->pc_first);
 }
 trace_guest_inst_before_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
+if (TRACE_GUEST_INST_INFO_BEFORE_EXEC_ENABLED) {
+insn_size_tcg = tcg_temp_new_i32();
+insn_size_opcode_idx = tcg_op_buf_count();
+tcg_gen_movi_i32(insn_size_tcg, 0xdeadbeef);
+
+trace_guest_inst_info_before_tcg(
+cpu, tcg_ctx.tcg_env, pc_insn, insn_size_tcg);
+
+tcg_temp_free_i32(insn_size_tcg);
+}
 
 /* Disassemble one instruction.  The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be
@@ -113,6 +125,12 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 ops->translate_insn(db, cpu);
 }
 
+/* Tracing after (patched values) */
+if (TRACE_GUEST_INST_INFO_BEFORE_EXEC_ENABLED) {
+unsigned int insn_size = db->pc_next - pc_insn;
+tcg_set_insn_param(insn_size_opcode_idx, 1, insn_size);
+}
+
 /* Stop translation if translate_insn so indicated.  */
 if (db->is_jmp != DISAS_NEXT) {
 break;
diff --git a/trace-events b/trace-events
index 46457c6158..4e61697297 100644
--- a/trace-events
+++ b/trace-events
@@ -107,6 +107,15 @@ vcpu tcg guest_bbl_before(uint64_t vaddr) 
"vaddr=0x%016"PRIx64, "vaddr=0x%016"PR
 # Targets: TCG(all)
 vcpu tcg guest_inst_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
 
+# @vaddr: Instruction's virtual address
+# @size: Instruction's size in bytes
+#
+# Same as 'guest_inst_before', with additional information.
+#
+# Mode: user, softmmu
+# Targets: TCG(all)
+disable vcpu tcg guest_inst_info_before(uint64_t vaddr, TCGv_i32 size) 
"vaddr=0x%016"PRIx64, "vaddr=0x%016"PRIx64" size=%d"
+
 # @vaddr: Access' virtual address.
 # @info : Access' information (see below).
 #




[Qemu-devel] [PATCH 2/7] trace: Add event "guest_inst_before"

2017-09-10 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c |3 +++
 trace-events   |8 
 2 files changed, 11 insertions(+)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index 91b3b0da32..287d27b4f7 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -69,6 +69,8 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
 
 while (true) {
+target_ulong pc_insn = db->pc_next;
+
 db->num_insns++;
 ops->insn_start(db, cpu);
 tcg_debug_assert(db->is_jmp == DISAS_NEXT);  /* no early exit */
@@ -96,6 +98,7 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 if (db->num_insns == 1) {
 trace_guest_bbl_before_tcg(cpu, tcg_ctx.tcg_env, db->pc_first);
 }
+trace_guest_inst_before_tcg(cpu, tcg_ctx.tcg_env, pc_insn);
 
 /* Disassemble one instruction.  The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be
diff --git a/trace-events b/trace-events
index d242f54254..46457c6158 100644
--- a/trace-events
+++ b/trace-events
@@ -99,6 +99,14 @@ vcpu guest_cpu_reset(void)
 # Targets: TCG(all)
 vcpu tcg guest_bbl_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
 
+# @vaddr: Instruction's virtual address
+#
+# Mark start of instruction execution (before anything gets really executed).
+#
+# Mode: user, softmmu
+# Targets: TCG(all)
+vcpu tcg guest_inst_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
+
 # @vaddr: Access' virtual address.
 # @info : Access' information (see below).
 #




[Qemu-devel] [PATCH 1/7] trace: Add event "guest_bbl_before"

2017-09-10 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 accel/tcg/translator.c |6 ++
 trace-events   |   11 +++
 2 files changed, 17 insertions(+)

diff --git a/accel/tcg/translator.c b/accel/tcg/translator.c
index afa3af478a..91b3b0da32 100644
--- a/accel/tcg/translator.c
+++ b/accel/tcg/translator.c
@@ -13,6 +13,7 @@
 #include "cpu.h"
 #include "tcg/tcg.h"
 #include "tcg/tcg-op.h"
+#include "trace-tcg.h"
 #include "exec/exec-all.h"
 #include "exec/gen-icount.h"
 #include "exec/log.h"
@@ -91,6 +92,11 @@ void translator_loop(const TranslatorOps *ops, 
DisasContextBase *db,
 }
 }
 
+/* Tracing before */
+if (db->num_insns == 1) {
+trace_guest_bbl_before_tcg(cpu, tcg_ctx.tcg_env, db->pc_first);
+}
+
 /* Disassemble one instruction.  The translate_insn hook should
update db->pc_next and db->is_jmp to indicate what should be
done next -- either exiting this loop or locate the start of
diff --git a/trace-events b/trace-events
index 1f50f56d9d..d242f54254 100644
--- a/trace-events
+++ b/trace-events
@@ -88,6 +88,17 @@ vcpu guest_cpu_exit(void)
 # Targets: all
 vcpu guest_cpu_reset(void)
 
+
+## Guest code
+
+# @vaddr: BBL's starting virtual address
+#
+# Mark start of BBL execution (before anything gets really executed).
+#
+# Mode: user, softmmu
+# Targets: TCG(all)
+vcpu tcg guest_bbl_before(uint64_t vaddr) "vaddr=0x%016"PRIx64, 
"vaddr=0x%016"PRIx64
+
 # @vaddr: Access' virtual address.
 # @info : Access' information (see below).
 #




[Qemu-devel] [PATCH 0/7] trace: Add guest code events

2017-09-10 Thread Lluís Vilanova
Adds events to trace guest code execution.

Events with additional info are disabled by default to minimize overheads, since
that additional information might not be necessarily needed.

Signed-off-by: Lluís Vilanova 
---

Lluís Vilanova (7):
  trace: Add event "guest_bbl_before"
  trace: Add event "guest_inst_before"
  trace: Add event "guest_inst_info_before"
  tcg: Add support for "inlining" regions of code
  trace: Add event "guest_bbl_after"
  trace: Add event "guest_inst_after"
  trace: Add event "guest_inst_info_after"


 accel/tcg/translator.c|  104 
 include/exec/translator.h |   22 ++
 include/qemu/log.h|1 
 include/qemu/typedefs.h   |1 
 tcg/tcg-op.c  |2 +
 tcg/tcg-op.h  |   40 +++
 tcg/tcg-opc.h |3 +
 tcg/tcg.c |  166 +
 tcg/tcg.h |   23 ++
 trace-events  |   55 +++
 util/log.c|2 +
 11 files changed, 418 insertions(+), 1 deletion(-)


To: qemu-devel@nongnu.org
Cc: Stefan Hajnoczi 



[Qemu-devel] [PATCH v4 20/20] instrument: Add API to manipulate guest memory

2017-09-06 Thread Lluís Vilanova
It includes access to the guest's memory and vCPU registers.

Signed-off-by: Lluís Vilanova 
---
 instrument/Makefile.objs  |1 
 instrument/qemu-instr/state.h |  104 +
 instrument/state.c|   72 
 3 files changed, 177 insertions(+)
 create mode 100644 instrument/qemu-instr/state.h
 create mode 100644 instrument/state.c

diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 8258dbfa79..c9bc4e75f4 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -6,3 +6,4 @@ target-obj-y += qmp.o
 
 target-obj-$(CONFIG_INSTRUMENT) += control.o
 target-obj-$(CONFIG_INSTRUMENT) += trace.o
+target-obj-$(CONFIG_INSTRUMENT) += state.o
diff --git a/instrument/qemu-instr/state.h b/instrument/qemu-instr/state.h
new file mode 100644
index 00..0ae6255fe5
--- /dev/null
+++ b/instrument/qemu-instr/state.h
@@ -0,0 +1,104 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__STATE_H
+#define QI__STATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include 
+
+
+/**
+ * qi_mem_read_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to read could be translated.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ *
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_virt:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Starting virtual address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of virtual addresses to write could be 
translated.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_virt(QICPU vcpu, uint64_t vaddr, size_t size, void *buf);
+
+/**
+ * qi_mem_virt_to_phys:
+ * @vcpu: CPU to use for address translation.
+ * @vaddr: Virtual address to translate.
+ * @paddr: Pointer to output physical address.
+ *
+ * Translate a virtual address into a physical address.
+ *
+ * Returns: Whether the address could be translated.
+ */
+bool qi_mem_virt_to_phys(QICPU vcpu, uint64_t vaddr, uint64_t *paddr);
+
+/**
+ * qi_mem_read_phys:
+ * @paddr: Starting physical address to read from.
+ * @size: Number of bytes to read.
+ * @buf: Buffer to write into.
+ *
+ * Read contents from physical memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination buffer might have been
+ *  modified.
+ * Precondition: The output buffer has at least "size" bytes.
+ */
+bool qi_mem_read_phys(uint64_t paddr, size_t size, void *buf);
+
+/**
+ * qi_mem_write_phys:
+ * @paddr: Starting physical address to write into.
+ * @size: Number of bytes to write.
+ * @buf: Buffer with the contents to write from.
+ *
+ * Write contents into virtual memory.
+ *
+ * Returns: Whether the range of physical addresses is valid.
+ *
+ * Warning: Even on error, some of the destination memory might have been
+ *  modified.
+ *
+ * Precondition: The input buffer has at least "size" bytes.
+ */
+bool qi_mem_write_phys(uint64_t paddr, size_t size, void *buf);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__STATE_H */
diff --git a/instrument/state.c b/instrument/state.c
new file mode 100644
index 00..4bf99b4882
--- /dev/null
+++ b/instrument/state.c
@@ -0,0 +1,72 @@
+/*
+ * Interface for accessing guest state.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "cpu.h"
+#include "exec/cpu-all.h"
+#include "instrument/control.h"
+#include "instrument/error.h"
+#include "instrument/qemu-instr/state.h"
+#include "instrument/qemu-instr/visibility.h"
+
+
+QI_VPUBLIC bool qi_mem_read_virt(QICPU vcpu, uint64_t vaddr,
+ size_t size, void *buf)
+{
+CPUState *vcpu_ = instr_cpu_get(vcpu);
+ERROR_IF_RET(!instr_get_state(), false, "called outside instrumentation");
+ERROR_IF_RET(!vcpu_, false, "invalid QICPU");
+return cpu_memory_rw_debug(vcpu_, vaddr, 

[Qemu-devel] [PATCH v4 19/20] instrument: Add event 'guest_user_syscall_ret'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |3 +++
 instrument/control.c|   11 +++
 instrument/events.h |5 +
 instrument/events.inc.h |   13 +
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   13 +
 linux-user/syscall.c|1 +
 stubs/instrument.c  |2 ++
 8 files changed, 49 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 43f8887529..dcfb31f436 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -406,6 +406,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_freebsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -483,6 +484,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #endif
 if (do_strace)
 print_netbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
@@ -560,6 +562,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #endif
 if (do_strace)
 print_openbsd_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
 return ret;
  efault:
diff --git a/instrument/control.c b/instrument/control.c
index 7e84dadf24..f8f368efb0 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -135,3 +135,14 @@ QI_VPUBLIC void qi_event_set_guest_user_syscall(
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_user_syscall, fn);
 }
+
+
+void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+
+QI_VPUBLIC void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_user_syscall_ret, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 8c944e1f91..6197ece466 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -75,6 +75,11 @@ static inline void instr_guest_user_syscall(
 CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
 uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
 
+extern void (*instr_event__guest_user_syscall_ret)(
+QICPU vcpu, uint64_t num, uint64_t ret);
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index 9c64497533..ca1d789cea 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -93,3 +93,16 @@ static inline void instr_guest_user_syscall(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall_ret(
+CPUState *vcpu, uint64_t num, uint64_t ret)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t ret)
+= instr_get_event(guest_user_syscall_ret);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_set(vcpu);
+(*cb)(vcpu_, num, ret);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index d977049082..decd357105 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -154,6 +154,7 @@ InstrUnloadError instr_unload(int64_t handle_id)
 instr_set_event(guest_mem_before_trans, NULL);
 instr_set_event(guest_mem_before_exec, NULL);
 instr_set_event(guest_user_syscall, NULL);
+instr_set_event(guest_user_syscall_ret, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index cba8ade54e..fd83c86c2b 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -149,6 +149,19 @@ void qi_event_set_guest_user_syscall(
uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
uint64_t arg7, uint64_t arg8));
 
+/*
+ * Finish executing a guest system call in syscall emulation mode.
+ *
+ * @num: System call number.
+ * @ret: System call result value.
+ *
+ * Mode: user
+ * Targets: TCG(all)
+ * Time: exec
+ */
+void qi_event_set_guest_user_syscall_ret(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t ret));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index c0c33d4a75..0f86b6935d 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -12397,6 +12397,7 @@ fail:
 #endif
 if(do_strace)
 print_syscall_ret(num, ret);
+instr_guest_user_syscall_ret(cpu, num, ret);
 trace_guest_user_syscall_ret(cpu, num, ret);
  

[Qemu-devel] [PATCH v4 18/20] instrument: Add event 'guest_user_syscall'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 bsd-user/syscall.c  |3 +++
 instrument/control.c|   14 ++
 instrument/events.h |7 +++
 instrument/events.inc.h |   16 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   15 +++
 linux-user/syscall.c|1 +
 stubs/instrument.c  |3 +++
 8 files changed, 60 insertions(+)

diff --git a/bsd-user/syscall.c b/bsd-user/syscall.c
index 3230f722f3..43f8887529 100644
--- a/bsd-user/syscall.c
+++ b/bsd-user/syscall.c
@@ -324,6 +324,7 @@ abi_long do_freebsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("freebsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 
arg7, arg8);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 
arg7, arg8);
 if(do_strace)
 print_freebsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -423,6 +424,7 @@ abi_long do_netbsd_syscall(void *cpu_env, int num, abi_long 
arg1,
 #ifdef DEBUG
 gemu_log("netbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_netbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
@@ -499,6 +501,7 @@ abi_long do_openbsd_syscall(void *cpu_env, int num, 
abi_long arg1,
 #ifdef DEBUG
 gemu_log("openbsd syscall %d\n", num);
 #endif
+instr_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 trace_guest_user_syscall(cpu, num, arg1, arg2, arg3, arg4, arg5, arg6, 0, 
0);
 if(do_strace)
 print_openbsd_syscall(num, arg1, arg2, arg3, arg4, arg5, arg6);
diff --git a/instrument/control.c b/instrument/control.c
index f39e81d7c7..7e84dadf24 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -121,3 +121,17 @@ QI_VPUBLIC void qi_event_set_guest_mem_before_exec(
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_mem_before_exec, fn);
 }
+
+
+void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
+QI_VPUBLIC void qi_event_set_guest_user_syscall(
+void (*fn)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_user_syscall, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 6507b26867..8c944e1f91 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -68,6 +68,13 @@ extern void (*instr_event__guest_mem_before_exec)(
 static inline void instr_guest_mem_before_exec(
 CPUState *vcpu, uint64_t vaddr, TraceMemInfo info);
 
+extern void (*instr_event__guest_user_syscall)(
+QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index d7a3065ac1..9c64497533 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -77,3 +77,19 @@ static inline void instr_guest_mem_before_exec(
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_user_syscall(
+CPUState *vcpu, uint64_t num, uint64_t arg1, uint64_t arg2, uint64_t arg3,
+uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7, uint64_t arg8)
+{
+void (*cb)(QICPU vcpu, uint64_t num, uint64_t arg1, uint64_t arg2,
+   uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6,
+   uint64_t arg7, uint64_t arg8)
+= instr_get_event(guest_user_syscall);
+if (cb) {
+instr_set_state(INSTR_STATE_ENABLE);
+QICPU vcpu_ = instr_cpu_set(vcpu);
+(*cb)(vcpu_, num, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 1df660d5d1..d977049082 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -153,6 +153,7 @@ InstrUnloadError instr_unload(int64_t handle_id)
 instr_set_event(guest_cpu_reset, NULL);
 instr_set_event(guest_mem_before_trans, NULL);
 instr_set_event(guest_mem_before_exec, NULL);
+instr_set_event(guest_user_syscall, NULL);
 
 /* this should 

[Qemu-devel] [PATCH v4 17/20] instrument: Add event 'guest_mem_before_exec'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |4 +++
 include/exec/cpu_ldst_useronly_template.h |4 +++
 include/exec/helper-gen.h |1 +
 include/exec/helper-proto.h   |1 +
 include/exec/helper-tcg.h |1 +
 instrument/control.c  |   35 +
 instrument/control.h  |   15 
 instrument/events.h   |5 
 instrument/events.inc.h   |   18 ++-
 instrument/helpers.h  |1 +
 instrument/load.c |1 +
 instrument/qemu-instr/control.h   |   21 +
 stubs/instrument.c|2 ++
 13 files changed, 108 insertions(+), 1 deletion(-)
 create mode 100644 instrument/helpers.h

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index debbabcfb2..8018e8b16a 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -28,6 +28,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -89,6 +90,7 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -126,6 +128,7 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
@@ -167,6 +170,7 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 
 #if !defined(SOFTMMU_CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index b0b3fc1b8d..c36c50ae41 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -27,6 +27,7 @@
 #include "trace-root.h"
 #endif
 
+#include "instrument/events.h"
 #include "trace/mem.h"
 
 #if DATA_SIZE == 8
@@ -62,6 +63,7 @@ glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
@@ -81,6 +83,7 @@ glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
@@ -102,6 +105,7 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
 {
 #if !defined(CODE_ACCESS)
 TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+instr_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo);
 trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
index 8239ffc77c..f351c3d050 100644
--- a/include/exec/helper-gen.h
+++ b/include/exec/helper-gen.h
@@ -57,6 +57,7 @@ static inline void glue(gen_helper_, 
name)(dh_retvar_decl(ret)  \
 }
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "trace/generated-helpers-wrappers.h"
 #include "tcg-runtime.h"
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
index 954bef85ce..8fdd02c132 100644
--- a/include/exec/helper-proto.h
+++ b/include/exec/helper-proto.h
@@ -27,6 +27,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), 
dh_ctype(t3), \
 dh_ctype(t4), dh_ctype(t5));
 
 #include "helper.h"
+#include "instrument/helpers.h"
 #include "trace/generated-helpers.h"
 #include "tcg-runtime.h"
 
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index b0c5bafa99..255e73c3e6 100644
--- a/include/exec/helper-tcg.h
+++ b/inclu

[Qemu-devel] [PATCH v4 16/20] instrument: Add event 'guest_mem_before_trans'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 Makefile.target |1 +
 instrument/control.c|   13 +++-
 instrument/control.h|   36 +-
 instrument/control.inc.h|   16 +++---
 instrument/events.h |   21 +
 instrument/events.inc.h |   19 
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   15 +
 instrument/qemu-instr/types.h   |   64 +++
 stubs/instrument.c  |4 ++
 tcg/tcg-op.c|5 +++
 trace/control.h |   23 ++
 trace/mem.h |   23 --
 13 files changed, 210 insertions(+), 31 deletions(-)

diff --git a/Makefile.target b/Makefile.target
index 7f42c45db8..6997b921c9 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -196,6 +196,7 @@ $(QEMU_PROG_BUILD): config-devices.mak
 COMMON_LDADDS = ../libqemuutil.a ../libqemustub.a
 
 # build either PROG or PROGW
+$(QEMU_PROG_BUILD): CFLAGS += -DQEMU_TARGET_BUILD=1
 $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
$(call LINK, $(filter-out %.mak, $^))
 ifdef CONFIG_DARWIN
diff --git a/instrument/control.c b/instrument/control.c
index 3cec1028e5..3c3875dc99 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -16,7 +16,7 @@
 #include "qom/cpu.h"
 
 
-__thread InstrState instr_cur_state;
+__thread InstrInfo instr_cur_info;
 
 
 unsigned int instr_cpus_count;
@@ -75,3 +75,14 @@ QI_VPUBLIC void qi_event_set_guest_cpu_reset(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_reset, fn);
 }
+
+
+void (*instr_event__guest_mem_before_trans)(
+QICPU vcpu_trans, QITCGv_cpu vcpu_exec, QITCGv vaddr, QIMemInfo info);
+
+QI_VPUBLIC void qi_event_set_guest_mem_before_trans(
+void (*fn)(QICPU vcpu_trans, QITCGv_cpu vcpu_exec, QITCGv vaddr, QIMemInfo 
info))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_mem_before_trans, fn);
+}
diff --git a/instrument/control.h b/instrument/control.h
index 0c37692465..d9e3dd3da6 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -56,12 +56,21 @@ typedef enum {
 INSTR_STATE_ENABLE,
 } InstrState;
 
+#define INSTR_MAX_TCG_REGS 16
+
+typedef struct InstrInfo {
+InstrState state;
+unsigned int max;
+void *tcg_regs[INSTR_MAX_TCG_REGS];
+} InstrInfo;
+
 /**
  * instr_set_state:
  *
- * Set the instrumentation state of the current host thread.
+ * Set the instrumentation state of the current host thread, and return its
+ * #InstrInfo.
  */
-static inline void instr_set_state(InstrState state);
+static inline InstrInfo *instr_set_state(InstrState state);
 
 /**
  * instr_get_state:
@@ -70,6 +79,29 @@ static inline void instr_set_state(InstrState state);
  */
 static inline InstrState instr_get_state(void);
 
+/**
+ * instr_tcg_set:
+ * @info: Pointer to #InstrInfo.
+ * @num: Number of TCG register used by instrumentation.
+ * @arg: TCG register.
+ *
+ * Get a suitable QITCGv* from a TCGv* value.
+ */
+#define instr_tcg_set(info, num, arg) \
+({\
+info->tcg_regs[num] = arg;\
+(void *)num;  \
+})
+
+/**
+ * instr_tcg_count:
+ * @info: Pointer to #InstrInfo.
+ * @count: Number of TCG registers used by instrumentation.
+ *
+ * Set the number of TCG registers used by instrumentation.
+ */
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count);
+
 
 #include "instrument/control.inc.h"
 
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 18ae6a34cc..e8224319e0 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -15,16 +15,18 @@
 #include 
 
 
-extern __thread InstrState instr_cur_state;
+extern __thread InstrInfo instr_cur_info;
 
-static inline void instr_set_state(InstrState state)
+static inline InstrInfo *instr_set_state(InstrState state)
 {
-atomic_store_release(&instr_cur_state, state);
+InstrInfo *info = &instr_cur_info;
+atomic_store_release(&info->state, state);
+return info;
 }
 
 static inline InstrState instr_get_state(void)
 {
-return atomic_load_acquire(&instr_cur_state);
+return atomic_load_acquire(&instr_cur_info.state);
 }
 
 
@@ -46,3 +48,9 @@ static inline QICPU instr_cpu_set(CPUState *vcpu)
 uintptr_t idx = vcpu->cpu_index;
 return (QICPU )idx;
 }
+
+
+static inline void instr_tcg_count(InstrInfo *info, unsigned int count)
+{
+info->max = count;
+}
diff --git a/instrument/events.h b/instrument/events.h
index 4a0560490a..1cc4dbb052 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -12,6 +12,8 @@
 
 #include "instrument/qemu-instr/control.h"
 #include "instrument/qemu-instr/types.h"
+#include "trace/control.h"

[Qemu-devel] [PATCH v4 15/20] trace: Introduce a proper structure to describe memory accesses

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 include/exec/cpu_ldst_template.h  |   15 ++
 include/exec/cpu_ldst_useronly_template.h |   15 ++
 tcg/tcg-op.c  |   22 +
 trace/mem-internal.h  |   22 -
 trace/mem.h   |   31 +
 5 files changed, 66 insertions(+), 39 deletions(-)

diff --git a/include/exec/cpu_ldst_template.h b/include/exec/cpu_ldst_template.h
index 4db2302962..debbabcfb2 100644
--- a/include/exec/cpu_ldst_template.h
+++ b/include/exec/cpu_ldst_template.h
@@ -88,9 +88,8 @@ glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -126,9 +125,8 @@ glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
@@ -168,9 +166,8 @@ glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), 
_ra)(CPUArchState *env,
 TCGMemOpIdx oi;
 
 #if !defined(SOFTMMU_CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(SHIFT, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(SHIFT, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 
 addr = ptr;
diff --git a/include/exec/cpu_ldst_useronly_template.h 
b/include/exec/cpu_ldst_useronly_template.h
index 7b8c7c506e..b0b3fc1b8d 100644
--- a/include/exec/cpu_ldst_useronly_template.h
+++ b/include/exec/cpu_ldst_useronly_template.h
@@ -61,9 +61,8 @@ static inline RES_TYPE
 glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, 
false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(ld, USUFFIX), _p)(g2h(ptr));
 }
@@ -81,9 +80,8 @@ static inline int
 glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, true, MO_TE, false));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, true, MO_TE, false);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 return glue(glue(lds, SUFFIX), _p)(g2h(ptr));
 }
@@ -103,9 +101,8 @@ glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, 
target_ulong ptr,
   RES_TYPE v)
 {
 #if !defined(CODE_ACCESS)
-trace_guest_mem_before_exec(
-ENV_GET_CPU(env), ptr,
-trace_mem_build_info(DATA_SIZE, false, MO_TE, true));
+TraceMemInfo meminfo = trace_mem_build_info(DATA_SIZE, false, MO_TE, true);
+trace_guest_mem_before_exec(ENV_GET_CPU(env), ptr, meminfo.raw);
 #endif
 glue(glue(st, SUFFIX), _p)(g2h(ptr), v);
 }
diff --git a/tcg/tcg-op.c b/tcg/tcg-op.c
index 87f673ef49..234e300ede 100644
--- a/tcg/tcg-op.c
+++ b/tcg/tcg-op.c
@@ -2664,22 +2664,26 @@ static void gen_ldst_i64(TCGOpcode opc, TCGv_i64 val, 
TCGv addr,
 
 void tcg_gen_qemu_ld_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 memop = tcg_canonicalize_memop(memop, 0, 0);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 0));
+meminfo = trace_mem_get_info(memop, 0);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_ld_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_st_i32(TCGv_i32 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo;
 memop = tcg_canonicalize_memop(memop, 0, 1);
-trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env,
-   addr, trace_mem_get_info(memop, 1));
+meminfo = trace_mem_get_info(memop, 1);
+trace_guest_mem_before_tcg(tcg_ctx.cpu, tcg_ctx.tcg_env, addr, 
meminfo.raw);
 gen_ldst_i32(INDEX_op_qemu_st_i32, val, addr, memop, idx);
 }
 
 void tcg_gen_qemu_ld_i64(TCGv_i64 val, TCGv addr, TCGArg idx, TCGMemOp memop)
 {
+TraceMemInfo meminfo

[Qemu-devel] [PATCH v4 14/20] instrument: Add event 'guest_cpu_reset'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |9 +
 qom/cpu.c   |2 ++
 stubs/instrument.c  |1 +
 7 files changed, 36 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 09ba682483..3cec1028e5 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -66,3 +66,12 @@ QI_VPUBLIC void qi_event_set_guest_cpu_exit(void (*fn)(QICPU 
vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_exit, fn);
 }
+
+
+void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+
+QI_VPUBLIC void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_reset, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index c743cb8180..4a0560490a 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -39,6 +39,9 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu);
 extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
 static inline void instr_guest_cpu_exit(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_reset)(QICPU vcpu);
+static inline void instr_guest_cpu_reset(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index bcbf0cb32a..2f2cd324aa 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -31,3 +31,14 @@ static inline void instr_guest_cpu_exit(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_reset(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_reset);
+if (cb) {
+QICPU vcpu_ = instr_cpu_set(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 63b7d564ec..d9310d1979 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -150,6 +150,7 @@ InstrUnloadError instr_unload(int64_t handle_id)
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
 instr_set_event(guest_cpu_exit, NULL);
+instr_set_event(guest_cpu_reset, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index c37a380ab0..238ea63301 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -89,6 +89,15 @@ void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
  */
 void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
 
+/*
+ * Reset the state of a virtual (guest) CPU.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_reset(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/qom/cpu.c b/qom/cpu.c
index 4f38db0dac..d09cf583eb 100644
--- a/qom/cpu.c
+++ b/qom/cpu.c
@@ -19,6 +19,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #include "qapi/error.h"
 #include "qemu-common.h"
 #include "qom/cpu.h"
@@ -271,6 +272,7 @@ void cpu_reset(CPUState *cpu)
 (*klass->reset)(cpu);
 }
 
+instr_guest_cpu_reset(cpu);
 trace_guest_cpu_reset(cpu);
 }
 
diff --git a/stubs/instrument.c b/stubs/instrument.c
index ea8df6d467..74935975da 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -13,3 +13,4 @@
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
 void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
+void (*instr_event__guest_cpu_reset)(QICPU *vcpu);




[Qemu-devel] [PATCH v4 13/20] instrument: Add event 'guest_cpu_exit'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 +
 instrument/events.h |3 +++
 instrument/events.inc.h |   11 +++
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |9 +
 stubs/instrument.c  |1 +
 trace/control.c |4 +++-
 7 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/instrument/control.c b/instrument/control.c
index ed0d537b88..09ba682483 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -57,3 +57,12 @@ QI_VPUBLIC void qi_event_set_guest_cpu_enter(void 
(*fn)(QICPU vcpu))
 ERROR_IF(!instr_get_state(), "called outside instrumentation");
 instr_set_event(guest_cpu_enter, fn);
 }
+
+
+void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+
+QI_VPUBLIC void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_exit, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 947f120aa9..c743cb8180 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -36,6 +36,9 @@ extern void *instr_event__fini_data;
 extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
 static inline void instr_guest_cpu_enter(CPUState *vcpu);
 
+extern void (*instr_event__guest_cpu_exit)(QICPU vcpu);
+static inline void instr_guest_cpu_exit(CPUState *vcpu);
+
 
 #include "instrument/events.inc.h"
 
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index 238cce9855..bcbf0cb32a 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -20,3 +20,14 @@ static inline void instr_guest_cpu_enter(CPUState *vcpu)
 instr_set_state(INSTR_STATE_DISABLE);
 }
 }
+
+static inline void instr_guest_cpu_exit(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_exit);
+if (cb) {
+QICPU vcpu_ = instr_cpu_set(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index 0fe878afa8..63b7d564ec 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -149,6 +149,7 @@ InstrUnloadError instr_unload(int64_t handle_id)
 
 instr_set_event(fini_fn, NULL);
 instr_set_event(guest_cpu_enter, NULL);
+instr_set_event(guest_cpu_exit, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index 26d8aa976d..c37a380ab0 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -80,6 +80,15 @@ void qi_set_fini(qi_fini_fn fn, void *data);
  */
 void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
 
+/*
+ * Hot-unplug a virtual (guest) CPU.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_exit(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/stubs/instrument.c b/stubs/instrument.c
index 658a872e1c..ea8df6d467 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -12,3 +12,4 @@
 
 __thread InstrState instr_cur_state;
 void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
+void (*instr_event__guest_cpu_exit)(QICPU *vcpu);
diff --git a/trace/control.c b/trace/control.c
index 82d8989c4d..946a0af818 100644
--- a/trace/control.c
+++ b/trace/control.c
@@ -1,13 +1,14 @@
 /*
  * Interface for configuring and controlling the state of tracing events.
  *
- * Copyright (C) 2011-2016 Lluís Vilanova 
+ * Copyright (C) 2011-2017 Lluís Vilanova 
  *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
 
 #include "qemu/osdep.h"
+#include "instrument/events.h"
 #include "trace/control.h"
 #include "qemu/help_option.h"
 #ifdef CONFIG_TRACE_SIMPLE
@@ -272,6 +273,7 @@ void trace_fini_vcpu(CPUState *vcpu)
 TraceEventIter iter;
 TraceEvent *ev;
 
+instr_guest_cpu_exit(vcpu);
 trace_guest_cpu_exit(vcpu);
 
 trace_event_iter_init(&iter, NULL);




[Qemu-devel] [PATCH v4 12/20] instrument: Add event 'guest_cpu_enter'

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 instrument/control.c|9 
 instrument/events.h |5 
 instrument/events.inc.h |   11 ++
 instrument/load.c   |1 +
 instrument/qemu-instr/control.h |   44 +++
 stubs/instrument.c  |1 +
 trace/control-target.c  |2 ++
 7 files changed, 73 insertions(+)

diff --git a/instrument/control.c b/instrument/control.c
index 83453ea561..ed0d537b88 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -48,3 +48,12 @@ QI_VPUBLIC void qi_set_fini(qi_fini_fn fn, void *data)
 instr_set_event(fini_fn, fn);
 instr_set_event(fini_data, data);
 }
+
+
+void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+
+QI_VPUBLIC void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu))
+{
+ERROR_IF(!instr_get_state(), "called outside instrumentation");
+instr_set_event(guest_cpu_enter, fn);
+}
diff --git a/instrument/events.h b/instrument/events.h
index 82ad0bd827..947f120aa9 100644
--- a/instrument/events.h
+++ b/instrument/events.h
@@ -11,6 +11,7 @@
 #define INSTRUMENT__EVENTS_H
 
 #include "instrument/qemu-instr/control.h"
+#include "instrument/qemu-instr/types.h"
 
 /**
  * instr_get_event:
@@ -32,6 +33,10 @@
 extern qi_fini_fn instr_event__fini_fn;
 extern void *instr_event__fini_data;
 
+extern void (*instr_event__guest_cpu_enter)(QICPU vcpu);
+static inline void instr_guest_cpu_enter(CPUState *vcpu);
+
+
 #include "instrument/events.inc.h"
 
 #endif  /* INSTRUMENT__EVENTS_H */
diff --git a/instrument/events.inc.h b/instrument/events.inc.h
index 8b1ce7fcb2..238cce9855 100644
--- a/instrument/events.inc.h
+++ b/instrument/events.inc.h
@@ -7,5 +7,16 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "instrument/control.h"
 
 
+static inline void instr_guest_cpu_enter(CPUState *vcpu)
+{
+void (*cb)(QICPU vcpu) = instr_get_event(guest_cpu_enter);
+if (cb) {
+QICPU vcpu_ = instr_cpu_set(vcpu);
+instr_set_state(INSTR_STATE_ENABLE);
+(*cb)(vcpu_);
+instr_set_state(INSTR_STATE_DISABLE);
+}
+}
diff --git a/instrument/load.c b/instrument/load.c
index e180f03429..0fe878afa8 100644
--- a/instrument/load.c
+++ b/instrument/load.c
@@ -148,6 +148,7 @@ InstrUnloadError instr_unload(int64_t handle_id)
 }
 
 instr_set_event(fini_fn, NULL);
+instr_set_event(guest_cpu_enter, NULL);
 
 /* this should never fail */
 if (dlclose(handle->dlhandle) < 0) {
diff --git a/instrument/qemu-instr/control.h b/instrument/qemu-instr/control.h
index f6e289daa0..26d8aa976d 100644
--- a/instrument/qemu-instr/control.h
+++ b/instrument/qemu-instr/control.h
@@ -16,6 +16,7 @@ extern "C" {
 
 #include 
 #include 
+#include 
 
 
 /**
@@ -36,6 +37,49 @@ typedef void (*qi_fini_fn)(void *arg);
  */
 void qi_set_fini(qi_fini_fn fn, void *data);
 
+
+/*
+ * Set callbacks for available events. Each event has a short description and
+ * various indicators of when it can be triggered:
+ *
+ * - Mode :: user
+ *   Triggered in QEMU user application emulation (e.g., linux-user).
+ *
+ * - Mode :: softmmy
+ *   Triggered in QEMU full-system emulation.
+ *
+ *
+ * - Targets :: all
+ *   Triggered on all targets, both using TCG or native hardware virtualization
+ *   (e.g., KVM).
+ *
+ * - Targets :: TCG()
+ *   Triggered on the given guest target architectures when executing with TCG
+ *   (no native hardware virtualization).
+ *
+ *
+ * - Time :: exec
+ *   Triggered when the guest executes the described operation.
+ *
+ * - Time :: trans
+ *   Triggered when QEMU translates a guest operation. This is only available
+ *   when executing with TCG. Guest instructions are decompiled and translated
+ *   into the intermediate TCG language (when "Time: trans" events are
+ *   triggered). Then, the TCG compiler translates TCG code into the native 
host
+ *   code that QEMU will execute to emulate the guest (when "Time: exec" events
+ *   are triggered). As QEMU uses a cache of translated code, the same
+ *   instruction might be translated more than once (when the cache overflows).
+ */
+
+/*
+ * Hot-plug a new virtual (guest) CPU.
+ *
+ * Mode: user, softmmu
+ * Targets: all
+ * Time: exec
+ */
+void qi_event_set_guest_cpu_enter(void (*fn)(QICPU vcpu));
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/stubs/instrument.c b/stubs/instrument.c
index 6731710fd5..658a872e1c 100644
--- a/stubs/instrument.c
+++ b/stubs/instrument.c
@@ -11,3 +11,4 @@
 
 
 __thread InstrState instr_cur_state;
+void (*instr_event__guest_cpu_enter)(QICPU *vcpu);
diff --git a/trace/control-target.c b/trace/control-target.c
index 0056da6a46..e47361cef8 100644
--- a/trace/control-target.c
+++ b/trace/control-target.c
@@ -9,6 +9,7 @@
 
 #include "qemu/osdep.h"
 #include "cpu.h"
+#include "instrument/events.h"
 #include "trac

[Qemu-devel] [PATCH v4 11/20] instrument: Track vCPUs

2017-09-06 Thread Lluís Vilanova
Keep a translation between instrumentation's QICPU and CPUState objects to avoid
exposing QEMU's internals to instrumentation clients.

Signed-off-by: Lluís Vilanova 
---
 cpus-common.c|9 +
 instrument/control.c |   22 ++
 instrument/control.h |   32 
 instrument/control.inc.h |   23 +++
 4 files changed, 86 insertions(+)

diff --git a/cpus-common.c b/cpus-common.c
index 59f751ecf9..ec5f46cc3d 100644
--- a/cpus-common.c
+++ b/cpus-common.c
@@ -22,6 +22,9 @@
 #include "exec/cpu-common.h"
 #include "qom/cpu.h"
 #include "sysemu/cpus.h"
+#if defined(CONFIG_INSTRUMENT)
+#include "instrument/control.h"
+#endif
 
 static QemuMutex qemu_cpu_list_lock;
 static QemuCond exclusive_cond;
@@ -84,6 +87,9 @@ void cpu_list_add(CPUState *cpu)
 } else {
 assert(!cpu_index_auto_assigned);
 }
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_add(cpu);
+#endif
 QTAILQ_INSERT_TAIL(&cpus, cpu, node);
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 
@@ -102,6 +108,9 @@ void cpu_list_remove(CPUState *cpu)
 assert(!(cpu_index_auto_assigned && cpu != QTAILQ_LAST(&cpus, CPUTailQ)));
 
 QTAILQ_REMOVE(&cpus, cpu, node);
+#if defined(CONFIG_INSTRUMENT)
+instr_cpu_remove(cpu);
+#endif
 cpu->cpu_index = UNASSIGNED_CPU_INDEX;
 qemu_mutex_unlock(&qemu_cpu_list_lock);
 }
diff --git a/instrument/control.c b/instrument/control.c
index 2c2781beeb..83453ea561 100644
--- a/instrument/control.c
+++ b/instrument/control.c
@@ -13,10 +13,32 @@
 #include "instrument/load.h"
 #include "instrument/qemu-instr/control.h"
 #include "instrument/qemu-instr/visibility.h"
+#include "qom/cpu.h"
+
 
 __thread InstrState instr_cur_state;
 
 
+unsigned int instr_cpus_count;
+CPUState **instr_cpus;
+
+void instr_cpu_add(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+if (idx >= instr_cpus_count) {
+instr_cpus_count = idx + 1;
+instr_cpus = realloc(instr_cpus, sizeof(*instr_cpus) * 
instr_cpus_count);
+}
+instr_cpus[idx] = vcpu;
+}
+
+void instr_cpu_remove(CPUState *vcpu)
+{
+unsigned int idx = vcpu->cpu_index;
+instr_cpus[idx] = NULL;
+}
+
+
 qi_fini_fn instr_event__fini_fn;
 void *instr_event__fini_data;
 
diff --git a/instrument/control.h b/instrument/control.h
index f2b085f69b..0c37692465 100644
--- a/instrument/control.h
+++ b/instrument/control.h
@@ -10,6 +10,38 @@
 #ifndef INSTRUMENT__CONTROL_H
 #define INSTRUMENT__CONTROL_H
 
+#include "qemu/typedefs.h"
+#include "instrument/qemu-instr/types.h"
+
+
+/**
+ * instr_cpu_add:
+ *
+ * Make @vcpu available to instrumentation clients.
+ */
+void instr_cpu_add(CPUState *vcpu);
+
+/**
+ * instr_cpu_remove:
+ *
+ * Make @vcpu unavailable to instrumentation clients.
+ */
+void instr_cpu_remove(CPUState *vcpu);
+
+/**
+ * instr_cpu_get:
+ *
+ * Get the #CPUState corresponding to the given #QICPU.
+ */
+static inline CPUState *instr_cpu_get(QICPU vcpu);
+
+/**
+ * instr_cpu_set:
+ *
+ * Get the #QICPU corresponding to the given #CPUState.
+ */
+static inline QICPU instr_cpu_set(CPUState *vcpu);
+
 
 /**
  * InstrState:
diff --git a/instrument/control.inc.h b/instrument/control.inc.h
index 0f649f4caa..18ae6a34cc 100644
--- a/instrument/control.inc.h
+++ b/instrument/control.inc.h
@@ -7,9 +7,12 @@
  * See the COPYING file in the top-level directory.
  */
 
+#include "qemu/osdep.h"
 #include "qemu/atomic.h"
 #include "qemu/compiler.h"
+#include "qom/cpu.h"
 #include 
+#include 
 
 
 extern __thread InstrState instr_cur_state;
@@ -23,3 +26,23 @@ static inline InstrState instr_get_state(void)
 {
 return atomic_load_acquire(&instr_cur_state);
 }
+
+
+extern unsigned int instr_cpus_count;
+extern CPUState **instr_cpus;
+
+static inline CPUState *instr_cpu_get(QICPU vcpu)
+{
+unsigned int idx = (uintptr_t)vcpu;
+if (idx >= instr_cpus_count) {
+return NULL;
+} else {
+return instr_cpus[idx];
+}
+}
+
+static inline QICPU instr_cpu_set(CPUState *vcpu)
+{
+uintptr_t idx = vcpu->cpu_index;
+return (QICPU )idx;
+}




[Qemu-devel] [PATCH v4 10/20] instrument: Add support for tracing events

2017-09-06 Thread Lluís Vilanova
Signed-off-by: Lluís Vilanova 
---
 .gitignore|1 
 Makefile  |3 +
 instrument/Makefile.objs  |1 
 instrument/error.h|6 ++
 instrument/qemu-instr/types.h |   51 +++
 instrument/qemu-instr/types.inc.h |   15 
 instrument/trace.c|  125 +
 trace/control.h   |1 
 8 files changed, 203 insertions(+)
 create mode 100644 instrument/qemu-instr/types.h
 create mode 100644 instrument/qemu-instr/types.inc.h
 create mode 100644 instrument/trace.c

diff --git a/.gitignore b/.gitignore
index cf65316863..5ffcb9a091 100644
--- a/.gitignore
+++ b/.gitignore
@@ -134,3 +134,4 @@ trace-dtrace-root.h
 trace-dtrace-root.dtrace
 trace-ust-all.h
 trace-ust-all.c
+!/instrument/*
diff --git a/Makefile b/Makefile
index 6171661458..6f4de75f79 100644
--- a/Makefile
+++ b/Makefile
@@ -592,6 +592,9 @@ endif
 ifdef CONFIG_INSTRUMENT
$(INSTALL_DIR) "$(DESTDIR)$(includedir)/qemu-instr/"
$(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/control.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/trace.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
+   $(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/types.inc.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
$(INSTALL_DATA) $(SRC_PATH)/instrument/qemu-instr/visibility.h 
"$(DESTDIR)$(includedir)/qemu-instr/"
 endif
 
diff --git a/instrument/Makefile.objs b/instrument/Makefile.objs
index 9b7e1c03aa..8258dbfa79 100644
--- a/instrument/Makefile.objs
+++ b/instrument/Makefile.objs
@@ -5,3 +5,4 @@ target-obj-$(CONFIG_INSTRUMENT) += load.o
 target-obj-y += qmp.o
 
 target-obj-$(CONFIG_INSTRUMENT) += control.o
+target-obj-$(CONFIG_INSTRUMENT) += trace.o
diff --git a/instrument/error.h b/instrument/error.h
index f8d1dd4b16..7a51d62fdb 100644
--- a/instrument/error.h
+++ b/instrument/error.h
@@ -25,4 +25,10 @@
 return;  \
 }
 
+#define ERROR_IF_RET(cond, ret, msg, args...)   \
+if (unlikely(cond)) {   \
+_ERROR(msg, ##args);\
+return ret; \
+}   \
+
 #endif  /* INSTRUMENT_ERROR_H */
diff --git a/instrument/qemu-instr/types.h b/instrument/qemu-instr/types.h
new file mode 100644
index 00..ea3a032b4f
--- /dev/null
+++ b/instrument/qemu-instr/types.h
@@ -0,0 +1,51 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef QI__TYPES_H
+#define QI__TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * SECTION: types
+ * @section_id: qi-types
+ * @title: Common types
+ */
+
+/**
+ * QITraceEvent:
+ *
+ * Opaque structure defining a tracing event.
+ */
+typedef struct QITraceEvent QITraceEvent;
+
+/**
+ * QITraceEventIter:
+ *
+ * Opaque structure defining a tracing event iterator.
+ */
+typedef struct QITraceEventIter QITraceEventIter;
+
+/**
+ * QICPU:
+ *
+ * Opaque guest CPU pointer.
+ */
+typedef struct QICPU_d *QICPU;
+
+
+#include 
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /* QI__TYPES_H */
diff --git a/instrument/qemu-instr/types.inc.h 
b/instrument/qemu-instr/types.inc.h
new file mode 100644
index 00..0d99ea59a2
--- /dev/null
+++ b/instrument/qemu-instr/types.inc.h
@@ -0,0 +1,15 @@
+/*
+ * QEMU-specific types for instrumentation clients.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include 
+
+
+struct QITraceEventIter {
+char buffer[(sizeof(size_t) * 2) + sizeof(char *)];
+};
diff --git a/instrument/trace.c b/instrument/trace.c
new file mode 100644
index 00..a73fcdf50a
--- /dev/null
+++ b/instrument/trace.c
@@ -0,0 +1,125 @@
+/*
+ * API for QEMU's tracing events.
+ *
+ * Copyright (C) 2012-2017 Lluís Vilanova 
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "qemu/osdep.h"
+#include "instrument/error.h"
+#include "qemu-instr/trace.h"
+#include "qemu-instr/visibility.h"
+#include "trace/control.h"
+
+
+QI_VPUBLIC
+QITraceEvent *qi_trace_event_name(const char *name)
+{
+ERROR_IF_RET(!name, NULL, "must provide a name");
+return (QITraceEvent *)trace_event_name(name);
+}
+
+QI_VPUBLIC
+void qi_trace_event_iter_init(QITraceEventIter *iter, const char *pattern)
+{
+Trace

  1   2   3   4   5   6   7   8   9   10   >