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