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