Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpftrace: Fix bitfield access for Big endian #1628

Merged
merged 2 commits into from
Nov 20, 2020

Conversation

sumanthkorikkar
Copy link
Contributor

This resolves bitfield access for big endian systems.
Also added testcases to cover few more cases.

Thanks

Checklist
  • Language changes are updated in docs/reference_guide.md
  • [x ] User-visible and non-trivial changes updated in CHANGELOG.md
  • [x ] The new behaviour is covered by tests

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
rshiftbits = field.bitfield.access_rshift;
#else
// Number of bytes to shift
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Number of bytes to shift
// Number of bits to shift

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but i'd leave the comment out, or explain the logic behind how this shifting works

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, Sure. I will explain with an example in the commit message then. Thanks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in the commit message. Thanks

Algorithm explaination with example:
1. struct Foo
{
  unsigned int a:4, b:8, c:3, d:1, e:16;
};

2. Let's say
a = 1, b = 2, c = 5, d = 0, c = 65535

3. Interpretation in Big endian:
0001 0000 0010 101 0 1111 1111 1111 1111
---- --------- --- - -------------------
 a      b       c  d     e

In clang_parser, we calculate number of bits to shift within the number
of bytes to be read.

For $foo->b, in clang_parser.cpp:
- bitfield.read_bytes = 2 bytes [ 2 bytes should be read inorder to
  retrieve the value associated with foo->b ]
- bitfield_offset = 4 [ starts from offset 4 ]
- bitfield_bitwidth = 8 [ length of the foo->b ]

bitfield.access_rshift -> calculate number of bits to shift within
bitfield.read_bytes read boundary.

Before that, Lets see the final output that is desired from codegen

0000 0000 0000 0000 0000 0001 0000 0010
				AND
			      FFFF FFFF
			      ---------
			      0000 0010

- Set field.bitfield.mask = FFFF FFFF
- Shift 4 bits in the 2 read bytes (16 bits), This is calculated as:
  - bitfield.access_rshift = (bitfield.read_bytes * 8 - bitfield_offset
    - bitfield_bitwidth);
  - bitfield.access_rshift = (2*8 - (4+8)) = 4 bits.

4.Consider codegen_llvm.cpp, bitfield usecase:

bpftrace -v -e 'struct Foo { unsigned int a:4, b:8, c:3, d:1, e: 16; }
uprobe:./testprogs/bitfield_test:func{ $foo = (struct Foo *)arg0;
printf("%d\n", $foo-> b); exit()}'
Attaching 1 probe...

Program ID: 54

The verifier log:
0: (bf) r6 = r1
1: (79) r3 = *(u64 *)(r6 +40)
2: (b7) r1 = 0
3: (7b) *(u64 *)(r10 -24) = r1
last_idx 3 first_idx 0
regs=2 stack=0 before 2: (b7) r1 = 0
4: (63) *(u32 *)(r10 -4) = r1  <---- dst size,  field.type.GetSize()
5: (bf) r1 = r10
6: (07) r1 += -4
7: (b7) r2 = 2
8: (85) call bpf_probe_read_user#112
last_idx 8 first_idx 0
regs=4 stack=0 before 7: (b7) r2 = 2
9: (61) r1 = *(u32 *)(r10 -4)

- field.offset is 0, start reading from offset 0 for $foo->b.
  For foo->c, field.offset is 1 [ start reading from byte 1 ]
- field.type.GetSize() is the destination size. [ 32 bit for int bitfield,
  for short 16 bit ]
- Perform the CreateProbeRead starting from offset 0, read 2 bytes
  0001 0000 0010 1010 0000 0000 0000 0000
  ---- |-------| |--| < zero >
   a     b
- Now calculate number of bytes to right shift (should be 2 bytes)
  - rshiftbits = (field.type.GetSize() - field.bitfield.read_bytes) * 8;
  - rshiftbits = (4-2)*8 = 16
  - 0000 0000 0000 0000 | 0001 0000 0010 1010 |
                               ---------
	 			   b
- Now rightshift 4 bits within this 2 bytes. [ This 4 bits value is already
  calculated in clang_parser.cpp ]
  - rshiftbits += field.bitfield.access_rshift;
  - 0000 0000 0000 0000 0000 0001 0000 0010
- Finally mask this value with 0xFFFF FFFF (field.bitfield.mask)
- 0000 0000 0000 0000 0000 0000 0010 -> which is 2.

Signed-off-by: Sumanth Korikkar <[email protected]>
Signed-off-by: Sumanth Korikkar <[email protected]>
@fbs fbs merged commit 2aa9c46 into bpftrace:master Nov 20, 2020
casparant added a commit to casparant/bpftrace that referenced this pull request Nov 20, 2020
* 'master' of github.com:iovisor/bpftrace:
  types: (hacky) fix sizedtype memleak with shared_ptr
  bpftrace: Fix bitfield access for Big endian (bpftrace#1628)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants