what's func_info in eBPF verifier? - ebpf

I'm developing an XDP program and I'm facing this error when trying to mount it in NIC driver:
libbpf: failed to guess program type based on ELF section name '.text'
libbpf: supported section(type) names are: socket kprobe/ uprobe/ kretprobe/ uretprobe/ classifier action tracepoint/ tp/ raw_tracepoint/ raw_tp/ tp_btf/ xdp perf_event lwt_in lwt_out lwt_xmit lwt_seg6local cgroup_skb/ingress cgroup_skb/egress cgroup/skb cgroup/sock cgroup/post_bind4 cgroup/post_bind6 cgroup/dev sockops sk_skb/stream_parser sk_skb/stream_verdict sk_skb sk_msg lirc_mode2 flow_dissector cgroup/bind4 cgroup/bind6 cgroup/connect4 cgroup/connect6 cgroup/sendmsg4 cgroup/sendmsg6 cgroup/recvmsg4 cgroup/recvmsg6 cgroup/sysctl cgroup/getsockopt cgroup/setsockopt
libbpf: load bpf program failed: Invalid argument
libbpf: -- BEGIN DUMP LOG ---
libbpf:
number of funcs in func_info doesn't match number of subprogs
processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program '.text'
I searched and found the error is raising when eBPF verifier trying to compare attr->func_info_cnt and env->subprog_cnt but I don't understand how these two values are set before processed by the verifier. I have one XDP program with one section and 6 functions as helpers, I'm not sure if this info can help but I can provide more about the structure of the program if needed.

Did you omit to put your programs in a dedicated ELF section? Something like:
SEC("xdp")
int my_prog(struct xdp_md *ctx)
{
...
}
(Where SEC() is a macro defined in libbpf's bpf_helpers.h header.)
If you do not specify any ELF section name, clang/LLVM defaults to .text, as in your error message. When you attempt to load a program with libbpf, the library usually guesses the program type from the name of the ELF section into which the program was put. If you do not use a dedicated section name, and do not otherwise specify the program type (for example, in libbpf with bpf_program__set_type()), then libbpf is unable to pick the relevant type for your program.
This could lead to some of your programs to fail to load. From the error message above, it looks like you use function calls in your program (instead of declaring, for example, your functions as static inline). When your main program passes the verifier, some parts will be missing: The “functions” may not be loaded, so the verifier complains that the expected number of functions/subprograms inferred from the main program (env->subprog_cnt) is different from the number of functions collected by your loader application (attr->func_info_cnt) and passed down to the kernel when loading the program with the bpf() system call.
If this is the case, you can probably fix the issue either by placing your code in dedicated ELF functions, or by declaring your functions as static inline if you do not require function calls in the generated bytecode.

Related

ebpf: where verifier prints its messages?

Where does the verifier print its messages? I have a simple code embedded in struct bpf_insn which I load and attach as BPF_PROG_TYPE_SOCKET_FILTER type:
struct bpf_insn prog[] = {
BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
BPF_EXIT_INSN(),
};
This code is intentionally made wrong (R0 is not initialized before the exit). bpf_prog_load() returns EACCESS error and fails to load, which is expected, but I wanted to the verifier messages (nothing in dmesg or console).
When attempting to load an eBPF program, it is up to the loader to pass a buffer to the kernel verifier and to later print it to get the verifier's output.
The verifier will use this buffer provided by the user space program and print all its logs in it. Excepted for a very few specific messages, it will not print anything to the kernel logs or to the console (which is handled by your shell, not the kernel directly).
Let's have a look at a snippet from samples/bpf/sock_example.c, that you mentioned in the comments.
prog_fd = bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, insns_cnt,
"GPL", 0, bpf_log_buf, BPF_LOG_BUF_SIZE);
if (prog_fd < 0) {
printf("failed to load prog '%s'\n", strerror(errno));
goto cleanup;
}
This is the part where we attempt to load the program. We call bpf_load_program() from libbpf, and we pass it, in this order, the program type, the instructions, the number of instructions, the license string, some flag related to kernel versions, and at last: an empty buffer and its size. The size BPF_LOG_BUF_SIZE is non-null (defined in tools/lib/bpf/bpf as (UINT32_MAX >> 8)).
The function bpf_load_program() will pass all this information, including the pointer to the buffer, to the bpf() system call, which will attempt to load the program. The verifier will populate the buffer with logs (whether the load succeeds or not, but see note at the bottom). Then it is up to the loader program, again, to use these logs. The function bpf_load_program() is low-level, it does nothing with the verifier's logs in the buffer, even on failure to load. It leaves it to the caller to process or dump the logs. The sample application that you attempt to run does nothing either; therefore, the buffer is unused, and you don't get to see the logs in the console.
To see the logs, in your case, you probably just need to dump this buffer. Something as simple as the following should work:
...
if (prog_fd < 0) {
printf("failed to load prog '%s'\n", strerror(errno));
printf("%s", bpf_log_buf);
goto cleanup;
}
Note: In addition to the buffer and the size of the buffer, the loader must pass a log_level integer to the verifier, to tell it what level of verbosity it should use. If the value is at 0, the verifier prints nothing to the buffer. In the current case, we do not handle the log_level directly. bpf_load_program() does not either and sets the value to 0, but it ends up calling libbpf__bpf_prog_load() in libbpf. That function tries to load the program a first time without changing the log_level, but in case of failure, it does a new attempt with the log_level set at 1 - See Mark's pointers in the comments for details. The different values for log_level are defined in internal kernel headers and are not part of the user API, meaning the behaviour of the verifier regarding log verbosity may vary between kernel versions.

"HelloWorld" program on MIPS is not working when loaded by linux core to another core

A program "HelloWorld" running on Mips Interaptive core0 VPE1, including crt0.S (which I wrote), main.c files creates an ELF in which the symbols are relative to 0x0:
0x0 - _core_reset (this is part of crt0.S)
...
0x460 - fw_reset (this is called from main)
...
0x484 - main (this is the main function)
(-) my ELF undergoes stripping of sections to create a binary file of instructions only, starting in _core_reset
(-) the binary image from last step is loaded to virtual address 0xADB00000, which is physical 0x2DB00000
(-) the first problem is that in _core_reset we do:
la t0,main
mtc0 t0,C0_ERRPC //store it as return address
but main has the address relative to 0x0, which causes memory exception,
what I need is main to be in address loaded + (offset relative to zero),
How do I do that? we can say that the address the image is loaded to and run from is constant
I tried to write in the crt0.S file, hardcoded to change the jump to main address:
lui t0, 0xa6b0 /* Assumtion the FW is loaded to 0xa6b00000 */
addiu t0, t0, main
and it worked an I reached main(), but later when tried to call fw_reset() from main, the address of fw_reset() was again relative to 0x0 and I got a memory exception
I tried from the makefile to add that the .text section of ELF will start from the address loaded, but then I get an issue that my image is loaded to:
(value i provide) + (actual loading address) and so it also doesn't work
I expected my code to reach main() and be stuck in the endless while loop, instead I get memory exceptions since the functions are relative to 0x0, while the code is loaded to another address not zero

Basic UVM sequence simulation query

I have a couple of issues with a basic UVM based TB I'm trying out to understand sequences and their working.
bvalid is being always picked as 0 in the driver when being updated in the response item
Couple of error messages for last 2 transactions (# UVM_ERROR # 18: uvm_test_top.axi_agent1.axi_base_seqr1##axi_base_seq1 [uvm_test_top.axi_agent1.axi_base_seqr1.axi_base_seq1] Response queue overflow, response was dropped)
Here is the link to the compiling code on EDA Playground
http://www.edaplayground.com/x/3x9
Any suggestions on what I'm missing??
Thanks
venkstart
Having a look at the specification for $urandom_range it shows the signature as: function int unsigned $urandom_range( int unsigned maxval, int unsigned minval = 0 ). Change your call to $urandom_range(1, 0) and it should work.
The second error comes from the fact that you are sending responses from the driver and not picking them up in your sequence. This is the line that does it: seq_item_port.item_done(axi_item_driv_src);. Either just do seq_item_port.item_done(); (don't send responses) or put a call to get_response() inside your sequence after finish_item(). What I usually do is update the fields of the original request and just call item_done(). For example, if I start a read transaction, in my driver I would drive the control signals and wait for the DUT to respond, update the data field of the request with the data I got from the DUT and call item_done() in my driver to mark the request as done. This way if I need this data in my sequence (to constrain some future item, for example) I have it.

How to interpret avr32-size output?

I have C program running on a AVR32 microcontroller (UC3C0512C).
Issuing the avr32-size -A PROGRAM.elf command generates the following output:
PROGRAM.elf :
section size addr
.reset 8200 2147483648
.rela.got 0 2147491848
.text 99512 2147491848
.exception 512 2147591680
.rodata 5072 2147592192
.dalign 4 4
.data 7036 8
.balign 4 7044
.bss 5856 7048
.heap 48536 12904
.comment 48 0
.debug_aranges 8672 0
.debug_pubnames 14476 0
.debug_info 311236 0
.debug_abbrev 49205 0
.debug_line 208324 0
.debug_frame 23380 0
.debug_str 43961 0
.debug_loc 63619 0
.debug_macinfo 94469328 0
.stack 4096 61440
.data_hram0 512 2684354560
.debug_ranges 8368 0
Total 95379957
Can someone explain how to interpret these values?
How can I calculate the flash and ram usage based on this list?
Update 1:
Without the -A flag, I am getting the following:
text data bss dec hex filename
113296 7548 58496 179340 2bc8c PROGRAM.elf
Update 2:
I'm not using dynamic memory allocation, so according the avr-libc user-manual, the free RAM space should be simply: stackpointer minus __heap_start.
In this case: 61440 - 12904 = 48536 byte free RAM space.
Can someone confirm that?
(There is a mismatch in the two outputs in your question. The bss number is wildly different.)
If you don't use malloc, and don't count the stack, then yes, the RAM usage is the data plus the bss (plus some alignment spacing). The data are the variables that are set in a declaration, and the bss are the variables that are not. The C runtime will probably initialize them to 0, but it doesn't have to.
The flash usage will be the text and the data. That is, the flash will include the program instructions and C runtime, but also the values that need to get copied into RAM on startup to initialize those variables. This data is generally tacked onto the end of the program instructions.
Re: update 2
RAM holds global variables, the heap, and then the stack in that order.
The global variables can be initialized in the program, or not. The .data section is stored in flash, and the C runtime copies these values into the beginning of RAM where the corresponding variables live before your code runs. The .bss section of global variables needs space in RAM to hold the values, but they aren't necessarily initialized. The C runtime that comes with avr-gcc does actually initialize these to 0. The point it that your don't need to store an array of 0s to copy over, as you do with the .data section.
You are not using heap, but dynamically allocated memory is obtained from the addresses between heap_start and heap_end.
But the stack is not limited. Yes, the stack-pointer is initialized at startup, but it changes as your program runs, and can move well into the heap or even into the global variables (stack overflow). The stack pointer moves whenever a function is called, or local variables within a function are used. For example, a large array declared inside a function will go on the stack.
So in answer to your question, there is no RAM that is guaranteed to remain free.
I think you should remove the -A (all) flag, since that gives you the more low-level list you're showing.
The default output is easier to parse, and seems to directly state the values you're after.
Note: I didn't try this, not a system with an AVR toolchain installed.
I guess that in your linker script you have RAM at 0, and Flash at 0x80000000, so all things that need to go to RAM are at addresses 0+ (.stack is the last at 61440 (spanning next 4k)). So you would need a bit more that 64k of RAM. Everything else you have is flash.
That is provided that your linker script is correct.
Also see unwind's comment.
These values are the assembly language sections of the compiled C code. See the docs for the details. This article is also helpful.
The section titled .text represents the instruction section, i.e. the assembly instructions. The .data section represents the size of the variables (ints, arrays, etc.). The size column has the significant info, and it has the size of each section in bytes. The .stack and .heap represent the memory allocated in preparation for the execution of the program to set up the virtual memory.
You can try
avr-nm --print-size --radix d --demangle x.elf
to get the sizes in decimal notation.
Then you can copy & paste into a spreadsheet, filter, sort by the sections, and sum it up.

entry() get into the different address from the entry point I set in the Elf

Recently I'm learning about the OS. And I want to write a simple bootloader, which change the real mode to protect mode and then load the simple kernel.
But I can't figure out the entry address problem.
At first I put the bootloader in the first sector of the OS.img(qemu), and then the kernel begin at the second sector.
Here's readelf result of my kernel:
The entry point address is 0x800c.
And the LMA and VMA are below:
A part of the bootloader which read elf-type kernel and then get into the entry(),which is the entry point address.
However, when I disassemble the bootloader, the entry() is below:
Call *0x8018, not *0x800c.
I don't know why this happen.
Could you please help me?
call *0x8018 performs a call to an address that is stored at 0x8018, that's correct since ELFHDR is 0x8000 and offset of e_entry in the header is 0x18.
The real problem is in the way you load segments into memory. Each segment should be loaded at address p_vaddr from file offset p_offset. Notice that in your case p_vaddr is 0x8000, that the same place in memory you loaded elf header to and that's why ELFHDR->e_entry gets overwritten. The easiest solution would be to load elf header at different address.
Source: http://www.skyfree.org/linux/references/ELF_Format.pdf