Skip to content

Commit c8c016d

Browse files
committed
Add VMOD version information to Panic output, debug.vmod and ELF
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
1 parent 818ca09 commit c8c016d

File tree

7 files changed

+134
-6
lines changed

7 files changed

+134
-6
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ cscope.*out
8080
/vmod/vcc_*_if.c
8181
/vmod/vcc_*_if.h
8282
/vmod/vmod_*.rst
83+
/vmod/vmod_vcs_version.txt
8384

8485
# Man-files and binaries
8586
/man/*.1

bin/varnishd/cache/cache_vrt_vmod.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ struct vmod {
6565
const char *abi;
6666
unsigned vrt_major;
6767
unsigned vrt_minor;
68+
const char *vcs;
69+
const char *version;
6870
};
6971

7072
static VTAILQ_HEAD(,vmod) vmods = VTAILQ_HEAD_INITIALIZER(vmods);
@@ -147,6 +149,8 @@ VPI_Vmod_Init(VRT_CTX, struct vmod **hdl, unsigned nbr, void *ptr, int len,
147149
v->abi = d->abi;
148150
v->vrt_major = d->vrt_major;
149151
v->vrt_minor = d->vrt_minor;
152+
v->vcs = d->vcs;
153+
v->version = d->version;
150154

151155
REPLACE(v->nm, nm);
152156
REPLACE(v->path, path);
@@ -201,9 +205,19 @@ VMOD_Panic(struct vsb *vsb)
201205

202206
VSB_cat(vsb, "vmods = {\n");
203207
VSB_indent(vsb, 2);
204-
VTAILQ_FOREACH(v, &vmods, list)
205-
VSB_printf(vsb, "%s = {%p, %s, %u.%u},\n",
206-
v->nm, v, v->abi, v->vrt_major, v->vrt_minor);
208+
VTAILQ_FOREACH(v, &vmods, list) {
209+
VSB_printf(vsb, "%s = {", v->nm);
210+
VSB_indent(vsb, 2);
211+
VSB_printf(vsb, "p=%p, abi=\"%s\", vrt=%u.%u,\n",
212+
v, v->abi, v->vrt_major, v->vrt_minor);
213+
VSB_bcat(vsb, "vcs=", 4);
214+
VSB_quote(vsb, v->vcs, -1, VSB_QUOTE_CSTR);
215+
VSB_bcat(vsb, ", version=", 10);
216+
VSB_quote(vsb, v->version, -1, VSB_QUOTE_CSTR);
217+
VSB_indent(vsb, -2);
218+
VSB_bcat(vsb, "},\n", 3);
219+
}
220+
207221
VSB_indent(vsb, -2);
208222
VSB_cat(vsb, "},\n");
209223
}
@@ -218,8 +232,11 @@ ccf_debug_vmod(struct cli *cli, const char * const *av, void *priv)
218232
(void)av;
219233
(void)priv;
220234
ASSERT_CLI();
221-
VTAILQ_FOREACH(v, &vmods, list)
222-
VCLI_Out(cli, "%5d %s (%s)\n", v->ref, v->nm, v->path);
235+
VTAILQ_FOREACH(v, &vmods, list) {
236+
VCLI_Out(cli, "%5d %s (path=\"%s\", version=\"%s\","
237+
" vcs=\"%s\")\n", v->ref, v->nm, v->path, v->version,
238+
v->vcs);
239+
}
223240
}
224241

225242
static struct cli_proto vcl_cmds[] = {

doc/changes.rst

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,42 @@ Varnish Cache NEXT (2025-03-15)
4141
.. PLEASE keep this roughly in commit order as shown by git-log / tig
4242
(new to old)
4343
44+
* Two fields have been added to the VMOD data registered with varnish-cache:
45+
46+
- ``vcs`` for Version Control System is intended as an identifier from the
47+
source code management system, e.g. the git revision, to identify the exact
48+
source code which was used to build a VMOD binary.
49+
50+
- ``version`` is intended as a more user friendly identifier as to which
51+
version of a vmod a binary represents.
52+
53+
Panics and the ``debug.vmod`` CLI command output now contain these
54+
identifiers.
55+
56+
Where supported by the compiler and linker, the ``vcs`` identifier is also
57+
reachable via the ``.vmod_vcs`` section of the vmod shared object ELF file and
58+
can be extracted, for example, using ``readelf -p.vmod_vcs <file>``
59+
60+
* ``vmodtool.py`` now creates a file ``vmod_vcs_version.txt`` in the current
61+
working directory when called from a git tree. This file is intended to
62+
transport version control system information to builds from distribution
63+
bundles.
64+
65+
vmod authors should add it to the distribution and otherwise ignore it for
66+
SCM.
67+
68+
Where git and automake are used, this can be accomplished by adding
69+
``vmod_vcs_version.txt`` to the ``.gitignore`` file and to the ``EXTRA_DIST``
70+
and ``DISTCLEANFILES`` variables in ``Makefile.am``.
71+
72+
If neither git is used nor ``vmod_vcs_version.txt`` present, ``vmodtool.py``
73+
will add ``NOGIT`` to the vmod as the vcs identifier.
74+
75+
* ``vmodtool.py`` now accepts a ``$Version`` stanza in vmod vcc files to set the
76+
vmod version as registered with Varnish-Cache. If ``$Version`` is not present,
77+
an attempt is made to extract ``PACKAGE_STRING`` from an automake
78+
``Makefile``, otherwise ``NOVERSION`` is used as the version identifier.
79+
4480
* The scope of VCL variables ``req.is_hitmiss`` and ``req.is_hitpass`` is now
4581
restricted to ``vcl_miss, vcl_deliver, vcl_pass, vcl_synth`` and ``vcl_pass,
4682
vcl_deliver, vcl_synth`` respectively.

doc/sphinx/reference/vmod.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ data structures that do all the hard work.
5656
The std VMODs vmod.vcc file looks somewhat like this::
5757

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

77+
The ``$Version`` line is also optional. It specifies the version identifier
78+
compiled into the VMOD binary for later identification. If omitted,
79+
``PACKAGE_STRING`` from an automake ``Makefile`` will be used, or ``NOVERSION``
80+
otherwise.
81+
7682
The ``$Module`` line gives the name of the module, the manual section
7783
where the documentation will reside, and the description.
7884

include/vrt.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,8 @@ struct vmod_data {
493493
const char *proto;
494494
const char *json;
495495
const char *abi;
496+
const char *vcs;
497+
const char *version;
496498
};
497499

498500
/***********************************************************************

lib/libvcc/vmodtool.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import optparse
4646
import os
4747
import re
48+
import subprocess
4849
import sys
4950
import time
5051

@@ -128,6 +129,7 @@
128129

129130
DEPRECATED = {}
130131

132+
131133
#######################################################################
132134

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

935+
class VersionStanza(Stanza):
936+
937+
''' $Version version ... '''
938+
939+
def parse(self):
940+
if len(self.toks) < 2:
941+
self.syntax()
942+
self.vcc.pkgstr = " ".join(self.toks[1:])
933943

934944
#######################################################################
935945

@@ -944,6 +954,7 @@ def json(self, jl):
944954
"Synopsis": SynopsisStanza,
945955
"Alias": AliasStanza,
946956
"Restrict": RestrictStanza,
957+
"Version": VersionStanza
947958
}
948959

949960

@@ -966,6 +977,7 @@ def __init__(self, inputvcc, rstdir, outputprefix):
966977
self.auto_synopsis = True
967978
self.modname = None
968979
self.csn = None
980+
self.pkgstr = None
969981

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

1195+
# parts from varnish-cache include/generate.py
1196+
def version(self):
1197+
srcdir = os.path.dirname(self.inputfile)
1198+
1199+
pkgstr = "NOVERSION"
1200+
1201+
if self.pkgstr is not None:
1202+
pkgstr = self.pkgstr
1203+
else:
1204+
for d in [srcdir, "."]:
1205+
f = os.path.join(d, "Makefile")
1206+
if not os.path.exists(f):
1207+
continue
1208+
for pkgstr in open(f):
1209+
if pkgstr[:14] == "PACKAGE_STRING":
1210+
pkgstr = pkgstr.split("=")[1].strip()
1211+
break
1212+
break
1213+
return pkgstr
1214+
1215+
# parts from varnish-cache include/generate.py
1216+
def vcs(self):
1217+
srcdir = os.path.dirname(self.inputfile)
1218+
1219+
gitver = subprocess.check_output([
1220+
"git -C %s rev-parse HEAD 2>/dev/null || echo NOGIT" %
1221+
srcdir], shell=True, universal_newlines=True).strip()
1222+
gitfile = "vmod_vcs_version.txt"
1223+
1224+
if gitver == "NOGIT":
1225+
for d in [".", srcdir]:
1226+
f = os.path.join(d, gitfile)
1227+
if not os.path.exists(f):
1228+
continue
1229+
fh = open(f, "r")
1230+
if not fh:
1231+
continue
1232+
gitver = fh.read()
1233+
fh.close()
1234+
break;
1235+
else:
1236+
fh = open(gitfile, "w")
1237+
fh.write(gitver)
1238+
fh.close()
1239+
1240+
return gitver
11831241

11841242
def vmod_data(self, fo):
1243+
version = json.dumps(self.version())
1244+
vcs = json.dumps(self.vcs())
11851245
vmd = "Vmod_%s_Data" % self.modname
11861246
fo.write('\n')
1247+
fo.write('__attribute__((section(".vmod_vcs"), used))\n')
1248+
fo.write('const char vmod_vcs[] = %s;' % vcs)
11871249
for i in (714, 759, 765):
11881250
fo.write("/*lint -esym(%d, %s) */\n" % (i, vmd))
11891251
fo.write("\nextern const struct vmod_data %s;\n" % vmd)
@@ -1197,6 +1259,8 @@ def vmod_data(self, fo):
11971259
fo.write('\t.func_len =\tsizeof(%s),\n' % self.csn)
11981260
fo.write('\t.json =\t\tVmod_Json,\n')
11991261
fo.write('\t.abi =\t\tVMOD_ABI_Version,\n')
1262+
fo.write('\t.version =\t%s,\n' % version)
1263+
fo.write('\t.vcs =\tvmod_vcs,\n')
12001264
fo.write("};\n")
12011265

12021266
def mkcfile(self):

vmod/Makefile.am

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ TESTS = @VMOD_TESTS@
55
include $(top_srcdir)/vsc.am
66
include $(top_srcdir)/vtc.am
77

8-
EXTRA_DIST = $(TESTS)
8+
EXTRA_DIST = $(TESTS) vmod_vcs_version.txt
9+
10+
DISTCLEANFILES = vmod_vcs_version.txt
911

1012
AM_LDFLAGS = $(AM_LT_LDFLAGS)
1113

0 commit comments

Comments
 (0)