Skip to content

Commit

Permalink
Add support for inet_ntoa6() subroutine
Browse files Browse the repository at this point in the history
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
  • Loading branch information
kvanhees committed Jul 27, 2023
1 parent 52aa48d commit 37ea121
Show file tree
Hide file tree
Showing 4 changed files with 298 additions and 2 deletions.
1 change: 1 addition & 0 deletions bpf/Build
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ bpf_dlib_SOURCES = \
get_dvar.c \
index.S \
inet_ntoa.S \
inet_ntoa6.S \
lltostr.S \
mutex_owned.S \
mutex_owner.S \
Expand Down
246 changes: 246 additions & 0 deletions bpf/inet_ntoa6.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
*/

#define BPF_FUNC_probe_read 4

#define DCTX_RODATA 56

.text

/*
* void write_hex16(const uint16_t src, char *dst)
*/
.align 4
.global write_hex16
.type write_hex16, @function
write_hex16:
mov %r0, 0

/*
* Branch-free implementation of num-to-hex print function. Given a
* number from 0 to 15, this will output a hex digit (0-9a-f) in the
* output buffer. It also supports suppression of leading 0s if it is
* used to output a sequence of digits.
*
* Given: c in [0, 15]
* Then, (c - 9) will be greater than 0 for c in [10, 15].
* Therefore, (-(c - 9)) will have its highest bit set if c in [10, 15].
* Thus, ((-(c - 9)) >> 63) will be 1 if c in [10, 15], and otherwise 0.
* Therefore, the hex digit (character) representing c can be computed
* as:
* c + '0' + ((-(c - 9)) >> 63) * ('a' - '0' - 10)
*
* Let s be a global suppression flag across the digits (initially 0).
* Let d be (c + s), and therefore ((-d) >> 63) will be 0 iff c and s
* are both 0, and otherwise 1. This is used to determine whether the
* output pointer should be advanced, and also to update the global
& suppression flag (s += ((-d) >> 63)).
*/
.macro WRITE_DIGIT n
mov %r3, %r1
rsh %r3, 4 * (3 - \n)
and %r3, 0xf
mov %r4, %r3
mov %r5, %r3
sub %r4, 9
neg %r4
rsh %r4, 63
mul %r4, 0x27
add %r4, 0x30
add %r3, %r4
stxb [%r2 + 0], %r3
add %r5, %r0
neg %r5
rsh %r5, 63 /* 0 if '0', 1 otherwise */
add %r2, %r5
add %r0, %r5
.endm

WRITE_DIGIT 0
WRITE_DIGIT 1
WRITE_DIGIT 2
WRITE_DIGIT 3

/*
* It is possible that all digits are 0, in which case the output
* pointer did not advance from its initial value. We do want a single
* 0 digit as output though.
*
* Since in this case, %r5 will be zero if all digits are zero, and 1
* otherwise, we can simply use %r0 + (%r5 ^ 1) to ensure that when all
* digits are 0, we retain the last one.
*/
xor %r5, 1
add %r0, %r5
exit
.size write_hex16, .-write_hex16

/*
* void inet_ntoa6(const dt_dctx_t *dctx, const uint8_t *src, char *dst,
* uint32 tbloff)
*/
.align 4
.global dt_inet_ntoa6
.type dt_inet_ntoa6, @function
dt_inet_ntoa6:
/* %r9 = dst, %r6 = dctx, %r8 = dctx->rodata + tbloff */
mov %r9, %r3 /* %r9 = dst */
mov %r6, %r1 /* %r6 = dctx */
mov %r8, %r1 /* %r8 = dctx->rodata + tbloff */
ldxdw %r8, [%r8 + DCTX_RODATA]
jge %r4, RODATA_SIZE, .Ldone
add %r8, %r4

mov %r3, %r2
mov %r2, 16
mov %r1, %fp
add %r1, -16
call BPF_FUNC_probe_read /* rc = probe_read(&fp[-16], 16, src) */
jne %r0, 0, .Ldone

/*
* Read the 8 words (16-bit values), and build a bitmap in %r7
* indicating which words are non-zero.
*
* We use an implementation that does not involve branches to reduce
* complexity for the BPF verifier.
*
* The IPv6 address has words in network byte order which may differ
* from the host byte order. We store a 2nd copy od the words, with
* the byte order reversed (if needed). We shouldn't need the 2nd copy
* if the byte order is the same but since the BPF verifier chokes on
* the output code below due to lack of tracking of relations between
* register values, the 2nd copy is needed anyway.
*/
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
# define NTOH(reg)
#else
# define NTOH(reg) endbe reg, 16
#endif
.macro GETWORD n
ldxh %r0, [%fp + (-16 + \n * 2)]
NTOH(%r0)
stxh [%fp + (-32 + \n * 2)], %r0
neg %r0
rsh %r0, 63
lsh %r0, 7 - \n
or %r7, %r0
.endm

mov %r7, 0
GETWORD 0
GETWORD 1
GETWORD 2
GETWORD 3
GETWORD 4
GETWORD 5
GETWORD 6
GETWORD 7

/* Set the upper bound for %r7. */
and %r7, 0xff

/* Handle mapped and embedded IPv4 addresses. */
mov %r0, %r7
and %r0, 0xfe
jeq %r0, 2, .Lipv4
jne %r0, 6, .Lnotipv4
ldxh %r0, [%fp + -22]
jeq %r0, 0xffff, .Lipv4
.Lnotipv4:

/*
* Perform a table lookup to determine the location and length of the
* longest run of 0-words (if any).
*/
mov %r0, %r8
add %r0, %r7
ldxb %r7, [%r0 + 0]

/*
* Determine the number of words to output at the start of the address.
* It is found in the upper 4 bits in %r7 (result of the table lookup
* above). We place an upper bound to make the BPF verifier happy.
*/
mov %r6, %r7
rsh %r6, 4
jgt %r6, 7, .Ldone
mov %r8, %fp
add %r8, -32

/* Write out the %r6 words at the beginning of the address. */
.Lpref_loop:
jle %r6, 0, .Lpref_done
ldxh %r1, [%r8 + 0]
mov %r2, %r9
call write_hex16
add %r9, %r0
stb [%r9 + 0], 0x3a
add %r9, 1
add %r8, 2
sub %r6, 1
ja .Lpref_loop

.Lpref_done:
stb [%r9 + 0], 0x3a

/*
* Determine the number of zero-words that can be collapsed. It is
* found in the lower 4 bits of %r7 (result of the table lookup above).
* (Note: it is either 0 or >1.)
*/
mov %r1, %r7
rsh %r1, 4 /* #(leading words) */
mov %r0, %r1
neg %r0
rsh %r0, 63
xor %r0, 1
add %r9, %r0
mov %r2, %r7
and %r2, 0xf /* #(zero words to collapse) */
add %r1, %r2 /* #(words used) */
jgt %r1, 8, .Ldone

mov %r8, %fp
add %r8, -32
mov %r0, %r1
mul %r0, 2
add %r8, %r0
mov %r6, 8
sub %r6, %r1 /* #(words left) */

stb [%r9 + 0], 0x3a
mov %r0, %r6
neg %r0
rsh %r0, 63
xor %r0, 1
add %r9, %r0

.Lpost_loop:
jle %r6, 0, .Ldone
stb [%r9 + 0], 0x3a
add %r9, 1
ldxh %r1, [%r8 + 0]
mov %r2, %r9
call write_hex16
add %r9, %r0
add %r8, 2
sub %r6, 1
ja .Lpost_loop

.Ldone:
stb [%r9 + 0], 0
mov %r0, 0
exit

.Lipv4:
mov %r1, %r6
mov %r2, %fp
add %r2, -4
mov %r3, %r9
call dt_inet_ntoa
add %r9, %r0
ja .Ldone
.size dt_inet_ntoa6, .-dt_inet_ntoa6
52 changes: 51 additions & 1 deletion libdtrace/dt_cg.c
Original file line number Diff line number Diff line change
Expand Up @@ -5878,6 +5878,56 @@ dt_cg_subr_inet_ntoa(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_inet_ntoa", DT_ISIGN, 0);
}

static void
dt_cg_subr_inet_ntoa6(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
{
dtrace_hdl_t *dtp = yypcb->pcb_hdl;
ssize_t tbloff;
const char tbl[] = {
0x08, 0x07, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x44, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x35, 0x34, 0x33, 0x33, 0x02, 0x02, 0x02, 0x02,
0x53, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x44, 0x43, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x53, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x26, 0x25, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23,
0x53, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x44, 0x43, 0x42, 0x42, 0x62, 0x70, 0x70, 0x70,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x35, 0x34, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x44, 0x43, 0x42, 0x42, 0x62, 0x70, 0x70, 0x70,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x17, 0x16, 0x15, 0x15, 0x14, 0x14, 0x14, 0x14,
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
0x44, 0x43, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x53, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
0x35, 0x34, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x44, 0x43, 0x42, 0x42, 0x62, 0x70, 0x70, 0x70,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x26, 0x25, 0x24, 0x24, 0x23, 0x23, 0x23, 0x23,
0x53, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22,
0x44, 0x43, 0x42, 0x42, 0x62, 0x70, 0x70, 0x70,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x35, 0x34, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
0x44, 0x43, 0x42, 0x42, 0x62, 0x70, 0x70, 0x70,
0x53, 0x52, 0x70, 0x70, 0x62, 0x70, 0x70, 0x70,
};

tbloff = dt_rodata_insert(dtp->dt_rodata, tbl, 256);
if (tbloff == -1L)
longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
if (tbloff > DIF_STROFF_MAX)
longjmp(yypcb->pcb_jmpbuf, EDT_STR2BIG);

dt_cg_subr_arg_to_tstring(dnp, dlp, drp, "dt_inet_ntoa6",
DT_ISIMM, tbloff);
}

typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *);

static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
Expand Down Expand Up @@ -5924,7 +5974,7 @@ static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
[DIF_SUBR_NTOHLL] = &dt_cg_subr_htonll,
[DIF_SUBR_INET_NTOP] = NULL,
[DIF_SUBR_INET_NTOA] = &dt_cg_subr_inet_ntoa,
[DIF_SUBR_INET_NTOA6] = NULL,
[DIF_SUBR_INET_NTOA6] = &dt_cg_subr_inet_ntoa6,
[DIF_SUBR_D_PATH] = NULL,
[DIF_SUBR_LINK_NTOP] = NULL,
};
Expand Down
1 change: 0 additions & 1 deletion test/unittest/funcs/tst.inet_ntoa6.d
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
/* @@xfail: dtv2 */

#pragma D option quiet

Expand Down

0 comments on commit 37ea121

Please sign in to comment.