summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/developer/xrefs.rst7
-rw-r--r--lib/xref.c106
-rw-r--r--lib/xref.h24
3 files changed, 88 insertions, 49 deletions
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_) \
{ \