From: Sandipan Das <hidden> Date: 2018-05-22 17:16:25
v3:
- Change base tree tag to bpf-next.
- Incorporate review comments from Alexei, Daniel and Jakub.
- Make sure that the JITed image does not grow or shrink after
the last pass due to the way the instruction sequence used
to load a callee's address maybe optimized.
- Make additional changes to the bpf system call and bpftool to
make multi-function JITed dumps easier to correlate.
v2:
- Incorporate review comments from Jakub.
Sandipan Das (10):
bpf: support 64-bit offsets for bpf function calls
bpf: powerpc64: pad function address loads with NOPs
bpf: powerpc64: add JIT support for multi-function programs
bpf: get kernel symbol addresses via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: resolve calls without using imm field
bpf: fix multi-function JITed dump obtained via syscall
bpf: get JITed image lengths of functions via syscall
tools: bpf: sync bpf uapi header
tools: bpftool: add delimiters to multi-function JITed dumps
arch/powerpc/net/bpf_jit_comp64.c | 110 ++++++++++++++++++++++++++++++--------
include/uapi/linux/bpf.h | 4 ++
kernel/bpf/syscall.c | 81 ++++++++++++++++++++++++++--
kernel/bpf/verifier.c | 22 +++++---
tools/bpf/bpftool/prog.c | 75 +++++++++++++++++++++++++-
tools/bpf/bpftool/xlated_dumper.c | 14 +++--
tools/bpf/bpftool/xlated_dumper.h | 3 ++
tools/include/uapi/linux/bpf.h | 4 ++
8 files changed, 278 insertions(+), 35 deletions(-)
--
2.14.3
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:25
The imm field of a bpf instruction is a signed 32-bit integer.
For JITed bpf-to-bpf function calls, it holds the offset of the
start address of the callee's JITed image from __bpf_call_base.
For some architectures, such as powerpc64, this offset may be
as large as 64 bits and cannot be accomodated in the imm field
without truncation.
We resolve this by:
[1] Additionally using the auxillary data of each function to
keep a list of start addresses of the JITed images for all
functions determined by the verifier.
[2] Retaining the subprog id inside the off field of the call
instructions and using it to index into the list mentioned
above and lookup the callee's address.
To make sure that the existing JIT compilers continue to work
without requiring changes, we keep the imm field as it is.
Signed-off-by: Sandipan Das <redacted>
---
kernel/bpf/verifier.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
@@ -5383,11 +5383,24 @@ static int jit_subprogs(struct bpf_verifier_env *env)insn->src_reg!=BPF_PSEUDO_CALL)continue;subprog=insn->off;-insn->off=0;insn->imm=(u64(*)(u64,u64,u64,u64,u64))func[subprog]->bpf_func-__bpf_call_base;}++/* we use the aux data to keep a list of the start addresses+*oftheJITedimagesforeachfunctionintheprogram+*+*forsomearchitectures,suchaspowerpc64,theimmfield+*mightnotbelargeenoughtoholdtheoffsetofthestart+*addressofthecallee'sJITedimagefrom__bpf_call_base+*+*insuchcases,wecanlookupthestartaddressofacallee+*byusingitssubprogid,availablefromtheofffieldof+*thecallinstruction,asanindexforthislist+*/+func[i]->aux->func=func;+func[i]->aux->func_cnt=env->subprog_cnt;}for(i=0;i<env->subprog_cnt;i++){old_bpf_func=func[i]->bpf_func;
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:27
For multi-function programs, loading the address of a callee
function to a register requires emitting instructions whose
count varies from one to five depending on the nature of the
address.
Since we come to know of the callee's address only before the
extra pass, the number of instructions required to load this
address may vary from what was previously generated. This can
make the JITed image grow or shrink.
To avoid this, we should generate a constant five-instruction
when loading function addresses by padding the optimized load
sequence with NOPs.
Signed-off-by: Sandipan Das <redacted>
---
arch/powerpc/net/bpf_jit_comp64.c | 34 +++++++++++++++++++++++-----------
1 file changed, 23 insertions(+), 11 deletions(-)
@@ -167,25 +167,37 @@ static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx)staticvoidbpf_jit_emit_func_call(u32*image,structcodegen_context*ctx,u64func){+unsignedinti,ctx_idx=ctx->idx;++/* Load function address into r12 */+PPC_LI64(12,func);++/* For bpf-to-bpf function calls, the callee's address is unknown+*untilthelastextrapass.Asseenabove,weusePPC_LI64()to+*loadthecallee'saddress,butthismayoptimizethenumberof+*instructionsrequiredbasedonthenatureoftheaddress.+*+*Sincewedon'twantthenumberofinstructionsemittedtochange,+*wepadtheoptimizedPPC_LI64()callwithNOPstoguaranteethat+*wealwayshaveafive-instructionsequence,whichisthemaximum+*thatPPC_LI64()canemit.+*/+for(i=ctx->idx-ctx_idx;i<5;i++)+PPC_NOP();+#ifdef PPC64_ELF_ABI_v1-/* func points to the function descriptor */-PPC_LI64(b2p[TMP_REG_2],func);-/* Load actual entry point from function descriptor */-PPC_BPF_LL(b2p[TMP_REG_1],b2p[TMP_REG_2],0);-/* ... and move it to LR */-PPC_MTLR(b2p[TMP_REG_1]);/**LoadTOCfromfunctiondescriptoratoffset8.*Wecanclobberr2sincewegetcalledthrougha*functionpointer(socallerwillsave/restorer2)*andsincewedon'tuseaTOCourself.*/-PPC_BPF_LL(2,b2p[TMP_REG_2],8);-#else-/* We can clobber r12 */-PPC_FUNC_ADDR(12,func);-PPC_MTLR(12);+PPC_BPF_LL(2,12,8);+/* Load actual entry point from function descriptor */+PPC_BPF_LL(12,12,0);#endif++PPC_MTLR(12);PPC_BLRL();}
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:30
This adds support for bpf-to-bpf function calls in the powerpc64
JIT compiler. The JIT compiler converts the bpf call instructions
to native branch instructions. After a round of the usual passes,
the start addresses of the JITed images for the callee functions
are known. Finally, to fixup the branch target addresses, we need
to perform an extra pass.
Because of the address range in which JITed images are allocated
on powerpc64, the offsets of the start addresses of these images
from __bpf_call_base are as large as 64 bits. So, for a function
call, we cannot use the imm field of the instruction to determine
the callee's address. Instead, we use the alternative method of
getting it from the list of function addresses in the auxiliary
data of the caller by using the off field as an index.
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Fix memory leak for jit_data when we fail to allocated addrs.
- Remove unnecessary bpf_jit_binary_lock_ro() call.
---
arch/powerpc/net/bpf_jit_comp64.c | 76 +++++++++++++++++++++++++++++++++------
1 file changed, 66 insertions(+), 10 deletions(-)
@@ -268,7 +268,7 @@ static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32/* Assemble the body code between the prologue & epilogue */staticintbpf_jit_build_body(structbpf_prog*fp,u32*image,structcodegen_context*ctx,-u32*addrs)+u32*addrs,boolextra_pass){conststructbpf_insn*insn=fp->insnsi;intflen=fp->len;
@@ -724,11 +724,25 @@ static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image,break;/*-*Callkernelhelper+*Callkernelhelperorbpffunction*/caseBPF_JMP|BPF_CALL:ctx->seen|=SEEN_FUNC;-func=(u8*)__bpf_call_base+imm;++/* bpf function call */+if(insn[i].src_reg==BPF_PSEUDO_CALL)+if(!extra_pass)+func=NULL;+elseif(fp->aux->func&&off<fp->aux->func_cnt)+/* use the subprog id from the off+*fieldtolookupthecalleeaddress+*/+func=(u8*)fp->aux->func[off]->bpf_func;+else+return-EINVAL;+/* kernel helper call */+else+func=(u8*)__bpf_call_base+imm;bpf_jit_emit_func_call(image,ctx,(u64)func);
@@ -947,7 +993,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)/* Now build the prologue, body code & epilogue for real. */cgctx.idx=0;bpf_jit_build_prologue(code_base,&cgctx);-bpf_jit_build_body(fp,code_base,&cgctx,addrs);+bpf_jit_build_body(fp,code_base,&cgctx,addrs,extra_pass);bpf_jit_build_epilogue(code_base,&cgctx);if(bpf_jit_enable>1)
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:36
Syncing the bpf.h uapi header with tools so that struct
bpf_prog_info has the two new fields for passing on the
addresses of the kernel symbols corresponding to each
function in a program.
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Move new fields to the end of bpf_prog_info to avoid
breaking userspace.
---
tools/include/uapi/linux/bpf.h | 2 ++
1 file changed, 2 insertions(+)
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:39
Currently, we resolve the callee's address for a JITed function
call by using the imm field of the call instruction as an offset
from __bpf_call_base. If bpf_jit_kallsyms is enabled, we further
use this address to get the callee's kernel symbol's name.
For some architectures, such as powerpc64, the imm field is not
large enough to hold this offset. So, instead of assigning this
offset to the imm field, the verifier now assigns the subprog
id. Also, a list of kernel symbol addresses for all the JITed
functions is provided in the program info. We now use the imm
field as an index for this list to lookup a callee's symbol's
address and resolve its name.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Avoid using redundant pointers.
- Fix indentation.
v2:
- Order variables from longest to shortest.
- Make sure that ksyms_ptr and ksyms_len are always initialized.
- Simplify code.
---
tools/bpf/bpftool/prog.c | 24 ++++++++++++++++++++++++
tools/bpf/bpftool/xlated_dumper.c | 10 +++++++++-
tools/bpf/bpftool/xlated_dumper.h | 2 ++
3 files changed, 35 insertions(+), 1 deletion(-)
@@ -174,7 +174,11 @@ static const char *print_call_pcrel(struct dump_data *dd,unsignedlongaddress,conststructbpf_insn*insn){-if(sym)+if(!dd->nr_jited_ksyms)+/* Do not show address for interpreted programs */+snprintf(dd->scratch_buff,sizeof(dd->scratch_buff),+"%+d",insn->off);+elseif(sym)snprintf(dd->scratch_buff,sizeof(dd->scratch_buff),"%+d#%s",insn->off,sym->name);else
From: Jakub Kicinski <hidden> Date: 2018-05-22 19:36:50
On Tue, 22 May 2018 22:46:09 +0530, Sandipan Das wrote:
Currently, we resolve the callee's address for a JITed function
call by using the imm field of the call instruction as an offset
from __bpf_call_base. If bpf_jit_kallsyms is enabled, we further
use this address to get the callee's kernel symbol's name.
For some architectures, such as powerpc64, the imm field is not
large enough to hold this offset. So, instead of assigning this
offset to the imm field, the verifier now assigns the subprog
id. Also, a list of kernel symbol addresses for all the JITed
functions is provided in the program info. We now use the imm
field as an index for this list to lookup a callee's symbol's
address and resolve its name.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Sandipan Das <redacted>
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:40
This adds new two new fields to struct bpf_prog_info. For
multi-function programs, these fields can be used to pass
a list of kernel symbol addresses for all functions in a
given program to userspace using the bpf system call with
the BPF_OBJ_GET_INFO_BY_FD command.
When bpf_jit_kallsyms is enabled, we can get the address
of the corresponding kernel symbol for a callee function
and resolve the symbol's name. The address is determined
by adding the value of the call instruction's imm field
to __bpf_call_base. This offset gets assigned to the imm
field by the verifier.
For some architectures, such as powerpc64, the imm field
is not large enough to hold this offset.
We resolve this by:
[1] Assigning the subprog id to the imm field of a call
instruction in the verifier instead of the offset of
the callee's symbol's address from __bpf_call_base.
[2] Determining the address of a callee's corresponding
symbol by using the imm field as an index for the
list of kernel symbol addresses now available from
the program info.
Suggested-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Sandipan Das <redacted>
---
v3:
- Copy addresses to jited_ksyms only if bpf_dump_raw_ok()
is true.
- Move new fields to the end of bpf_prog_info to avoid
breaking userspace.
---
include/uapi/linux/bpf.h | 2 ++
kernel/bpf/syscall.c | 25 +++++++++++++++++++++++++
kernel/bpf/verifier.c | 7 +------
3 files changed, 28 insertions(+), 6 deletions(-)
@@ -1933,6 +1933,7 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,if(!capable(CAP_SYS_ADMIN)){info.jited_prog_len=0;info.xlated_prog_len=0;+info.nr_jited_ksyms=0;gotodone;}
@@ -1981,6 +1982,30 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,}}+ulen=info.nr_jited_ksyms;+info.nr_jited_ksyms=prog->aux->func_cnt;+if(info.nr_jited_ksyms&&ulen){+if(bpf_dump_raw_ok()){+u64__user*user_ksyms;+ulongksym_addr;+u32i;++/* copy the address of the kernel symbol+*correspondingtoeachfunction+*/+ulen=min_t(u32,info.nr_jited_ksyms,ulen);+user_ksyms=u64_to_user_ptr(info.jited_ksyms);+for(i=0;i<ulen;i++){+ksym_addr=(ulong)prog->aux->func[i]->bpf_func;+ksym_addr&=PAGE_MASK;+if(put_user((u64)ksym_addr,&user_ksyms[i]))+return-EFAULT;+}+}else{+info.jited_ksyms=0;+}+}+done:if(copy_to_user(uinfo,&info,info_len)||put_user(info_len,&uattr->info.info_len))
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:42
Currently, for multi-function programs, we cannot get the JITed
instructions using the bpf system call's BPF_OBJ_GET_INFO_BY_FD
command. Because of this, userspace tools such as bpftool fail
to identify a multi-function program as being JITed or not.
With the JIT enabled and the test program running, this can be
verified as follows:
# cat /proc/sys/net/core/bpf_jit_enable
1
Before applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T11:43:38+0530 uid 0
xlated 216B not jited memlock 65536B
...
# bpftool prog dump jited id 1
no instructions returned
After applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T12:13:01+0530 uid 0
xlated 216B jited 308B memlock 65536B
...
# bpftool prog dump jited id 1
0: nop
4: nop
8: mflr r0
c: std r0,16(r1)
10: stdu r1,-112(r1)
14: std r31,104(r1)
18: addi r31,r1,48
1c: li r3,10
...
Signed-off-by: Sandipan Das <redacted>
---
kernel/bpf/syscall.c | 36 +++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
@@ -1970,13 +1970,43 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,*foroffload.*/ulen=info.jited_prog_len;-info.jited_prog_len=prog->jited_len;+if(prog->aux->func_cnt){+u32i;++info.jited_prog_len=0;+for(i=0;i<prog->aux->func_cnt;i++)+info.jited_prog_len+=prog->aux->func[i]->jited_len;+}else{+info.jited_prog_len=prog->jited_len;+}+if(info.jited_prog_len&&ulen){if(bpf_dump_raw_ok()){uinsns=u64_to_user_ptr(info.jited_prog_insns);ulen=min_t(u32,info.jited_prog_len,ulen);-if(copy_to_user(uinsns,prog->bpf_func,ulen))-return-EFAULT;++/* for multi-function programs, copy the JITed+*instructionsforallthefunctions+*/+if(prog->aux->func_cnt){+u32len,free,i;+u8*img;++free=ulen;+for(i=0;i<prog->aux->func_cnt;i++){+len=prog->aux->func[i]->jited_len;+img=(u8*)prog->aux->func[i]->bpf_func;+if(len>free)+break;+if(copy_to_user(uinsns,img,len))+return-EFAULT;+uinsns+=len;+free-=len;+}+}else{+if(copy_to_user(uinsns,prog->bpf_func,ulen))+return-EFAULT;+}}else{info.jited_prog_insns=0;}
From: Jakub Kicinski <hidden> Date: 2018-05-22 19:47:20
On Tue, 22 May 2018 22:46:10 +0530, Sandipan Das wrote:
quoted hunk
Currently, for multi-function programs, we cannot get the JITed
instructions using the bpf system call's BPF_OBJ_GET_INFO_BY_FD
command. Because of this, userspace tools such as bpftool fail
to identify a multi-function program as being JITed or not.
With the JIT enabled and the test program running, this can be
verified as follows:
# cat /proc/sys/net/core/bpf_jit_enable
1
Before applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T11:43:38+0530 uid 0
xlated 216B not jited memlock 65536B
...
# bpftool prog dump jited id 1
no instructions returned
After applying this patch:
# bpftool prog list
1: kprobe name foo tag b811aab41a39ad3d gpl
loaded_at 2018-05-16T12:13:01+0530 uid 0
xlated 216B jited 308B memlock 65536B
...
# bpftool prog dump jited id 1
0: nop
4: nop
8: mflr r0
c: std r0,16(r1)
10: stdu r1,-112(r1)
14: std r31,104(r1)
18: addi r31,r1,48
1c: li r3,10
...
Signed-off-by: Sandipan Das <redacted>
---
kernel/bpf/syscall.c | 36 +++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
@@ -1970,13 +1970,43 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,*foroffload.*/ulen=info.jited_prog_len;-info.jited_prog_len=prog->jited_len;+if(prog->aux->func_cnt){+u32i;++info.jited_prog_len=0;+for(i=0;i<prog->aux->func_cnt;i++)+info.jited_prog_len+=prog->aux->func[i]->jited_len;+}else{+info.jited_prog_len=prog->jited_len;+}+if(info.jited_prog_len&&ulen){if(bpf_dump_raw_ok()){uinsns=u64_to_user_ptr(info.jited_prog_insns);ulen=min_t(u32,info.jited_prog_len,ulen);-if(copy_to_user(uinsns,prog->bpf_func,ulen))-return-EFAULT;++/* for multi-function programs, copy the JITed+*instructionsforallthefunctions+*/+if(prog->aux->func_cnt){+u32len,free,i;+u8*img;++free=ulen;+for(i=0;i<prog->aux->func_cnt;i++){+len=prog->aux->func[i]->jited_len;+img=(u8*)prog->aux->func[i]->bpf_func;+if(len>free)+break;
nit: interesting, the previous code used to fill up the space
completely, I would personally vote to keep that behaviour and do:
len = min(len, free);
copy();
free -= len;
if (!free)
break;
otherwise the user space doesn't know when to stop disassembling
truncated output. But that's really a corner case, so not sure we care.
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:44
This adds new two new fields to struct bpf_prog_info. For
multi-function programs, these fields can be used to pass
a list of the JITed image lengths of each function for a
given program to userspace using the bpf system call with
the BPF_OBJ_GET_INFO_BY_FD command.
This can be used by userspace applications like bpftool
to split up the contiguous JITed dump, also obtained via
the system call, into more relatable chunks corresponding
to each function.
Signed-off-by: Sandipan Das <redacted>
---
include/uapi/linux/bpf.h | 2 ++
kernel/bpf/syscall.c | 20 ++++++++++++++++++++
2 files changed, 22 insertions(+)
@@ -2036,6 +2036,26 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,}}+ulen=info.nr_jited_func_lens;+info.nr_jited_func_lens=prog->aux->func_cnt;+if(info.nr_jited_func_lens&&ulen){+if(bpf_dump_raw_ok()){+u32__user*user_lens;+u32func_len,i;++/* copy the JITed image lengths for each function */+ulen=min_t(u32,info.nr_jited_func_lens,ulen);+user_lens=u64_to_user_ptr(info.jited_func_lens);+for(i=0;i<ulen;i++){+func_len=prog->aux->func[i]->jited_len;+if(put_user(func_len,&user_lens[i]))+return-EFAULT;+}+}else{+info.jited_func_lens=0;+}+}+done:if(copy_to_user(uinfo,&info,info_len)||put_user(info_len,&uattr->info.info_len))
From: Sandipan Das <hidden> Date: 2018-05-22 17:16:45
Syncing the bpf.h uapi header with tools so that struct
bpf_prog_info has the two new fields for passing on the
JITed image lengths of each function in a multi-function
program.
Signed-off-by: Sandipan Das <redacted>
---
tools/include/uapi/linux/bpf.h | 2 ++
1 file changed, 2 insertions(+)
The output doesn't seem to be JSON-compatible :( We try to make sure
all bpftool command can produce valid JSON when run with -j (or -p)
switch.
Would it be possible to make each function a separate JSON object with
"name" and "insn" array? Would that work?
The output doesn't seem to be JSON-compatible :( We try to make sure
all bpftool command can produce valid JSON when run with -j (or -p)
switch.
Would it be possible to make each function a separate JSON object with
"name" and "insn" array? Would that work?
Sandipan, could you take a look at this? Given there's json output today we
should definitely try not to break it; presumably this would be one final
respin of your series with this fixed.
Thanks,
Daniel
The output doesn't seem to be JSON-compatible :( We try to make sure
all bpftool command can produce valid JSON when run with -j (or -p)
switch.
Would it be possible to make each function a separate JSON object with
"name" and "insn" array? Would that work?
Sandipan, could you take a look at this? Given there's json output today we
should definitely try not to break it; presumably this would be one final
respin of your series with this fixed.
Sure. With a few changes, I am able get JSON output like the following:
# echo 0 > /proc/sys/net/core/bpf_jit_kallsyms
# bpftool prog -p dump jited id 1
[{
"name": "0xd00000000aa80000",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
"operands": ["r0"
]
},{
"pc": "0xc",
"operation": "std",
"operands": ["r0","16","(","r1",")"
]
},{
"pc": "0x10",
"operation": "stdu",
"operands": ["r1","-112","(","r1",")"
]
},{
...
}
]
},{
"name": "0xd00000000aae0000",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
"operands": ["r0"
]
},{
...
}
]
}
]
# echo 1 > /proc/sys/net/core/bpf_jit_kallsyms
# bpftool prog -p dump jited id 1
[{
"name": "bpf_prog_b811aab41a39ad3d_foo",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
"operands": ["r0"
]
},{
"pc": "0xc",
"operation": "std",
"operands": ["r0","16","(","r1",")"
]
},{
"pc": "0x10",
"operation": "stdu",
"operands": ["r1","-112","(","r1",")"
]
},{
...
}
]
},{
"name": "bpf_prog_196af774a3477707_F",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
"operands": ["r0"
]
},{
...
}
]
}
]
If this is okay, I can send out the next revision with these changes.
Other than that, for powerpc64, there is a problem with the way the
binutils disassembler code (in "opcodes/ppc-dis.c") passes arguments
to the callback fprintf_json().
In fprintf_json(), we always expect the va_list elements to resolve
to strings (char *). But for powerpc64, the register or immediate
operands are always passed as integers. So, when the code attempts
to resolve these operands using va_arg(ap, char *), bpftool crashes.
For now, I am using a workaround based on vsnprintf() but this does
not get the semantics correct for memory operands. You can probably
see that for the store instructions in the JSON dump above this.
Daniel,
Would it be okay if I send out a fix for this in a different series?
- Sandipan
From: Daniel Borkmann <daniel@iogearbox.net> Date: 2018-05-23 13:50:44
On 05/23/2018 12:37 PM, Sandipan Das wrote:
[...]
Other than that, for powerpc64, there is a problem with the way the
binutils disassembler code (in "opcodes/ppc-dis.c") passes arguments
to the callback fprintf_json().
In fprintf_json(), we always expect the va_list elements to resolve
to strings (char *). But for powerpc64, the register or immediate
operands are always passed as integers. So, when the code attempts
to resolve these operands using va_arg(ap, char *), bpftool crashes.
For now, I am using a workaround based on vsnprintf() but this does
not get the semantics correct for memory operands. You can probably
see that for the store instructions in the JSON dump above this.
Daniel,
Would it be okay if I send out a fix for this in a different series?
I'm fine either way with regards to the fix. Feels like a portability bug
in the binutils disassembler?
We could probably have a feature test like in test-disassembler-four-args
and select a workaround in bpftool based on that outcome.
Thanks Sandipan!
[1] tools/build/feature/test-disassembler-four-args.c
From: Sandipan Das <hidden> Date: 2018-05-23 13:59:20
On 05/23/2018 07:20 PM, Daniel Borkmann wrote:
On 05/23/2018 12:37 PM, Sandipan Das wrote:
[...]
quoted
Other than that, for powerpc64, there is a problem with the way the
binutils disassembler code (in "opcodes/ppc-dis.c") passes arguments
to the callback fprintf_json().
In fprintf_json(), we always expect the va_list elements to resolve
to strings (char *). But for powerpc64, the register or immediate
operands are always passed as integers. So, when the code attempts
to resolve these operands using va_arg(ap, char *), bpftool crashes.
For now, I am using a workaround based on vsnprintf() but this does
not get the semantics correct for memory operands. You can probably
see that for the store instructions in the JSON dump above this.
Daniel,
Would it be okay if I send out a fix for this in a different series?
I'm fine either way with regards to the fix. Feels like a portability bug
in the binutils disassembler?
We could probably have a feature test like in test-disassembler-four-args
and select a workaround in bpftool based on that outcome.
Thanks Sandipan!
[1] tools/build/feature/test-disassembler-four-args.c
From: Jakub Kicinski <hidden> Date: 2018-05-23 21:32:51
On Wed, 23 May 2018 16:07:40 +0530, Sandipan Das wrote:
"name": "bpf_prog_196af774a3477707_F",
"insns": [{
"pc": "0x0",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x4",
"operation": "nop",
"operands": [null
]
},{
"pc": "0x8",
"operation": "mflr",
"operands": ["r0"
]
},{
...
}
]
}
]
If this is okay, I can send out the next revision with these changes.