On Fri, 4 Jul 2025 14:51:06 -0700 Guy Harris <ghar...@sonic.net> wrote:
> In the longer term, the compilation process should probably be split > into: > > a phase that compiles a filter into a target-independent > *and* link-layer-independent *and* snapshot-length-independent > intermediate representation, optionally doing whatever optimization > can be done with that; > > a phase that compiles that intermediate representation into > optionally-optimized code for a particular link layer, snapshot > length, and target. A few years ago I noticed that bug reporters and myself sometimes have to reconstruct the origin of particular BPF instruction manually, for example, (000) ldh [12] (001) jeq #0x800 jt 2 jf 10 (002) ldb [23] (003) jeq #0x6 jt 4 jf 10 (004) ldh [20] (005) jset #0x1fff jt 10 jf 6 (006) ldxb 4*([14]&0xf) (007) ldh [x + 16] (008) jeq #0x50 jt 9 jf 10 (009) ret #262144 (010) ret #0 after some exercise becomes (000) ldh [12] ; EtherType (001) jeq #0x800 jt 2 jf 10 ; IPv4 (002) ldb [23] ; IP protocol (003) jeq #0x6 jt 4 jf 10 ; TCP (004) ldh [20] ; IPv4 fragment offset (005) jset #0x1fff jt 10 jf 6 ; first fragment (006) ldxb 4*([14]&0xf) ; IPv4 IHL (007) ldh [x + 16] ; TCP dst port (008) jeq #0x50 jt 9 jf 10 ; 80 (009) ret #262144 (010) ret #0 (and so on) After doing this a few times I thought it would be nice to have these comments generated automatically at the time of the conversion from a parse tree to BPF instructions (which I presumed was the case). Then I realised the grammar code generated BPF instructions (using gencode.c) without an intermediate parse tree, but did not understand why. LBL developers produced two major designs in this department and it seems most likely they were aware of parse trees, so it would be useful to reconstruct the line of thinking that lead to the current tree-less design and to see how much of it still holds. One potential reason to consider a parse tree could be implementing these comments if it would be easier this way. That said, for this purpose a parse tree may be not strictly necessary: if every function that generates BPF instructions knew the syntax context (as is currently done using a separate argument in gen_mac48host(), for example, or as could be done by making the context a part of compiler_state_t), it would be possible to use that for both the error messages and the BPF instruction comments. However, another reason why the comments would not be easy is that there is no room for a comment in struct bpf_insn, and struct bpf_program contains an array of those. A potential way to approach that would be introducing a new structure that is a superset of bpf_insn and producing two arrays of instructions in the output bpf_program: one with the bare 64-bit elements and another with the same plus debugging information, including the comments. Or even the additional array could contain the debugging information only and be of the same size. Then bpf_dump() could de-interleave the two arrays and produce the annotated form above. If this works, one of the reasonable things to do would be to avoid generating the debugging information when it is not required (that is, in most cases), which could be managed along the following lines: // This would be PCAP_NO by default. pcap_setopt(handle, PCAP_DUMP_WITH_COMMENTS, PCAP_YES); But I digress. Speaking of the parse tree again, it potentially could also make at least the following optimisations easier: * eliminating always-true and always-false components from filter programs, see libpcap issue 1022 for more detail (in fact, the optimisation proposed there is based on what had been implemented in RackCode parse tree about 15 years ago) -- this part may possibly be implementable without a parse tree, I had a look earlier and identified one obstacle on paper, but didn't prototype any code yet * pre-computing arithmetic expressions that do not depend on the packet data before generating any BPF instructions, for example, "2 * 2 = 4" will always be true for every packet, which the optimiser already catches, but it would be better not to generate the unnecessary BPF instructions for that in the first place, and not to consume the BPF registers; also the optimiser is not always available One thing that can complicate this is that some always-true and always-false components are in fact specific to the link-layer type, for example, "ip" generates: * always-true for DLT_IPV4 * always-false for DLT_IPV6 * a load and a comparison for DLT_RAW Also it would be useful before reworking the code generator in major ways to have it in as good shape as possible, such as: * no known obvious bugs (documented design quirks allowed) * as much test coverage as is practicable * no C code duplication without a good reason * no BPF instruction duplication without a good reason * what the C code looks is what it actually does, and vice versa * no known discrepancies in pcap-filter(7) Overall the parse tree looks like quite a demanding change. -- Denis Ovsienko _______________________________________________ tcpdump-workers mailing list -- tcpdump-workers@lists.tcpdump.org To unsubscribe send an email to tcpdump-workers-le...@lists.tcpdump.org %(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s