diff mbox

i386: fix breakpoints handling in icount mode

Message ID 20141022113831.9548.36452.stgit@PASHA-ISP
State New
Headers show

Commit Message

Pavel Dovgalyuk Oct. 22, 2014, 11:38 a.m. UTC
This patch fixes instructions counting when execution is stopped on
breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
and icount is incremented by invalid value (which equals to number of
executed instructions + 1).

Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
---
 target-i386/translate.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

Comments

fred.konrad@greensocs.com Oct. 22, 2014, 12:53 p.m. UTC | #1
On 22/10/2014 13:38, Pavel Dovgalyuk wrote:

Hi Pavel,
> This patch fixes instructions counting when execution is stopped on
> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
> and icount is incremented by invalid value (which equals to number of
> executed instructions + 1).
>
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> ---
>   target-i386/translate.c |    3 ++-
>   1 files changed, 2 insertions(+), 1 deletions(-)
>
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index 1284173..193cf9f 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>                   if (bp->pc == pc_ptr &&
>                       !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
>                       gen_debug(dc, pc_ptr - dc->cs_base);
> -                    break;
> +                    goto done_generating;
This makes sense to me.
But I don't see why you don't just "break" like the other instruction in 
this loop?

>                   }
>               }
>           }
> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>               break;
>           }
>       }
> +done_generating:
>       if (tb->cflags & CF_LAST_IO)
>           gen_io_end();
Is there any reason why you don't jump over this two lines in case of a
breakpoint?

>       gen_tb_end(tb, num_insns);
>
>

I'll give it a try later and I'll let you know.

Thanks,
Fred
Pavel Dovgalyuk Oct. 23, 2014, 5:57 a.m. UTC | #2
> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
> On 22/10/2014 13:38, Pavel Dovgalyuk wrote:
> 
> Hi Pavel,
> > This patch fixes instructions counting when execution is stopped on
> > breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
> > and icount is incremented by invalid value (which equals to number of
> > executed instructions + 1).
> >
> > Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> > ---
> >   target-i386/translate.c |    3 ++-
> >   1 files changed, 2 insertions(+), 1 deletions(-)
> >
> > diff --git a/target-i386/translate.c b/target-i386/translate.c
> > index 1284173..193cf9f 100644
> > --- a/target-i386/translate.c
> > +++ b/target-i386/translate.c
> > @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
> >                   if (bp->pc == pc_ptr &&
> >                       !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
> >                       gen_debug(dc, pc_ptr - dc->cs_base);
> > -                    break;
> > +                    goto done_generating;
> This makes sense to me.
> But I don't see why you don't just "break" like the other instruction in
> this loop?

Single break will just exit the breakpoints iteration loop. I'll need an additional flag
to break the translation loop. ARM does the same thing, anyway :)

> >                   }
> >               }
> >           }
> > @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
> >               break;
> >           }
> >       }
> > +done_generating:
> >       if (tb->cflags & CF_LAST_IO)
> >           gen_io_end();
> Is there any reason why you don't jump over this two lines in case of a
> breakpoint?

Shouldn't we switch off can_do_io flag if it was switched on?

> 
> >       gen_tb_end(tb, num_insns);
> >
> >
> 
> I'll give it a try later and I'll let you know.

Thanks.

Pavel Dovgalyuk
fred.konrad@greensocs.com Oct. 23, 2014, 7:39 a.m. UTC | #3
On 23/10/2014 07:57, Pavel Dovgaluk wrote:
>> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
>> On 22/10/2014 13:38, Pavel Dovgalyuk wrote:
>>
>> Hi Pavel,
>>> This patch fixes instructions counting when execution is stopped on
>>> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
>>> and icount is incremented by invalid value (which equals to number of
>>> executed instructions + 1).
>>>
>>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
>>> ---
>>>    target-i386/translate.c |    3 ++-
>>>    1 files changed, 2 insertions(+), 1 deletions(-)
>>>
>>> diff --git a/target-i386/translate.c b/target-i386/translate.c
>>> index 1284173..193cf9f 100644
>>> --- a/target-i386/translate.c
>>> +++ b/target-i386/translate.c
>>> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>>>                    if (bp->pc == pc_ptr &&
>>>                        !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
>>>                        gen_debug(dc, pc_ptr - dc->cs_base);
>>> -                    break;
>>> +                    goto done_generating;
>> This makes sense to me.
>> But I don't see why you don't just "break" like the other instruction in
>> this loop?
> Single break will just exit the breakpoints iteration loop. I'll need an additional flag
> to break the translation loop. ARM does the same thing, anyway :)

Yes that's what I mentioned.
>
>>>                    }
>>>                }
>>>            }
>>> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>>>                break;
>>>            }
>>>        }
>>> +done_generating:
>>>        if (tb->cflags & CF_LAST_IO)
>>>            gen_io_end();
>> Is there any reason why you don't jump over this two lines in case of a
>> breakpoint?
> Shouldn't we switch off can_do_io flag if it was switched on?

Yes but can we switch on can_do_io if we have a breakpoint?

The code is not shown in this patch but there is:

         if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
             gen_io_start();

I think you can't reach this code if you exit the translation loop?

Fred
>
>>>        gen_tb_end(tb, num_insns);
>>>
>>>
>> I'll give it a try later and I'll let you know.
> Thanks.
>
> Pavel Dovgalyuk
>
>
Pavel Dovgalyuk Oct. 23, 2014, 7:52 a.m. UTC | #4
> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
> On 23/10/2014 07:57, Pavel Dovgaluk wrote:
> >> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
> >> On 22/10/2014 13:38, Pavel Dovgalyuk wrote:
> >>
> >> Hi Pavel,
> >>> This patch fixes instructions counting when execution is stopped on
> >>> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
> >>> and icount is incremented by invalid value (which equals to number of
> >>> executed instructions + 1).
> >>>
> >>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> >>> ---
> >>>    target-i386/translate.c |    3 ++-
> >>>    1 files changed, 2 insertions(+), 1 deletions(-)
> >>>
> >>> diff --git a/target-i386/translate.c b/target-i386/translate.c
> >>> index 1284173..193cf9f 100644
> >>> --- a/target-i386/translate.c
> >>> +++ b/target-i386/translate.c
> >>> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
> >>>                    if (bp->pc == pc_ptr &&
> >>>                        !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
> >>>                        gen_debug(dc, pc_ptr - dc->cs_base);
> >>> -                    break;
> >>> +                    goto done_generating;
> >> This makes sense to me.
> >> But I don't see why you don't just "break" like the other instruction in
> >> this loop?
> > Single break will just exit the breakpoints iteration loop. I'll need an additional flag
> > to break the translation loop. ARM does the same thing, anyway :)
> 
> Yes that's what I mentioned.
> >
> >>>                    }
> >>>                }
> >>>            }
> >>> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
> >>>                break;
> >>>            }
> >>>        }
> >>> +done_generating:
> >>>        if (tb->cflags & CF_LAST_IO)
> >>>            gen_io_end();
> >> Is there any reason why you don't jump over this two lines in case of a
> >> breakpoint?
> > Shouldn't we switch off can_do_io flag if it was switched on?
> 
> Yes but can we switch on can_do_io if we have a breakpoint?
> 
> The code is not shown in this patch but there is:
> 
>          if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
>              gen_io_start();
> 
> I think you can't reach this code if you exit the translation loop?

This is not the only gen_io_start call. It is called from some of the instructions'
translation functions, that could precede the breakpoint.

Pavel Dovgalyuk
fred.konrad@greensocs.com Oct. 23, 2014, 8:47 a.m. UTC | #5
On 23/10/2014 09:52, Pavel Dovgaluk wrote:
>> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
>> On 23/10/2014 07:57, Pavel Dovgaluk wrote:
>>>> From: Frederic Konrad [mailto:fred.konrad@greensocs.com]
>>>> On 22/10/2014 13:38, Pavel Dovgalyuk wrote:
>>>>
>>>> Hi Pavel,
>>>>> This patch fixes instructions counting when execution is stopped on
>>>>> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
>>>>> and icount is incremented by invalid value (which equals to number of
>>>>> executed instructions + 1).
>>>>>
>>>>> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
>>>>> ---
>>>>>     target-i386/translate.c |    3 ++-
>>>>>     1 files changed, 2 insertions(+), 1 deletions(-)
>>>>>
>>>>> diff --git a/target-i386/translate.c b/target-i386/translate.c
>>>>> index 1284173..193cf9f 100644
>>>>> --- a/target-i386/translate.c
>>>>> +++ b/target-i386/translate.c
>>>>> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>>>>>                     if (bp->pc == pc_ptr &&
>>>>>                         !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
>>>>>                         gen_debug(dc, pc_ptr - dc->cs_base);
>>>>> -                    break;
>>>>> +                    goto done_generating;
>>>> This makes sense to me.
>>>> But I don't see why you don't just "break" like the other instruction in
>>>> this loop?
>>> Single break will just exit the breakpoints iteration loop. I'll need an additional flag
>>> to break the translation loop. ARM does the same thing, anyway :)
>> Yes that's what I mentioned.
>>>>>                     }
>>>>>                 }
>>>>>             }
>>>>> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>>>>>                 break;
>>>>>             }
>>>>>         }
>>>>> +done_generating:
>>>>>         if (tb->cflags & CF_LAST_IO)
>>>>>             gen_io_end();
>>>> Is there any reason why you don't jump over this two lines in case of a
>>>> breakpoint?
>>> Shouldn't we switch off can_do_io flag if it was switched on?
>> Yes but can we switch on can_do_io if we have a breakpoint?
>>
>> The code is not shown in this patch but there is:
>>
>>           if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
>>               gen_io_start();
>>
>> I think you can't reach this code if you exit the translation loop?
> This is not the only gen_io_start call. It is called from some of the instructions'
> translation functions, that could precede the breakpoint.
>
> Pavel Dovgalyuk
>
>
True, there are 8 others place where gen_io_start is called in this 
file, but they
seems to be each time followed by a gen_io_end?

eg:

static inline void gen_ins(DisasContext *s, TCGMemOp ot)
{
     if (use_icount)
         gen_io_start();
     gen_string_movl_A0_EDI(s);
     /* Note: we must do this dummy write first to be restartable in
        case of page fault. */
     tcg_gen_movi_tl(cpu_T[0], 0);
     gen_op_st_v(s, ot, cpu_T[0], cpu_A0);
     tcg_gen_trunc_tl_i32(cpu_tmp2_i32, cpu_regs[R_EDX]);
     tcg_gen_andi_i32(cpu_tmp2_i32, cpu_tmp2_i32, 0xffff);
     gen_helper_in_func(ot, cpu_T[0], cpu_tmp2_i32);
     gen_op_st_v(s, ot, cpu_T[0], cpu_A0);
     gen_op_movl_T0_Dshift(ot);
     gen_op_add_reg_T0(s->aflag, R_EDI);
     if (use_icount)
         gen_io_end();
}
Paolo Bonzini Oct. 31, 2014, 3:41 p.m. UTC | #6
On 22/10/2014 13:38, Pavel Dovgalyuk wrote:
> This patch fixes instructions counting when execution is stopped on
> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
> and icount is incremented by invalid value (which equals to number of
> executed instructions + 1).
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> ---
>  target-i386/translate.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index 1284173..193cf9f 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>                  if (bp->pc == pc_ptr &&
>                      !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
>                      gen_debug(dc, pc_ptr - dc->cs_base);
> -                    break;
> +                    goto done_generating;
>                  }
>              }
>          }
> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>              break;
>          }
>      }
> +done_generating:
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
>      gen_tb_end(tb, num_insns);
> 

Applied, thanks.

Paolo
Jan Kiszka Jan. 12, 2015, 8:03 a.m. UTC | #7
On 2014-10-22 13:38, Pavel Dovgalyuk wrote:
> This patch fixes instructions counting when execution is stopped on
> breakpoint (e.g. set from gdb). Without a patch extra instruction is translated
> and icount is incremented by invalid value (which equals to number of
> executed instructions + 1).
> 
> Signed-off-by: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
> ---
>  target-i386/translate.c |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/target-i386/translate.c b/target-i386/translate.c
> index 1284173..193cf9f 100644
> --- a/target-i386/translate.c
> +++ b/target-i386/translate.c
> @@ -8000,7 +8000,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>                  if (bp->pc == pc_ptr &&
>                      !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
>                      gen_debug(dc, pc_ptr - dc->cs_base);
> -                    break;
> +                    goto done_generating;
>                  }
>              }
>          }
> @@ -8049,6 +8049,7 @@ static inline void gen_intermediate_code_internal(X86CPU *cpu,
>              break;
>          }
>      }
> +done_generating:
>      if (tb->cflags & CF_LAST_IO)
>          gen_io_end();
>      gen_tb_end(tb, num_insns);
> 
> 
> 

Didn't looked into why, just bisected that this patch breaks at least
certain guest-originated break- or watchpoints in TCG mode. Can be
triggered by booting a Linux kernel with kgdb self-tests enabled. The
result is some false reporting of a host-originated debug stop to
gdb_set_stop_cpu while gdbserver_state is NULL -> SEGV.

Jan
diff mbox

Patch

diff --git a/target-i386/translate.c b/target-i386/translate.c
index 1284173..193cf9f 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -8000,7 +8000,7 @@  static inline void gen_intermediate_code_internal(X86CPU *cpu,
                 if (bp->pc == pc_ptr &&
                     !((bp->flags & BP_CPU) && (tb->flags & HF_RF_MASK))) {
                     gen_debug(dc, pc_ptr - dc->cs_base);
-                    break;
+                    goto done_generating;
                 }
             }
         }
@@ -8049,6 +8049,7 @@  static inline void gen_intermediate_code_internal(X86CPU *cpu,
             break;
         }
     }
+done_generating:
     if (tb->cflags & CF_LAST_IO)
         gen_io_end();
     gen_tb_end(tb, num_insns);