<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>leodido.dev - Clang</title>
    <subtitle>Leo&#x27;s take on security, eBPF, Linux, kernel, and whatever tech he meets</subtitle>
    <link rel="self" type="application/atom+xml" href="https://leodido.dev/tags/clang/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://leodido.dev"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2022-02-07T00:00:00+00:00</updated>
    <id>https://leodido.dev/tags/clang/atom.xml</id>
    <entry xml:lang="en">
        <title>Code coverage for eBPF programs</title>
        <published>2022-02-07T00:00:00+00:00</published>
        <updated>2022-02-07T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/code-coverage-ebpf/"/>
        <id>https://leodido.dev/code-coverage-ebpf/</id>
        
        <content type="html" xml:base="https://leodido.dev/code-coverage-ebpf/">&lt;p&gt;I bet we all have heard so much about &lt;abbr title=&quot;extended Berkeley Packet Filter&quot;&gt;eBPF&lt;&#x2F;abbr&gt; in recent years. Every day we hear about a new project or application using some eBPF black magic underneath. &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.google.com&#x2F;url?q=https:&#x2F;&#x2F;thenewstack.io&#x2F;this-week-in-programming-ebpf-coming-to-a-windows-near-you&quot;&gt;Data&lt;&#x2F;a&gt; shows that eBPF is quickly becoming the first choice for implementing tracing and security applications.&lt;&#x2F;p&gt;
&lt;p&gt;However, one major challenge is that the eBPF ecosystem lacks tooling to make developers&#x27; lives easier. eBPF programs are written in C but compiled for a specific ISA later executed by the eBPF Virtual Machine. LLVM has a specific backend allowing us to write C and get eBPF ELF objects out. There are no tools helping developers to clearly &lt;mark&gt;understand&lt;&#x2F;mark&gt; which &lt;mark&gt;path&lt;&#x2F;mark&gt; their code took while running in the Linux kernel, which &lt;mark&gt;code regions&lt;&#x2F;mark&gt;, or, even better, &lt;mark&gt;code branches&lt;&#x2F;mark&gt; are uncovered, and maybe why.&lt;&#x2F;p&gt;
&lt;p&gt;You may already be familiar with code coverage, which shows you which lines of code execute. Code coverage is usually applied to tests to discover which line gets run and which does not. But even testing the eBPF programs is a pain, given that &lt;code&gt;BPF_PROG_TEST_RUN&lt;&#x2F;code&gt; does not support all the types of eBPF programs living in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;That&#x27;s why I sat down and wrote bpfcov&lt;&#x2F;a&gt;: a tool to gather &lt;mark&gt;source-based coverage&lt;&#x2F;mark&gt; info for our eBPF programs running in the Linux kernel. Whether they are getting loaded via &lt;code&gt;BPF_PROG_TEST_RUN&lt;&#x2F;code&gt; or by other ordinary means. Until today, there was no simple way to visualize how the flow of your eBPF program running in the kernel was. Hopefully, there is one starting today.&lt;&#x2F;p&gt;
&lt;p&gt;So, let&#x27;s jump straight into the topic.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;source-based-code-coverage-for-ebpf&quot;&gt;Source-based code coverage for eBPF&lt;a class=&quot;zola-anchor&quot; href=&quot;#source-based-code-coverage-for-ebpf&quot; aria-label=&quot;Anchor link for: source-based-code-coverage-for-ebpf&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Everyone reading this post probably knows what the code coverage is. Common line-level coverage gives us a sense of what line is executed. In some cases, it even tells us how many times a line got executed.&lt;&#x2F;p&gt;
&lt;p&gt;When building this tool, driven by my experience fighting with BPF, I knew I wanted something more. Line-level granularity is often too coarse. We do not want an approximation of what code actually executed.
We need something more precise to understand the execution path of our eBPF programs in the Linux kernel. We even want to know what part of an &lt;code&gt;if&lt;&#x2F;code&gt; conditional executed&lt;label for=&quot;sn-1&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;I suggest you watch &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?app=desktop&amp;amp;v=H1hvtJPGWNQ&quot;&gt;this talk&lt;&#x2F;a&gt; by Alan Phipps to know more about branch coverage.&lt;&#x2F;span&gt;. Source-based code coverage is what I wanted for this reason.&lt;&#x2F;p&gt;
&lt;p&gt;Since it starts at code generation time in LLVM, it has the notion of &lt;mark&gt;regions&lt;&#x2F;mark&gt; of the code, &lt;mark&gt;branches&lt;&#x2F;mark&gt;, and so on. It even precisely counts things like &lt;mark&gt;short-circuited conditionals&lt;&#x2F;mark&gt;, thanks to the &lt;mark&gt;counter expression&lt;&#x2F;mark&gt; and arithmetics between them. It generates coverage summaries with very fine-grained code regions, helping us find gaps in the code and its execution flow.&lt;&#x2F;p&gt;
&lt;p&gt;So, given eBPF programs are usually written in C, couldn&#x27;t we just instrument them for &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;docs&#x2F;SourceBasedCodeCoverage.html&quot;&gt;source-based code coverage&lt;&#x2F;a&gt; as we would commonly do with Clang for our C programs? I bet this is the first argument popping into the head of many readers. It also was one of my thoughts when approaching this problem. Turns out that we definitely can, and we will do it. But it won&#x27;t work as is.&lt;&#x2F;p&gt;
&lt;p&gt;To understand why it won&#x27;t work, we need to keep in mind that BPF programs are compiled via Clang&lt;label for=&quot;sn-2&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-2&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Thanks to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;tree&#x2F;main&#x2F;llvm&#x2F;lib&#x2F;Target&#x2F;BPF&quot;&gt;LLVM BPF target&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; to BPF ELF object files, containing instructions specific to the chosen BPF instruction set, which need to be later loaded in the Linux kernel via the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.kernel.org&#x2F;doc&#x2F;html&#x2F;latest&#x2F;userspace-api&#x2F;ebpf&#x2F;syscall.html&quot;&gt;bpf()&lt;&#x2F;a&gt; syscall. Furthermore, it&#x27;s paramount to mention that the BPF programs will be verified by an in-kernel verifier and then executed by the BPF VM.&lt;&#x2F;p&gt;
&lt;p&gt;Such a lifecycle and environment imposes a set of constraints that make it infeasible to get them working with the plain instrumentation that LLVM applies to get source-based code coverage. In fact, when compiling a C program for source-based coverage with the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; and &lt;code&gt;-fcoverage-mapping&lt;&#x2F;code&gt; Clang flags, LLVM instruments it with a bunch of global variables and, in some cases, functions.&lt;&#x2F;p&gt;
&lt;p&gt;Observing the LLVM IR of a C program after compiling it with the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; flag, we can notice that, LLVM...&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;defines the counters, in the form of &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; private global arrays whose size is the number of counters needed to cover all the regions and branches of such a function&lt;&#x2F;li&gt;
&lt;li&gt;marks those counters to be into the &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; private global struct instances that contains an identifier of the function, the pointer to its counters, the pointer to the function itself, the number of the counters for the target function, and a bunch of other info needed to tie together the counters and the coverage mappings&lt;&#x2F;li&gt;
&lt;li&gt;marks the &lt;code&gt;__profd_&lt;&#x2F;code&gt; globals to end up into the &lt;code&gt;__llvm_prf_data&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) a private constant (&lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt;) containing the names of the target functions&lt;&#x2F;li&gt;
&lt;li&gt;marks the names constant to end up in the &lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt; section of the ELF&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The first issue to address here is that we can&#x27;t have random ELF sections (like&lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt;, etc.) into valid BPF ELF files.&lt;&#x2F;p&gt;
&lt;p&gt;We know that we can have eBPF global constants with a scalar type like &lt;code&gt;__profc_&lt;&#x2F;code&gt; ones, at least on recent Linux kernels. At the same time, we know it&#x27;s not wise to have global structs like &lt;code&gt;__profd_&lt;&#x2F;code&gt; or whatever loader for our eBPF programs we will write, as we&#x27;ll need the struct definitions. Too clunky.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; flag also generates a global constructor and a set of global functions, all prefixed with &lt;code&gt;__llvm_profile&lt;&#x2F;code&gt;, intended to set up the profiling runtime in the resulting binary so that when it dies or exits it will automatically generate a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;Here we meet another stumbling block to overcome. The BPF verifier will refuse our BPF ELF containing strange global functions, not to mention &quot;constructors&quot;...&lt;&#x2F;p&gt;
&lt;p&gt;We need to get rid of them and replace their functionality with a feasible approach for BPF. Clearly, LLVM also patches our instructions in the right spots, by placing the counters and incrementing them. As you can see in the following annotated screenshot:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;profile-instr-generate2.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;profile-instr-generate2.png&quot; alt=&quot;LLVM IR incrementing profiling counters at the correct spots&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;If you write an eBPF program incrementing a &lt;mark&gt;counter&lt;&#x2F;mark&gt; (defined as an &lt;mark&gt;eBPF global variable&lt;&#x2F;mark&gt;) you will notice that the resulting instructions will be like those here in the screenshot. It means we can keep these the way they are generated by LLVM and let it do all its magic without interfering at the instructions level. Finally, some good news!&lt;&#x2F;p&gt;
&lt;p&gt;Instead, focusing on the &lt;code&gt;-fcoverage-mapping&lt;&#x2F;code&gt; Clang flag and inspecting the LLVM IR it outputs, we notice that it...&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;defines (and initializes) &lt;code&gt;__covrec_&lt;&#x2F;code&gt; global (constant) structs, most notably containing the same ID that the &lt;code&gt;__profd_&lt;&#x2F;code&gt; variables contain, and a LEB128&lt;label for=&quot;sn-3&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-3&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;The encoding of the coverage mapping values is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;LEB128&quot;&gt;LEB128&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; encoded string containing all the region, branches, and generally the coverage mapping info&lt;&#x2F;li&gt;
&lt;li&gt;defines (and initializes) a &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt;&lt;label for=&quot;sn-4&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-4&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;llvm.org&#x2F;docs&#x2F;CoverageMappingFormat.html&quot;&gt;Coverage Mapping&lt;&#x2F;a&gt; format.&lt;&#x2F;span&gt; function containing meta info about the coverage mapping format (eg., the version), and the source file names&lt;&#x2F;li&gt;
&lt;li&gt;marks the &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt; variable to be put into the &lt;code&gt;__llvm_covmap&lt;&#x2F;code&gt; section of the ELF.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In this case, we have the same category of issues mentioned before.&lt;&#x2F;p&gt;
&lt;p&gt;We need to keep at least the header of &lt;code&gt;__llvm_coverage_mapping&lt;&#x2F;code&gt; because it contains the coverage mappings version, which we need for generating a valid &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file&lt;label for=&quot;sn-5&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-5&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;More on the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; format &lt;a href=&quot;&#x2F;demystifying-profraw&quot;&gt;in a previous blog post&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;. Also, we need to put it in a &lt;mark&gt;custom BPF ELF section&lt;&#x2F;mark&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Luckily, we can remove the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; structs from the BPF ELF meant to be loaded in the kernel. We can keep them in a second BPF ELF that would be intended to be given to tools needing the coverage mappings for generating the coverage reports, just like &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; does.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-it-s-done&quot;&gt;How it&#x27;s done&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-it-s-done&quot; aria-label=&quot;Anchor link for: how-it-s-done&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;h3 id=&quot;libbpfcov-so-a-llvm-pass&quot;&gt;libBPFCov.so - A LLVM pass&lt;a class=&quot;zola-anchor&quot; href=&quot;#libbpfcov-so-a-llvm-pass&quot; aria-label=&quot;Anchor link for: libbpfcov-so-a-llvm-pass&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;p&gt;By analyzing the resulting LLVM IR for source-based coverage instrumented programs, we should now have a better understanding of what we need to do for having it on eBPF programs running in the Linux kernel. We now know what to completely get rid of and do differently, and what we need to patch to make it loadable and usable by the BPF VM in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;The plan is simple: get Clang to instrument a BPF LLVM intermediate representation for source-based code coverage, then patch it to model it into a valid representation for BPF ELF.&lt;&#x2F;p&gt;
&lt;p&gt;How do we need to transform it?&lt;&#x2F;p&gt;
&lt;p&gt;First of all, we are so lucky we don&#x27;t have to mess with the actual BPF instructions, namely the counters increments. We can keep them the way they are. This is a huge win because we let LLVM keep track of the global state of the registers and we avoid a lot of work this way.&lt;&#x2F;p&gt;
&lt;p&gt;But for sure we have to strip any profile initialization stuff that Clang creates, things like &lt;code&gt;__llvm_profile_runtime&lt;&#x2F;code&gt; and &lt;code&gt;__llvm_profile_init&lt;&#x2F;code&gt; - when present - are no good for the BPF VM in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;We also want to ensure the global variables, whether constants or not, have the right visibility (ie., &lt;code&gt;dso_local&lt;&#x2F;code&gt;) and linkage, to have them in the &lt;mark&gt;libbpf&lt;&#x2F;mark&gt; skeletons if we plan to use them.&lt;&#x2F;p&gt;
&lt;p&gt;For the global structs that we need for generating the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files, namely the &lt;code&gt;__profd_&lt;&#x2F;code&gt; variables, we just transform them into different and single global variables, one for each field.&lt;&#x2F;p&gt;
&lt;p&gt;For example, this is what I did for the &lt;code&gt;__profd_*&lt;&#x2F;code&gt; variables which originally are a struct with 7 fields. For other global structs like the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; ones, we can just strip them from the BPF ELF that is meant to be loaded in the kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, the report generation phase (ie., &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; or &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt;) will need them for knowing at which line and column a code region or a branch starts. For this reason, I decided to give the LLVM pass an option (enabled with the &lt;code&gt;strip-initializers-only&lt;&#x2F;code&gt; flag) that keeps them, so we can later create a BPF ELF that is only meant for this phase and not for loading.&lt;&#x2F;p&gt;
&lt;p&gt;This BPF ELF will have &lt;code&gt;.bpf.obj&lt;&#x2F;code&gt; as an extension, rather than &lt;code&gt;.bpf.o&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we know that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;libbpf&#x2F;libbpf&quot;&gt;libbpf&lt;&#x2F;a&gt; supports (on recent Linux kernels) &lt;mark&gt;eBPF global variables&lt;&#x2F;mark&gt;&lt;label for=&quot;sn-6&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-6&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Kernel patch: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;patchwork.ozlabs.org&#x2F;project&#x2F;netdev&#x2F;cover&#x2F;20190409212018.32423-1-daniel@iogearbox.net&#x2F;&quot;&gt;eBPF support for global data&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;, which are simply eBPF maps with one single value, and we are planning to use them. But, as already mentioned, it does not accept or recognize the ELF sections that the Clang instrumentation injects in the intermediate representation.&lt;&#x2F;p&gt;
&lt;p&gt;So we need our LLVM pass to change them to &lt;mark&gt;custom eBPF sections&lt;&#x2F;mark&gt;&lt;label for=&quot;sn-7&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-7&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Kernel patch: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;lore.kernel.org&#x2F;bpf&#x2F;20211021014404.2635234-8-andrii@kernel.org&#x2F;&quot;&gt;libbpf: support global data&#x2F;bss&#x2F;rodata sections&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;. The eBPF custom sections are in the form of &lt;code&gt;.rodata.*&lt;&#x2F;code&gt; or &lt;code&gt;.data.*&lt;&#x2F;code&gt; made to contain static and&#x2F;or global data. We can change the section of the counters to be &lt;code&gt;.data.profc&lt;&#x2F;code&gt;. The section of the &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; from &lt;code&gt;_llvm_prf_names&lt;&#x2F;code&gt; to &lt;code&gt;.rodata.profn&lt;&#x2F;code&gt;, and so on. You can find all this logic summarized in these &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;blob&#x2F;5607ee6b5419cd72dfd9c17e00455188865f8766&#x2F;lib&#x2F;BPFCov.cpp#L660-L694&quot;&gt;bits of code&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So, assuming the following dummy eBPF program:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;code-coverage-ebpf-programs-dummy-ebpf.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;code-coverage-ebpf-programs-dummy-ebpf.png&quot; alt=&quot;Raw tracepoint on sys_enter with eBPF&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I think that the following snippet tells everything about what we obtain from the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; LLVM pass:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;libbpfcov-llvm-ir.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;libbpfcov-llvm-ir.png&quot; alt=&quot;Resulting LLVM IR after running bpfcov libBPFCov.so LLVM pass&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;For example, you may notice that we have 2 &lt;code&gt;__profc_&lt;&#x2F;code&gt; counters.&lt;&#x2F;p&gt;
&lt;p&gt;The first is for the &lt;code&gt;BPF_PROG&lt;&#x2F;code&gt; macro that expands to a function, the second for the actual BPF raw tracepoint program &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt;. This one has size 3. That&#x27;s because the &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt; function has 3 main regions: the entry of the function, the &lt;code&gt;if&lt;&#x2F;code&gt; conditional, and the &lt;code&gt;for&lt;&#x2F;code&gt; cycle.&lt;&#x2F;p&gt;
&lt;p&gt;You may also notice that the LLVM pass, for each one of the 2 functions we have, split the &lt;code&gt;__profd_&lt;&#x2F;code&gt; global structs into 7 different global variables in the &lt;code&gt;.rodata.profd&lt;&#x2F;code&gt; section.&lt;&#x2F;p&gt;
&lt;p&gt;Someone who has an eye for it may also have noticed that the third field of &lt;code&gt;__profd_&lt;&#x2F;code&gt; (now &lt;code&gt;__profd_something.2&lt;&#x2F;code&gt;) does not contain anymore the address of its counters. I didn&#x27;t want (nor I could) to expose kernel addresses, so I put here the offset of the counters in their section (&lt;code&gt;.data.profc&lt;&#x2F;code&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;Finally, you can also see that, as anticipated before, we completely deleted the &lt;code&gt;__covrec_&lt;&#x2F;code&gt; global constant structs from this IR that&#x27;s meant to generate a valid and loadable BPF ELF. While the instructions incrementing the counters in the correct spots are not touched at all. So we don&#x27;t need another screenshot to show them!&lt;&#x2F;p&gt;
&lt;p&gt;The only missing moving part is how to generate a valid &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file. We stripped any logic for doing it. We know that for generating it we need all the globals we left in this LLVM intermediate representation. But we have no sane way to hook the exit or the stop of an eBPF program in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;Suddenly, inspiration came: let&#x27;s &lt;mark&gt;pin&lt;&#x2F;mark&gt; the globals to the &lt;mark&gt;BPF file system&lt;&#x2F;mark&gt; so that we can decouple the process of generating the &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file from the running (and exiting) of the instrumented eBPF application!&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s what the &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; does.&lt;&#x2F;p&gt;
&lt;p&gt;Before moving to the next section, I suggest you go to the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov repository&lt;&#x2F;a&gt; and start building the pass to obtain &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt;. You can find the instructions on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;blob&#x2F;main&#x2F;README.md#building&quot;&gt;how to build it here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;instrument-your-ebpf-program&quot;&gt;Instrument your eBPF program&lt;a class=&quot;zola-anchor&quot; href=&quot;#instrument-your-ebpf-program&quot; aria-label=&quot;Anchor link for: instrument-your-ebpf-program&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Now that we have built &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; we can finally take action!&lt;&#x2F;p&gt;
&lt;p&gt;Instrumenting an eBPF program for source-based coverage is not that different than compiling it normally with Clang and the BPF target.&lt;&#x2F;p&gt;
&lt;p&gt;The only difference is that we ask Clang to output LLVM IR (either in textual or binary form), run the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; pass on it (with &lt;code&gt;opt&lt;&#x2F;code&gt;), and finally compile it (with &lt;code&gt;llc&lt;&#x2F;code&gt;) to a BPF ELF.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clang&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -g -O2&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -target&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bpf&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -D__TARGET_ARCH_x86 -I$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;YOUR_INCLUDES&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -fprofile-instr-generate -fcoverage-mapping&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -emit-llvm -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;  -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;opt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -load-pass-plugin&lt;&#x2F;span&gt;&lt;span&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;BUILD_DIR&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;lib&#x2F;libBPFCov.so&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -passes=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;bpf-cov&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt; \&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt;    -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.ll&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; raw_enter.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llc&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -march=bpf -filetype=obj -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cov&#x2F;raw_enter.bpf.o raw_enter.bpf.cov.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can see in the Makefile inside the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&#x2F;tree&#x2F;main&#x2F;examples&#x2F;src&quot;&gt;examples&#x2F;src&lt;&#x2F;a&gt; directory of the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov GitHub repository&lt;&#x2F;a&gt; how to automate those steps.&lt;&#x2F;p&gt;
&lt;p&gt;We now have a valid and coverage instrumented BPF ELF: &lt;code&gt;cov&#x2F;raw_enter.bpf.o&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;From now on, you can instruct your loader and userspace code to use it, so to obtain a binary (eg., &lt;code&gt;&#x2F;cov&#x2F;raw_enter&lt;&#x2F;code&gt;) that is your eBPF application.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;use-it&quot;&gt;Use it&lt;a class=&quot;zola-anchor&quot; href=&quot;#use-it&quot; aria-label=&quot;Anchor link for: use-it&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;bpfcov-run-bpfcov-gen&quot;&gt;bpfcov run + bpfcov gen&lt;a class=&quot;zola-anchor&quot; href=&quot;#bpfcov-run-bpfcov-gen&quot; aria-label=&quot;Anchor link for: bpfcov-run-bpfcov-gen&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h4&gt;
&lt;p&gt;What&#x27;s left to do? Just three steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Run our eBPF application with the &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; run command&lt;&#x2F;li&gt;
&lt;li&gt;Generate its &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file&lt;&#x2F;li&gt;
&lt;li&gt;Generate beautiful source-based coverage reports&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;So, let&#x27;s run our eBPF application with:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -v2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; run cov&#x2F;raw_enter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This command acts similar to strace. It will detect the &lt;code&gt;bpf()&lt;&#x2F;code&gt; syscalls with the &lt;code&gt;BPF_MAP_CREATE&lt;&#x2F;code&gt; command.&lt;&#x2F;p&gt;
&lt;p&gt;Meaning that it will detect the eBPF globals in the &lt;code&gt;.profc&lt;&#x2F;code&gt;, &lt;code&gt;.profd&lt;&#x2F;code&gt;, &lt;code&gt;.profn&lt;&#x2F;code&gt;, and &lt;code&gt;.covmap&lt;&#x2F;code&gt; custom eBPF sections and pin them to the BPF file system, as you can see in the following screenshot.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;bpfcov-run.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;bpfcov-run.png&quot; alt=&quot;Output of bpfcov run&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;You may also notice that - since the LLVM pass annotated the counters correctly - &lt;mark&gt;libbpf&lt;&#x2F;mark&gt; can collect relocations for them...&lt;&#x2F;p&gt;
&lt;p&gt;At this point, whether we stopped our eBPF application or it exited... We have eBPF maps pinned to our BPF file system. Let&#x27;s check it:&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;pinned-maps.png&quot;&gt;
    &lt;img src=&quot;pinned-maps.png&quot;  alt=&quot;eBPF maps pinned by bpfcov&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Wonderful, we already know that the &lt;code&gt;hook_sys_enter&lt;&#x2F;code&gt; function executed 1 time, the &lt;code&gt;if&lt;&#x2F;code&gt; condition did not evaluate to true, while the &lt;code&gt;for&lt;&#x2F;code&gt; iterated 9 times!&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s time to put the counters, the function names, the functions data, in a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file now.&lt;&#x2F;p&gt;
&lt;p&gt;This is why the &lt;mark&gt;bpfcov gen&lt;&#x2F;mark&gt; command exists: to dump the pinned maps in a &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sudo&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -v2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gen –unpin cov&#x2F;raw_enter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;bpfcov-gen.png&quot;&gt;
    &lt;img src=&quot;bpfcov-gen.png&quot;  alt=&quot;Generating a profraw file from eBPF pinned maps with bpfcov&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;And this is the resulting &lt;mark&gt;profraw&lt;&#x2F;mark&gt; file for our instrumented eBPF program!&lt;&#x2F;p&gt;
&lt;p&gt;You can see it&#x27;s made of four parts: a header, &lt;code&gt;.rodata.profd&lt;&#x2F;code&gt;, &lt;code&gt;.data.profc&lt;&#x2F;code&gt; (ie., the counters!), and the names (&lt;code&gt;.rodata.profn&lt;&#x2F;code&gt;), plus some padding for alignment...&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;bpf-profraw.png&quot;&gt;
    &lt;img src=&quot;bpf-profraw.png&quot;  alt=&quot;A profraw file from an eBPF program running in the Linux kernel&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;We can now either use the existing LLVM tools (&lt;mark&gt;llvm-profdata&lt;&#x2F;mark&gt; and &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt;) with it or simply use the &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt; subcommand.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;mark&gt;bpfcov out&lt;&#x2F;mark&gt; command is an opinionated shortcut to generate HTML, JSON, or LCOV coverage reports even from multiple eBPF programs and their &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files.&lt;&#x2F;p&gt;
&lt;p&gt;It is very convenient because it avoids us having to generate &lt;mark&gt;profdata&lt;&#x2F;mark&gt; from the &lt;mark&gt;profraw&lt;&#x2F;mark&gt;, calling &lt;mark&gt;llvm-cov&lt;&#x2F;mark&gt; with a bunch of long and different options. And it even works with multiple &lt;mark&gt;profraw&lt;&#x2F;mark&gt; files coming from different eBPF applications...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;.&#x2F;bpfcov&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; out&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; yey –f html cov&#x2F;raw_enter.profraw ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It outputs a very nice HTML directory whose index file gives us summaries not only about function and line coverage but also and notably about region and branch coverages for our eBPF applications.&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;mult1.png&quot;&gt;
    &lt;img src=&quot;mult1.png&quot;  alt=&quot;HTML report of source-base code coverage of a few eBPF programs&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;By clicking on any item in the table we end up visualizing very fine-grained, source-based coverage. A good example is the one in the following image:&lt;&#x2F;p&gt;

&lt;figure class=&quot;center&quot;&gt;
    &lt;a href=&quot;html1.png&quot;&gt;
    &lt;img src=&quot;html1.png&quot;  alt=&quot;HTML report of a raw tracepoint eBPF program on sys_enter&quot;  loading=&quot;lazy&quot; &#x2F;&gt;
    &lt;&#x2F;a&gt;
    
&lt;&#x2F;figure&gt;
&lt;p&gt;Furthermore, it does work also on very complicated and real-life eBPF programs. For example, the following screenshot is a part of the coverage report obtained for a BPF LSM test (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;tools&#x2F;testing&#x2F;selftests&#x2F;bpf&#x2F;progs&#x2F;lsm.c&quot;&gt;progs&#x2F;lsm.c&lt;&#x2F;a&gt;, loaded by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;torvalds&#x2F;linux&#x2F;blob&#x2F;master&#x2F;tools&#x2F;testing&#x2F;selftests&#x2F;bpf&#x2F;prog_tests&#x2F;test_lsm.c&quot;&gt;prog_tests&#x2F;test_lsm.c&lt;&#x2F;a&gt;) living in the Linux kernel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;html2.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;code-coverage-ebpf&#x2F;html2.png&quot; alt=&quot;HTML report of a few BPF LSM programs from the Linux kernel&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to this tool I can finally understand that over a total of eight executions of the &lt;code&gt;lsm&#x2F;file_mprotect&lt;&#x2F;code&gt; BPF LSM program on my kernel, its &lt;code&gt;is_stack&lt;&#x2F;code&gt; variable was true two times out of eight, because six times the &lt;code&gt;vma-&amp;gt;vm_end &amp;gt;= vma-&amp;gt;vm_mm-&amp;gt;start_stack&lt;&#x2F;code&gt; branch condition (98:58) evaluated to false.&lt;&#x2F;p&gt;
&lt;p&gt;Line 100, using &lt;code&gt;is_stack&lt;&#x2F;code&gt; in another condition, confirms that it was indeed true two times out of six. And that, for this reason (first operand - 100:6 - &lt;code&gt;is_stack&lt;&#x2F;code&gt; being false six times), the following check (100:18) on &lt;code&gt;monitored_pid&lt;&#x2F;code&gt; was short-circuited and evaluated (to true, by the way) only two times.&lt;&#x2F;p&gt;
&lt;p&gt;We finally have a tool helping us write and understand the way our eBPF programs run in the Linux kernel. I can&#x27;t stress enough how this is something I dreamt of so many times during the past few years I&#x27;ve been working with BPF...&lt;&#x2F;p&gt;
&lt;p&gt;Hope that the eBPF community and ecosystem will find bpfcov useful and cool the same way I do.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;bits-of-the-future&quot;&gt;Bits of the future&lt;a class=&quot;zola-anchor&quot; href=&quot;#bits-of-the-future&quot; aria-label=&quot;Anchor link for: bits-of-the-future&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; tool is open-source, and it will stay that way. It is still in its early days so it will probably need a bit more tests, examples, and fixes. Just like any new software out there.&lt;&#x2F;p&gt;
&lt;p&gt;I will soon publish another project showcasing the coverage of the kernel BPF selftests, using this tool. This means there are a lot of contribution opportunities. I&#x27;d invite you to take a look at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;its source code&lt;&#x2F;a&gt; and send patches! :blush:&lt;&#x2F;p&gt;
&lt;p&gt;Also, in case you want to start using it on your eBPF applications and repositories, feel free to contact me for support. I&#x27;d love to help you to use it.&lt;&#x2F;p&gt;
&lt;p&gt;From a technical perspective these are the topics that are on top of my mind for its future:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A project like &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; &lt;strong&gt;must&lt;&#x2F;strong&gt; have a logo!&lt;&#x2F;li&gt;
&lt;li&gt;Write &lt;mark&gt;llvm-lit&lt;&#x2F;mark&gt; tests for the &lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt; LLVM pass&lt;&#x2F;li&gt;
&lt;li&gt;Support newer LLVM versions&lt;&#x2F;li&gt;
&lt;li&gt;Workaround solutions to have it working on Linux kernels where BPF does not support custom eBPF sections and eBPF globals&lt;&#x2F;li&gt;
&lt;li&gt;Create a versioning and release process&lt;&#x2F;li&gt;
&lt;li&gt;Publish artifacts on GitHub (&lt;mark&gt;libBPFCov.so&lt;&#x2F;mark&gt;, &lt;mark&gt;bpfcov&lt;&#x2F;mark&gt; &lt;strong&gt;CLI&lt;&#x2F;strong&gt; binary)&lt;&#x2F;li&gt;
&lt;li&gt;Add more examples&lt;&#x2F;li&gt;
&lt;li&gt;Publish HTML reports of the example eBPF applications via GitHub pages&lt;&#x2F;li&gt;
&lt;li&gt;Maybe, contribute it &lt;strong&gt;upstream&lt;&#x2F;strong&gt; to the LLVM BPF target!&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;fosdem-2022&quot;&gt;FOSDEM 2022&lt;a class=&quot;zola-anchor&quot; href=&quot;#fosdem-2022&quot; aria-label=&quot;Anchor link for: fosdem-2022&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;In case you made it to the end, and you still want to hear more details on building source-based coverage for eBPF, I want to bring to your attention that I gave a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fosdem.org&#x2F;2022&#x2F;schedule&#x2F;event&#x2F;llvm_ebpf&#x2F;&quot;&gt;talk&lt;&#x2F;a&gt; on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;fosdem.org&#x2F;2022&#x2F;schedule&#x2F;event&#x2F;llvm_ebpf&#x2F;&quot;&gt;FOSDEM 2022&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I will update my &lt;a href=&quot;&#x2F;talks&quot;&gt;speaking&lt;&#x2F;a&gt; section with the video recording as soon it&#x27;ll be ready.&lt;&#x2F;p&gt;
&lt;p&gt;In the meantime, you can take a look at the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;leodido&#x2F;coverage-for-ebpf-programs&quot;&gt;talk&#x27;s deck&lt;&#x2F;a&gt;&lt;label for=&quot;sn-8&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-8&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;While you can find the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;leodido&#x2F;presentations&#x2F;tree&#x2F;master&#x2F;2022&#x2F;02&#x2F;05&#x2F;fosdem-llvm-room&#x2F;coverage-for-ebpf-programs&quot;&gt;slides in PDF and markdown format here, if you prefer&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;While at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;elastic&#x2F;bpfcov&lt;&#x2F;a&gt; you can take a look at the project. Don&#x27;t forget to star it, if you don&#x27;t mind! :star:&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Demystifying the profraw format</title>
        <published>2022-01-28T00:00:00+00:00</published>
        <updated>2022-01-28T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://leodido.dev/demystifying-profraw/"/>
        <id>https://leodido.dev/demystifying-profraw/</id>
        
        <content type="html" xml:base="https://leodido.dev/demystifying-profraw/">&lt;p&gt;Three months ago, I was looking into building coverage for eBPF programs.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s how &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;elastic&#x2F;bpfcov&quot;&gt;bpfcov&lt;&#x2F;a&gt; was born.&lt;&#x2F;p&gt;
&lt;p&gt;I did not want to reinvent the wheel, so I was looking into the existing coverage instrumentation features of LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;Among the different options LLVM provides, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;clang.llvm.org&#x2F;docs&#x2F;SourceBasedCodeCoverage.html&quot;&gt;source-based code coverage&lt;&#x2F;a&gt; suddenly appeared very appealing to me.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s the most precise type of code coverage. In my opinion, the only one that gives its user a damn clue on what code region of the program is executing. It also helps understand why a particular code branch gets executed.&lt;&#x2F;p&gt;
&lt;p&gt;Using it is pretty straightforward. All resolve to the following steps:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;compile your C&#x2F;C++ code with the &lt;code&gt;-fprofile-instr-generate -fcoverage-mapping&lt;&#x2F;code&gt; Clang options&lt;&#x2F;li&gt;
&lt;li&gt;run the program&lt;&#x2F;li&gt;
&lt;li&gt;the execution of the program automatically creates a &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file&lt;label for=&quot;sn-1&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-1&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;You can set it to something else via the &lt;code&gt;LLVM_PROFILE_FILE&lt;&#x2F;code&gt; environment variable.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;feed the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file to LLVM tools like &lt;code&gt;llvm-profdata&lt;&#x2F;code&gt; and &lt;code&gt;llvm-cov&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;You now have a beautifully fine-grained coverage report for your C&#x2F;C++ code.&lt;&#x2F;p&gt;
&lt;p&gt;But what caught my eye was feeling that this kind of coverage was not using debug info (like &lt;code&gt;gcov&lt;&#x2F;code&gt; does) at all, but it was using profiling data, coming directly from the darkest parts of LLVM.&lt;&#x2F;p&gt;
&lt;p&gt;My curiosity took me to some extraordinary places in the LLVM codebase...&lt;&#x2F;p&gt;
&lt;p&gt;I wanted to understand what the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; was causing.&lt;&#x2F;p&gt;
&lt;p&gt;Also, I wanted to know how I got a binary file (&lt;code&gt;default.profraw&lt;&#x2F;code&gt;) without my code writing anything to the disk.&lt;&#x2F;p&gt;
&lt;p&gt;And what it contained.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;em&gt;Spoiler&lt;&#x2F;em&gt;. It contains the globals that the &lt;code&gt;-fprofile-instr-generate&lt;&#x2F;code&gt; instruments into your code.&lt;&#x2F;p&gt;
&lt;p&gt;But we probably need to move one step at a time to learn something new.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;fprofile-instr-generate&quot;&gt;-fprofile-instr-generate&lt;a class=&quot;zola-anchor&quot; href=&quot;#fprofile-instr-generate&quot; aria-label=&quot;Anchor link for: fprofile-instr-generate&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;So, this is the dummy C code - &lt;code&gt;hello.c&lt;&#x2F;code&gt; - that I used to walk myself through this study.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;c&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;stdio.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;#include&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;lt;stdint.h&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; ciao&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;ciao&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; main&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; argc&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; char&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; **&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;argv&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;    if&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; (argc &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        foo&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-control&quot;&gt;        for&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;int&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; i =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;; i &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 22&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;; i++) {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;            ciao&lt;&#x2F;span&gt;&lt;span&gt;();&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;main&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-character z-escape&quot;&gt;\n&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;);&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I compiled it to textual LLVM IR:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clang&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -g -fprofile-instr-generate -emit-llvm -S&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; $&amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello.ll&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In a matter of milliseconds, I was able to look at its intermediate representation:&lt;&#x2F;p&gt;
&lt;div class=&quot;collapsable-code&quot;&gt;
    &lt;input id=&quot;code-1&quot; type=&quot;checkbox&quot;&gt;
    &lt;label for=&quot;code-1&quot;&gt;&lt;span class=&quot;collapsable-code__label&quot;&gt;LLVM IR &amp;#x2F; PROFILING DATA&lt;&#x2F;span&gt;&lt;span class=&quot;collapsable-code__title&quot;&gt;hello.ll&lt;&#x2F;span&gt;&lt;span class=&quot;collapsable-code__toggle&quot; data-label-expand=&quot;▽&quot; data-label-collapse=&quot;△&quot;&gt;&lt;&#x2F;span&gt;
    &lt;&#x2F;label&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;llvm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_ciao&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_cnts&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profd_ciao&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] } { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; -1479480177954886802&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_ciao&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i8* bitcast&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt; ()* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@ciao&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt; to i8*&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-constant z-language&quot;&gt;i8* null&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt; }, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_foo&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_cnts&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profd_foo&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] } { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 6699318081062747564&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_foo&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i8* bitcast&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;void&lt;&#x2F;span&gt;&lt;span&gt; ()* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt; to i8*&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-constant z-language&quot;&gt;i8* null&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt; }, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_cnts&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profd_main&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private global&lt;&#x2F;span&gt;&lt;span&gt; { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] } { &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; -2624081020897602054&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 717562688593&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i8* bitcast&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8**&lt;&#x2F;span&gt;&lt;span&gt;)* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@main&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt; to i8*&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-constant z-language&quot;&gt;i8* null&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span&gt;, [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i16&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;zeroinitializer&lt;&#x2F;span&gt;&lt;span&gt; }, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_data&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__llvm_prf_nm&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;private constant&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8&lt;&#x2F;span&gt;&lt;span&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;c&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&amp;quot;\0D\15x\DAK\CEL\CCgL\CB\CFg\CCM\CC\CC\03\00\1Fy\04\88&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;section&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;quot;__llvm_prf_names&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;It stands out from what we see that it contains:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;3 &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global arrays
&lt;ul&gt;
&lt;li&gt;one for every function existing in the source code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;3 &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global structs
&lt;ul&gt;
&lt;li&gt;one for every function existing in the source code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1 constant - &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; - encoding the &lt;strong&gt;function names&lt;&#x2F;strong&gt;&lt;label for=&quot;sn-2&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-2&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Recompiling with the &lt;code&gt;-mllvm -enable-name-compression=false&lt;&#x2F;code&gt; flags makes this variable easier to read.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Also, all these variables have ELF sections.&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables end up into the &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; section.
The &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables end up into the &lt;code&gt;__llvm_prf_data&lt;&#x2F;code&gt; section.
The &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; variable ends up into the &lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt; section.&lt;&#x2F;p&gt;
&lt;p&gt;But what &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables are?&lt;&#x2F;p&gt;
&lt;p&gt;The section names helped me here: they are the &lt;mark&gt;counters&lt;&#x2F;mark&gt; used by LLVM for instrumenting our code for &lt;mark&gt;profiling&lt;&#x2F;mark&gt;!&lt;&#x2F;p&gt;
&lt;p&gt;Scrolling down into the LLVM IR, we see they&#x27;re getting incremented (&lt;code&gt;load&lt;&#x2F;code&gt;, &lt;code&gt;add&lt;&#x2F;code&gt;, &lt;code&gt;store&lt;&#x2F;code&gt; instructions sequence) at the correct spots:&lt;&#x2F;p&gt;
&lt;div class=&quot;collapsable-code&quot;&gt;
    &lt;input id=&quot;code-2&quot; type=&quot;checkbox&quot;&gt;
    &lt;label for=&quot;code-2&quot;&gt;&lt;span class=&quot;collapsable-code__label&quot;&gt;LLVM IR &amp;#x2F; Main function&lt;&#x2F;span&gt;&lt;span class=&quot;collapsable-code__title&quot;&gt;hello.ll&lt;&#x2F;span&gt;&lt;span class=&quot;collapsable-code__toggle&quot; data-label-expand=&quot;▽&quot; data-label-collapse=&quot;△&quot;&gt;&lt;&#x2F;span&gt;
    &lt;&#x2F;label&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;llvm&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-modifier z-storage z-type&quot;&gt;define dso_local i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; @main&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8**&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %1&lt;&#x2F;span&gt;&lt;span&gt;) #&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; !dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;19&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %7&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %8&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;add i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %7&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  store i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;30&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br i1&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %10&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %11&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %24&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;34&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;11&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %12&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;34&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %13&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;add i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %12&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;34&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  store i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %13&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;34&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  call void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; @foo&lt;&#x2F;span&gt;&lt;span&gt;(), &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;35&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %14&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;14&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %20, %11&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %15&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %6&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;41&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %16&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;icmp slt i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %15&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;22&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;43&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br i1&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %16&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %17&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %23&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;44&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;17&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %18&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i64&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;44&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %19&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;add i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %18&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;44&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  store i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %19&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i64* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@__profc_main&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span&gt;), &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 8&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;44&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  call void&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; @ciao&lt;&#x2F;span&gt;&lt;span&gt;(), &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;45&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %20&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;47&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;20&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %17&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %21&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %6&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;48&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %22&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;add nsw i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %21&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;48&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  store i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %22&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %6&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;48&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %14&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;49&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!llvm.loop&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;50&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;23&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %14&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  br label&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %24&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;53&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;24&lt;&#x2F;span&gt;&lt;span&gt;:                                               &lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt;; preds = %23, %2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %25&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;call i32&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8*&lt;&#x2F;span&gt;&lt;span&gt;, ...) &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@printf&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type z-keyword&quot;&gt;i8* getelementptr inbounds&lt;&#x2F;span&gt;&lt;span&gt; ([&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8&lt;&#x2F;span&gt;&lt;span&gt;], [&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;6&lt;&#x2F;span&gt;&lt;span&gt; x &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i8&lt;&#x2F;span&gt;&lt;span&gt;]* &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@.str.2&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i64&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span&gt;)), &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;54&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable&quot;&gt;  %26&lt;&#x2F;span&gt;&lt;span&gt; = &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;load i32&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;i32*&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %3&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-modifier&quot;&gt;align&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;55&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-storage z-type&quot;&gt;  ret i32&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt; %26&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable&quot;&gt;!dbg&lt;&#x2F;span&gt;&lt;span&gt; !&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;55&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;&#x2F;div&gt;
&lt;p&gt;We now know why the &lt;code&gt;__profc_main&lt;&#x2F;code&gt; array has size 3 (see &lt;code&gt;[3 x i64]&lt;&#x2F;code&gt;): LLVM instrumented one counter for the &lt;code&gt;main()&lt;&#x2F;code&gt; function&#x27;s entry, one for the &lt;code&gt;if&lt;&#x2F;code&gt; block, while the last one regards the &lt;code&gt;for&lt;&#x2F;code&gt; block.&lt;&#x2F;p&gt;
&lt;p&gt;We also know that we have a total of 5 counters, given the &lt;code&gt;__profc_ciao&lt;&#x2F;code&gt; and &lt;code&gt;__profc_foo&lt;&#x2F;code&gt; have both size 1.&lt;&#x2F;p&gt;
&lt;p&gt;Verifying this is just a matter of obtaining our program binary...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clang&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -g -fprofile-instr-generate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello.c&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And playing with &lt;code&gt;llvm-objdump&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-objdump&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --section-headers&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; __llvm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 17 __llvm_prf_names   00000017 0000000000008b89 DATA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 26 __llvm_prf_cnts    00000028 000000000000c110 DATA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 27 __llvm_prf_data    00000090 000000000000c138 DATA&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-objdump&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --syms&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; __llvm_prf_cnts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 000000000000c110 g       __llvm_prf_cnts        0000000000000000 .hidden __start___llvm_prf_cnts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 000000000000c138 g       __llvm_prf_cnts        0000000000000000 .hidden __stop___llvm_prf_cnts&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The output here helps us confirm that we have 5 total counters of 8 bytes each, starting at address &lt;code&gt;c110&lt;&#x2F;code&gt; and ending at &lt;code&gt;c138&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, $c138 - c110 = 28$, which means 40 bytes in decimal base (ie., $8 * 5$).&lt;&#x2F;p&gt;
&lt;p&gt;What about the &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables instead?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-objdump&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --syms&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; __llvm_prf_data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 000000000000c1c8 g       __llvm_prf_data        0000000000000000 .hidden __stop___llvm_prf_data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 000000000000c138 g       __llvm_prf_data        0000000000000000 .hidden __start___llvm_prf_data&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At the moment, all you need to know is that those are structs containing data about the function they refer to and the instrumented counters for it.&lt;&#x2F;p&gt;
&lt;p&gt;I hope the following image clarifies the relationship. Anyways, we&#x27;ll dig deeper into the &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#data&quot;&gt;later&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profile-instr-generate.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profile-instr-generate.png&quot; alt=&quot;LLVM IR with profiling data&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;generating-the-profraw&quot;&gt;Generating the profraw&lt;a class=&quot;zola-anchor&quot; href=&quot;#generating-the-profraw&quot; aria-label=&quot;Anchor link for: generating-the-profraw&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;At this point, I still didn&#x27;t know &lt;strong&gt;how&lt;&#x2F;strong&gt; the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file got created every time I executed my binary.&lt;&#x2F;p&gt;
&lt;p&gt;I came back to the LLVM source code. It&#x27;s incredible the superpowers that reading the source gives you...&lt;&#x2F;p&gt;
&lt;p&gt;I found &lt;code&gt;InstrProfilingFile.c&lt;&#x2F;code&gt;&lt;label for=&quot;sn-3&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-3&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;main&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingFile.c&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Long story short: the code in this LLVM source file implements the &lt;mark&gt;profiling runtime initialization&lt;&#x2F;mark&gt;, which means it is responsible for gathering all the data from the variables (counters, data, etc.) we&#x27;ve seen and flushing them out in the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;p&gt;While looking at it, I suddenly noticed the &lt;code&gt;__llvm_profile_initialize&lt;&#x2F;code&gt;&lt;label for=&quot;sn-4&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-4&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;b7fd91c84b4eea5324d9757243387280f4284236&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingFile.c#L995&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;It gets invoked by the profiling runtime initialization hook to get the filename of the profraw to create. Either from an environment variable (&lt;code&gt;LLVM_PROFILE_FILE&lt;&#x2F;code&gt;) or using the default one (&lt;code&gt;default.profraw&lt;&#x2F;code&gt;). Finally, it calls the C library function &lt;code&gt;atexit(__llvm_profile_write_file)&lt;&#x2F;code&gt;. Which will cause the &lt;code&gt;__llvm_profile_write_file&lt;&#x2F;code&gt; function to be invoked when the program terminates.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, I also noticed the &lt;code&gt;__llvm_profile_write_file&lt;&#x2F;code&gt;&lt;label for=&quot;sn-5&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-5&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;b7fd91c84b4eea5324d9757243387280f4284236&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingFile.c#L1017&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt; function.&lt;&#x2F;p&gt;
&lt;p&gt;The main thing this function does is to invoke &lt;code&gt;writeFile(Filename)&lt;&#x2F;code&gt;&lt;label for=&quot;sn-6&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-6&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;b7fd91c84b4eea5324d9757243387280f4284236&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingFile.c#L1051&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;. Which, in turn, calls &lt;code&gt;lprofWriteData&lt;&#x2F;code&gt; &lt;label for=&quot;sn-7&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-7&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;b7fd91c84b4eea5324d9757243387280f4284236&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingFile.c#L480&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;It&#x27;s again time to verify with &lt;code&gt;llvm-objdump&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-objdump&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --syms&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; hello&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; __llvm_profile&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 0000000000004180 l     F .text  00000000000001a1 __llvm_profile_write_file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 0000000000004610 g     F .text  0000000000000037 .hidden __llvm_profile_register_write_file_atexit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 00000000000121e4 g     O .bss   0000000000000004 .hidden __llvm_profile_runtime&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 000000000000c108  w    O .data  0000000000000008 __llvm_profile_raw_version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 00000000000122e8  w    O .bss   0000000000000001 __llvm_profile_filename&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# 00000000000040a0 g     F .text  00000000000000ae .hidden __llvm_profile_initialize&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Our ELF got flooded by &lt;code&gt;__llvm_profile_*&lt;&#x2F;code&gt; functions.&lt;&#x2F;p&gt;
&lt;p&gt;Seeing all those symbols in the ELF made me 100% sure this is how LLVM makes our binary open the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file as soon it executes. In this way, it also makes our program automatically dump the profile data when it terminates.&lt;&#x2F;p&gt;
&lt;p&gt;Coming back to the &lt;code&gt;lprofWriteData&lt;&#x2F;code&gt; function implementation (in the &lt;code&gt;InstrProfilingWriter.c&lt;&#x2F;code&gt; source file), we instead discover &lt;strong&gt;what&lt;&#x2F;strong&gt; it dumps into &lt;code&gt;default.profraw&lt;&#x2F;code&gt;. It&#x27;s while doing so that we understand what a profraw file contains.&lt;&#x2F;p&gt;
&lt;p&gt;Such a function&lt;label for=&quot;sn-8&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-8&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;e356027016c6365b3d8924f54c33e2c63d931492&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingWriter.c#L257&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;calculates the size of the data, counters, and names&lt;&#x2F;li&gt;
&lt;li&gt;calculates the paddings needed before and after the counters section (&lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt;) and after the names section (&lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;initializes the header structure (more on it &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#header&quot;&gt;below&lt;&#x2F;a&gt;)&lt;&#x2F;li&gt;
&lt;li&gt;writes the header&lt;&#x2F;li&gt;
&lt;li&gt;writes the binary IDs
&lt;ol&gt;
&lt;li&gt;if &lt;code&gt;NT_GNU_BUILD_ID&lt;&#x2F;code&gt; is defined, otherwise skips them&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;writes the data
&lt;ol&gt;
&lt;li&gt;the &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; globals&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;writes the padding bytes before the counters for page alignment&lt;&#x2F;li&gt;
&lt;li&gt;writes the counters
&lt;ol&gt;
&lt;li&gt;the content of the &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; globals at program termination&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;writes the padding bytes after the counters for page alignment&lt;&#x2F;li&gt;
&lt;li&gt;writes the names
&lt;ol&gt;
&lt;li&gt;the &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; variable&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;writes the padding bytes after the names part
&lt;ol&gt;
&lt;li&gt;the profraw format want its size to be a multiple of 8&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;writes the value profiling data
&lt;ol&gt;
&lt;li&gt;only in case it was enabled&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;All these moving parts are written using the &lt;code&gt;ProfDataIOVec&lt;&#x2F;code&gt; data structure&lt;label for=&quot;sn-9&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-9&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;e356027016c6365b3d8924f54c33e2c63d931492&#x2F;compiler-rt&#x2F;lib&#x2F;profile&#x2F;InstrProfilingInternal.h#L41-L56&quot;&gt;Source&lt;&#x2F;a&gt;.&lt;&#x2F;span&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;So, we can finally assert what a profraw binary file is composed by:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#header&quot;&gt;header&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;the &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#data&quot;&gt;data&lt;&#x2F;a&gt; variables&lt;&#x2F;li&gt;
&lt;li&gt;the &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#counters&quot;&gt;counters&lt;&#x2F;a&gt; variables&lt;&#x2F;li&gt;
&lt;li&gt;the &lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;#names&quot;&gt;names&lt;&#x2F;a&gt; variable&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;header&quot;&gt;Header&lt;a class=&quot;zola-anchor&quot; href=&quot;#header&quot; aria-label=&quot;Anchor link for: header&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;The &lt;code&gt;INSTR_PROF_RAW_HEADER&lt;&#x2F;code&gt; macro at &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;llvm&#x2F;llvm-project&#x2F;blob&#x2F;b72b56016a6b586a22a49f145c924c03e4239b1d&#x2F;llvm&#x2F;include&#x2F;llvm&#x2F;ProfileData&#x2F;InstrProfData.inc#L121-L141&quot;&gt;InstrProfData.inc&lt;&#x2F;a&gt; defines the parts composing the header of the profraw file. Which are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;the magic&lt;&#x2F;li&gt;
&lt;li&gt;the version&lt;&#x2F;li&gt;
&lt;li&gt;the size of binary IDs&lt;&#x2F;li&gt;
&lt;li&gt;the size of the data section:
&lt;ol&gt;
&lt;li&gt;it is equal to the number of &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global variables&lt;&#x2F;li&gt;
&lt;li&gt;the data part starts where &lt;code&gt;__start___llvm_prf_data&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;li&gt;the data part ends where &lt;code&gt;__stop___llvm_prf_data&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;li&gt;assuming 3 &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global struct exists&lt;label for=&quot;sn-10&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-10&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;&lt;code&gt;{i64, i64, i64*, i8*, i8*, i32, [2 x i16]}&lt;&#x2F;code&gt; (48 bytes)&lt;&#x2F;span&gt;, the data section size is the difference between the &lt;code&gt;__stop_&lt;&#x2F;code&gt; (&lt;code&gt;c1c8&lt;&#x2F;code&gt;) and &lt;code&gt;__start_&lt;&#x2F;code&gt; addresses (&lt;code&gt;c138&lt;&#x2F;code&gt;), thus 90 in hexadecimal&lt;label for=&quot;sn-11&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-11&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;0x90 is 144 decimal, so $144 &#x2F; 48 = 3$.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;the padding bytes before the counters section&lt;label for=&quot;sn-12&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-12&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;It can also be 0 bytes.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;the size of the counters section
&lt;ol&gt;
&lt;li&gt;it is equal to the number of &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global variables&lt;&#x2F;li&gt;
&lt;li&gt;the counters part starts where the (&lt;code&gt;__start_&lt;&#x2F;code&gt;) &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;li&gt;the counters part ends where the (&lt;code&gt;__stop_&lt;&#x2F;code&gt;) &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;li&gt;assuming 3 &lt;code&gt;__profc_*&lt;&#x2F;code&gt; global variables exists&lt;label for=&quot;sn-13&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-13&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;For a total of 5 counters, 8 bytes each: &lt;code&gt;[1 x i64]&lt;&#x2F;code&gt;, &lt;code&gt;[1 x i64]&lt;&#x2F;code&gt;, &lt;code&gt;[3 x i64]&lt;&#x2F;code&gt;&lt;&#x2F;span&gt;, the counters section size is the difference between the &lt;code&gt;__stop_&lt;&#x2F;code&gt; (&lt;code&gt;c138&lt;&#x2F;code&gt;) and the &lt;code&gt;__start_&lt;&#x2F;code&gt; addresses (&lt;code&gt;c110&lt;&#x2F;code&gt;), thus 28 in hexadecimal&lt;label for=&quot;sn-14&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-14&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;0x28 is 40 decimal, so $40 &#x2F; 8 = 5$ which is the total number of counters.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;the padding bytes after the counters section&lt;label for=&quot;sn-15&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-15&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;It can also be 0 bytes.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;the size of the names section
&lt;ol&gt;
&lt;li&gt;it is equal to the size of &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; global variable&lt;&#x2F;li&gt;
&lt;li&gt;the names part starts where the (&lt;code&gt;__start_&lt;&#x2F;code&gt;) &lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;li&gt;the names part ends where the (&lt;code&gt;__stop_&lt;&#x2F;code&gt;) &lt;code&gt;__llvm_prf_names&lt;&#x2F;code&gt; is&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;the counters delta&lt;&#x2F;li&gt;
&lt;li&gt;it is the difference between the address at which the counter section begins and the address at which the data section begins&lt;&#x2F;li&gt;
&lt;li&gt;it is equal to the address of the first &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; counter&lt;&#x2F;li&gt;
&lt;li&gt;the names delta
&lt;ol&gt;
&lt;li&gt;the address at which the names section begins&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IPVK_Last&lt;&#x2F;code&gt;&lt;label for=&quot;sn-16&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-16&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;It seems to be always 1.&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;With the following table I tried to summarize the header&#x27;s content:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th style=&quot;text-align: left&quot;&gt;00 01 02 03 04 05 06 07&lt;&#x2F;th&gt;&lt;th style=&quot;text-align: left&quot;&gt;08 09 0A 0B 0C 0D 0E 0F&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;magic&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;version&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;data size&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;padding before counters&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;counters size&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;padding after counters&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;names size&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;counters delta&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td style=&quot;text-align: left&quot;&gt;names begin&lt;&#x2F;td&gt;&lt;td style=&quot;text-align: left&quot;&gt;value kind last&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;But probably an image is worth a thousand words.&lt;&#x2F;p&gt;
&lt;p&gt;This is the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file after executing &lt;code&gt;.&#x2F;hello yay&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-header.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-header.png&quot; alt=&quot;Header&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;We can see that its header is composed of:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the magic (in black)&lt;&#x2F;li&gt;
&lt;li&gt;the version (in blue)&lt;&#x2F;li&gt;
&lt;li&gt;the number of functions (in red)
&lt;ul&gt;
&lt;li&gt;it equals to the number of &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables too: &lt;strong&gt;3&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;the padding bytes before the counters (in light green)&lt;&#x2F;li&gt;
&lt;li&gt;the total number of the counters (in fluo green)
&lt;ul&gt;
&lt;li&gt;meaning, the total size of &lt;code&gt;__profc_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; variables: &lt;strong&gt;5&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;the padding bytes after the counters (in dark green)&lt;&#x2F;li&gt;
&lt;li&gt;the length of the &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; variable (in magenta): 0F in hex, 15 decimal&lt;&#x2F;li&gt;
&lt;li&gt;the address of the first counter (in brown)&lt;&#x2F;li&gt;
&lt;li&gt;the address of &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; (in pink)&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;IPVK_Last&lt;&#x2F;code&gt; (1) in yellow&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Exactly the way we were now expecting it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;data&quot;&gt;Data&lt;a class=&quot;zola-anchor&quot; href=&quot;#data&quot; aria-label=&quot;Anchor link for: data&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Focusing on the data part, I&#x27;ve highlighted with (orange) rectangles the 3 &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; global variables.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-data.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-data.png&quot; alt=&quot;Data&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Each of the  &lt;code&gt;__profd_&amp;lt;function_name&amp;gt;&lt;&#x2F;code&gt; contains 6 parts:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1 is the ID (hex, reverse order) of the function to which it refers&lt;&#x2F;li&gt;
&lt;li&gt;2 is the function control flow hash&lt;&#x2F;li&gt;
&lt;li&gt;3 points to the counter it relates to&lt;&#x2F;li&gt;
&lt;li&gt;4 points to the function it refers to&lt;&#x2F;li&gt;
&lt;li&gt;5 points to the value expressions, if any&lt;&#x2F;li&gt;
&lt;li&gt;6 contains the number of the counters (2 bytes) and the initialization array (number of value sites, 2 elements, 2 bytes each, often zero)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;counters&quot;&gt;Counters&lt;a class=&quot;zola-anchor&quot; href=&quot;#counters&quot; aria-label=&quot;Anchor link for: counters&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;After the data part comes the counters part.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-counters.png&quot; alt=&quot;Counters&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It just is a serialization of what the variables in the &lt;code&gt;__llvm_prf_cnts&lt;&#x2F;code&gt; ELF section contains.&lt;&#x2F;p&gt;
&lt;p&gt;In fact, in this screenshot you can see underlined (with waves, in shades of cyan&#x2F;blue):&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__profc_ciao&lt;&#x2F;code&gt;: [1 x i64]
&lt;ul&gt;
&lt;li&gt;1 counter, with value &lt;strong&gt;16&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;it means the &lt;code&gt;ciao()&lt;&#x2F;code&gt; function was executed 22 (decimal) times&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;__profc_foo&lt;&#x2F;code&gt;: [1 x i64]
&lt;ul&gt;
&lt;li&gt;1 counter, with value &lt;strong&gt;1&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;it means the &lt;code&gt;foo()&lt;&#x2F;code&gt; function only was executed 1 time&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;__profc_main&lt;&#x2F;code&gt;: [3 x i64]
&lt;ul&gt;
&lt;li&gt;3 counters, first two with value &lt;strong&gt;1&lt;&#x2F;strong&gt;, last one with value &lt;strong&gt;16&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;it means the function &lt;code&gt;main()&lt;&#x2F;code&gt; was executed 1 time, its &lt;code&gt;if&lt;&#x2F;code&gt; conditional evaluated to true, and the &lt;code&gt;for&lt;&#x2F;code&gt; inside it got executed &lt;strong&gt;22&lt;&#x2F;strong&gt; (decimal) times&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;names&quot;&gt;Names&lt;a class=&quot;zola-anchor&quot; href=&quot;#names&quot; aria-label=&quot;Anchor link for: names&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;Finally, the &lt;code&gt;__llvm_prf_nm&lt;&#x2F;code&gt; variable populates the last part of the profraw file.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-names.png&quot;&gt;&lt;img src=&quot;https:&#x2F;&#x2F;leodido.dev&#x2F;demystifying-profraw&#x2F;profraw-names.png&quot; alt=&quot;Names&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here (in grey) you can see its content&lt;label for=&quot;sn-17&quot; class=&quot;sidenote-toggle sidenote-number&quot;&gt;&lt;&#x2F;label&gt;&lt;input type=&quot;checkbox&quot; id=&quot;sn-17&quot; class=&quot;sidenote-toggle&quot;&#x2F;&gt;&lt;span class=&quot;sidenote&quot;&gt;Function names are uncompressed because I compiled the binary with &lt;code&gt;-mllvm -enable-name-compression=false&lt;&#x2F;code&gt; flags.&lt;&#x2F;span&gt;, padded with a &lt;code&gt;\0&lt;&#x2F;code&gt; byte (the one circled) at the end to align the profraw file size to be multiple of 8.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;a class=&quot;zola-anchor&quot; href=&quot;#usage&quot; aria-label=&quot;Anchor link for: usage&quot;&gt;§&lt;&#x2F;a&gt;
&lt;&#x2F;h2&gt;
&lt;p&gt;It&#x27;s time to use the &lt;code&gt;default.profraw&lt;&#x2F;code&gt; file now:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;llvm-profdata&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; show&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-other z-option&quot;&gt; --all-functions --counts&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; default.profraw&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Counters:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#   ciao:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Hash: 0x0000000000000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Counters: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Function count: 22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Block counts: []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#   foo:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Hash: 0x0000000000000000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Counters: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Function count: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Block counts: []&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#   main:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Hash: 0x000000a71211b451&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Counters: 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Function count: 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;#     Block counts: [1, 22]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Instrumentation level: Front-end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Functions shown: 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Total functions: 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Maximum function count: 22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-comment&quot;&gt;# Maximum internal block count: 22&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Isn&#x27;t it cool?&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s more you can do with profraw files and the LLVM toolchain, indeed. But showing that was not the goal of this post.&lt;&#x2F;p&gt;
&lt;p&gt;I hope you now have a better understanding of what profraw files are.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
