Skip to content

Commit

Permalink
Add VMOD version information to Panic output, debug.vmod and ELF
Browse files Browse the repository at this point in the history
This commit adds a facility which I had wanted for a very long time, and should
have added much earlier: Analyzing bug reports with VMODs involved used to be
complicated by the fact that they typically did not contain reliable version
information.

We add to vmodtool.py the generic code to create version information from
generate.py with minor modifications. It adds the version set for autotools and,
if possible, the git revision to the vmodtool-generated interface code. We copy
that to struct vrt and output it for panics and the debug.vmod CLI command. For
builds from distributions, save the git revision to a file.

Being at it, we polish the panic output slightly for readability.

There are two elements to the version information:

- "version", which is intended to be user-friendly and

- "vcs" (for version control system) which is intended to represent a commit id
  from the scm.

The VCC file Stanza $Version overrides "version".

As an example, the output from a panic now might look like this:

vmods = {
  debug = {p=0x7f5b19c2c600, abi=\"Varnish trunk 172e7b43a49bdf43d82cc6b10ab08362939fc8a5\", vrt=19.1,
    vcs=\"172e7b43a49bdf43d82cc6b10ab08362939fc8a5\", version=\"Varnish trunk\"},
},

The debug.vmod CLI outout is, for example:

    1 vtc (path="/home/slink/Devel/varnish-git/varnish-cache/vmod/.libs/libvmod_vtc.so", version="Varnish trunk", vcs="172e7b43a49bdf43d82cc6b10ab08362939fc8a5")

And, finally, a readelf example to extract the vcs string:

 $ readelf -p.vmod_vcs ./vmod/.libs/libvmod_std.so

 String dump of section '.vmod_vcs':
   [     0]  172e7b43a49bdf43d82cc6b10ab08362939fc8a5
  • Loading branch information
nigoroll committed Jan 20, 2025
1 parent 818ca09 commit c8c016d
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ cscope.*out
/vmod/vcc_*_if.c
/vmod/vcc_*_if.h
/vmod/vmod_*.rst
/vmod/vmod_vcs_version.txt

# Man-files and binaries
/man/*.1
Expand Down
27 changes: 22 additions & 5 deletions bin/varnishd/cache/cache_vrt_vmod.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ struct vmod {
const char *abi;
unsigned vrt_major;
unsigned vrt_minor;
const char *vcs;
const char *version;
};

static VTAILQ_HEAD(,vmod) vmods = VTAILQ_HEAD_INITIALIZER(vmods);
Expand Down Expand Up @@ -147,6 +149,8 @@ VPI_Vmod_Init(VRT_CTX, struct vmod **hdl, unsigned nbr, void *ptr, int len,
v->abi = d->abi;
v->vrt_major = d->vrt_major;
v->vrt_minor = d->vrt_minor;
v->vcs = d->vcs;
v->version = d->version;

REPLACE(v->nm, nm);
REPLACE(v->path, path);
Expand Down Expand Up @@ -201,9 +205,19 @@ VMOD_Panic(struct vsb *vsb)

VSB_cat(vsb, "vmods = {\n");
VSB_indent(vsb, 2);
VTAILQ_FOREACH(v, &vmods, list)
VSB_printf(vsb, "%s = {%p, %s, %u.%u},\n",
v->nm, v, v->abi, v->vrt_major, v->vrt_minor);
VTAILQ_FOREACH(v, &vmods, list) {
VSB_printf(vsb, "%s = {", v->nm);
VSB_indent(vsb, 2);
VSB_printf(vsb, "p=%p, abi=\"%s\", vrt=%u.%u,\n",
v, v->abi, v->vrt_major, v->vrt_minor);
VSB_bcat(vsb, "vcs=", 4);
VSB_quote(vsb, v->vcs, -1, VSB_QUOTE_CSTR);
VSB_bcat(vsb, ", version=", 10);
VSB_quote(vsb, v->version, -1, VSB_QUOTE_CSTR);
VSB_indent(vsb, -2);
VSB_bcat(vsb, "},\n", 3);
}

VSB_indent(vsb, -2);
VSB_cat(vsb, "},\n");
}
Expand All @@ -218,8 +232,11 @@ ccf_debug_vmod(struct cli *cli, const char * const *av, void *priv)
(void)av;
(void)priv;
ASSERT_CLI();
VTAILQ_FOREACH(v, &vmods, list)
VCLI_Out(cli, "%5d %s (%s)\n", v->ref, v->nm, v->path);
VTAILQ_FOREACH(v, &vmods, list) {
VCLI_Out(cli, "%5d %s (path=\"%s\", version=\"%s\","
" vcs=\"%s\")\n", v->ref, v->nm, v->path, v->version,
v->vcs);
}
}

static struct cli_proto vcl_cmds[] = {
Expand Down
36 changes: 36 additions & 0 deletions doc/changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,42 @@ Varnish Cache NEXT (2025-03-15)
.. PLEASE keep this roughly in commit order as shown by git-log / tig
(new to old)
* Two fields have been added to the VMOD data registered with varnish-cache:

- ``vcs`` for Version Control System is intended as an identifier from the
source code management system, e.g. the git revision, to identify the exact
source code which was used to build a VMOD binary.

- ``version`` is intended as a more user friendly identifier as to which
version of a vmod a binary represents.

Panics and the ``debug.vmod`` CLI command output now contain these
identifiers.

Where supported by the compiler and linker, the ``vcs`` identifier is also
reachable via the ``.vmod_vcs`` section of the vmod shared object ELF file and
can be extracted, for example, using ``readelf -p.vmod_vcs <file>``

* ``vmodtool.py`` now creates a file ``vmod_vcs_version.txt`` in the current
working directory when called from a git tree. This file is intended to
transport version control system information to builds from distribution
bundles.

vmod authors should add it to the distribution and otherwise ignore it for
SCM.

Where git and automake are used, this can be accomplished by adding
``vmod_vcs_version.txt`` to the ``.gitignore`` file and to the ``EXTRA_DIST``
and ``DISTCLEANFILES`` variables in ``Makefile.am``.

If neither git is used nor ``vmod_vcs_version.txt`` present, ``vmodtool.py``
will add ``NOGIT`` to the vmod as the vcs identifier.

* ``vmodtool.py`` now accepts a ``$Version`` stanza in vmod vcc files to set the
vmod version as registered with Varnish-Cache. If ``$Version`` is not present,
an attempt is made to extract ``PACKAGE_STRING`` from an automake
``Makefile``, otherwise ``NOVERSION`` is used as the version identifier.

* The scope of VCL variables ``req.is_hitmiss`` and ``req.is_hitpass`` is now
restricted to ``vcl_miss, vcl_deliver, vcl_pass, vcl_synth`` and ``vcl_pass,
vcl_deliver, vcl_synth`` respectively.
Expand Down
6 changes: 6 additions & 0 deletions doc/sphinx/reference/vmod.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ data structures that do all the hard work.
The std VMODs vmod.vcc file looks somewhat like this::

$ABI strict
$Version my.version
$Module std 3 "Varnish Standard Module"
$Event event_function
$Function STRING toupper(STRANDS s)
Expand All @@ -73,6 +74,11 @@ version, use ``strict``. If it complies to the VRT and only needs
to be rebuilt when breaking changes are introduced to the VRT API,
use ``vrt``.

The ``$Version`` line is also optional. It specifies the version identifier
compiled into the VMOD binary for later identification. If omitted,
``PACKAGE_STRING`` from an automake ``Makefile`` will be used, or ``NOVERSION``
otherwise.

The ``$Module`` line gives the name of the module, the manual section
where the documentation will reside, and the description.

Expand Down
2 changes: 2 additions & 0 deletions include/vrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ struct vmod_data {
const char *proto;
const char *json;
const char *abi;
const char *vcs;
const char *version;
};

/***********************************************************************
Expand Down
64 changes: 64 additions & 0 deletions lib/libvcc/vmodtool.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import optparse
import os
import re
import subprocess
import sys
import time

Expand Down Expand Up @@ -128,6 +129,7 @@

DEPRECATED = {}


#######################################################################

def deprecated(key, txt):
Expand Down Expand Up @@ -930,6 +932,14 @@ def rsthead(self, fo, unused_man):
def json(self, jl):
jl.append(["$ALIAS", self.sym_alias, self.sym_name])

class VersionStanza(Stanza):

''' $Version version ... '''

def parse(self):
if len(self.toks) < 2:
self.syntax()
self.vcc.pkgstr = " ".join(self.toks[1:])

#######################################################################

Expand All @@ -944,6 +954,7 @@ def json(self, jl):
"Synopsis": SynopsisStanza,
"Alias": AliasStanza,
"Restrict": RestrictStanza,
"Version": VersionStanza
}


Expand All @@ -966,6 +977,7 @@ def __init__(self, inputvcc, rstdir, outputprefix):
self.auto_synopsis = True
self.modname = None
self.csn = None
self.pkgstr = None

def openfile(self, fn):
self.commit_files.append(fn)
Expand Down Expand Up @@ -1180,10 +1192,60 @@ def json(self, fo, fnx):
fo.write('\t\"\\n\\x03\"\n};\n')
fo.write('#undef STRINGIFY\n')

# parts from varnish-cache include/generate.py
def version(self):
srcdir = os.path.dirname(self.inputfile)

pkgstr = "NOVERSION"

if self.pkgstr is not None:
pkgstr = self.pkgstr
else:
for d in [srcdir, "."]:
f = os.path.join(d, "Makefile")
if not os.path.exists(f):
continue
for pkgstr in open(f):
if pkgstr[:14] == "PACKAGE_STRING":
pkgstr = pkgstr.split("=")[1].strip()
break
break
return pkgstr

# parts from varnish-cache include/generate.py
def vcs(self):
srcdir = os.path.dirname(self.inputfile)

gitver = subprocess.check_output([
"git -C %s rev-parse HEAD 2>/dev/null || echo NOGIT" %
srcdir], shell=True, universal_newlines=True).strip()
gitfile = "vmod_vcs_version.txt"

if gitver == "NOGIT":
for d in [".", srcdir]:
f = os.path.join(d, gitfile)
if not os.path.exists(f):
continue
fh = open(f, "r")
if not fh:
continue
gitver = fh.read()
fh.close()
break;
else:
fh = open(gitfile, "w")
fh.write(gitver)
fh.close()

return gitver

def vmod_data(self, fo):
version = json.dumps(self.version())
vcs = json.dumps(self.vcs())
vmd = "Vmod_%s_Data" % self.modname
fo.write('\n')
fo.write('__attribute__((section(".vmod_vcs"), used))\n')
fo.write('const char vmod_vcs[] = %s;' % vcs)
for i in (714, 759, 765):
fo.write("/*lint -esym(%d, %s) */\n" % (i, vmd))
fo.write("\nextern const struct vmod_data %s;\n" % vmd)
Expand All @@ -1197,6 +1259,8 @@ def vmod_data(self, fo):
fo.write('\t.func_len =\tsizeof(%s),\n' % self.csn)
fo.write('\t.json =\t\tVmod_Json,\n')
fo.write('\t.abi =\t\tVMOD_ABI_Version,\n')
fo.write('\t.version =\t%s,\n' % version)
fo.write('\t.vcs =\tvmod_vcs,\n')
fo.write("};\n")

def mkcfile(self):
Expand Down
4 changes: 3 additions & 1 deletion vmod/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ TESTS = @VMOD_TESTS@
include $(top_srcdir)/vsc.am
include $(top_srcdir)/vtc.am

EXTRA_DIST = $(TESTS)
EXTRA_DIST = $(TESTS) vmod_vcs_version.txt

DISTCLEANFILES = vmod_vcs_version.txt

AM_LDFLAGS = $(AM_LT_LDFLAGS)

Expand Down

0 comments on commit c8c016d

Please sign in to comment.