diff --git a/doc/developer/xrefs.rst b/doc/developer/xrefs.rst index 689a21cc1f..6a0794d41b 100644 --- a/doc/developer/xrefs.rst +++ b/doc/developer/xrefs.rst @@ -161,3 +161,10 @@ the xref array is in the file. Also note the owner is clearly marked as For SystemTap's use of ELF notes, refer to https://libstapsdt.readthedocs.io/en/latest/how-it-works/internals.html as an entry point. + +.. note:: + + Due to GCC bug 41091, the "xref_array" section is not correctly generated + for C++ code when compiled by GCC. A workaround is present for runtime + functionality, but to extract the xrefs from a C++ source file, it needs + to be built with clang (or a future fixed version of GCC) instead. diff --git a/lib/xref.c b/lib/xref.c index eb5e8ed2c2..40efe51363 100644 --- a/lib/xref.c +++ b/lib/xref.c @@ -63,60 +63,68 @@ static void base32(uint8_t **inpos, int *bitpos, *bitpos = bp; } +static void xref_add_one(const struct xref *xref) +{ + SHA256_CTX sha; + struct xrefdata *xrefdata; + + const char *filename, *p, *q; + uint8_t hash[32], *h = hash; + uint32_t be_val; + int bitpos; + + if (!xref || !xref->xrefdata) + return; + + xrefdata = xref->xrefdata; + xrefdata->xref = xref; + + if (!xrefdata->hashstr) + return; + + /* as far as the unique ID is concerned, only use the last + * directory name + filename, e.g. "bgpd/bgp_route.c". This + * gives a little leeway in moving things and avoids IDs being + * screwed up by out of tree builds or absolute pathnames. + */ + filename = xref->file; + p = strrchr(filename, '/'); + if (p) { + q = memrchr(filename, '/', p - filename); + if (q) + filename = q + 1; + else + filename = p + 1; + } + + SHA256_Init(&sha); + SHA256_Update(&sha, filename, strlen(filename)); + SHA256_Update(&sha, xrefdata->hashstr, + strlen(xrefdata->hashstr)); + be_val = htonl(xrefdata->hashu32[0]); + SHA256_Update(&sha, &be_val, sizeof(be_val)); + be_val = htonl(xrefdata->hashu32[1]); + SHA256_Update(&sha, &be_val, sizeof(be_val)); + SHA256_Final(hash, &sha); + + bitpos = -1; + base32(&h, &bitpos, &xrefdata->uid[0], 5); + xrefdata->uid[5] = '-'; + base32(&h, &bitpos, &xrefdata->uid[6], 5); +} + +void xref_gcc_workaround(const struct xref *xref) +{ + xref_add_one(xref); +} + void xref_block_add(struct xref_block *block) { const struct xref * const *xrefp; - SHA256_CTX sha; *xref_block_last = block; xref_block_last = &block->next; - for (xrefp = block->start; xrefp < block->stop; xrefp++) { - const struct xref *xref = *xrefp; - struct xrefdata *xrefdata; - - const char *filename, *p, *q; - uint8_t hash[32], *h = hash; - uint32_t be_val; - int bitpos; - - if (!xref || !xref->xrefdata) - continue; - - xrefdata = xref->xrefdata; - xrefdata->xref = xref; - - if (!xrefdata->hashstr) - continue; - - /* as far as the unique ID is concerned, only use the last - * directory name + filename, e.g. "bgpd/bgp_route.c". This - * gives a little leeway in moving things and avoids IDs being - * screwed up by out of tree builds or absolute pathnames. - */ - filename = xref->file; - p = strrchr(filename, '/'); - if (p) { - q = memrchr(filename, '/', p - filename); - if (q) - filename = q + 1; - else - filename = p + 1; - } - - SHA256_Init(&sha); - SHA256_Update(&sha, filename, strlen(filename)); - SHA256_Update(&sha, xrefdata->hashstr, - strlen(xrefdata->hashstr)); - be_val = htonl(xrefdata->hashu32[0]); - SHA256_Update(&sha, &be_val, sizeof(be_val)); - be_val = htonl(xrefdata->hashu32[1]); - SHA256_Update(&sha, &be_val, sizeof(be_val)); - SHA256_Final(hash, &sha); - - bitpos = -1; - base32(&h, &bitpos, &xrefdata->uid[0], 5); - xrefdata->uid[5] = '-'; - base32(&h, &bitpos, &xrefdata->uid[6], 5); - } + for (xrefp = block->start; xrefp < block->stop; xrefp++) + xref_add_one(*xrefp); } diff --git a/lib/xref.h b/lib/xref.h index e464da4131..426ffad705 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -119,6 +119,7 @@ struct xref_block { extern struct xref_block *xref_blocks; extern void xref_block_add(struct xref_block *block); +extern void xref_gcc_workaround(const struct xref *xref); #ifndef HAVE_SECTION_SYMS /* we have a build system patch to use GNU ld on Solaris; if that doesn't @@ -218,12 +219,35 @@ extern const struct xref * const __stop_xref_array[1] DSO_LOCAL; #endif /* HAVE_SECTION_SYMS */ /* emit the array entry / pointer to xref */ +#if defined(__clang__) || !defined(__cplusplus) #define XREF_LINK(dst) \ static const struct xref * const NAMECTR(xref_p_) \ __attribute__((used, section("xref_array"))) \ = &(dst) \ /* end */ +#else /* GCC && C++ */ +/* workaround for GCC bug 41091 (dated 2009), added in 2021... + * + * this breaks extraction of xrefs with xrelfo.py (because the xref_array + * entry will be missing), but provides full runtime functionality. To get + * the proper list of xrefs from C++ code, build with clang... + */ +struct _xref_p { + const struct xref * const ptr; + + _xref_p(const struct xref *_ptr) : ptr(_ptr) + { + xref_gcc_workaround(_ptr); + } +}; + +#define XREF_LINK(dst) \ + static const struct _xref_p __attribute__((used)) \ + NAMECTR(xref_p_)(&(dst)) \ + /* end */ +#endif + /* initializer for a "struct xref" */ #define XREF_INIT(type_, xrefdata_, func_) \ { \