back to topotato report
topotato coverage report
Current view: top level - lib - xref.h (source / functions) Hit Total Coverage
Test: test_bgp_ecmp_enhe.py::BGP_Unnumbered_ECMP Lines: 3 3 100.0 %
Date: 2023-11-16 17:19:14 Functions: 2 4 50.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: ISC
       2             : /*
       3             :  * Copyright (c) 2017-20  David Lamparter, for NetDEF, Inc.
       4             :  */
       5             : 
       6             : #ifndef _FRR_XREF_H
       7             : #define _FRR_XREF_H
       8             : 
       9             : #include <stdint.h>
      10             : #include <stdlib.h>
      11             : #include <limits.h>
      12             : #include <errno.h>
      13             : #include "compiler.h"
      14             : #include "typesafe.h"
      15             : 
      16             : #ifdef __cplusplus
      17             : extern "C" {
      18             : #endif
      19             : 
      20             : enum xref_type {
      21             :         XREFT_NONE = 0,
      22             : 
      23             :         XREFT_EVENTSCHED = 0x100,
      24             : 
      25             :         XREFT_LOGMSG = 0x200,
      26             :         XREFT_ASSERT = 0x280,
      27             : 
      28             :         XREFT_DEFUN = 0x300,
      29             :         XREFT_INSTALL_ELEMENT = 0x301,
      30             : };
      31             : 
      32             : /* struct xref is the "const" part;  struct xrefdata is the writable part. */
      33             : struct xref;
      34             : struct xrefdata;
      35             : 
      36             : struct xref {
      37             :         /* this may be NULL, depending on the type of the xref.
      38             :          * if it is NULL, the xref has no unique ID and cannot be accessed
      39             :          * through that mechanism.
      40             :          */
      41             :         struct xrefdata *xrefdata;
      42             : 
      43             :         /* type isn't generally needed at runtime */
      44             :         enum xref_type type;
      45             : 
      46             :         /* code location */
      47             :         int line;
      48             :         const char *file;
      49             :         const char *func;
      50             : 
      51             :         /* -- 32 bytes (on 64bit) -- */
      52             : 
      53             :         /* type-specific bits appended by embedding this struct */
      54             : };
      55             : 
      56             : PREDECL_RBTREE_UNIQ(xrefdata_uid);
      57             : 
      58             : struct xrefdata {
      59             :         /* pointer back to the const part;  this will be initialized at
      60             :          * program startup by xref_block_add().  (Creating structs with
      61             :          * cyclic pointers to each other is not easily possible for
      62             :          * function-scoped static variables.)
      63             :          *
      64             :          * There is no xrefdata w/o xref, but there are xref w/o xrefdata.
      65             :          */
      66             :         const struct xref *xref;
      67             : 
      68             :         /* base32(crockford) of unique ID.  not all bytes are used, but
      69             :          * let's pad to 16 for simplicity
      70             :          */
      71             :         char uid[16];
      72             : 
      73             :         /* hash/uid input
      74             :          * if hashstr is NULL, no UID is assigned/calculated.  Use macro
      75             :          * string concatenation if multiple values need to be fed in.
      76             :          * (This is here to not make the UID calculation independent of
      77             :          * xref type.)
      78             :          */
      79             :         const char *hashstr;
      80             :         uint32_t hashu32[2];
      81             : 
      82             :         /* -- 32 bytes (on 64bit) -- */
      83             :         struct xrefdata_uid_item xui;
      84             : };
      85             : 
      86       90512 : static inline int xrefdata_uid_cmp(const struct xrefdata *a,
      87             :                                    const struct xrefdata *b)
      88             : {
      89       90512 :         return strcmp(a->uid, b->uid);
      90             : }
      91             : 
      92       99812 : DECLARE_RBTREE_UNIQ(xrefdata_uid, struct xrefdata, xui, xrefdata_uid_cmp);
      93             : extern struct xrefdata_uid_head xrefdata_uid;
      94             : 
      95             : /* linker "magic" is used to create an array of pointers to struct xref.
      96             :  * the result is a contiguous block of pointers, each pointing to an xref
      97             :  * somewhere in the code.  The linker gives us start and end pointers, we
      98             :  * stuff those into the struct below and hook up a constructor to run at
      99             :  * program startup with the struct passed.
     100             :  *
     101             :  * Placing the xrefs themselves into an array doesn't work because they'd
     102             :  * need to be constant size, but we're embedding struct xref into other
     103             :  * container structs with extra data.  Also this means that external code
     104             :  * (like the python xref dumper) can safely ignore extra data at the end of
     105             :  * xrefs without needing to account for size in iterating the array.
     106             :  *
     107             :  * If you're curious, this is also how __attribute__((constructor)) (and
     108             :  * destructor) are implemented - there are 2 arrays, ".init_array" and
     109             :  * ".fini_array", containing function pointers.  The magic turns out to be
     110             :  * quite mundane, actually ;)
     111             :  *
     112             :  * The slightly tricky bit is that this is a per-object (i.e. per shared
     113             :  * library & daemon) thing and we need a bit of help (in XREF_SETUP) to
     114             :  * initialize correctly.
     115             :  */
     116             : 
     117             : struct xref_block {
     118             :         struct xref_block *next;
     119             :         const struct xref * const *start;
     120             :         const struct xref * const *stop;
     121             : };
     122             : 
     123             : extern struct xref_block *xref_blocks;
     124             : extern void xref_block_add(struct xref_block *block);
     125             : extern void xref_gcc_workaround(const struct xref *xref);
     126             : 
     127             : #ifndef HAVE_SECTION_SYMS
     128             : /* we have a build system patch to use GNU ld on Solaris;  if that doesn't
     129             :  * work we end up on Solaris ld which doesn't support the section start/end
     130             :  * symbols.
     131             :  */
     132             : #define XREF_SETUP() \
     133             :         CPP_NOTICE("Missing linker support for section arrays.  Solaris ld?")
     134             : #else
     135             : /* the actual symbols that the linker provides for us.  Note these are
     136             :  * _symbols_ referring to the actual section start/end, i.e. they are very
     137             :  * much NOT _pointers_, rather the symbol *value* is the pointer.  Declaring
     138             :  * them as size-1 arrays is the "best" / "right" thing.
     139             :  */
     140             : extern const struct xref * const __start_xref_array[1] DSO_LOCAL;
     141             : extern const struct xref * const __stop_xref_array[1] DSO_LOCAL;
     142             : 
     143             : #if defined(__has_feature)
     144             : #if __has_feature(address_sanitizer)
     145             : /* no redzone around each of the xref_p please, we're building an array out
     146             :  * of variables here.  kinda breaks things if there's redzones between each
     147             :  * array item.
     148             :  */
     149             : #define xref_array_attr used, section("xref_array"), no_sanitize("address")
     150             : #endif
     151             : #endif
     152             : #ifndef xref_array_attr
     153             : #define xref_array_attr used, section("xref_array")
     154             : #endif
     155             : 
     156             : /* this macro is invoked once for each standalone DSO through
     157             :  *   FRR_MODULE_SETUP  \
     158             :  *                      }-> FRR_COREMOD_SETUP -> XREF_SETUP
     159             :  *   FRR_DAEMON_INFO   /
     160             :  */
     161             : #define XREF_SETUP()                                                           \
     162             :         static const struct xref _dummy_xref = {                               \
     163             :                         /* .xrefdata = */ NULL,                                \
     164             :                         /* .type = */ XREFT_NONE,                              \
     165             :                         /* .line = */ __LINE__,                                \
     166             :                         /* .file = */ __FILE__,                                \
     167             :                         /* .func = */ "dummy",                                 \
     168             :         };                                                                     \
     169             :         static const struct xref * const _dummy_xref_p                         \
     170             :                         __attribute__((xref_array_attr)) = &_dummy_xref;       \
     171             :         static void __attribute__((used, _CONSTRUCTOR(1100)))                  \
     172             :                         _xref_init(void) {                                     \
     173             :                 static struct xref_block _xref_block = {                       \
     174             :                         .next = NULL,                                          \
     175             :                         .start = __start_xref_array,                           \
     176             :                         .stop = __stop_xref_array,                             \
     177             :                 };                                                             \
     178             :                 xref_block_add(&_xref_block);                                  \
     179             :         }                                                                      \
     180             :         asm(XREF_NOTE);                                                        \
     181             :         MACRO_REQUIRE_SEMICOLON() /* end */
     182             : 
     183             : /* the following blurb emits an ELF note indicating start and end of the xref
     184             :  * array in the binary.  This is technically the "correct" entry point for
     185             :  * external tools reading xrefs out of an ELF shared library or executable.
     186             :  *
     187             :  * right now, the extraction tools use the section header for "xref_array"
     188             :  * instead; however, section headers are technically not necessarily preserved
     189             :  * for fully linked libraries or executables.  (In practice they are only
     190             :  * stripped by obfuscation tools.)
     191             :  *
     192             :  * conversely, for reading xrefs out of a single relocatable object file (e.g.
     193             :  * bar.o), section headers are the right thing to look at since the note is
     194             :  * only emitted for the final binary once.
     195             :  *
     196             :  * FRR itself does not need this note to operate correctly, so if you have
     197             :  * some build issue with it just add -DFRR_XREF_NO_NOTE to your build flags
     198             :  * to disable it.
     199             :  */
     200             : #if defined(FRR_XREF_NO_NOTE) || defined(__mips64)
     201             : #define XREF_NOTE ""
     202             : 
     203             : /* mips64 note:  MIPS64 (regardless of endianness, both mips64 & mips64el)
     204             :  * does not have a 64-bit PC-relative relocation type.  Unfortunately, a
     205             :  * 64-bit PC-relative relocation is exactly what the below asm magic emits.
     206             :  * Therefore, the xref ELF note is permanently disabled on MIPS64.
     207             :  *
     208             :  * For some context, refer to https://reviews.llvm.org/D80390
     209             :  *
     210             :  * As noted above, xref extraction still works through the section header
     211             :  * path, so no functionality is lost.
     212             :  */
     213             : #else
     214             : 
     215             : #if __SIZEOF_POINTER__ == 4
     216             : #define _NOTE_2PTRSIZE  "8"
     217             : #define _NOTE_PTR       ".long"
     218             : #elif __SIZEOF_POINTER__ == 8
     219             : #define _NOTE_2PTRSIZE  "16"
     220             : #define _NOTE_PTR       ".quad"
     221             : #else
     222             : #error unsupported pointer size
     223             : #endif
     224             : 
     225             : #ifdef __arm__
     226             : # define asmspecial "%"
     227             : #else
     228             : # define asmspecial "@"
     229             : #endif
     230             : 
     231             : #define XREF_NOTE                                                              \
     232             :         ""                                                                 "\n"\
     233             :         "  .type _frr_xref_note," asmspecial "object"                 "\n"\
     234             :         "  .pushsection .note.FRR,\"a\"," asmspecial "note"           "\n"\
     235             :         "  .p2align 2"                                                "\n"\
     236             :         "_frr_xref_note:"                                                  "\n"\
     237             :         "  .long   9"                                                 "\n"\
     238             :         "  .long   " _NOTE_2PTRSIZE                                   "\n"\
     239             :         "  .ascii  \"XREF\""                                          "\n"\
     240             :         "  .ascii  \"FRRouting\\0\\0\\0\""                            "\n"\
     241             :         "  " _NOTE_PTR " __start_xref_array-."                      "\n"\
     242             :         "  " _NOTE_PTR " __stop_xref_array-."                       "\n"\
     243             :         "  .size _frr_xref_note, .-_frr_xref_note"                    "\n"\
     244             :         "  .popsection"                                               "\n"\
     245             :         ""                                                                 "\n"\
     246             :         /* end */
     247             : #endif
     248             : 
     249             : #endif /* HAVE_SECTION_SYMS */
     250             : 
     251             : /* emit the array entry / pointer to xref */
     252             : #if defined(__clang__) || !defined(__cplusplus)
     253             : #define XREF_LINK(dst)                                                         \
     254             :         static const struct xref * const NAMECTR(xref_p_)                      \
     255             :                         __attribute__((xref_array_attr))                       \
     256             :                 = &(dst)                                                       \
     257             :         /* end */
     258             : 
     259             : #else /* GCC && C++ */
     260             : /* workaround for GCC bug 41091 (dated 2009), added in 2021...
     261             :  *
     262             :  * this breaks extraction of xrefs with xrelfo.py (because the xref_array
     263             :  * entry will be missing), but provides full runtime functionality.  To get
     264             :  * the proper list of xrefs from C++ code, build with clang...
     265             :  */
     266             : struct _xref_p {
     267             :         const struct xref * const ptr;
     268             : 
     269             :         _xref_p(const struct xref *_ptr) : ptr(_ptr)
     270             :         {
     271             :                 xref_gcc_workaround(_ptr);
     272             :         }
     273             : };
     274             : 
     275             : #define XREF_LINK(dst)                                                         \
     276             :         static const struct _xref_p __attribute__((used))                      \
     277             :                         NAMECTR(xref_p_)(&(dst))                               \
     278             :         /* end */
     279             : #endif
     280             : 
     281             : /* initializer for a "struct xref" */
     282             : #define XREF_INIT(type_, xrefdata_, func_)                                     \
     283             :         {                                                                      \
     284             :                 /* .xrefdata = */ (xrefdata_),                                 \
     285             :                 /* .type = */ (type_),                                         \
     286             :                 /* .line = */ __LINE__,                                        \
     287             :                 /* .file = */ __FILE__,                                        \
     288             :                 /* .func = */ func_,                                           \
     289             :         }                                                                      \
     290             :         /* end */
     291             : 
     292             : /* use with XREF_INIT when outside of a function, i.e. no __func__ */
     293             : #define XREF_NO_FUNC    "<global>"
     294             : 
     295             : #ifdef __cplusplus
     296             : }
     297             : #endif
     298             : 
     299             : #endif /* _FRR_XREF_H */

Generated by: LCOV version v1.16-topotato