public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* Is this a bug from function kernel_int?
@ 2019-01-20  9:49 Yue Cao
  2019-01-21 15:41 ` David Smith
  2019-01-22 15:57 ` David Smith
  0 siblings, 2 replies; 6+ messages in thread
From: Yue Cao @ 2019-01-20  9:49 UTC (permalink / raw)
  To: systemtap

Hi there,

Recently I find systemtap generates a wrong result when I use kernel_int to
print out the int value from the pointer. In my case, systemtap prints out
a huge value (18446744072649393666) with kernel_int. As you can see, this
value is larger than 2^32 (the maximal value for int). However, when I use
kernel_long, the result is within 2^32. The new value (3234809346) actually
is equal to what I expected by using kernel_int. I have tried multiple
times and the results are same. I wonder is it a bug. Could anyone tell me
how to fix it?

Here is another example that I have used to reproduce the error above. The
following two values are supposed to be same. But the first value returns
(18446744072649393666), while the second one returns (3234809346), which is
the expected value.
 *kernel_int(&*@cast($skb->cb, "tcp_skb_cb", "kernel<net/tcp.h>")->end_seq)
@cast($skb->cb, "tcp_skb_cb", "kernel<net/tcp.h>")->end_seq

Looking forward to your reply.

Best,
Yue

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Is this a bug from function kernel_int?
  2019-01-20  9:49 Is this a bug from function kernel_int? Yue Cao
@ 2019-01-21 15:41 ` David Smith
  2019-01-22  8:59   ` Victor Kamensky
  2019-01-22 15:57 ` David Smith
  1 sibling, 1 reply; 6+ messages in thread
From: David Smith @ 2019-01-21 15:41 UTC (permalink / raw)
  To: Yue Cao; +Cc: systemtap

On Sun, Jan 20, 2019 at 3:49 AM Yue Cao <yuecao1990@gmail.com> wrote:
>
> Hi there,
>
> Recently I find systemtap generates a wrong result when I use kernel_int to
> print out the int value from the pointer. In my case, systemtap prints out
> a huge value (18446744072649393666) with kernel_int. As you can see, this
> value is larger than 2^32 (the maximal value for int). However, when I use
> kernel_long, the result is within 2^32. The new value (3234809346) actually
> is equal to what I expected by using kernel_int. I have tried multiple
> times and the results are same. I wonder is it a bug. Could anyone tell me
> how to fix it?

You are confusing an 'int' with a 32-bit value. Depending on the
architecture, they aren't the same. Typically on a 64-bit platform,
the C language type 'int' is a 64-bit value. Typically on a 32-bit
platform, the C language type 'int' is a 32-bit value.

If you are sure you want a 32-bit value, you can call the __int32()
function on a value. (Although note that the '__' prefix means that is
really an internal function by convention.)

So, depending on your architecture, kernel_int() returning a 64-bit
value could be a bug or could be the expected behavior.

-- 
David Smith
Associate Manager
Red Hat

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Is this a bug from function kernel_int?
  2019-01-21 15:41 ` David Smith
@ 2019-01-22  8:59   ` Victor Kamensky
  2019-01-22 15:38     ` David Smith
  0 siblings, 1 reply; 6+ messages in thread
From: Victor Kamensky @ 2019-01-22  8:59 UTC (permalink / raw)
  To: David Smith; +Cc: Yue Cao, systemtap



On Mon, 21 Jan 2019, David Smith wrote:

> On Sun, Jan 20, 2019 at 3:49 AM Yue Cao <yuecao1990@gmail.com> wrote:
>>
>> Hi there,
>>
>> Recently I find systemtap generates a wrong result when I use kernel_int to
>> print out the int value from the pointer. In my case, systemtap prints out
>> a huge value (18446744072649393666) with kernel_int. As you can see, this
>> value is larger than 2^32 (the maximal value for int). However, when I use
>> kernel_long, the result is within 2^32. The new value (3234809346) actually
>> is equal to what I expected by using kernel_int. I have tried multiple
>> times and the results are same. I wonder is it a bug. Could anyone tell me
>> how to fix it?
>
> You are confusing an 'int' with a 32-bit value. Depending on the
> architecture, they aren't the same. Typically on a 64-bit platform,
> the C language type 'int' is a 64-bit value. Typically on a 32-bit
> platform, the C language type 'int' is a 32-bit value.

David, above does not seem to be true wrt in in C language on today's
64bit Linux systems. Nowdays,
in C language LP64 64-Bit Programming Models: 'int' type is always
32bit value. And its size does not change between 32bit and 64bit
address spaces. The only type that typically changes size in LP64
memory model that Linux uses is long.

Here is simple example

[kamensky@kamensky-w541 tmp]$ cat intsize.c
#include <stdio.h>

int main (void)
{
     printf("sizeof(char) = %d\n", sizeof(char));
     printf("sizeof(short) = %d\n", sizeof(short));
     printf("sizeof(int) = %d\n", sizeof(int));
     printf("sizeof(long) = %d\n", sizeof(long));
     printf("sizeof(long long) = %d\n", sizeof(long long));
     return 0;
}
[kamensky@kamensky-w541 tmp]$ gcc -o intsize intsize.c
[kamensky@kamensky-w541 tmp]$ file intsize
intsize: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically 
linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, 
BuildID[sha1]=1f8b0f11c6206829ba7dab12f51700b98e350d1c, not stripped
[kamensky@kamensky-w541 tmp]$ ./intsize
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 8
sizeof(long long) = 8
[kamensky@kamensky-w541 tmp]$ gcc -m32 -o intsize intsize.c
[kamensky@kamensky-w541 tmp]$ file intsize
intsize: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), 
dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, 
BuildID[sha1]=16a7ff56fc7828a30d63ddccc5a72e91310ddaac, not stripped
[kamensky@kamensky-w541 tmp]$ ./intsize
sizeof(char) = 1
sizeof(short) = 2
sizeof(int) = 4
sizeof(long) = 4
sizeof(long long) = 8

You can try to run on any reasonable CPU archs it will come out like
above on all of them, with only size difference of long.

Note in LLP64 (or P64) model long size stays as 4 bytes, I believe this
is model that Windows uses for its 64bit apps.

You can define semantics of kernel_int as you wish, but I agree with 
Yue's opinion, current one does defy normal expectaion of well
accepted LP64 model.

Please look at this:

http://www.unix.org/version2/whatsnew/lp64_wp.html

The model that David alluded is ILP64 and actually never used
except very few esoteric, old cases.

Thanks,
Victor

> If you are sure you want a 32-bit value, you can call the __int32()
> function on a value. (Although note that the '__' prefix means that is
> really an internal function by convention.)
>
> So, depending on your architecture, kernel_int() returning a 64-bit
> value could be a bug or could be the expected behavior.
>
> -- 
> David Smith
> Associate Manager
> Red Hat
>

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Is this a bug from function kernel_int?
  2019-01-22  8:59   ` Victor Kamensky
@ 2019-01-22 15:38     ` David Smith
  0 siblings, 0 replies; 6+ messages in thread
From: David Smith @ 2019-01-22 15:38 UTC (permalink / raw)
  To: Victor Kamensky; +Cc: Yue Cao, systemtap

Sigh. That's what I get for depending on my memory.

Victor, you are correct. My analysis was wrong.

On Tue, Jan 22, 2019 at 2:59 AM Victor Kamensky <kamensky@cisco.com> wrote:
>
>
>
> On Mon, 21 Jan 2019, David Smith wrote:
>
> > On Sun, Jan 20, 2019 at 3:49 AM Yue Cao <yuecao1990@gmail.com> wrote:
> >>
> >> Hi there,
> >>
> >> Recently I find systemtap generates a wrong result when I use kernel_int to
> >> print out the int value from the pointer. In my case, systemtap prints out
> >> a huge value (18446744072649393666) with kernel_int. As you can see, this
> >> value is larger than 2^32 (the maximal value for int). However, when I use
> >> kernel_long, the result is within 2^32. The new value (3234809346) actually
> >> is equal to what I expected by using kernel_int. I have tried multiple
> >> times and the results are same. I wonder is it a bug. Could anyone tell me
> >> how to fix it?
> >
> > You are confusing an 'int' with a 32-bit value. Depending on the
> > architecture, they aren't the same. Typically on a 64-bit platform,
> > the C language type 'int' is a 64-bit value. Typically on a 32-bit
> > platform, the C language type 'int' is a 32-bit value.
>
> David, above does not seem to be true wrt in in C language on today's
> 64bit Linux systems. Nowdays,
> in C language LP64 64-Bit Programming Models: 'int' type is always
> 32bit value. And its size does not change between 32bit and 64bit
> address spaces. The only type that typically changes size in LP64
> memory model that Linux uses is long.
>
> Here is simple example
>
> [kamensky@kamensky-w541 tmp]$ cat intsize.c
> #include <stdio.h>
>
> int main (void)
> {
>      printf("sizeof(char) = %d\n", sizeof(char));
>      printf("sizeof(short) = %d\n", sizeof(short));
>      printf("sizeof(int) = %d\n", sizeof(int));
>      printf("sizeof(long) = %d\n", sizeof(long));
>      printf("sizeof(long long) = %d\n", sizeof(long long));
>      return 0;
> }
> [kamensky@kamensky-w541 tmp]$ gcc -o intsize intsize.c
> [kamensky@kamensky-w541 tmp]$ file intsize
> intsize: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically
> linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0,
> BuildID[sha1]=1f8b0f11c6206829ba7dab12f51700b98e350d1c, not stripped
> [kamensky@kamensky-w541 tmp]$ ./intsize
> sizeof(char) = 1
> sizeof(short) = 2
> sizeof(int) = 4
> sizeof(long) = 8
> sizeof(long long) = 8
> [kamensky@kamensky-w541 tmp]$ gcc -m32 -o intsize intsize.c
> [kamensky@kamensky-w541 tmp]$ file intsize
> intsize: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV),
> dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0,
> BuildID[sha1]=16a7ff56fc7828a30d63ddccc5a72e91310ddaac, not stripped
> [kamensky@kamensky-w541 tmp]$ ./intsize
> sizeof(char) = 1
> sizeof(short) = 2
> sizeof(int) = 4
> sizeof(long) = 4
> sizeof(long long) = 8
>
> You can try to run on any reasonable CPU archs it will come out like
> above on all of them, with only size difference of long.
>
> Note in LLP64 (or P64) model long size stays as 4 bytes, I believe this
> is model that Windows uses for its 64bit apps.
>
> You can define semantics of kernel_int as you wish, but I agree with
> Yue's opinion, current one does defy normal expectaion of well
> accepted LP64 model.
>
> Please look at this:
>
> http://www.unix.org/version2/whatsnew/lp64_wp.html
>
> The model that David alluded is ILP64 and actually never used
> except very few esoteric, old cases.
>
> Thanks,
> Victor
>
> > If you are sure you want a 32-bit value, you can call the __int32()
> > function on a value. (Although note that the '__' prefix means that is
> > really an internal function by convention.)
> >
> > So, depending on your architecture, kernel_int() returning a 64-bit
> > value could be a bug or could be the expected behavior.
> >
> > --
> > David Smith
> > Associate Manager
> > Red Hat
> >



-- 
David Smith
Associate Manager
Red Hat

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Is this a bug from function kernel_int?
  2019-01-20  9:49 Is this a bug from function kernel_int? Yue Cao
  2019-01-21 15:41 ` David Smith
@ 2019-01-22 15:57 ` David Smith
  2019-01-29  1:23   ` Frank Ch. Eigler
  1 sibling, 1 reply; 6+ messages in thread
From: David Smith @ 2019-01-22 15:57 UTC (permalink / raw)
  To: Yue Cao; +Cc: systemtap

OK, let's try this again.

You got a huge value from kernel_int(). Why did you get that big
value? Sign extension. 18446744072649393666 is 0xffffffffc0cf4602.
Internally in systemtap, all numeric values are long longs (if I
remember correctly). So, when that signed 32-bit value gets put in a
long long, it gets sign extended.

Now, the next issue with your code is that you aren't handling the
sign correctly. At least in the 4.19 kernel source, in net/tcp.h I see
the following:

    __u32 end_seq; /* SEQ + FIN + SYN + datalen */

So, end_seq is an unsigned 32-bit value, not a signed 32-bit value.
Strangely enough, we don't have a kernel_uint() function. But, you
could do something like:

  __uint32(*kernel_int(&*@cast($skb->cb, "tcp_skb_cb",
"kernel<net/tcp.h>")->end_seq))

But, to tell you the truth, I've forgotten all the details of
@cast()/kernel_int() and I'm not 100% sure you need the kernel_int()
in the first place.

On Sun, Jan 20, 2019 at 3:49 AM Yue Cao <yuecao1990@gmail.com> wrote:
>
> Hi there,
>
> Recently I find systemtap generates a wrong result when I use kernel_int to
> print out the int value from the pointer. In my case, systemtap prints out
> a huge value (18446744072649393666) with kernel_int. As you can see, this
> value is larger than 2^32 (the maximal value for int). However, when I use
> kernel_long, the result is within 2^32. The new value (3234809346) actually
> is equal to what I expected by using kernel_int. I have tried multiple
> times and the results are same. I wonder is it a bug. Could anyone tell me
> how to fix it?
>
> Here is another example that I have used to reproduce the error above. The
> following two values are supposed to be same. But the first value returns
> (18446744072649393666), while the second one returns (3234809346), which is
> the expected value.
>  *kernel_int(&*@cast($skb->cb, "tcp_skb_cb", "kernel<net/tcp.h>")->end_seq)
> @cast($skb->cb, "tcp_skb_cb", "kernel<net/tcp.h>")->end_seq
>
> Looking forward to your reply.
>
> Best,
> Yue
>
>


-- 
David Smith
Associate Manager
Red Hat

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Is this a bug from function kernel_int?
  2019-01-22 15:57 ` David Smith
@ 2019-01-29  1:23   ` Frank Ch. Eigler
  0 siblings, 0 replies; 6+ messages in thread
From: Frank Ch. Eigler @ 2019-01-29  1:23 UTC (permalink / raw)
  To: Yue Cao, systemtap


Hi -

> [...]
>     __u32 end_seq; /* SEQ + FIN + SYN + datalen */
>
> So, end_seq is an unsigned 32-bit value, not a signed 32-bit value.
> Strangely enough, we don't have a kernel_uint() function. But, you
> could do something like:
>
>   __uint32(*kernel_int(&*@cast($skb->cb, "tcp_skb_cb",
> "kernel<net/tcp.h>")->end_seq))

Chances are you don't need that much machinery.  
A 

    probe SOMEWHERE {
       end_seq = @cast($skb->cb, "tcp_skb_cb", "kernel<net/tcp.h>")->end_seq
    }

works for me here, though I think the unsignedness of end_seq is not
specifically handled.  We should probably treat that as a systemtap bug,
but you can work around it with a

      end_seq = end_seq & 0xffffffff

- FChE

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-01-29  1:23 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-20  9:49 Is this a bug from function kernel_int? Yue Cao
2019-01-21 15:41 ` David Smith
2019-01-22  8:59   ` Victor Kamensky
2019-01-22 15:38     ` David Smith
2019-01-22 15:57 ` David Smith
2019-01-29  1:23   ` Frank Ch. Eigler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).