Lockup with --accel tcg,thread=single

2019-09-30 Thread Doug Gale
I found a lockup in single threaded TCG, with OVMF bios, 16 CPUs.

qemu-system-x86_64 --accel tcg,thread=single -smp cpus=16 -bios
/usr/share/ovmf/OVMF.fd

Using Ubuntu 18.04 LTS, default gnome desktop. There is no guest OS,
there is no hard drive, just the OVMF firmware locks it up. (I
narrowed it down to this from a much larger repro)

Let that run for about 10 seconds or so, then attempt to Ctrl-C in the
terminal that launched qemu. You should see the hung program thing
(wait or force quit) appear on the qemu window, and the terminal just
prints ^C without interrupting qemu. DO NOT click force quit or wait.
Use killall -9 qemu-system-x86_64 to kill it if you must, gdb kill is
also okay. If you force quit you will likely freeze the entire gnome
desktop. This is what kmsg reports:
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/end%2520of%2520syslog%2520after%2520desktop%2520lockup,
this is what syslog reports:
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/the%2520end%2520of%2520dmesg%2520after%2520desktop%2520lockup.
Probably bugs in gnome but just warning about locking up your machines
when reproducing.

Peter Maydell helped me bisect it in IRC.
 Works fine at commit 1e8a98b53867f61
 Fails at commit 9458a9a1df1a4c7

MTTCG works fine all the way up to master.

Configure command line:

../qemu/configure --target-list=x86_64-softmmu,i386-softmmu
--audio-drv-list=pa --enable-libusb --disable-libssh
--enable-virglrenderer --enable-opengl --enable-debug

The issue occurs without --enable-debug. I didn't strip the configure
down though, it may not need all of those configure options exactly.

OVMF from ubuntu package manager, package named ovmf, exact version is
0~20180205.c0d9813c-2ubuntu0.1

Stack trace at lockup at
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/backtrace%2520all



Lockup with --accel tcg,thread=single

2019-09-30 Thread Doug Gale
I found a lockup in single threaded TCG, with OVMF bios, 16 CPUs.

qemu-system-x86_64 --accel tcg,thread=single -smp cpus=16 -bios
/usr/share/ovmf/OVMF.fd

Using Ubuntu 18.04 LTS, default gnome desktop. There is no guest OS, there
is no hard drive, just the OVMF firmware locks it up. (I narrowed it down
to this from a much larger repro)

Let that run for about 10 seconds or so, then attempt to Ctrl-C in the
terminal that launched qemu. You should see the hung program thing (wait or
force quit) appear on the qemu window, and the terminal just prints ^C
without interrupting qemu. DO NOT click force quit or wait. Use killall -9
qemu-system-x86_64 to kill it if you must, gdb kill is also okay. If you
force quit you will likely freeze the entire gnome desktop. This is what
kmsg reports:
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/end%2520of%2520syslog%2520after%2520desktop%2520lockup,
this is what syslog reports:
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/the%2520end%2520of%2520dmesg%2520after%2520desktop%2520lockup.
Probably bugs in gnome but just warning about locking up your machines when
reproducing.

Peter Maydell helped me bisect it in IRC.
 Works fine at commit 1e8a98b53867f61
 Fails at commit 9458a9a1df1a4c7

MTTCG works fine all the way up to master.

Configure command line:

../qemu/configure --target-list=x86_64-softmmu,i386-softmmu
--audio-drv-list=pa --enable-libusb --disable-libssh --enable-virglrenderer
--enable-opengl --enable-debug

The issue occurs without --enable-debug. I didn't strip the configure down
though, it may not need all of those configure options exactly.

OVMF from ubuntu package manager, package named ovmf, exact version
is 0~20180205.c0d9813c-2ubuntu0.1

Stack trace at lockup at
https://gist.githubusercontent.com/doug65536/810e0471c11008c97edb4aa0d86ddd66/raw/40038a355542f0edb1f14a7c7fb7c2db60da0025/backtrace%2520all


Re: [Qemu-devel] [PATCH] gdbstub: Fix i386/x86_64 machine description and add control registers

2019-01-25 Thread Doug Gale
On Fri, Jan 25, 2019 at 6:22 AM Peter Maydell 
wrote:

>
> Thanks for this explanation -- the patch makes a lot more sense with it.
> I'm confused though -- the XML we ship is basically what gdb itself
> ships and uses internally:
>
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=blob;f=gdb/features/i386/i386.xml;h=beb1496d9773efcf0e0526dc540a5e206a2e21fc;hb=HEAD
>
> and that uses xi:include to pull in the other files.
> So it seems odd that gdb can't parse the XML it is using
> itself internally. Maybe QEMU is doing something else wrong
> somewhere?
>
>
I thought that too. I implemented gdbstub tracing a while ago and had it
enabled (-trace gdb*). The binary data it sends is exactly what I expect.
When I break into gdb, I checked the data and it looked correct. debug_xml
even prints out what it's going to parse. Looks fine. GDB calls into an XML
parser library, which I don't have built from source, so I didn't find
precisely where it fails, only the high level log showing unexpected
elements at nested feature.


Re: [Qemu-devel] [PATCH] gdbstub: Fix i386/x86_64 machine description and add control registers

2019-01-24 Thread Doug Gale
Here is the sequence that led to this patch:

- Debugging my kernel, I wished I could use conditional breapoints to put a
condition on CR3 to make breakpoints in user processes only break when they
are the active address space.
- Knew it was no problem to add a register to GDB stub
- Added CR3. While there, added CR0 and CR2 and CR4 and CR8 and EFER
- Attempted to use it. Dreaded g packet error.
- Setup to debug GDB. Step tdesc code. Find it failing and silently
dropping description.
- Changed register count in gdbstub to match what default machine
description would want. No more error. GDB definitely dropping to default.
- Learn more about GDB XML parser. Find it has a verbose parser log. set
debug_xml=1
- Watch in horror as parser gets messed up parsing nesting due to feature
including feature
- Wonder if any QEMU machine descriptions xi:include actually work or if
all architectures are lined up to coincidentally use the same register
numbers as the default.
- Run everything through XML validators that strictly enforce DTD and
everything, no problem, totally valid.
- Try several changes to make include work. Not working.
- Move the content of the includes into the top level file so no include.
Bingo, works.
- Discover that fsbase and gsbase now working because the entire machine
description is correctly implemented, makes the register window in
qtcreator suddenly work great
- Make sure 32 bit works too. Find a couple of issues. Fix.
- Submit


On Thu, Jan 24, 2019 at 4:59 PM Doug Gale  wrote:

> The machine description we send is being (silently) thrown on the floor by
> GDB and GDB silently uses the default machine description.
>
> With current QEMU, if you debug gdb, and set debug_xml=1 and continue,
> then attach to qemu gdbstub from the debugged gdb, you will see the xml
> parse fail completely, and gdb will fall back to the default machine
> description, silently, and changes to our xml (in qemu source code) have no
> effect. They might as well be empty.
>
> The point of fixing the machine description was IDE's with GDB integration
> will break on QEMU. The default machine description has fs_base, which
> fails to be retrieved, whick breaks the whole register window (in
> qt-creator at least, likely others). With my patch the register window
> works perfectly.
>
> I didn't delete anything, I removed the superfluous nesting of files by
> xi:include and moved the description into a single xml file. I added
> fs_base, gs_base, k_gs_base, cr0/2/3/4/6, efer.
>
> Removing the nesting into xml includes fixes it because the xml parse
> fails on  unnecessary include indirections and placed the data inline.
>
> I tried lots of things to fix the nesting. After a while I asked, why
> bother? It doesn't need to go through that include level of indirection
> does it?
>
> This patch leads to another patch I want to submit later, which fixes the
> broken real mode and protected mode debugging on x86_64. I want to add the
> ability to turn off the "always 64 bit registers" hack that works around
> 'g' packet too large. You fix that by patching gdb (which then reacts to
> packet to large with realloc instead of freaking out), not by breaking real
> and protected mode debugging on x86_64 target by forcing always-64-bit. My
> intention is to default to current behavior and have a command line switch
> that enables changing register sizes (fixing real and protected mode
> debugging on x86_64).
>
> This patch includes a FORCE_64 define that will be replaced by a check for
> the option that indicates patched gdb and "register size change ok mode".
>
>
> On Thu, Jan 24, 2019 at 6:44 AM Peter Maydell 
> wrote:
>
>> On Thu, 24 Jan 2019 at 04:08, Doug Gale  wrote:
>> >
>> > Signed-off-by: Doug Gale 
>> > ---
>> >  configure   |   4 +-
>> >  gdb-xml/i386-32bit-core.xml |  65 ---
>> >  gdb-xml/i386-32bit-sse.xml  |  52 -
>> >  gdb-xml/i386-32bit.xml  | 184 ++-
>> >  gdb-xml/i386-64bit-core.xml |  73 -
>> >  gdb-xml/i386-64bit-sse.xml  |  60 ---
>> >  gdb-xml/i386-64bit.xml  | 210 +++-
>> >  target/i386/cpu.c   |   4 +-
>> >  target/i386/gdbstub.c   | 186 +++-
>> >  9 files changed, 573 insertions(+), 265 deletions(-)
>> >  delete mode 100644 gdb-xml/i386-32bit-core.xml
>> >  delete mode 100644 gdb-xml/i386-32bit-sse.xml
>> >  delete mode 100644 gdb-xml/i386-64bit-core.xml
>> >  delete mode 100644 gdb-xml/i386-64bit-sse.xml
>>
>> Could you provide a commit message that explains what's
>> wrong with the machine description we have (ie what bug
>> or bugs this change is fixing) and why deleting half
>> the xml files is the right way to fix it, please?
>>
>> Does the "add control registers" part need to be in
>> the same patch, or is it a separate feature which
>> could be in its own patch ?
>>
>> thanks
>> -- PMM
>>
>


Re: [Qemu-devel] [PATCH] gdbstub: Fix i386/x86_64 machine description and add control registers

2019-01-24 Thread Doug Gale
The machine description we send is being (silently) thrown on the floor by
GDB and GDB silently uses the default machine description.

With current QEMU, if you debug gdb, and set debug_xml=1 and continue, then
attach to qemu gdbstub from the debugged gdb, you will see the xml parse
fail completely, and gdb will fall back to the default machine description,
silently, and changes to our xml (in qemu source code) have no effect. They
might as well be empty.

The point of fixing the machine description was IDE's with GDB integration
will break on QEMU. The default machine description has fs_base, which
fails to be retrieved, whick breaks the whole register window (in
qt-creator at least, likely others). With my patch the register window
works perfectly.

I didn't delete anything, I removed the superfluous nesting of files by
xi:include and moved the description into a single xml file. I added
fs_base, gs_base, k_gs_base, cr0/2/3/4/6, efer.

Removing the nesting into xml includes fixes it because the xml parse fails
on 
wrote:

> On Thu, 24 Jan 2019 at 04:08, Doug Gale  wrote:
> >
> > Signed-off-by: Doug Gale 
> > ---
> >  configure   |   4 +-
> >  gdb-xml/i386-32bit-core.xml |  65 ---
> >  gdb-xml/i386-32bit-sse.xml  |  52 -
> >  gdb-xml/i386-32bit.xml  | 184 ++-
> >  gdb-xml/i386-64bit-core.xml |  73 -
> >  gdb-xml/i386-64bit-sse.xml  |  60 ---
> >  gdb-xml/i386-64bit.xml  | 210 +++-
> >  target/i386/cpu.c   |   4 +-
> >  target/i386/gdbstub.c   | 186 +++-
> >  9 files changed, 573 insertions(+), 265 deletions(-)
> >  delete mode 100644 gdb-xml/i386-32bit-core.xml
> >  delete mode 100644 gdb-xml/i386-32bit-sse.xml
> >  delete mode 100644 gdb-xml/i386-64bit-core.xml
> >  delete mode 100644 gdb-xml/i386-64bit-sse.xml
>
> Could you provide a commit message that explains what's
> wrong with the machine description we have (ie what bug
> or bugs this change is fixing) and why deleting half
> the xml files is the right way to fix it, please?
>
> Does the "add control registers" part need to be in
> the same patch, or is it a separate feature which
> could be in its own patch ?
>
> thanks
> -- PMM
>


[Qemu-devel] [PATCH] gdbstub: Fix i386/x86_64 machine description and add control registers

2019-01-23 Thread Doug Gale
Signed-off-by: Doug Gale 
---
 configure   |   4 +-
 gdb-xml/i386-32bit-core.xml |  65 ---
 gdb-xml/i386-32bit-sse.xml  |  52 -
 gdb-xml/i386-32bit.xml  | 184 ++-
 gdb-xml/i386-64bit-core.xml |  73 -
 gdb-xml/i386-64bit-sse.xml  |  60 ---
 gdb-xml/i386-64bit.xml  | 210 +++-
 target/i386/cpu.c   |   4 +-
 target/i386/gdbstub.c   | 186 +++-
 9 files changed, 573 insertions(+), 265 deletions(-)
 delete mode 100644 gdb-xml/i386-32bit-core.xml
 delete mode 100644 gdb-xml/i386-32bit-sse.xml
 delete mode 100644 gdb-xml/i386-64bit-core.xml
 delete mode 100644 gdb-xml/i386-64bit-sse.xml

diff --git a/configure b/configure
index 4ea3f14883..c55a97b91c 100755
--- a/configure
+++ b/configure
@@ -7121,14 +7121,14 @@ TARGET_ABI_DIR=""
 case "$target_name" in
   i386)
 mttcg="yes"
-gdb_xml_files="i386-32bit.xml i386-32bit-core.xml i386-32bit-sse.xml"
+   gdb_xml_files="i386-32bit.xml"
 target_compiler=$cross_cc_i386
 target_compiler_cflags=$cross_cc_ccflags_i386
   ;;
   x86_64)
 TARGET_BASE_ARCH=i386
 mttcg="yes"
-gdb_xml_files="i386-64bit.xml i386-64bit-core.xml i386-64bit-sse.xml"
+   gdb_xml_files="i386-64bit.xml"
 target_compiler=$cross_cc_x86_64
   ;;
   alpha)
diff --git a/gdb-xml/i386-32bit-core.xml b/gdb-xml/i386-32bit-core.xml
deleted file mode 100644
index 7aeeeca3b2..00
--- a/gdb-xml/i386-32bit-core.xml
+++ /dev/null
@@ -1,65 +0,0 @@
-
-
-
-
-
-  
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
diff --git a/gdb-xml/i386-32bit-sse.xml b/gdb-xml/i386-32bit-sse.xml
deleted file mode 100644
index 57678473d6..00
--- a/gdb-xml/i386-32bit-sse.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-
-
-
-
-
-  
-  
-  
-  
-  
-  
-  
-
-
-
-
-
-
-
-  
-  
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-
diff --git a/gdb-xml/i386-32bit.xml b/gdb-xml/i386-32bit.xml
index 956fc7f45f..872fcea9c2 100644
--- a/gdb-xml/i386-32bit.xml
+++ b/gdb-xml/i386-32bit.xml
@@ -8,7 +8,185 @@
 
 
 
-
-  
-  
+
+  
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+
+  
+  
+  
+  
+  
+  
+
+  
+
+  
+  
+  
+  
+
+  
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+  
+
+  
+   
+   
+   
+  
+
+  
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+  
+
+  
+   
+   
+   
+   
+   
+   
+   
+   
+  
+
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
+  
+  
+  
+  
+  
+  
+   
+   
+   
+   
+   
+   
+   
+  
+  
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+   
+  
+
+  
+  
+  
+  
+  
+  
+  
+  
+
+  
 
diff --git a/gdb-xml/i386-64bit-core.xml b/gdb-xml/i386-64bit-core.xml
deleted file mode 100644
index 5088d84ceb..00
--- a/gdb-xml/i386-64bit-core.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
-
-
-
-  
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-
diff --git a/gdb-xml/i386-64bit-sse.xml b/gdb-xml/i386-64bit-sse.xml
deleted file mode 100644
index e86efc9ce5..00
--- a/gdb-xml/i386-64bit-sse.xml
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
-
-
-  
-  
-  
-  
-  
-  
-  
-
-
-
-
-
-
-
-  
-  
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-  
-
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-  
-
-  
-
diff --git a/gdb-xml/i386-64bit.xml b/gdb-xml/i386-64bit.xml
index 0b2f00ccbe..6d88969211 100644
--- a/gdb-xml/i386-64bit.xml
+++ b/gdb-xml/i386-64bit.xml
@@ -5,10 +5,212 @@
  are permitted in any medium w

Re: [Qemu-devel] [PATCH] i386/monitor.c: make addresses canonical for "info mem" and "info tlb"

2018-07-01 Thread Doug Gale
On Sun, Jun 17, 2018 at 4:40 AM, Doug Gale  wrote:

> Correct the output of the "info mem" and "info tlb" monitor commands to
> correctly show canonical addresses.
>
> In 48-bit addressing mode, the upper 16 bits of linear addresses are
> equal to bit 47. In 57-bit addressing mode (LA57), the upper 7 bits of
> linear addresses are equal to bit 56.
>
> Signed-off-by: Doug Gale 
> ---
>  target/i386/monitor.c | 76 +--
>  1 file changed, 44 insertions(+), 32 deletions(-)
>
> diff --git a/target/i386/monitor.c b/target/i386/monitor.c
> index a890b3c2ab..99c97a63e2 100644
> --- a/target/i386/monitor.c
> +++ b/target/i386/monitor.c
> @@ -35,21 +35,28 @@
>  #include "sev_i386.h"
>  #include "qapi/qapi-commands-misc.h"
>
> -
> -static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
> -  hwaddr pte, hwaddr mask)
> +/* Perform linear address sign extension */
> +static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
>  {
>  #ifdef TARGET_X86_64
>  if (env->cr[4] & CR4_LA57_MASK) {
>  if (addr & (1ULL << 56)) {
> -addr |= -1LL << 57;
> +addr |= (hwaddr)-(1LL << 57);
>  }
>  } else {
>  if (addr & (1ULL << 47)) {
> -addr |= -1LL << 48;
> +addr |= (hwaddr)-(1LL << 48);
>  }
>  }
>  #endif
> +return addr;
> +}
> +
> +static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
> +  hwaddr pte, hwaddr mask)
> +{
> +addr = addr_canonical(env, addr);
> +
>  monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx
> " %c%c%c%c%c%c%c%c%c\n",
> addr,
> @@ -243,8 +250,8 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
>  }
>  }
>
> -static void mem_print(Monitor *mon, hwaddr *pstart,
> -  int *plast_prot,
> +static void mem_print(Monitor *mon, CPUArchState *env,
> +  hwaddr *pstart, int *plast_prot,
>hwaddr end, int prot)
>  {
>  int prot1;
> @@ -253,7 +260,9 @@ static void mem_print(Monitor *mon, hwaddr *pstart,
>  if (*pstart != -1) {
>  monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " "
> TARGET_FMT_plx " %c%c%c\n",
> -   *pstart, end, end - *pstart,
> +   addr_canonical(env, *pstart),
> +   addr_canonical(env, end),
> +   addr_canonical(env, end - *pstart),
> prot1 & PG_USER_MASK ? 'u' : '-',
> 'r',
> prot1 & PG_RW_MASK ? 'w' : '-');
> @@ -283,7 +292,7 @@ static void mem_info_32(Monitor *mon, CPUArchState
> *env)
>  if (pde & PG_PRESENT_MASK) {
>  if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
>  prot = pde & (PG_USER_MASK | PG_RW_MASK |
> PG_PRESENT_MASK);
> -mem_print(mon, &start, &last_prot, end, prot);
> +mem_print(mon, env, &start, &last_prot, end, prot);
>  } else {
>  for(l2 = 0; l2 < 1024; l2++) {
>  cpu_physical_memory_read((pde & ~0xfff) + l2 * 4,
> &pte, 4);
> @@ -295,16 +304,16 @@ static void mem_info_32(Monitor *mon, CPUArchState
> *env)
>  } else {
>  prot = 0;
>  }
> -mem_print(mon, &start, &last_prot, end, prot);
> +mem_print(mon, env, &start, &last_prot, end, prot);
>  }
>  }
>  } else {
>  prot = 0;
> -mem_print(mon, &start, &last_prot, end, prot);
> +mem_print(mon, env, &start, &last_prot, end, prot);
>  }
>  }
>  /* Flush last range */
> -mem_print(mon, &start, &last_prot, (hwaddr)1 << 32, 0);
> +mem_print(mon, env, &start, &last_prot, (hwaddr)1 << 32, 0);
>  }
>
>  static void mem_info_pae32(Monitor *mon, CPUArchState *env)
> @@ -332,7 +341,7 @@ static void mem_info_pae32(Monitor *mon, CPUArchState
> *env)
>  if (pde & PG_PSE_MASK) {
>  prot = pde & (PG_USER_MASK | PG_RW_MASK |
>PG_PRESENT_MASK);
> -   

[Qemu-devel] [PATCH] i386/monitor.c: make addresses canonical for "info mem" and "info tlb"

2018-06-17 Thread Doug Gale
Correct the output of the "info mem" and "info tlb" monitor commands to
correctly show canonical addresses.

In 48-bit addressing mode, the upper 16 bits of linear addresses are
equal to bit 47. In 57-bit addressing mode (LA57), the upper 7 bits of
linear addresses are equal to bit 56.

Signed-off-by: Doug Gale 
---
 target/i386/monitor.c | 76 +--
 1 file changed, 44 insertions(+), 32 deletions(-)

diff --git a/target/i386/monitor.c b/target/i386/monitor.c
index a890b3c2ab..99c97a63e2 100644
--- a/target/i386/monitor.c
+++ b/target/i386/monitor.c
@@ -35,21 +35,28 @@
 #include "sev_i386.h"
 #include "qapi/qapi-commands-misc.h"
 
-
-static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
-  hwaddr pte, hwaddr mask)
+/* Perform linear address sign extension */
+static hwaddr addr_canonical(CPUArchState *env, hwaddr addr)
 {
 #ifdef TARGET_X86_64
 if (env->cr[4] & CR4_LA57_MASK) {
 if (addr & (1ULL << 56)) {
-addr |= -1LL << 57;
+addr |= (hwaddr)-(1LL << 57);
 }
 } else {
 if (addr & (1ULL << 47)) {
-addr |= -1LL << 48;
+addr |= (hwaddr)-(1LL << 48);
 }
 }
 #endif
+return addr;
+}
+
+static void print_pte(Monitor *mon, CPUArchState *env, hwaddr addr,
+  hwaddr pte, hwaddr mask)
+{
+addr = addr_canonical(env, addr);
+
 monitor_printf(mon, TARGET_FMT_plx ": " TARGET_FMT_plx
" %c%c%c%c%c%c%c%c%c\n",
addr,
@@ -243,8 +250,8 @@ void hmp_info_tlb(Monitor *mon, const QDict *qdict)
 }
 }
 
-static void mem_print(Monitor *mon, hwaddr *pstart,
-  int *plast_prot,
+static void mem_print(Monitor *mon, CPUArchState *env,
+  hwaddr *pstart, int *plast_prot,
   hwaddr end, int prot)
 {
 int prot1;
@@ -253,7 +260,9 @@ static void mem_print(Monitor *mon, hwaddr *pstart,
 if (*pstart != -1) {
 monitor_printf(mon, TARGET_FMT_plx "-" TARGET_FMT_plx " "
TARGET_FMT_plx " %c%c%c\n",
-   *pstart, end, end - *pstart,
+   addr_canonical(env, *pstart),
+   addr_canonical(env, end),
+   addr_canonical(env, end - *pstart),
prot1 & PG_USER_MASK ? 'u' : '-',
'r',
prot1 & PG_RW_MASK ? 'w' : '-');
@@ -283,7 +292,7 @@ static void mem_info_32(Monitor *mon, CPUArchState *env)
 if (pde & PG_PRESENT_MASK) {
 if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) {
 prot = pde & (PG_USER_MASK | PG_RW_MASK | PG_PRESENT_MASK);
-mem_print(mon, &start, &last_prot, end, prot);
+mem_print(mon, env, &start, &last_prot, end, prot);
 } else {
 for(l2 = 0; l2 < 1024; l2++) {
 cpu_physical_memory_read((pde & ~0xfff) + l2 * 4, &pte, 4);
@@ -295,16 +304,16 @@ static void mem_info_32(Monitor *mon, CPUArchState *env)
 } else {
 prot = 0;
 }
-mem_print(mon, &start, &last_prot, end, prot);
+mem_print(mon, env, &start, &last_prot, end, prot);
 }
 }
 } else {
 prot = 0;
-mem_print(mon, &start, &last_prot, end, prot);
+mem_print(mon, env, &start, &last_prot, end, prot);
 }
 }
 /* Flush last range */
-mem_print(mon, &start, &last_prot, (hwaddr)1 << 32, 0);
+mem_print(mon, env, &start, &last_prot, (hwaddr)1 << 32, 0);
 }
 
 static void mem_info_pae32(Monitor *mon, CPUArchState *env)
@@ -332,7 +341,7 @@ static void mem_info_pae32(Monitor *mon, CPUArchState *env)
 if (pde & PG_PSE_MASK) {
 prot = pde & (PG_USER_MASK | PG_RW_MASK |
   PG_PRESENT_MASK);
-mem_print(mon, &start, &last_prot, end, prot);
+mem_print(mon, env, &start, &last_prot, end, prot);
 } else {
 pt_addr = pde & 0x3f000ULL;
 for (l3 = 0; l3 < 512; l3++) {
@@ -345,21 +354,21 @@ static void mem_info_pae32(Monitor *mon, CPUArchState 
*env)
 } else {
 prot = 0;
 }
-mem_print(mon, &start, &a

[Qemu-devel] [Bug 1748296] Re: TCG throws Invalid Opcode when executing x86 BMI shlx instruction

2018-02-08 Thread Doug Gale
** Description changed:

  I am unable to use BMI in my project when running under TCG. I narrowed
  the problem down to incorrect instruction decoding for BMI instructions
  (which have a 2 byte VEX prefix). The gen_sse function in translate.c
  reaches the goto label do_0f_38_fx, but b does not equal 0x1f7, 0x2f7,
  or 0x3f7, so the switch takes the default path and raises an invalid
  opcode exception.
  
  The code executes correctly and passes the test under KVM.
  
  I have created a complete repro here: https://github.com/doug65536/qemu-
  bmibug
  
  The makefile has the following utility targets:
  
  debug-kvm: Build and run the VM using KVM and wait for gdbstub attach
  
  run: Run the test case with TCG, make fails if the test fails. (It will
  fail)
  
  run-kvm: Run the test case with KVM, make fails if the test fails. (It
  will succeed)
  
  debug: Build and run the VM with TCG and wait for GDB attach
  
- attach-gdb: Run GDB and attach to KVM gdbstub
+ attach-gdb: Run GDB and attach to QEMU gdbstub
  
  The VM runs with -cpu max. CPUID reports support for BMI, BMI2, and ABM.
  
  You can quickly verify the issue by executing `make run-kvm` to confirm
  that KVM passes, then `make run` to confirm that TCG fails.
  
  I believe the bug affects other BMI, BMI2, and ABM instructions, but I
  have only completely verified incorrect execution of SHLX.

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1748296

Title:
  TCG throws Invalid Opcode when executing x86 BMI shlx instruction

Status in QEMU:
  New

Bug description:
  I am unable to use BMI in my project when running under TCG. I
  narrowed the problem down to incorrect instruction decoding for BMI
  instructions (which have a 2 byte VEX prefix). The gen_sse function in
  translate.c reaches the goto label do_0f_38_fx, but b does not equal
  0x1f7, 0x2f7, or 0x3f7, so the switch takes the default path and
  raises an invalid opcode exception.

  The code executes correctly and passes the test under KVM.

  I have created a complete repro here: https://github.com/doug65536
  /qemu-bmibug

  The makefile has the following utility targets:

  debug-kvm: Build and run the VM using KVM and wait for gdbstub attach

  run: Run the test case with TCG, make fails if the test fails. (It
  will fail)

  run-kvm: Run the test case with KVM, make fails if the test fails. (It
  will succeed)

  debug: Build and run the VM with TCG and wait for GDB attach

  attach-gdb: Run GDB and attach to QEMU gdbstub

  The VM runs with -cpu max. CPUID reports support for BMI, BMI2, and
  ABM.

  You can quickly verify the issue by executing `make run-kvm` to
  confirm that KVM passes, then `make run` to confirm that TCG fails.

  I believe the bug affects other BMI, BMI2, and ABM instructions, but I
  have only completely verified incorrect execution of SHLX.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1748296/+subscriptions



[Qemu-devel] [Bug 1748296] [NEW] TCG throws Invalid Opcode when executing x86 BMI shlx instruction

2018-02-08 Thread Doug Gale
Public bug reported:

I am unable to use BMI in my project when running under TCG. I narrowed
the problem down to incorrect instruction decoding for BMI instructions
(which have a 2 byte VEX prefix). The gen_sse function in translate.c
reaches the goto label do_0f_38_fx, but b does not equal 0x1f7, 0x2f7,
or 0x3f7, so the switch takes the default path and raises an invalid
opcode exception.

The code executes correctly and passes the test under KVM.

I have created a complete repro here: https://github.com/doug65536/qemu-
bmibug

The makefile has the following utility targets:

debug-kvm: Build and run the VM using KVM and wait for gdbstub attach

run: Run the test case with TCG, make fails if the test fails. (It will
fail)

run-kvm: Run the test case with KVM, make fails if the test fails. (It
will succeed)

debug: Build and run the VM with TCG and wait for GDB attach

attach-gdb: Run GDB and attach to KVM gdbstub

The VM runs with -cpu max. CPUID reports support for BMI, BMI2, and ABM.

You can quickly verify the issue by executing `make run-kvm` to confirm
that KVM passes, then `make run` to confirm that TCG fails.

I believe the bug affects other BMI, BMI2, and ABM instructions, but I
have only completely verified incorrect execution of SHLX.

** Affects: qemu
 Importance: Undecided
 Status: New

-- 
You received this bug notification because you are a member of qemu-
devel-ml, which is subscribed to QEMU.
https://bugs.launchpad.net/bugs/1748296

Title:
  TCG throws Invalid Opcode when executing x86 BMI shlx instruction

Status in QEMU:
  New

Bug description:
  I am unable to use BMI in my project when running under TCG. I
  narrowed the problem down to incorrect instruction decoding for BMI
  instructions (which have a 2 byte VEX prefix). The gen_sse function in
  translate.c reaches the goto label do_0f_38_fx, but b does not equal
  0x1f7, 0x2f7, or 0x3f7, so the switch takes the default path and
  raises an invalid opcode exception.

  The code executes correctly and passes the test under KVM.

  I have created a complete repro here: https://github.com/doug65536
  /qemu-bmibug

  The makefile has the following utility targets:

  debug-kvm: Build and run the VM using KVM and wait for gdbstub attach

  run: Run the test case with TCG, make fails if the test fails. (It
  will fail)

  run-kvm: Run the test case with KVM, make fails if the test fails. (It
  will succeed)

  debug: Build and run the VM with TCG and wait for GDB attach

  attach-gdb: Run GDB and attach to KVM gdbstub

  The VM runs with -cpu max. CPUID reports support for BMI, BMI2, and
  ABM.

  You can quickly verify the issue by executing `make run-kvm` to
  confirm that KVM passes, then `make run` to confirm that TCG fails.

  I believe the bug affects other BMI, BMI2, and ABM instructions, but I
  have only completely verified incorrect execution of SHLX.

To manage notifications about this bug go to:
https://bugs.launchpad.net/qemu/+bug/1748296/+subscriptions



Re: [Qemu-devel] [PATCH v2] Add AVX, AVX-512, MPX support to x86_cpu_dump_state

2017-12-07 Thread Doug Gale
On Thu, Dec 7, 2017 at 5:37 PM, Richard Henderson <
richard.hender...@linaro.org> wrote:

> On 12/02/2017 10:35 PM, Doug Gale wrote:
> > Signed-off-by: Doug Gale 
> > ---
> > Fix MSB LSB showing when SSE is disabled
> >  target/i386/helper.c | 95 ++
> +++---
> >  1 file changed, 83 insertions(+), 12 deletions(-)
> >
> > diff --git a/target/i386/helper.c b/target/i386/helper.c
> > index f63eb3d3f4..03812b6e87 100644
> > --- a/target/i386/helper.c
> > +++ b/target/i386/helper.c
> > @@ -543,6 +543,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f,
> fprintf_function cpu_fprintf,
> >  }
> >  }
> >  cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
> > +cpu_fprintf(f, "XCR0=%016" PRIx64 "\n", env->xcr0);
> >  if (flags & CPU_DUMP_FPU) {
> >  int fptag;
> >  fptag = 0;
> > @@ -565,21 +566,91 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f,
> fprintf_function cpu_fprintf,
> >  else
> >  cpu_fprintf(f, " ");
> >  }
> > -if (env->hflags & HF_CS64_MASK)
> > -nb = 16;
> > -else
> > +
> > +if (env->hflags & HF_CS64_MASK) {
> > +if (env->xcr0 & XSTATE_Hi16_ZMM_MASK) {
> > +/* AVX-512 32 registers enabled */
> > +nb = 32;
> > +} else {
> > +/* 64-bit mode, 16 registers */
> > +nb = 16;
> > +}
> > +} else {
> > +/* 32 bit mode, 8 registers */
> >  nb = 8;
> > -for(i=0;i > -cpu_fprintf(f, "XMM%02d=%08x%08x%08x%08x",
> > -i,
> > -env->xmm_regs[i].ZMM_L(3),
> > -env->xmm_regs[i].ZMM_L(2),
> > -env->xmm_regs[i].ZMM_L(1),
> > -env->xmm_regs[i].ZMM_L(0));
> > -if ((i & 1) == 1)
> > +}
> > +
> > +/* sse register width in units of 64 bits */
> > +int zmm_width;
> > +char zmm_name;
> > +if (env->xcr0 & XSTATE_ZMM_Hi256_MASK) {
> > +/* 512-bit "ZMM" - AVX-512 registers enabled */
> > +zmm_width = 8;
> > +zmm_name = 'Z';
> > +} else if (env->xcr0 & XSTATE_YMM_MASK) {
> > +/* 256-bit "YMM" - AVX enabled */
> > +zmm_width = 4;
> > +zmm_name = 'Y';
> > +} else if (env->cr[4] & CR4_OSFXSR_MASK) {
> > +/* 128-bit "XMM" - SSE enabled */
> > +zmm_width = 2;
> > +zmm_name = 'X';
> > +} else {
> > +/* SSE not enabled */
> > +zmm_width = 0;
> > +zmm_name = 0;
>
> You should exit the function here ...
>
> > +}
> > +
> > +if (zmm_width > 0) {
> > +cpu_fprintf(f, "  MSB%*sLSB\n",
> > +-(zmm_width * 16 + zmm_width - 7), "");
> > +}
> > +
> > +for (i = 0; i < nb; i++) {
> > +if (zmm_width == 0) {
> > +cpu_fprintf(f, "SSE not enabled\n");
> > +break;
> > +}
>
> ... rather than performing this test in a loop.
> Or indeed, printing anything at all.
>
> I assume this is in order to examine registers in the monitor under kvm?
>
>
> r~
>

​
Yes, to examine the registers in the monitor and improve the output of
things like -d int. I ran into an issue with
​ guest​
code and I wanted to check XCR0 to see if AVX was enabled, and I didn't see
any AVX registers
​, which was very misleading​
.
​ I couldn't check XCR0 to see if it was enabled either.​
I investigated and found that AVX was enabled, and the monitor output was
false. I added XCR0 and the entire AVX
​/AVX-512​
and MPX state to the
​qemu ​
output.

Why would it exit the function there? Are you sure the other states I
further down won't be enabled? It prints the MPX state further down. I put
the test in the loop so I wouldn't have to indent that whole `for` loop
another level, to improve readability. Is the performance of that loop
really relevant? The fprintf's will take at least thousands of times more
CPU time than that predictable branch.​


[Qemu-devel] [PATCH v2] Add AVX, AVX-512, MPX support to x86_cpu_dump_state

2017-12-02 Thread Doug Gale
Signed-off-by: Doug Gale 
---
Fix MSB LSB showing when SSE is disabled
 target/i386/helper.c | 95 +---
 1 file changed, 83 insertions(+), 12 deletions(-)

diff --git a/target/i386/helper.c b/target/i386/helper.c
index f63eb3d3f4..03812b6e87 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -543,6 +543,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, 
fprintf_function cpu_fprintf,
 }
 }
 cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
+cpu_fprintf(f, "XCR0=%016" PRIx64 "\n", env->xcr0);
 if (flags & CPU_DUMP_FPU) {
 int fptag;
 fptag = 0;
@@ -565,21 +566,91 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, 
fprintf_function cpu_fprintf,
 else
 cpu_fprintf(f, " ");
 }
-if (env->hflags & HF_CS64_MASK)
-nb = 16;
-else
+
+if (env->hflags & HF_CS64_MASK) {
+if (env->xcr0 & XSTATE_Hi16_ZMM_MASK) {
+/* AVX-512 32 registers enabled */
+nb = 32;
+} else {
+/* 64-bit mode, 16 registers */
+nb = 16;
+}
+} else {
+/* 32 bit mode, 8 registers */
 nb = 8;
-for(i=0;ixmm_regs[i].ZMM_L(3),
-env->xmm_regs[i].ZMM_L(2),
-env->xmm_regs[i].ZMM_L(1),
-env->xmm_regs[i].ZMM_L(0));
-if ((i & 1) == 1)
+}
+
+/* sse register width in units of 64 bits */
+int zmm_width;
+char zmm_name;
+if (env->xcr0 & XSTATE_ZMM_Hi256_MASK) {
+/* 512-bit "ZMM" - AVX-512 registers enabled */
+zmm_width = 8;
+zmm_name = 'Z';
+} else if (env->xcr0 & XSTATE_YMM_MASK) {
+/* 256-bit "YMM" - AVX enabled */
+zmm_width = 4;
+zmm_name = 'Y';
+} else if (env->cr[4] & CR4_OSFXSR_MASK) {
+/* 128-bit "XMM" - SSE enabled */
+zmm_width = 2;
+zmm_name = 'X';
+} else {
+/* SSE not enabled */
+zmm_width = 0;
+zmm_name = 0;
+}
+
+if (zmm_width > 0) {
+cpu_fprintf(f, "  MSB%*sLSB\n",
+-(zmm_width * 16 + zmm_width - 7), "");
+}
+
+for (i = 0; i < nb; i++) {
+if (zmm_width == 0) {
+cpu_fprintf(f, "SSE not enabled\n");
+break;
+}
+
+cpu_fprintf(f, "%cMM%02d=", zmm_name, i);
+int qw;
+for (qw = zmm_width; qw > 0; qw -= 2) {
+/* ':' separator every 64 bits */
+cpu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
+env->xmm_regs[i].ZMM_Q(qw - 1),
+env->xmm_regs[i].ZMM_Q(qw - 2),
+qw > 2 ? ":" : "");
+}
+
+/* two registers per line for 128-bit registers */
+if (zmm_width > 2 || (i & 1)) {
 cpu_fprintf(f, "\n");
-else
+} else {
 cpu_fprintf(f, " ");
+}
+}
+
+if (env->xcr0 & XSTATE_OPMASK_MASK) {
+/* AVX-512 opmask registers */
+for (i = 0; i < 8; ++i) {
+cpu_fprintf(f, "K%d=%08" PRIx64 "%s", i, env->opmask_regs[i],
+   (i & 3) == 3 ? "\n" : " ");
+}
+}
+
+if (env->xcr0 & XSTATE_BNDREGS_MASK) {
+/* MPX bound registers */
+for (i = 0; i < 4; ++i) {
+cpu_fprintf(f, "BND%d=%016" PRIx64 ":%016" PRIx64 "%s",
+i, env->bnd_regs[i].ub, env->bnd_regs[i].lb,
+(i & 1) ? "\n" : " ");
+}
+}
+
+if (env->xcr0 & XSTATE_BNDCSR_MASK) {
+/* MPX bound status/config registers */
+cpu_fprintf(f, "BNDCFGU=%016" PRIx64 " BNDSTATUS=%016" PRIx64 "\n",
+env->bndcs_regs.cfgu, env->bndcs_regs.sts);
 }
 }
 if (flags & CPU_DUMP_CODE) {
-- 
2.14.1




[Qemu-devel] [PATCH] Add AVX, AVX-512, MPX support to x86_cpu_dump_state

2017-12-02 Thread Doug Gale
Signed-off-by: Doug Gale 
---
 target/i386/helper.c | 94 +---
 1 file changed, 82 insertions(+), 12 deletions(-)

diff --git a/target/i386/helper.c b/target/i386/helper.c
index f63eb3d3f4..708fe13f2f 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -543,6 +543,7 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, 
fprintf_function cpu_fprintf,
 }
 }
 cpu_fprintf(f, "EFER=%016" PRIx64 "\n", env->efer);
+cpu_fprintf(f, "XCR0=%016" PRIx64 "\n", env->xcr0);
 if (flags & CPU_DUMP_FPU) {
 int fptag;
 fptag = 0;
@@ -565,21 +566,90 @@ void x86_cpu_dump_state(CPUState *cs, FILE *f, 
fprintf_function cpu_fprintf,
 else
 cpu_fprintf(f, " ");
 }
-if (env->hflags & HF_CS64_MASK)
-nb = 16;
-else
+
+if (env->hflags & HF_CS64_MASK) {
+if (env->xcr0 & XSTATE_Hi16_ZMM_MASK) {
+/* AVX-512 32 registers enabled */
+nb = 32;
+} else {
+/* 64-bit mode, 16 registers */
+nb = 16;
+}
+} else {
+/* 32 bit mode, 8 registers */
 nb = 8;
-for(i=0;ixmm_regs[i].ZMM_L(3),
-env->xmm_regs[i].ZMM_L(2),
-env->xmm_regs[i].ZMM_L(1),
-env->xmm_regs[i].ZMM_L(0));
-if ((i & 1) == 1)
+}
+
+/* sse register width in units of 64 bits */
+int zmm_width;
+char zmm_name;
+if (env->xcr0 & XSTATE_ZMM_Hi256_MASK) {
+/* 512-bit "ZMM" - AVX-512 registers enabled */
+zmm_width = 8;
+zmm_name = 'Z';
+} else if (env->xcr0 & XSTATE_YMM_MASK) {
+/* 256-bit "YMM" - AVX enabled */
+zmm_width = 4;
+zmm_name = 'Y';
+} else if (env->cr[4] & CR4_OSFXSR_MASK) {
+/* 128-bit "XMM" - SSE enabled */
+zmm_width = 2;
+zmm_name = 'X';
+} else {
+/* SSE not enabled */
+zmm_width = 0;
+zmm_name = 0;
+}
+
+
+cpu_fprintf(f, "  MSB%*sLSB\n",
+-(zmm_width * 16 + zmm_width - 7), "");
+
+for (i = 0; i < nb; i++) {
+if (zmm_width == 0) {
+cpu_fprintf(f, "SSE not enabled\n");
+break;
+}
+
+cpu_fprintf(f, "%cMM%02d=", zmm_name, i);
+int qw;
+for (qw = zmm_width; qw > 0; qw -= 2) {
+/* ':' separator every 64 bits */
+cpu_fprintf(f, "%016" PRIx64 ":%016" PRIx64 "%s",
+env->xmm_regs[i].ZMM_Q(qw - 1),
+env->xmm_regs[i].ZMM_Q(qw - 2),
+qw > 2 ? ":" : "");
+}
+
+/* two registers per line for 128-bit registers */
+if (zmm_width > 2 || (i & 1)) {
 cpu_fprintf(f, "\n");
-else
+} else {
 cpu_fprintf(f, " ");
+}
+}
+
+if (env->xcr0 & XSTATE_OPMASK_MASK) {
+/* AVX-512 opmask registers */
+for (i = 0; i < 8; ++i) {
+cpu_fprintf(f, "K%d=%08" PRIx64 "%s", i, env->opmask_regs[i],
+   (i & 3) == 3 ? "\n" : " ");
+}
+}
+
+if (env->xcr0 & XSTATE_BNDREGS_MASK) {
+/* MPX bound registers */
+for (i = 0; i < 4; ++i) {
+cpu_fprintf(f, "BND%d=%016" PRIx64 ":%016" PRIx64 "%s",
+i, env->bnd_regs[i].ub, env->bnd_regs[i].lb,
+(i & 1) ? "\n" : " ");
+}
+}
+
+if (env->xcr0 & XSTATE_BNDCSR_MASK) {
+/* MPX bound status/config registers */
+cpu_fprintf(f, "BNDCFGU=%016" PRIx64 " BNDSTATUS=%016" PRIx64 "\n",
+env->bndcs_regs.cfgu, env->bndcs_regs.sts);
 }
 }
 if (flags & CPU_DUMP_CODE) {
-- 
2.14.1




[Qemu-devel] [PATCH v4] gdbstub: add tracing

2017-12-02 Thread Doug Gale
Signed-off-by: Doug Gale 
---
Fix usage of %c in trace output, now uses 0x%02x
Fix possible sign extended char that could cause 0xfc to say 0xfffc
Add missing traces for hitting breakpoints, continuing, stepping
Fix incorrect dynamic check for tracing being enabled in hexdump
Fix missing braces around single line if body
Fix incorrectly indented return statement
Fix order of trace-events to be more tidy
 gdbstub.c| 113 +--
 trace-events |  28 +++
 2 files changed, 106 insertions(+), 35 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2a94030d3b..f1d51480f7 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -21,6 +21,7 @@
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
 #include "cpu.h"
+#include "trace-root.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig)
 return -1;
 }
 
-/* #define DEBUG_GDB */
-
-#ifdef DEBUG_GDB
-# define DEBUG_GDB_GATE 1
-#else
-# define DEBUG_GDB_GATE 0
-#endif
-
-#define gdb_debug(fmt, ...) do { \
-if (DEBUG_GDB_GATE) { \
-fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
-} \
-} while (0)
-
-
 typedef struct GDBRegisterState {
 int base_reg;
 int num_regs;
@@ -410,10 +396,13 @@ int use_gdb_syscalls(void)
 /* Resume execution.  */
 static inline void gdb_continue(GDBState *s)
 {
+
 #ifdef CONFIG_USER_ONLY
 s->running_state = 1;
+trace_gdbstub_op_continue();
 #else
 if (!runstate_needs_reset()) {
+trace_gdbstub_op_continue();
 vm_start();
 }
 #endif
@@ -434,6 +423,7 @@ static int gdb_continue_partial(GDBState *s, char 
*newstates)
  */
 CPU_FOREACH(cpu) {
 if (newstates[cpu->cpu_index] == 's') {
+trace_gdbstub_op_stepping(cpu->cpu_index);
 cpu_single_step(cpu, sstep_flags);
 }
 }
@@ -452,11 +442,13 @@ static int gdb_continue_partial(GDBState *s, char 
*newstates)
 case 1:
 break; /* nothing to do here */
 case 's':
+trace_gdbstub_op_stepping(cpu->cpu_index);
 cpu_single_step(cpu, sstep_flags);
 cpu_resume(cpu);
 flag = 1;
 break;
 case 'c':
+trace_gdbstub_op_continue_cpu(cpu->cpu_index);
 cpu_resume(cpu);
 flag = 1;
 break;
@@ -538,12 +530,49 @@ static void hextomem(uint8_t *mem, const char *buf, int 
len)
 }
 }
 
+static void hexdump(const char *buf, int len,
+void (*trace_fn)(size_t ofs, char const *text))
+{
+char line_buffer[3 * 16 + 4 + 16 + 1];
+
+size_t i;
+for (i = 0; i < len || (i & 0xF); ++i) {
+size_t byte_ofs = i & 15;
+
+if (byte_ofs == 0) {
+memset(line_buffer, ' ', 3 * 16 + 4 + 16);
+line_buffer[3 * 16 + 4 + 16] = 0;
+}
+
+size_t col_group = (i >> 2) & 3;
+size_t hex_col = byte_ofs * 3 + col_group;
+size_t txt_col = 3 * 16 + 4 + byte_ofs;
+
+if (i < len) {
+char value = buf[i];
+
+line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
+line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
+line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
+? value
+: '.';
+}
+
+if (byte_ofs == 0xF)
+trace_fn(i & -16, line_buffer);
+}
+}
+
 /* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len)
+static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
 {
 int csum, i;
 uint8_t *p;
 
+if (dump && trace_event_get_state_backends(TRACE_GDBSTUB_IO_BINARYREPLY)) {
+hexdump(buf, len, trace_gdbstub_io_binaryreply);
+}
+
 for(;;) {
 p = s->last_packet;
 *(p++) = '$';
@@ -576,9 +605,9 @@ static int put_packet_binary(GDBState *s, const char *buf, 
int len)
 /* return -1 if error, 0 if OK */
 static int put_packet(GDBState *s, const char *buf)
 {
-gdb_debug("reply='%s'\n", buf);
+trace_gdbstub_io_reply(buf);
 
-return put_packet_binary(s, buf, strlen(buf));
+return put_packet_binary(s, buf, strlen(buf), false);
 }
 
 /* Encode data using the encoding for 'x' packets.  */
@@ -975,8 +1004,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 
-
-gdb_debug("command='%s'\n", line_buf);
+trace_gdbstub_io_command(line_buf);
 
 p = line_buf;
 ch = *p++;
@@ -999,7 +1027,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*li

Re: [Qemu-devel] [PATCH] gdbstub: add tracing

2017-11-29 Thread Doug Gale
On Mon, Nov 27, 2017 at 5:00 AM, Markus Armbruster  wrote:
> Drive-by question...
>
> Doug Gale  writes:
>
>> Signed-off-by: Doug Gale 
>> ---
>>  gdbstub.c| 100 
>> ++-
>>  trace-events |  21 +
>>  2 files changed, 86 insertions(+), 35 deletions(-)
>>
>> diff --git a/gdbstub.c b/gdbstub.c
>> index 2a94030d3b..a75f319bd0 100644
>> --- a/gdbstub.c
>> +++ b/gdbstub.c
>> @@ -21,6 +21,7 @@
>>  #include "qemu/error-report.h"
>>  #include "qemu/cutils.h"
>>  #include "cpu.h"
>> +#include "trace-root.h"
>>  #ifdef CONFIG_USER_ONLY
>>  #include "qemu.h"
>>  #else
>> @@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig)
>>  return -1;
>>  }
>>
>> -/* #define DEBUG_GDB */
>> -
>> -#ifdef DEBUG_GDB
>> -# define DEBUG_GDB_GATE 1
>> -#else
>> -# define DEBUG_GDB_GATE 0
>> -#endif
>> -
>> -#define gdb_debug(fmt, ...) do { \
>> -if (DEBUG_GDB_GATE) { \
>> -fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
>> -} \
>> -} while (0)
>> -
>> -
>>  typedef struct GDBRegisterState {
>>  int base_reg;
>>  int num_regs;
>> @@ -538,12 +524,47 @@ static void hextomem(uint8_t *mem, const char *buf, 
>> int len)
>>  }
>>  }
>>
>> +static void hexdump(const char *buf, int len,
>> +void (*trace_fn)(size_t ofs, char const *text))
>> +{
>> +char line_buffer[3 * 16 + 4 + 16 + 1];
>> +
>> +for (size_t i = 0; i < len || (i & 0xF); ++i) {
>> +size_t byte_ofs = i & 15;
>> +
>> +if (byte_ofs == 0) {
>> +memset(line_buffer, ' ', 3 * 16 + 4 + 16);
>> +line_buffer[3 * 16 + 4 + 16] = 0;
>> +}
>> +
>> +size_t col_group = (i >> 2) & 3;
>> +size_t hex_col = byte_ofs * 3 + col_group;
>> +size_t txt_col = 3 * 16 + 4 + byte_ofs;
>> +
>> +if (i < len) {
>> +char value = buf[i];
>> +
>> +line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
>> +line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
>> +line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
>> +? value
>> +: '.';
>> +}
>> +
>> +if (byte_ofs == 0xF)
>> +trace_fn(i & -16, line_buffer);
>> +}
>> +}
>
> Could existing qemu_hexdump() serve?
>
>> +
>>  /* return -1 if error, 0 if OK */
>> -static int put_packet_binary(GDBState *s, const char *buf, int len)
>> +static int put_packet_binary(GDBState *s, const char *buf, int len, bool 
>> dump)
>>  {
>>  int csum, i;
>>  uint8_t *p;
>>
>> +if (TRACE_GDBSTUB_IO_BINARYREPLY_ENABLED && dump)
>> +hexdump(buf, len, trace_gdbstub_io_binaryreply);
>> +
>>  for(;;) {
>>  p = s->last_packet;
>>  *(p++) = '$';
> [...]

It is incorrect to use qemu_hexdump, tracing isn't printf. The whole
point of this patch is to _not_ dump traces to printf. I have already
submitted tracing that used printf, and it was rejected with a request
to use trace_ infrastructure.

It might be a better idea to refactor qemu_hexdump to use this
algorithm and use a trace_fn callback which dumps lines to printf for
qemu_hexdump case. qemu_hexdump hammers printf with a couple of
characters at a time of output and uses several loops, this algorithm
generates whole lines and more efficiently does one I/O per line. This
algorithm also breaks the hex into groups of four bytes to make it
easy to visually find a given byte.

I opted not to do that refactor of qemu_hexdump to reduce the scope of
my patch. Should I do that and resubmit?



[Qemu-devel] [PATCH v3] gdbstub: add tracing

2017-11-26 Thread Doug Gale
Signed-off-by: Doug Gale 
---
 gdbstub.c| 101 ++-
 trace-events |  21 +
 2 files changed, 87 insertions(+), 35 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2a94030d3b..86482fa009 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -21,6 +21,7 @@
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
 #include "cpu.h"
+#include "trace-root.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig)
 return -1;
 }
 
-/* #define DEBUG_GDB */
-
-#ifdef DEBUG_GDB
-# define DEBUG_GDB_GATE 1
-#else
-# define DEBUG_GDB_GATE 0
-#endif
-
-#define gdb_debug(fmt, ...) do { \
-if (DEBUG_GDB_GATE) { \
-fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
-} \
-} while (0)
-
-
 typedef struct GDBRegisterState {
 int base_reg;
 int num_regs;
@@ -538,12 +524,48 @@ static void hextomem(uint8_t *mem, const char *buf, int 
len)
 }
 }
 
+static void hexdump(const char *buf, int len,
+void (*trace_fn)(size_t ofs, char const *text))
+{
+char line_buffer[3 * 16 + 4 + 16 + 1];
+
+size_t i;
+for (i = 0; i < len || (i & 0xF); ++i) {
+size_t byte_ofs = i & 15;
+
+if (byte_ofs == 0) {
+memset(line_buffer, ' ', 3 * 16 + 4 + 16);
+line_buffer[3 * 16 + 4 + 16] = 0;
+}
+
+size_t col_group = (i >> 2) & 3;
+size_t hex_col = byte_ofs * 3 + col_group;
+size_t txt_col = 3 * 16 + 4 + byte_ofs;
+
+if (i < len) {
+char value = buf[i];
+
+line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
+line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
+line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
+? value
+: '.';
+}
+
+if (byte_ofs == 0xF)
+trace_fn(i & -16, line_buffer);
+}
+}
+
 /* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len)
+static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
 {
 int csum, i;
 uint8_t *p;
 
+if (TRACE_GDBSTUB_IO_BINARYREPLY_ENABLED && dump)
+hexdump(buf, len, trace_gdbstub_io_binaryreply);
+
 for(;;) {
 p = s->last_packet;
 *(p++) = '$';
@@ -576,9 +598,9 @@ static int put_packet_binary(GDBState *s, const char *buf, 
int len)
 /* return -1 if error, 0 if OK */
 static int put_packet(GDBState *s, const char *buf)
 {
-gdb_debug("reply='%s'\n", buf);
+trace_gdbstub_io_reply(buf);
 
-return put_packet_binary(s, buf, strlen(buf));
+return put_packet_binary(s, buf, strlen(buf), false);
 }
 
 /* Encode data using the encoding for 'x' packets.  */
@@ -975,8 +997,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 
-
-gdb_debug("command='%s'\n", line_buf);
+trace_gdbstub_io_command(line_buf);
 
 p = line_buf;
 ch = *p++;
@@ -999,7 +1020,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 s->signal = 0;
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'C':
 s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
 if (s->signal == -1)
@@ -1045,7 +1066,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 cpu_single_step(s->c_cpu, sstep_flags);
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'F':
 {
 target_ulong ret;
@@ -1267,6 +1288,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 len = snprintf((char *)mem_buf, sizeof(buf) / 2,
"CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
+trace_gdbstub_op_extra_info((char *)mem_buf);
 memtohex(buf, mem_buf, len);
 put_packet(s, buf);
 }
@@ -1350,7 +1372,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 buf[0] = 'l';
 len = memtox(buf + 1, xml + addr, total_len - addr);
 }
-put_packet_binary(s, buf, len + 1);
+put_packet_binary(s, buf, len + 1, true);
 break;
 }
 if (is_query_packet(p, "Attached", ':')) {
@@ -1407,6 +1429,8 @@ static void gdb_vm_state_change(void *opaque, int 
running, RunState state)
 type = "";
 break;
 }
+ 

[Qemu-devel] [PATCH v2] gdbstub: add tracing

2017-11-26 Thread Doug Gale
Signed-off-by: Doug Gale 
---
 gdbstub.c| 101 ++-
 trace-events |  21 +
 2 files changed, 87 insertions(+), 35 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2a94030d3b..86482fa009 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -21,6 +21,7 @@
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
 #include "cpu.h"
+#include "trace-root.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig)
 return -1;
 }
 
-/* #define DEBUG_GDB */
-
-#ifdef DEBUG_GDB
-# define DEBUG_GDB_GATE 1
-#else
-# define DEBUG_GDB_GATE 0
-#endif
-
-#define gdb_debug(fmt, ...) do { \
-if (DEBUG_GDB_GATE) { \
-fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
-} \
-} while (0)
-
-
 typedef struct GDBRegisterState {
 int base_reg;
 int num_regs;
@@ -538,12 +524,48 @@ static void hextomem(uint8_t *mem, const char *buf, int 
len)
 }
 }
 
+static void hexdump(const char *buf, int len,
+void (*trace_fn)(size_t ofs, char const *text))
+{
+char line_buffer[3 * 16 + 4 + 16 + 1];
+
+size_t i;
+for (i = 0; i < len || (i & 0xF); ++i) {
+size_t byte_ofs = i & 15;
+
+if (byte_ofs == 0) {
+memset(line_buffer, ' ', 3 * 16 + 4 + 16);
+line_buffer[3 * 16 + 4 + 16] = 0;
+}
+
+size_t col_group = (i >> 2) & 3;
+size_t hex_col = byte_ofs * 3 + col_group;
+size_t txt_col = 3 * 16 + 4 + byte_ofs;
+
+if (i < len) {
+char value = buf[i];
+
+line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
+line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
+line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
+? value
+: '.';
+}
+
+if (byte_ofs == 0xF)
+trace_fn(i & -16, line_buffer);
+}
+}
+
 /* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len)
+static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
 {
 int csum, i;
 uint8_t *p;
 
+if (TRACE_GDBSTUB_IO_BINARYREPLY_ENABLED && dump)
+hexdump(buf, len, trace_gdbstub_io_binaryreply);
+
 for(;;) {
 p = s->last_packet;
 *(p++) = '$';
@@ -576,9 +598,9 @@ static int put_packet_binary(GDBState *s, const char *buf, 
int len)
 /* return -1 if error, 0 if OK */
 static int put_packet(GDBState *s, const char *buf)
 {
-gdb_debug("reply='%s'\n", buf);
+trace_gdbstub_io_reply(buf);
 
-return put_packet_binary(s, buf, strlen(buf));
+return put_packet_binary(s, buf, strlen(buf), false);
 }
 
 /* Encode data using the encoding for 'x' packets.  */
@@ -975,8 +997,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 
-
-gdb_debug("command='%s'\n", line_buf);
+trace_gdbstub_io_command(line_buf);
 
 p = line_buf;
 ch = *p++;
@@ -999,7 +1020,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 s->signal = 0;
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'C':
 s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
 if (s->signal == -1)
@@ -1045,7 +1066,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 cpu_single_step(s->c_cpu, sstep_flags);
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'F':
 {
 target_ulong ret;
@@ -1267,6 +1288,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 len = snprintf((char *)mem_buf, sizeof(buf) / 2,
"CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
+trace_gdbstub_op_extra_info((char *)mem_buf);
 memtohex(buf, mem_buf, len);
 put_packet(s, buf);
 }
@@ -1350,7 +1372,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 buf[0] = 'l';
 len = memtox(buf + 1, xml + addr, total_len - addr);
 }
-put_packet_binary(s, buf, len + 1);
+put_packet_binary(s, buf, len + 1, true);
 break;
 }
 if (is_query_packet(p, "Attached", ':')) {
@@ -1407,6 +1429,8 @@ static void gdb_vm_state_change(void *opaque, int 
running, RunState state)
 type = "";
 break;
 }
+ 

[Qemu-devel] [PATCH] gdbstub: add tracing

2017-11-26 Thread Doug Gale
Signed-off-by: Doug Gale 
---
 gdbstub.c| 100 ++-
 trace-events |  21 +
 2 files changed, 86 insertions(+), 35 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 2a94030d3b..a75f319bd0 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -21,6 +21,7 @@
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
 #include "cpu.h"
+#include "trace-root.h"
 #ifdef CONFIG_USER_ONLY
 #include "qemu.h"
 #else
@@ -287,21 +288,6 @@ static int gdb_signal_to_target (int sig)
 return -1;
 }
 
-/* #define DEBUG_GDB */
-
-#ifdef DEBUG_GDB
-# define DEBUG_GDB_GATE 1
-#else
-# define DEBUG_GDB_GATE 0
-#endif
-
-#define gdb_debug(fmt, ...) do { \
-if (DEBUG_GDB_GATE) { \
-fprintf(stderr, "%s: " fmt, __func__, ## __VA_ARGS__); \
-} \
-} while (0)
-
-
 typedef struct GDBRegisterState {
 int base_reg;
 int num_regs;
@@ -538,12 +524,47 @@ static void hextomem(uint8_t *mem, const char *buf, int 
len)
 }
 }
 
+static void hexdump(const char *buf, int len,
+void (*trace_fn)(size_t ofs, char const *text))
+{
+char line_buffer[3 * 16 + 4 + 16 + 1];
+
+for (size_t i = 0; i < len || (i & 0xF); ++i) {
+size_t byte_ofs = i & 15;
+
+if (byte_ofs == 0) {
+memset(line_buffer, ' ', 3 * 16 + 4 + 16);
+line_buffer[3 * 16 + 4 + 16] = 0;
+}
+
+size_t col_group = (i >> 2) & 3;
+size_t hex_col = byte_ofs * 3 + col_group;
+size_t txt_col = 3 * 16 + 4 + byte_ofs;
+
+if (i < len) {
+char value = buf[i];
+
+line_buffer[hex_col + 0] = tohex((value >> 4) & 0xF);
+line_buffer[hex_col + 1] = tohex((value >> 0) & 0xF);
+line_buffer[txt_col + 0] = (value >= ' ' && value < 127)
+? value
+: '.';
+}
+
+if (byte_ofs == 0xF)
+trace_fn(i & -16, line_buffer);
+}
+}
+
 /* return -1 if error, 0 if OK */
-static int put_packet_binary(GDBState *s, const char *buf, int len)
+static int put_packet_binary(GDBState *s, const char *buf, int len, bool dump)
 {
 int csum, i;
 uint8_t *p;
 
+if (TRACE_GDBSTUB_IO_BINARYREPLY_ENABLED && dump)
+hexdump(buf, len, trace_gdbstub_io_binaryreply);
+
 for(;;) {
 p = s->last_packet;
 *(p++) = '$';
@@ -576,9 +597,9 @@ static int put_packet_binary(GDBState *s, const char *buf, 
int len)
 /* return -1 if error, 0 if OK */
 static int put_packet(GDBState *s, const char *buf)
 {
-gdb_debug("reply='%s'\n", buf);
+trace_gdbstub_io_reply(buf);
 
-return put_packet_binary(s, buf, strlen(buf));
+return put_packet_binary(s, buf, strlen(buf), false);
 }
 
 /* Encode data using the encoding for 'x' packets.  */
@@ -975,8 +996,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 uint8_t *registers;
 target_ulong addr, len;
 
-
-gdb_debug("command='%s'\n", line_buf);
+trace_gdbstub_io_command(line_buf);
 
 p = line_buf;
 ch = *p++;
@@ -999,7 +1019,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 s->signal = 0;
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'C':
 s->signal = gdb_signal_to_target (strtoul(p, (char **)&p, 16));
 if (s->signal == -1)
@@ -1045,7 +1065,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 }
 cpu_single_step(s->c_cpu, sstep_flags);
 gdb_continue(s);
-   return RS_IDLE;
+return RS_IDLE;
 case 'F':
 {
 target_ulong ret;
@@ -1267,6 +1287,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 len = snprintf((char *)mem_buf, sizeof(buf) / 2,
"CPU#%d [%s]", cpu->cpu_index,
cpu->halted ? "halted " : "running");
+trace_gdbstub_op_extra_info((char *)mem_buf);
 memtohex(buf, mem_buf, len);
 put_packet(s, buf);
 }
@@ -1350,7 +1371,7 @@ static int gdb_handle_packet(GDBState *s, const char 
*line_buf)
 buf[0] = 'l';
 len = memtox(buf + 1, xml + addr, total_len - addr);
 }
-put_packet_binary(s, buf, len + 1);
+put_packet_binary(s, buf, len + 1, true);
 break;
 }
 if (is_query_packet(p, "Attached", ':')) {
@@ -1407,6 +1428,8 @@ static void gdb_vm_state_change(void *opaque, int 
running, RunState state)
 type = "";
 break;
 }
+  

Re: [Qemu-devel] [PATCH v5] nvme: Add tracing

2017-11-24 Thread Doug Gale
Ping

On Thu, Nov 16, 2017 at 6:16 AM, Doug Gale  wrote:
> I submitted it with git Nov 3 - the long lines issue with git-am
> should be resolved. Please let me know if there's still a problem.
>
> Thanks.
>
>
> On Fri, Nov 3, 2017 at 11:58 AM, Philippe Mathieu-Daudé  
> wrote:
>> Cc'ing Trivial ;)
>>
>> On 11/03/2017 10:37 AM, Doug Gale wrote:
>>> Add trace output for commands, errors, and undefined behavior.
>>> Add guest error log output for undefined behavior.
>>> Report invalid undefined accesses to MMIO.
>>> Annotate unlikely error checks with unlikely.
>>>
>>> Signed-off-by: Doug Gale 
>>> Reviewed-by: Philippe Mathieu-Daudé 
>>> Reviewed-by: Stefan Hajnoczi 
>>> ---
>>> changes v4 -> v5: add R-b tags
>>>  hw/block/nvme.c   | 349 
>>> ++
>>>  hw/block/trace-events |  93 ++
>>>  2 files changed, 390 insertions(+), 52 deletions(-)
>>>
>>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>>> index 441e21ed1f..4d98ed9fba 100644
>>> --- a/hw/block/nvme.c
>>> +++ b/hw/block/nvme.c
>>> @@ -34,8 +34,17 @@
>>>  #include "qapi/visitor.h"
>>>  #include "sysemu/block-backend.h"
>>>
>>> +#include "qemu/log.h"
>>> +#include "trace.h"
>>>  #include "nvme.h"
>>>
>>> +#define NVME_GUEST_ERR(trace, fmt, ...) \
>>> +do { \
>>> +(trace_##trace)(__VA_ARGS__); \
>>> +qemu_log_mask(LOG_GUEST_ERROR, #trace \
>>> +" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
>>> +} while (0)
>>> +
>>>  static void nvme_process_sq(void *opaque);
>>>
>>>  static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
>>> @@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
>>>  {
>>>  if (cq->irq_enabled) {
>>>  if (msix_enabled(&(n->parent_obj))) {
>>> +trace_nvme_irq_msix(cq->vector);
>>>  msix_notify(&(n->parent_obj), cq->vector);
>>>  } else {
>>> +trace_nvme_irq_pin();
>>>  pci_irq_pulse(&n->parent_obj);
>>>  }
>>> +} else {
>>> +trace_nvme_irq_masked();
>>>  }
>>>  }
>>>
>>> @@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>>> QEMUIOVector *iov, uint64_t prp1,
>>>  trans_len = MIN(len, trans_len);
>>>  int num_prps = (len >> n->page_bits) + 1;
>>>
>>> -if (!prp1) {
>>> +if (unlikely(!prp1)) {
>>> +trace_nvme_err_invalid_prp();
>>>  return NVME_INVALID_FIELD | NVME_DNR;
>>>  } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
>>> prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
>>> @@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>>> QEMUIOVector *iov, uint64_t prp1,
>>>  }
>>>  len -= trans_len;
>>>  if (len) {
>>> -if (!prp2) {
>>> +if (unlikely(!prp2)) {
>>> +trace_nvme_err_invalid_prp2_missing();
>>>  goto unmap;
>>>  }
>>>  if (len > n->page_size) {
>>> @@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>>> QEMUIOVector *iov, uint64_t prp1,
>>>  uint64_t prp_ent = le64_to_cpu(prp_list[i]);
>>>
>>>  if (i == n->max_prp_ents - 1 && len > n->page_size) {
>>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>>> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 
>>> 1))) {
>>> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>>>  goto unmap;
>>>  }
>>>
>>> @@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>>> QEMUIOVector *iov, uint64_t prp1,
>>>  prp_ent = le64_to_cpu(prp_list[i]);
>>>  }
>>>
>>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>>> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
>>> +tr

Re: [Qemu-devel] [PATCH v5] nvme: Add tracing

2017-11-16 Thread Doug Gale
I submitted it with git Nov 3 - the long lines issue with git-am
should be resolved. Please let me know if there's still a problem.

Thanks.


On Fri, Nov 3, 2017 at 11:58 AM, Philippe Mathieu-Daudé  wrote:
> Cc'ing Trivial ;)
>
> On 11/03/2017 10:37 AM, Doug Gale wrote:
>> Add trace output for commands, errors, and undefined behavior.
>> Add guest error log output for undefined behavior.
>> Report invalid undefined accesses to MMIO.
>> Annotate unlikely error checks with unlikely.
>>
>> Signed-off-by: Doug Gale 
>> Reviewed-by: Philippe Mathieu-Daudé 
>> Reviewed-by: Stefan Hajnoczi 
>> ---
>> changes v4 -> v5: add R-b tags
>>  hw/block/nvme.c   | 349 
>> ++
>>  hw/block/trace-events |  93 ++
>>  2 files changed, 390 insertions(+), 52 deletions(-)
>>
>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>> index 441e21ed1f..4d98ed9fba 100644
>> --- a/hw/block/nvme.c
>> +++ b/hw/block/nvme.c
>> @@ -34,8 +34,17 @@
>>  #include "qapi/visitor.h"
>>  #include "sysemu/block-backend.h"
>>
>> +#include "qemu/log.h"
>> +#include "trace.h"
>>  #include "nvme.h"
>>
>> +#define NVME_GUEST_ERR(trace, fmt, ...) \
>> +do { \
>> +(trace_##trace)(__VA_ARGS__); \
>> +qemu_log_mask(LOG_GUEST_ERROR, #trace \
>> +" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
>> +} while (0)
>> +
>>  static void nvme_process_sq(void *opaque);
>>
>>  static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
>> @@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
>>  {
>>  if (cq->irq_enabled) {
>>  if (msix_enabled(&(n->parent_obj))) {
>> +trace_nvme_irq_msix(cq->vector);
>>  msix_notify(&(n->parent_obj), cq->vector);
>>  } else {
>> +trace_nvme_irq_pin();
>>  pci_irq_pulse(&n->parent_obj);
>>  }
>> +} else {
>> +trace_nvme_irq_masked();
>>  }
>>  }
>>
>> @@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>> QEMUIOVector *iov, uint64_t prp1,
>>  trans_len = MIN(len, trans_len);
>>  int num_prps = (len >> n->page_bits) + 1;
>>
>> -if (!prp1) {
>> +if (unlikely(!prp1)) {
>> +trace_nvme_err_invalid_prp();
>>  return NVME_INVALID_FIELD | NVME_DNR;
>>  } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
>> prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
>> @@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>> QEMUIOVector *iov, uint64_t prp1,
>>  }
>>  len -= trans_len;
>>  if (len) {
>> -if (!prp2) {
>> +if (unlikely(!prp2)) {
>> +trace_nvme_err_invalid_prp2_missing();
>>  goto unmap;
>>  }
>>  if (len > n->page_size) {
>> @@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>> QEMUIOVector *iov, uint64_t prp1,
>>  uint64_t prp_ent = le64_to_cpu(prp_list[i]);
>>
>>  if (i == n->max_prp_ents - 1 && len > n->page_size) {
>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) 
>> {
>> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>>  goto unmap;
>>  }
>>
>> @@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>> QEMUIOVector *iov, uint64_t prp1,
>>  prp_ent = le64_to_cpu(prp_list[i]);
>>  }
>>
>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
>> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>>  goto unmap;
>>  }
>>
>> @@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, 
>> QEMUIOVector *iov, uint64_t prp1,
>>  i++;
>>  }
>>  } else {
>> -if (prp2 & (n->page_size - 1)) {
>> +if (unlikely(prp2 & (n->page_size - 1))) {
>> +  

[Qemu-devel] [PATCH v5] nvme: Add tracing

2017-11-03 Thread Doug Gale
Add trace output for commands, errors, and undefined behavior.
Add guest error log output for undefined behavior.
Report invalid undefined accesses to MMIO.
Annotate unlikely error checks with unlikely.

Signed-off-by: Doug Gale 
Reviewed-by: Philippe Mathieu-Daudé 
Reviewed-by: Stefan Hajnoczi 
---
changes v4 -> v5: add R-b tags
 hw/block/nvme.c   | 349 ++
 hw/block/trace-events |  93 ++
 2 files changed, 390 insertions(+), 52 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 441e21ed1f..4d98ed9fba 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,8 +34,17 @@
 #include "qapi/visitor.h"
 #include "sysemu/block-backend.h"
 
+#include "qemu/log.h"
+#include "trace.h"
 #include "nvme.h"
 
+#define NVME_GUEST_ERR(trace, fmt, ...) \
+do { \
+(trace_##trace)(__VA_ARGS__); \
+qemu_log_mask(LOG_GUEST_ERROR, #trace \
+" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
+} while (0)
+
 static void nvme_process_sq(void *opaque);
 
 static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+trace_nvme_irq_msix(cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+trace_nvme_irq_pin();
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+trace_nvme_irq_masked();
 }
 }
 
@@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 trans_len = MIN(len, trans_len);
 int num_prps = (len >> n->page_bits) + 1;
 
-if (!prp1) {
+if (unlikely(!prp1)) {
+trace_nvme_err_invalid_prp();
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 }
 len -= trans_len;
 if (len) {
-if (!prp2) {
+if (unlikely(!prp2)) {
+trace_nvme_err_invalid_prp2_missing();
 goto unmap;
 }
 if (len > n->page_size) {
@@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 uint64_t prp_ent = le64_to_cpu(prp_list[i]);
 
 if (i == n->max_prp_ents - 1 && len > n->page_size) {
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }
 
@@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 prp_ent = le64_to_cpu(prp_list[i]);
 }
 
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }
 
@@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 i++;
 }
 } else {
-if (prp2 & (n->page_size - 1)) {
+if (unlikely(prp2 & (n->page_size - 1))) {
+trace_nvme_err_invalid_prp2_align(prp2);
 goto unmap;
 }
 if (qsg->nsg) {
@@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t 
*ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;
 
+trace_nvme_dma_read(prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
-if (dma_buf_read(ptr, len, &qsg)) {
+if (unlikely(dma_buf_read(ptr, len, &qsg))) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
-if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace 
*ns, NvmeCmd *cmd,
 uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
 uint32_t aio_nlb = nlb <

[Qemu-devel] [PATCH] nvme: Add tracing

2017-11-03 Thread Doug Gale
Add trace output for commands, errors, and undefined behavior.
Add guest error log output for undefined behavior.
Report invalid undefined accesses to MMIO.
Annotate unlikely error checks with unlikely.

Signed-off-by: Doug Gale 
---
 hw/block/nvme.c   | 349 ++
 hw/block/trace-events |  93 ++
 2 files changed, 390 insertions(+), 52 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 441e21ed1f..4d98ed9fba 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,8 +34,17 @@
 #include "qapi/visitor.h"
 #include "sysemu/block-backend.h"
 
+#include "qemu/log.h"
+#include "trace.h"
 #include "nvme.h"
 
+#define NVME_GUEST_ERR(trace, fmt, ...) \
+do { \
+(trace_##trace)(__VA_ARGS__); \
+qemu_log_mask(LOG_GUEST_ERROR, #trace \
+" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
+} while (0)
+
 static void nvme_process_sq(void *opaque);
 
 static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+trace_nvme_irq_msix(cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+trace_nvme_irq_pin();
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+trace_nvme_irq_masked();
 }
 }
 
@@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 trans_len = MIN(len, trans_len);
 int num_prps = (len >> n->page_bits) + 1;
 
-if (!prp1) {
+if (unlikely(!prp1)) {
+trace_nvme_err_invalid_prp();
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 }
 len -= trans_len;
 if (len) {
-if (!prp2) {
+if (unlikely(!prp2)) {
+trace_nvme_err_invalid_prp2_missing();
 goto unmap;
 }
 if (len > n->page_size) {
@@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 uint64_t prp_ent = le64_to_cpu(prp_list[i]);
 
 if (i == n->max_prp_ents - 1 && len > n->page_size) {
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }
 
@@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 prp_ent = le64_to_cpu(prp_list[i]);
 }
 
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }
 
@@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg, QEMUIOVector 
*iov, uint64_t prp1,
 i++;
 }
 } else {
-if (prp2 & (n->page_size - 1)) {
+if (unlikely(prp2 & (n->page_size - 1))) {
+trace_nvme_err_invalid_prp2_align(prp2);
 goto unmap;
 }
 if (qsg->nsg) {
@@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n, uint8_t 
*ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;
 
+trace_nvme_dma_read(prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
-if (dma_buf_read(ptr, len, &qsg)) {
+if (unlikely(dma_buf_read(ptr, len, &qsg))) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
-if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n, NvmeNamespace 
*ns, NvmeCmd *cmd,
 uint64_t aio_slba = slba << (data_shift - BDRV_SECTOR_BITS);
 uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);
 
-if (slba + nlb > ns->id_ns.nsze) {
+if (unlikely

[Qemu-devel] [PATCH v4] nvme: Add tracing

2017-10-30 Thread Doug Gale
>From 0e27b5dca8f4f32a1b194e1b3544be77dd4f45d9 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Mon, 30 Oct 2017 09:28:43 -0400
Subject: [PATCH] nvme: Add tracing

Add trace output for commands, errors, and undefined behavior.
Add guest error log output for undefined behavior.
Report invalid undefined accesses to MMIO.
Annotate unlikely error checks with unlikely.

Signed-off-by: Doug Gale 
---
 hw/block/nvme.c   | 349 ++
 hw/block/trace-events |  93 ++
 2 files changed, 390 insertions(+), 52 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 441e21ed1f..4d98ed9fba 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,8 +34,17 @@
 #include "qapi/visitor.h"
 #include "sysemu/block-backend.h"

+#include "qemu/log.h"
+#include "trace.h"
 #include "nvme.h"

+#define NVME_GUEST_ERR(trace, fmt, ...) \
+do { \
+(trace_##trace)(__VA_ARGS__); \
+qemu_log_mask(LOG_GUEST_ERROR, #trace \
+" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
+} while (0)
+
 static void nvme_process_sq(void *opaque);

 static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+trace_nvme_irq_msix(cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+trace_nvme_irq_pin();
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+trace_nvme_irq_masked();
 }
 }

@@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 trans_len = MIN(len, trans_len);
 int num_prps = (len >> n->page_bits) + 1;

-if (!prp1) {
+if (unlikely(!prp1)) {
+trace_nvme_err_invalid_prp();
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 }
 len -= trans_len;
 if (len) {
-if (!prp2) {
+if (unlikely(!prp2)) {
+trace_nvme_err_invalid_prp2_missing();
 goto unmap;
 }
 if (len > n->page_size) {
@@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 uint64_t prp_ent = le64_to_cpu(prp_list[i]);

 if (i == n->max_prp_ents - 1 && len > n->page_size) {
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 prp_ent = le64_to_cpu(prp_list[i]);
 }

-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 i++;
 }
 } else {
-if (prp2 & (n->page_size - 1)) {
+if (unlikely(prp2 & (n->page_size - 1))) {
+trace_nvme_err_invalid_prp2_align(prp2);
 goto unmap;
 }
 if (qsg->nsg) {
@@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n,
uint8_t *ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;

+trace_nvme_dma_read(prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
-if (dma_buf_read(ptr, len, &qsg)) {
+if (unlikely(dma_buf_read(ptr, len, &qsg))) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
-if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 uint64_t aio_slba = slba << (data_shift - BDRV

Re: [Qemu-devel] nvme: Add tracing v3

2017-10-30 Thread Doug Gale
On Fri, Oct 20, 2017 at 4:11 PM, Doug Gale  wrote:

> On Thu, Oct 12, 2017 at 3:07 PM, Doug Gale  wrote:
>
>> From c7f12a5949458fdd195b5e0b52f158e8f114f203 Mon Sep 17 00:00:00 2001
>> From: Doug Gale 
>> Date: Thu, 12 Oct 2017 14:29:07 -0400
>> Subject: [PATCH] nvme: Add tracing
>>
>> Add trace output for commands, errors, and undefined behavior.
>> Add guest error log output for undefined behavior.
>> Report and ignore invalid undefined accesses to MMIO.
>> Annotate unlikely error checks with unlikely.
>>
>> Signed-off-by: Doug Gale 
>> ---
>>  hw/block/nvme.c   | 347 ++
>> 
>>  hw/block/trace-events |  93 ++
>>  2 files changed, 387 insertions(+), 53 deletions(-)
>>
>> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>> index 9aa32692a3..adac19f5b0 100644
>> --- a/hw/block/nvme.c
>> +++ b/hw/block/nvme.c
>> @@ -34,8 +34,17 @@
>>  #include "qapi/visitor.h"
>>  #include "sysemu/block-backend.h"
>>
>> +#include "qemu/log.h"
>> +#include "trace.h"
>>  #include "nvme.h"
>>
>> +#define NVME_GUEST_ERR(trace, fmt, ...) \
>> +do { \
>> +(trace_##trace)(__VA_ARGS__); \
>> +qemu_log_mask(LOG_GUEST_ERROR, #trace \
>> +" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
>> +} while (0)
>> +
>>  static void nvme_process_sq(void *opaque);
>>
>>  static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
>> @@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue
>> *cq)
>>  {
>>  if (cq->irq_enabled) {
>>  if (msix_enabled(&(n->parent_obj))) {
>> +trace_nvme_irq_msix(cq->vector);
>>  msix_notify(&(n->parent_obj), cq->vector);
>>  } else {
>> +trace_nvme_irq_pin();
>>  pci_irq_pulse(&n->parent_obj);
>>  }
>> +} else {
>> +trace_nvme_irq_masked();
>>  }
>>  }
>>
>> @@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
>> QEMUIOVector *iov, uint64_t prp1,
>>  trans_len = MIN(len, trans_len);
>>  int num_prps = (len >> n->page_bits) + 1;
>>
>> -if (!prp1) {
>> +if (unlikely(!prp1)) {
>> +trace_nvme_err_invalid_prp();
>>  return NVME_INVALID_FIELD | NVME_DNR;
>>  } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
>> prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size))
>> {
>> @@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
>> QEMUIOVector *iov, uint64_t prp1,
>>  }
>>  len -= trans_len;
>>  if (len) {
>> -if (!prp2) {
>> +if (unlikely(!prp2)) {
>> +trace_nvme_err_invalid_prp2_missing();
>>  goto unmap;
>>  }
>>  if (len > n->page_size) {
>> @@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
>> QEMUIOVector *iov, uint64_t prp1,
>>  uint64_t prp_ent = le64_to_cpu(prp_list[i]);
>>
>>  if (i == n->max_prp_ents - 1 && len > n->page_size) {
>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>> +if (unlikely(!prp_ent || prp_ent & (n->page_size -
>> 1))) {
>> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>>  goto unmap;
>>  }
>>
>> @@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
>> QEMUIOVector *iov, uint64_t prp1,
>>  prp_ent = le64_to_cpu(prp_list[i]);
>>  }
>>
>> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
>> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
>> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>>  goto unmap;
>>  }
>>
>> @@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
>> QEMUIOVector *iov, uint64_t prp1,
>>  i++;
>>  }
>>  } else {
>> -if (prp2 & (n->page_size - 1)) {
>> +if (unlikely(prp2 & (n->page_size - 1))) {
>> +trace_nvme_err_invalid_prp2_align(prp2);
>>  goto unma

Re: [Qemu-devel] nvme: Add tracing v3

2017-10-20 Thread Doug Gale
On Thu, Oct 12, 2017 at 3:07 PM, Doug Gale  wrote:

> From c7f12a5949458fdd195b5e0b52f158e8f114f203 Mon Sep 17 00:00:00 2001
> From: Doug Gale 
> Date: Thu, 12 Oct 2017 14:29:07 -0400
> Subject: [PATCH] nvme: Add tracing
>
> Add trace output for commands, errors, and undefined behavior.
> Add guest error log output for undefined behavior.
> Report and ignore invalid undefined accesses to MMIO.
> Annotate unlikely error checks with unlikely.
>
> Signed-off-by: Doug Gale 
> ---
>  hw/block/nvme.c   | 347 ++
> 
>  hw/block/trace-events |  93 ++
>  2 files changed, 387 insertions(+), 53 deletions(-)
>
> diff --git a/hw/block/nvme.c b/hw/block/nvme.c
> index 9aa32692a3..adac19f5b0 100644
> --- a/hw/block/nvme.c
> +++ b/hw/block/nvme.c
> @@ -34,8 +34,17 @@
>  #include "qapi/visitor.h"
>  #include "sysemu/block-backend.h"
>
> +#include "qemu/log.h"
> +#include "trace.h"
>  #include "nvme.h"
>
> +#define NVME_GUEST_ERR(trace, fmt, ...) \
> +do { \
> +(trace_##trace)(__VA_ARGS__); \
> +qemu_log_mask(LOG_GUEST_ERROR, #trace \
> +" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
> +} while (0)
> +
>  static void nvme_process_sq(void *opaque);
>
>  static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
> @@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue
> *cq)
>  {
>  if (cq->irq_enabled) {
>  if (msix_enabled(&(n->parent_obj))) {
> +trace_nvme_irq_msix(cq->vector);
>  msix_notify(&(n->parent_obj), cq->vector);
>  } else {
> +trace_nvme_irq_pin();
>  pci_irq_pulse(&n->parent_obj);
>  }
> +} else {
> +trace_nvme_irq_masked();
>  }
>  }
>
> @@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
> QEMUIOVector *iov, uint64_t prp1,
>  trans_len = MIN(len, trans_len);
>  int num_prps = (len >> n->page_bits) + 1;
>
> -if (!prp1) {
> +if (unlikely(!prp1)) {
> +trace_nvme_err_invalid_prp();
>  return NVME_INVALID_FIELD | NVME_DNR;
>  } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
> prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size))
> {
> @@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
> QEMUIOVector *iov, uint64_t prp1,
>  }
>  len -= trans_len;
>  if (len) {
> -if (!prp2) {
> +if (unlikely(!prp2)) {
> +trace_nvme_err_invalid_prp2_missing();
>  goto unmap;
>  }
>  if (len > n->page_size) {
> @@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
> QEMUIOVector *iov, uint64_t prp1,
>  uint64_t prp_ent = le64_to_cpu(prp_list[i]);
>
>  if (i == n->max_prp_ents - 1 && len > n->page_size) {
> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
> +if (unlikely(!prp_ent || prp_ent & (n->page_size -
> 1))) {
> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>  goto unmap;
>  }
>
> @@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
> QEMUIOVector *iov, uint64_t prp1,
>  prp_ent = le64_to_cpu(prp_list[i]);
>  }
>
> -if (!prp_ent || prp_ent & (n->page_size - 1)) {
> +if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
> +trace_nvme_err_invalid_prplist_ent(prp_ent);
>  goto unmap;
>  }
>
> @@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
> QEMUIOVector *iov, uint64_t prp1,
>  i++;
>  }
>  } else {
> -if (prp2 & (n->page_size - 1)) {
> +if (unlikely(prp2 & (n->page_size - 1))) {
> +trace_nvme_err_invalid_prp2_align(prp2);
>  goto unmap;
>  }
>  if (qsg->nsg) {
> @@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n,
> uint8_t *ptr, uint32_t len,
>  QEMUIOVector iov;
>  uint16_t status = NVME_SUCCESS;
>
> +trace_nvme_dma_read(prp1, prp2);
> +
>  if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
>  return NVME_INVALID_FIELD | NVME_DNR;
>  }
>  if (qsg.nsg > 0) {
> -if (dma_buf_read(ptr, len, &q

[Qemu-devel] nvme: Add tracing v3

2017-10-12 Thread Doug Gale
>From c7f12a5949458fdd195b5e0b52f158e8f114f203 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Thu, 12 Oct 2017 14:29:07 -0400
Subject: [PATCH] nvme: Add tracing

Add trace output for commands, errors, and undefined behavior.
Add guest error log output for undefined behavior.
Report and ignore invalid undefined accesses to MMIO.
Annotate unlikely error checks with unlikely.

Signed-off-by: Doug Gale 
---
 hw/block/nvme.c   | 347 ++
 hw/block/trace-events |  93 ++
 2 files changed, 387 insertions(+), 53 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 9aa32692a3..adac19f5b0 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,8 +34,17 @@
 #include "qapi/visitor.h"
 #include "sysemu/block-backend.h"

+#include "qemu/log.h"
+#include "trace.h"
 #include "nvme.h"

+#define NVME_GUEST_ERR(trace, fmt, ...) \
+do { \
+(trace_##trace)(__VA_ARGS__); \
+qemu_log_mask(LOG_GUEST_ERROR, #trace \
+" in %s: " fmt "\n", __func__, ## __VA_ARGS__); \
+} while (0)
+
 static void nvme_process_sq(void *opaque);

 static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +95,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+trace_nvme_irq_msix(cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+trace_nvme_irq_pin();
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+trace_nvme_irq_masked();
 }
 }

@@ -100,7 +113,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 trans_len = MIN(len, trans_len);
 int num_prps = (len >> n->page_bits) + 1;

-if (!prp1) {
+if (unlikely(!prp1)) {
+trace_nvme_err_invalid_prp();
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -113,7 +127,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 }
 len -= trans_len;
 if (len) {
-if (!prp2) {
+if (unlikely(!prp2)) {
+trace_nvme_err_invalid_prp2_missing();
 goto unmap;
 }
 if (len > n->page_size) {
@@ -128,7 +143,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 uint64_t prp_ent = le64_to_cpu(prp_list[i]);

 if (i == n->max_prp_ents - 1 && len > n->page_size) {
-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -140,7 +156,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 prp_ent = le64_to_cpu(prp_list[i]);
 }

-if (!prp_ent || prp_ent & (n->page_size - 1)) {
+if (unlikely(!prp_ent || prp_ent & (n->page_size - 1))) {
+trace_nvme_err_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -154,7 +171,8 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 i++;
 }
 } else {
-if (prp2 & (n->page_size - 1)) {
+if (unlikely(prp2 & (n->page_size - 1))) {
+trace_nvme_err_invalid_prp2_align(prp2);
 goto unmap;
 }
 if (qsg->nsg) {
@@ -178,16 +196,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n,
uint8_t *ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;

+trace_nvme_dma_read(prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
-if (dma_buf_read(ptr, len, &qsg)) {
+if (unlikely(dma_buf_read(ptr, len, &qsg))) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
-if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+if (unlikely(qemu_iovec_to_buf(&iov, 0, ptr, len) != len)) {
+trace_nvme_err_invalid_dma();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -273,7 +295,8 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 uint64_t aio_slba = slba << 

Re: [Qemu-devel] Patch to add helpful tracing output for driver authors in NVMe emulation

2017-10-11 Thread Doug Gale
On Tue, Oct 10, 2017 at 4:02 AM, Kevin Wolf  wrote:
> Am 10.10.2017 um 08:58 hat Markus Armbruster geschrieben:
>> Doug Gale  writes:
>>
>> > I used exclamations as a concise way of indicating that the driver did
>> > something nonsensical, or horribly invalid, like something likely to
>> > cause a memory corruption, trying to start the controller with a
>> > nonsense configuration, providing invalid PRDs or writing to
>> > unrecognized MMIO offsets that might hang or do something extremely
>> > bad on a poorly implemented controller. Exclaiming is not shouting, I
>> > thought shouting was when it was all uppercase.
>> >
>> > If a driver might trash memory or hang a controller, maybe it should
>> > shout at the driver author or person investigating an unstable VM.
>> > None of those messages with exclamations should ever happen. If any of
>> > them are possible when the driver is correct, then I have made a
>> > mistake.
>>
>> Please do not top-quote on this mailing list.
>>
>> Existing tracepoints do not use exclamation marks to signal severity.
>>
>> Consider using assertions for "if this happens, either the program's
>> state is shot (and continuing is unsafe), or the author's mental state
>> was shot (and continuing is probably unsafe, too)" conditions.
>> Tracepoints are for tracing.
>
> Assertions are for checking that assumptions in qemu code hold true.
> Here it's about bad guest code, and you can't let qemu abort for that.
>
> Tracing is the right tool to detect bad guest code, and I think it makes
> sense to mark conditions that shouldn't happen with a correctly
> operating guest driver. I'm not sure if an exclamation mark is the best
> syntax for this, because I wouldn't have intuitively understood what
> it's supposed to tell me.
>
> If we do use the exclamation mark, we should document it somewhere
> (docs/devel/tracing.txt?) and make it a qemu-wide pattern. If not, we
> should choose something else and still document it and use it
> consistently.
>
> Kevin
>

Should I give up on indicating severity for now (removing the
exclamations) and just group together the severe ones with a comment
heading in the trace-events file?
I added "" at the end of some traces to help possibly-incorrect
parsing code find the end of the string reliably. Was that a good idea
or is it okay and expected to end them with something like PRIx64 and
drop the extra ""?
I found a few cases of missing 0x that I will fix in the next version
of this patch. Policy is to have 0x before every hex value, right?

Also, so I'm clear, when I submit the patch I should put the patch
first and put my message after the -- at the end?
And use "nvme: Add tracing" for the commit message,
And put nvme: Add tracing v3 in my subject line in a completely new
email thread?



Re: [Qemu-devel] Patch to add helpful tracing output for driver authors in NVMe emulation

2017-10-09 Thread Doug Gale
I used exclamations as a concise way of indicating that the driver did
something nonsensical, or horribly invalid, like something likely to
cause a memory corruption, trying to start the controller with a
nonsense configuration, providing invalid PRDs or writing to
unrecognized MMIO offsets that might hang or do something extremely
bad on a poorly implemented controller. Exclaiming is not shouting, I
thought shouting was when it was all uppercase.

If a driver might trash memory or hang a controller, maybe it should
shout at the driver author or person investigating an unstable VM.
None of those messages with exclamations should ever happen. If any of
them are possible when the driver is correct, then I have made a
mistake.

On Mon, Oct 9, 2017 at 11:52 AM, Eric Blake  wrote:
> On 10/07/2017 02:51 AM, Doug Gale wrote:
>> Completely re-implemented patch, with significant improvements (now
>> specifies values in several places I missed, also reduced the amount
>> of redundant lines). I used the nvme_ as the tracing infrastructure
>> prefix. Tested with -trace nvme_* on the qemu command line, worked for
>> me.
>
> This information belongs...
>
>>
>>>From 166f57458d60d363a10a0933c3e860985531ac96 Mon Sep 17 00:00:00 2001
>> From: Doug Gale 
>> Date: Thu, 5 Oct 2017 19:02:03 -0400
>> Subject: [PATCH] Add tracing output to NVMe emulation to help driver authors.
>>
>> This uses the tracing infrastructure using nvme_ as the prefix.
>>
>> Signed-off-by: Doug Gale 
>> ---
>
> ...here, after the --- separator.  It is useful to the patch reviewer,
> but does not need to be in the 'git log' history.  The maintainers use
> 'git am' to process incoming patches, which automatically prunes review
> comments located in this location.
>
> Also, since this is a version 2 patch, it is best if your subject line
> includes 'v2', and if you send the patch as a new top-level thread
> rather than in-reply-to v1.  This can be done with 'git send-email -v2'.
>
> The subject line is atypical; we tend to prefer 'topic: Short summary',
> where you are missing the topic, you had a trailing dot that is not
> typical, and where your line is longer than usual.  A better subject
> line might be:
>
> nvme: Add tracing output
>
>
> For more helpful information on patch submission:
>
> https://wiki.qemu.org/Contribute/SubmitAPatch
>
> I didn't look closely at the patch itself, but did notice:
>
>> +nvme_mmio_start_failed(void) "setting controller enable bit failed!"
>> +nvme_mmio_start_success(void) "setting controller enable bit succeeded"
>> +nvme_mmio_stopped(void) "cleared controller enable bit"
>> +nvme_mmio_shutdown_set(void) "shutdown bit set"
>> +nvme_mmio_shutdown_cleared(void) "shutdown bit cleared"
>> +nvme_mmio_ignored(uint64_t offset, uint64_t data) "invalid MMIO
>> write, offset=0x%"PRIx64", data=%"PRIx64"!"
>
> You have a couple of traces with a trailing '!'; that is atypical,
> because we don't need our traces to shout at the user.
>
> --
> Eric Blake, Principal Software Engineer
> Red Hat, Inc.   +1-919-301-3266
> Virtualization:  qemu.org | libvirt.org
>



Re: [Qemu-devel] Patch to add helpful tracing output for driver authors in NVMe emulation

2017-10-07 Thread Doug Gale
Completely re-implemented patch, with significant improvements (now
specifies values in several places I missed, also reduced the amount
of redundant lines). I used the nvme_ as the tracing infrastructure
prefix. Tested with -trace nvme_* on the qemu command line, worked for
me.

>From 166f57458d60d363a10a0933c3e860985531ac96 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Thu, 5 Oct 2017 19:02:03 -0400
Subject: [PATCH] Add tracing output to NVMe emulation to help driver authors.

This uses the tracing infrastructure using nvme_ as the prefix.

Signed-off-by: Doug Gale 
---
 hw/block/nvme.c   | 158 +-
 hw/block/trace-events |  89 
 2 files changed, 233 insertions(+), 14 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 9aa32692a3..3e3cd820a3 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -34,6 +34,7 @@
 #include "qapi/visitor.h"
 #include "sysemu/block-backend.h"

+#include "trace.h"
 #include "nvme.h"

 static void nvme_process_sq(void *opaque);
@@ -86,10 +87,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+trace_nvme_msix_intr(cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+trace_nvme_pin_intr();
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+trace_nvme_masked_intr();
 }
 }

@@ -101,6 +106,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 int num_prps = (len >> n->page_bits) + 1;

 if (!prp1) {
+trace_nvme_invalid_prp();
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
@@ -114,6 +120,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 len -= trans_len;
 if (len) {
 if (!prp2) {
+trace_nvme_invalid_prp2_missing();
 goto unmap;
 }
 if (len > n->page_size) {
@@ -129,6 +136,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,

 if (i == n->max_prp_ents - 1 && len > n->page_size) {
 if (!prp_ent || prp_ent & (n->page_size - 1)) {
+trace_nvme_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -141,6 +149,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 }

 if (!prp_ent || prp_ent & (n->page_size - 1)) {
+trace_nvme_invalid_prplist_ent(prp_ent);
 goto unmap;
 }

@@ -155,6 +164,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 }
 } else {
 if (prp2 & (n->page_size - 1)) {
+trace_nvme_invalid_prp2_align(prp2);
 goto unmap;
 }
 if (qsg->nsg) {
@@ -178,16 +188,20 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n,
uint8_t *ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;

+trace_nvme_dma_read(prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
 if (dma_buf_read(ptr, len, &qsg)) {
+trace_nvme_dma_too_short();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
 if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+trace_nvme_dma_too_short();
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -274,6 +288,7 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);

 if (slba + nlb > ns->id_ns.nsze) {
+trace_nvme_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
 return NVME_LBA_RANGE | NVME_DNR;
 }

@@ -301,8 +316,11 @@ static uint16_t nvme_rw(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
 enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;

+trace_nvme_rw(is_write ? "write" : "read", nlb, data_size, slba);
+
 if ((slba + nlb) > ns->id_ns.nsze) {
 block_acct_invalid(blk_get_stats(n->conf.blk), acct);
+trace_nvme_invalid_lba_range(slba, nlb, ns->id_ns.nsze);
 return NVME_LBA_RANGE | NVME_DNR;
 }

@@ -337,6 +355,7 @@ static uint16_t nvme_io_cmd(Nv

Re: [Qemu-devel] Patch to add helpful tracing output for driver authors in NVMe emulation

2017-10-06 Thread Doug Gale
I tried to get tracing to work before and I have never gotten it
working. I'll give it another try and redo the patch with tracing
infrastructure if necessary. The printf are nice because the dev can
just look at the terminal where qemu is running. Can you view the
trace output in realtime? When their code is sitting at a breakpoint
in their driver, can they see the last thing that was traced right
there? Or do they have to go run some cumbersome command and wade
through it after an entire test run after the vm shut down?


On Fri, Oct 6, 2017 at 9:54 AM, Daniel P. Berrange  wrote:
> On Fri, Oct 06, 2017 at 08:50:31AM -0500, Eric Blake wrote:
>> On 10/05/2017 06:18 PM, Doug Gale wrote:
>> > I added the tracing output in this patch to assist me in implementing
>> > an NVMe driver. It helped tremendously.
>> >
>> >>From 1d19086cdef8d492929852d582cb41dcc5026f71 Mon Sep 17 00:00:00 2001
>> > From: Doug Gale 
>> > Date: Thu, 5 Oct 2017 19:02:03 -0400
>> > Subject: [PATCH] Add tracing output to NVMe emulation to help driver 
>> > authors.
>> >
>> > It is off by default, enable it by uncommenting #define DEBUG_NVME
>> > or through CFLAGS
>> >
>> > Signed-off-by: Doug Gale 
>> > ---
>> >  hw/block/nvme.c | 191 
>> > +++-
>> >  1 file changed, 177 insertions(+), 14 deletions(-)
>> >
>> > diff --git a/hw/block/nvme.c b/hw/block/nvme.c
>> > index 9aa32692a3..74220c0171 100644
>> > --- a/hw/block/nvme.c
>> > +++ b/hw/block/nvme.c
>> > @@ -36,6 +36,14 @@
>> >
>> >  #include "nvme.h"
>> >
>> > +//#define DEBUG_NVME
>> > +
>> > +#ifdef DEBUG_NVME
>> > +#define DPRINTF(fmt, ...) fprintf(stderr, "nvme: " fmt "\n", ## 
>> > __VA_ARGS__)
>> > +#else
>> > +#define DPRINTF(fmt, ...) ((void)0)
>> > +#endif
>>
>> As Kevin said, using trace-events is nicer than fprintf().  But if you
>> absolutely insist on fprintf(), then do NOT do it like this, because
>> this leads to bit-rot.  Instead, do it in a form that lets -Wformat
>> checking work even when tracing is disabled:
>
> [snip]
>
> IMHO using of trace() instead of fprintf() is pretty much mandatory
> at this point. We've been making a concious effort to replace fprintfs
> with trace across code, so shouldn't add more fprintfs. It is just so
> much more useful to be able to enable the debugging without having to
> recompile the binary.
>
> Regards,
> Daniel
> --
> |: https://berrange.com  -o-https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org -o-https://fstop138.berrange.com :|
> |: https://entangle-photo.org-o-https://www.instagram.com/dberrange :|



[Qemu-devel] Patch to add helpful tracing output for driver authors in NVMe emulation

2017-10-05 Thread Doug Gale
I added the tracing output in this patch to assist me in implementing
an NVMe driver. It helped tremendously.

>From 1d19086cdef8d492929852d582cb41dcc5026f71 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Thu, 5 Oct 2017 19:02:03 -0400
Subject: [PATCH] Add tracing output to NVMe emulation to help driver authors.

It is off by default, enable it by uncommenting #define DEBUG_NVME
or through CFLAGS

Signed-off-by: Doug Gale 
---
 hw/block/nvme.c | 191 +++-
 1 file changed, 177 insertions(+), 14 deletions(-)

diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index 9aa32692a3..74220c0171 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -36,6 +36,14 @@

 #include "nvme.h"

+//#define DEBUG_NVME
+
+#ifdef DEBUG_NVME
+#define DPRINTF(fmt, ...) fprintf(stderr, "nvme: " fmt "\n", ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) ((void)0)
+#endif
+
 static void nvme_process_sq(void *opaque);

 static void nvme_addr_read(NvmeCtrl *n, hwaddr addr, void *buf, int size)
@@ -86,10 +94,14 @@ static void nvme_isr_notify(NvmeCtrl *n, NvmeCQueue *cq)
 {
 if (cq->irq_enabled) {
 if (msix_enabled(&(n->parent_obj))) {
+DPRINTF("raising MSI-X IRQ vector %u", cq->vector);
 msix_notify(&(n->parent_obj), cq->vector);
 } else {
+DPRINTF("pulsing IRQ pin");
 pci_irq_pulse(&n->parent_obj);
 }
+} else {
+DPRINTF("IRQ is masked");
 }
 }

@@ -101,9 +113,11 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,
 int num_prps = (len >> n->page_bits) + 1;

 if (!prp1) {
+DPRINTF("Invalid PRP!");
 return NVME_INVALID_FIELD | NVME_DNR;
 } else if (n->cmbsz && prp1 >= n->ctrl_mem.addr &&
prp1 < n->ctrl_mem.addr + int128_get64(n->ctrl_mem.size)) {
+DPRINTF("PRP in controller memory");
 qsg->nsg = 0;
 qemu_iovec_init(iov, num_prps);
 qemu_iovec_add(iov, (void *)&n->cmbuf[prp1 -
n->ctrl_mem.addr], trans_len);
@@ -168,6 +182,7 @@ static uint16_t nvme_map_prp(QEMUSGList *qsg,
QEMUIOVector *iov, uint64_t prp1,

  unmap:
 qemu_sglist_destroy(qsg);
+DPRINTF("invalid SGL!");
 return NVME_INVALID_FIELD | NVME_DNR;
 }

@@ -178,16 +193,22 @@ static uint16_t nvme_dma_read_prp(NvmeCtrl *n,
uint8_t *ptr, uint32_t len,
 QEMUIOVector iov;
 uint16_t status = NVME_SUCCESS;

+DPRINTF("DMA read, prp1=0x%"PRIx64" prp2=0x%"PRIx64,
+prp1, prp2);
+
 if (nvme_map_prp(&qsg, &iov, prp1, prp2, len, n)) {
+DPRINTF("DMA read invalid PRP field!");
 return NVME_INVALID_FIELD | NVME_DNR;
 }
 if (qsg.nsg > 0) {
 if (dma_buf_read(ptr, len, &qsg)) {
+DPRINTF("DMA read invalid SGL field!");
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_sglist_destroy(&qsg);
 } else {
 if (qemu_iovec_to_buf(&iov, 0, ptr, len) != len) {
+DPRINTF("invalid field!");
 status = NVME_INVALID_FIELD | NVME_DNR;
 }
 qemu_iovec_destroy(&iov);
@@ -274,6 +295,7 @@ static uint16_t nvme_write_zeros(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 uint32_t aio_nlb = nlb << (data_shift - BDRV_SECTOR_BITS);

 if (slba + nlb > ns->id_ns.nsze) {
+DPRINTF("Invalid LBA!");
 return NVME_LBA_RANGE | NVME_DNR;
 }

@@ -301,13 +323,19 @@ static uint16_t nvme_rw(NvmeCtrl *n,
NvmeNamespace *ns, NvmeCmd *cmd,
 int is_write = rw->opcode == NVME_CMD_WRITE ? 1 : 0;
 enum BlockAcctType acct = is_write ? BLOCK_ACCT_WRITE : BLOCK_ACCT_READ;

+DPRINTF("%s %"PRIu32" blocks (%"PRIu64" bytes) from LBA %"PRIu64,
+is_write ? "write" : "read",
+nlb, data_size, slba);
+
 if ((slba + nlb) > ns->id_ns.nsze) {
 block_acct_invalid(blk_get_stats(n->conf.blk), acct);
+DPRINTF("Invalid LBA!");
 return NVME_LBA_RANGE | NVME_DNR;
 }

 if (nvme_map_prp(&req->qsg, &req->iov, prp1, prp2, data_size, n)) {
 block_acct_invalid(blk_get_stats(n->conf.blk), acct);
+DPRINTF("Invalid PRP!");
 return NVME_INVALID_FIELD | NVME_DNR;
 }

@@ -337,6 +365,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd
*cmd, NvmeRequest *req)
 uint32_t nsid = le32_to_cpu(cmd->nsid);

 if (nsid == 0 || nsid > n->num_namespaces) {
+DPRINTF("Invalid namespace!");
 return NVME_INVALID_NSID | NVME_DNR;
 }

@@ -350,6 +379,7 @@ static uint16_t nvme_io_cmd(NvmeCtrl *n, NvmeCmd
*cmd, NvmeRequest *req)
 case NVME_CMD_READ:

Re: [Qemu-devel] [PATCH] gdbstub: implement remote debugging protocol escapes for command receive

2017-05-08 Thread Doug Gale
Right, only GETLINE_* states write to the linebuf, so line_buf_index <
1 is correct. Updated patch:

>From 2e6c45260cae60bbae446bffe43f948ab002c529 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Mon, 1 May 2017 12:22:10 -0400
Subject: [PATCH] gdbstub: implement remote debugging protocol escapes for
 command receive

- decode escape sequences
- decompress run-length encoding escape sequences
- report command parsing problems to output when debug output is enabled
- reject packet checksums that are not valid hex digits
- compute the checksum based on the packet stream, not based on the
  decoded packet

Tested with GDB and QtCreator integrated debugger on SMP QEMU instance.
Works for me.

Signed-off-by: Doug Gale 
---
 gdbstub.c | 108 --
 1 file changed, 99 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9911153..dee0ff3 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
 RS_INACTIVE,
 RS_IDLE,
 RS_GETLINE,
+RS_GETLINE_ESC,
+RS_GETLINE_RLE,
 RS_CHKSUM1,
 RS_CHKSUM2,
 };
@@ -296,7 +298,8 @@ typedef struct GDBState {
 enum RSState state; /* parsing state */
 char line_buf[MAX_PACKET_LENGTH];
 int line_buf_index;
-int line_csum;
+int line_sum; /* running checksum */
+int line_csum; /* checksum at the end of the packet */
 uint8_t last_packet[MAX_PACKET_LENGTH + 4];
 int last_packet_len;
 int signal;
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb,
const char *fmt, ...)

 static void gdb_read_byte(GDBState *s, int ch)
 {
-int i, csum;
 uint8_t reply;

 #ifndef CONFIG_USER_ONLY
@@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch)
 switch(s->state) {
 case RS_IDLE:
 if (ch == '$') {
+/* start of command packet */
 s->line_buf_index = 0;
+s->line_sum = 0;
 s->state = RS_GETLINE;
+} else {
+#ifdef DEBUG_GDB
+printf("gdbstub received garbage between packets: 0x%x\n", ch);
+#endif
 }
 break;
 case RS_GETLINE:
+if (ch == '}') {
+/* start escape sequence */
+s->state = RS_GETLINE_ESC;
+s->line_sum += ch;
+} else if (ch == '*') {
+/* start run length encoding sequence */
+s->state = RS_GETLINE_RLE;
+s->line_sum += ch;
+} else if (ch == '#') {
+/* end of command, start of checksum*/
+s->state = RS_CHKSUM1;
+} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else {
+/* unescaped command character */
+s->line_buf[s->line_buf_index++] = ch;
+s->line_sum += ch;
+}
+break;
+case RS_GETLINE_ESC:
 if (ch == '#') {
-s->state = RS_CHKSUM1;
+/* unexpected end of command in escape sequence */
+s->state = RS_CHKSUM1;
 } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+/* command buffer overrun */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
 s->state = RS_IDLE;
 } else {
-s->line_buf[s->line_buf_index++] = ch;
+/* parse escaped character and leave escape state */
+s->line_buf[s->line_buf_index++] = ch ^ 0x20;
+s->line_sum += ch;
+s->state = RS_GETLINE;
+}
+break;
+case RS_GETLINE_RLE:
+if (ch < ' ') {
+/* invalid RLE count encoding */
+#ifdef DEBUG_GDB
+printf("gdbstub got invalid RLE count: 0x%x\n", ch);
+#endif
+s->state = RS_GETLINE;
+} else {
+/* decode repeat length */
+int repeat = (unsigned char)ch - ' ' + 3;
+if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+/* that many repeats would overrun the command buffer */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun,"
+   " dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else if (s->line_buf_index < 1) {
+/* got a repeat but we have nothing to repeat */
+#ifdef DEBUG_GDB
+printf("gdbstub go

Re: [Qemu-devel] [PATCH] gdbstub: implement remote debugging protocol escapes for command receive

2017-05-07 Thread Doug Gale
Updated patch with comments addressed:

>From 6bce4e5c87c255f10b22d2bf6fc951dde2bbf457 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Mon, 1 May 2017 12:22:10 -0400
Subject: [PATCH] gdbstub: implement remote debugging protocol escapes for
 command receive

- decode escape sequences
- decompress run-length encoding escape sequences
- report command parsing problems to output when debug output is enabled
- reject packet checksums that are not valid hex digits
- compute the checksum based on the packet stream, not based on the
  decoded packet

Tested with GDB and QtCreator integrated debugger on SMP QEMU instance.
Works for me.

Signed-off-by: Doug Gale 
---
 gdbstub.c | 108 --
 1 file changed, 99 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9911153..3abaf7c 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
 RS_INACTIVE,
 RS_IDLE,
 RS_GETLINE,
+RS_GETLINE_ESC,
+RS_GETLINE_RLE,
 RS_CHKSUM1,
 RS_CHKSUM2,
 };
@@ -296,7 +298,8 @@ typedef struct GDBState {
 enum RSState state; /* parsing state */
 char line_buf[MAX_PACKET_LENGTH];
 int line_buf_index;
-int line_csum;
+int line_sum; /* running checksum */
+int line_csum; /* checksum at the end of the packet */
 uint8_t last_packet[MAX_PACKET_LENGTH + 4];
 int last_packet_len;
 int signal;
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb,
const char *fmt, ...)

 static void gdb_read_byte(GDBState *s, int ch)
 {
-int i, csum;
 uint8_t reply;

 #ifndef CONFIG_USER_ONLY
@@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch)
 switch(s->state) {
 case RS_IDLE:
 if (ch == '$') {
+/* start of command packet */
 s->line_buf_index = 0;
+s->line_sum = 0;
 s->state = RS_GETLINE;
+} else {
+#ifdef DEBUG_GDB
+printf("gdbstub received garbage between packets: 0x%x\n", ch);
+#endif
 }
 break;
 case RS_GETLINE:
+if (ch == '}') {
+/* start escape sequence */
+s->state = RS_GETLINE_ESC;
+s->line_sum += ch;
+} else if (ch == '*') {
+/* start run length encoding sequence */
+s->state = RS_GETLINE_RLE;
+s->line_sum += ch;
+} else if (ch == '#') {
+/* end of command, start of checksum*/
+s->state = RS_CHKSUM1;
+} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else {
+/* unescaped command character */
+s->line_buf[s->line_buf_index++] = ch;
+s->line_sum += ch;
+}
+break;
+case RS_GETLINE_ESC:
 if (ch == '#') {
-s->state = RS_CHKSUM1;
+/* unexpected end of command in escape sequence */
+s->state = RS_CHKSUM1;
 } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+/* command buffer overrun */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
 s->state = RS_IDLE;
 } else {
-s->line_buf[s->line_buf_index++] = ch;
+/* parse escaped character and leave escape state */
+s->line_buf[s->line_buf_index++] = ch ^ 0x20;
+s->line_sum += ch;
+s->state = RS_GETLINE;
+}
+break;
+case RS_GETLINE_RLE:
+if (ch < ' ') {
+/* invalid RLE count encoding */
+#ifdef DEBUG_GDB
+printf("gdbstub got invalid RLE count: 0x%x\n", ch);
+#endif
+s->state = RS_GETLINE;
+} else {
+/* decode repeat length */
+int repeat = (unsigned char)ch - ' ' + 3;
+if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+/* that many repeats would overrun the command buffer */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun,"
+   " dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else if (s->line_buf_index < 2) {
+/* got a repeat but we have nothing to repeat */
+#ifdef DEBUG_GDB
+printf("gdbstub got invalid RLE sequence\n");
+#endif
+  

Re: [Qemu-devel] [PATCH] gdbstub: implement remote debugging protocol escapes for command receive

2017-05-07 Thread Doug Gale
[Oops, forgot to reply all, resending...]

Yes, on second thought, <= 2 is off by one. [0] would be the '$', [1]
would be the repeated character, and [2] would be the '*'.

And yes, there is a missing s->state = RS_IDLE there. Good catch. I'll
post updated patch shortly...

On Fri, May 5, 2017 at 10:45 AM, Stefan Hajnoczi  wrote:
> On Tue, May 02, 2017 at 10:32:40AM -0400, Doug Gale wrote:
>> +} else {
>> +/* decode repeat length */
>> +int repeat = (unsigned char)ch - ' ' + 3;
>> +if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
>> +/* that many repeats would overrun the command buffer */
>> +#ifdef DEBUG_GDB
>> +printf("gdbstub command buffer overrun,"
>> +   " dropping command\n");
>> +#endif
>> +s->state = RS_IDLE;
>> +} else if (s->line_buf_index <= 2) {
>
> Why s->line_buf_index <= 2?  I expected s->line_buf_index < 1 since we
> just need 1 character to clone for run-length decoding.
>
>> +/* got a repeat but we have nothing to repeat */
>> +#ifdef DEBUG_GDB
>> +printf("gdbstub got invalid RLE sequence\n");
>> +#endif
>> +} else {
>
> Missing s->state = RS_IDLE?



Re: [Qemu-devel] [PATCH] gdbstub: implement remote debugging protocol escapes for command receive

2017-05-02 Thread Doug Gale
Oops. Thanks, here's the patch inline.

>From c238752f10434970af8ef620ce3bf6c0e18a20b5 Mon Sep 17 00:00:00 2001
From: Doug Gale 
Date: Mon, 1 May 2017 12:22:10 -0400
Subject: [PATCH] gdbstub: implement remote debugging protocol escapes for
 command receive

- decode escape sequences
- decompress run-length encoding escape sequences
- report command parsing problems to output when debug output is enabled
- reject packet checksums that are not valid hex digits
- compute the checksum based on the packet stream, not based on the
  decoded packet

Tested with GDB and QtCreator integrated debugger on SMP QEMU instance.
Works for me.

Signed-off-by: Doug Gale 
---
 gdbstub.c | 107 --
 1 file changed, 98 insertions(+), 9 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index 9911153..d6f1b0e 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
 RS_INACTIVE,
 RS_IDLE,
 RS_GETLINE,
+RS_GETLINE_ESC,
+RS_GETLINE_RLE,
 RS_CHKSUM1,
 RS_CHKSUM2,
 };
@@ -296,7 +298,8 @@ typedef struct GDBState {
 enum RSState state; /* parsing state */
 char line_buf[MAX_PACKET_LENGTH];
 int line_buf_index;
-int line_csum;
+int line_sum; /* running checksum */
+int line_csum; /* checksum at the end of the packet */
 uint8_t last_packet[MAX_PACKET_LENGTH + 4];
 int last_packet_len;
 int signal;
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb,
const char *fmt, ...)

 static void gdb_read_byte(GDBState *s, int ch)
 {
-int i, csum;
 uint8_t reply;

 #ifndef CONFIG_USER_ONLY
@@ -1542,35 +1544,122 @@ static void gdb_read_byte(GDBState *s, int ch)
 switch(s->state) {
 case RS_IDLE:
 if (ch == '$') {
+/* start of command packet */
 s->line_buf_index = 0;
+s->line_sum = 0;
 s->state = RS_GETLINE;
+} else {
+#ifdef DEBUG_GDB
+printf("gdbstub received garbage between packets: 0x%x\n", ch);
+#endif
 }
 break;
 case RS_GETLINE:
+if (ch == '}') {
+/* start escape sequence */
+s->state = RS_GETLINE_ESC;
+s->line_sum += ch;
+} else if (ch == '*') {
+/* start run length encoding sequence */
+s->state = RS_GETLINE_RLE;
+s->line_sum += ch;
+} else if (ch == '#') {
+/* end of command, start of checksum*/
+s->state = RS_CHKSUM1;
+} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else {
+/* unescaped command character */
+s->line_buf[s->line_buf_index++] = ch;
+s->line_sum += ch;
+}
+break;
+case RS_GETLINE_ESC:
 if (ch == '#') {
-s->state = RS_CHKSUM1;
+/* unexpected end of command in escape sequence */
+s->state = RS_CHKSUM1;
 } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+/* command buffer overrun */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun, dropping command\n");
+#endif
 s->state = RS_IDLE;
 } else {
-s->line_buf[s->line_buf_index++] = ch;
+/* parse escaped character and leave escape state */
+s->line_buf[s->line_buf_index++] = ch ^ 0x20;
+s->line_sum += ch;
+s->state = RS_GETLINE;
+}
+break;
+case RS_GETLINE_RLE:
+if (ch < ' ') {
+/* invalid RLE count encoding */
+#ifdef DEBUG_GDB
+printf("gdbstub got invalid RLE count: 0x%x\n", ch);
+#endif
+s->state = RS_GETLINE;
+} else {
+/* decode repeat length */
+int repeat = (unsigned char)ch - ' ' + 3;
+if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+/* that many repeats would overrun the command buffer */
+#ifdef DEBUG_GDB
+printf("gdbstub command buffer overrun,"
+   " dropping command\n");
+#endif
+s->state = RS_IDLE;
+} else if (s->line_buf_index <= 2) {
+/* got a repeat but we have nothing to repeat */
+#ifdef DEBUG_GDB
+printf("gdbstub got invalid RLE sequence\n");
+#endif
+

[Qemu-devel] [PATCH] gdbstub: implement remote debugging protocol escapes for command receive

2017-05-01 Thread Doug Gale
The attached patch implements the GDB Remote Serial Protocol for
command receive as per the documentation provided at
https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol
and from inspection of remote.c in the gdb source (the documentation
didn't clearly document whether the packet or the unescaped data were
used for the checksum, turns out the packet data is used for the
checksum, as expected).

get_maintainer.pl didn't find a maintainer for gdbstub.c, so I didn't
cc any maintainers.


patch
Description: Binary data