Provided by: libdevel-mat-dumper-perl_0.50-1build1_amd64 

NAME
"Devel::MAT::Dumper::Helper" - give XS modules extensions for memory dumping
SYNOPSIS
In Build.PL
if( eval { require Devel::MAT::Dumper::Helper } ) {
Devel::MAT::Dumper::Helper->extend_module_build( $build );
}
In your module's XS source:
#ifdef HAVE_DMD_HELPER
# define WANT_DMD_API_044
# include "DMD_helper.h"
#endif
...
#ifdef HAVE_DMD_HELPER
static int dumpstruct(pTHX_ DMDContext *ctx, const SV *sv)
{
int ret = 0;
ret += DMD_ANNOTATE_SV(sv, another_sv,
"the description of this field");
...
return ret;
}
static int dumpmagic(pTHX_ DMDContext *ctx, const SV *sv, MAGIC *mg)
{
int ret = 0;
ret += DMD_ANNOTATE_SV(sv, another_sv,
"the description of this field");
...
return ret;
}
#endif
...
BOOT:
#ifdef HAVE_DMD_HELPER
DMD_SET_PACKAGE_HELPER("My::Package", dumpstruct);
DMD_SET_MAGIC_HELPER(&vtbl, dumpmagic);
#endif
DESCRIPTION
This module provides a build-time helper to assist in writing XS modules that can provide extra
information to a Devel::MAT heap dump file when dumping data structures relating to that module.
Following the example in the "SYNOPSIS" section above, the "dumpstruct" function is called whenever
Devel::MAT::Dumper finds an SV blessed into the given package, and the "dumpmagic" function is called
whenever Devel::MAT::Dumper finds an SV with extension magic matching the given magic virtual table
pointer. These functions may then inspect the module's state from the SV or MAGIC pointers, and invoke
the "DMD_ANNOTATE_SV" macro to provide extra annotations into the heap dump file about how this SV is
related to another one.
The "WANT_DMD_API_044" macro is required before "#include"ing the file, so as to enable the API structure
described here. Without that, an earlier version of the module is provided instead, which will eventually
be removed in some later version.
Under this code structure, a module will cleanly build, install and run just fine if
Devel::MAT::Dumper::Helper is not available at build time, so it is not necessary to list that as a
"configure_requires" or "build_requires" requirement.
Additionally, the way the inserted code is structured does not cause the XS module to load
"Devel::MAT::Dumper" itself, so there is no runtime dependency either, even if the support was made
available. The newly inserted code is only invoked if both "Devel::MAT::Dumper" and this XS module are
actually loaded.
Note that this entire mechanism is currently experimental.
FUNCTIONS
write_DMD_helper_h
Devel::MAT::Dumper::Helper->write_DMD_helper_h;
Writes the DMD_helper.h file to the current working directory. To cause the compiler to actually find
this file, see extra_compiler_flags.
extra_compiler_flags
@flags = Devel::MAT::Dumper::Helper->extra_compiler_flags;
Returns a list of extra flags that the build scripts should add to the compiler invocation. This enables
the C compiler to find the DMD_helper.h file, and also defines a symbol "HAVE_DMD_HELPER" which the XS
code can then use in "#ifdef" guards:
#ifdef HAVE_DMD_HELPER
...
#endif
extend_module_build
Devel::MAT::Dumper::Helper->extend_module_build( $build );
A convenient shortcut for performing all the tasks necessary to make a Module::Build-based distribution
use the helper.
XS MACROS
The header file provides the following macros, which may be used by the XS module.
DMD_SET_PACKAGE_HELPER
typedef int DMD_Helper(pTHX_ DMDContext *ctx, const SV *sv);
DMD_SET_PACKAGE_HELPER(char *packagename, DMD_Helper *helper);
This macro should be called from the "BOOT" section of the XS module to associate a helper function with
a named package. Whenever an instance of an object blessed into that package is encountered by the
dumper, the helper function will be called to provide extra information about it.
When invoked, the helper function is passed a pointer to the blessed SV directly - remember this will be
the underlying object storage and not the "RV" that the Perl code uses to refer to it. It should return
an integer that is the sum total of the return values of all the calls to "DMD_ANNOTATE_SV" that it made,
or 0 if it did not make any.
The ctx pointer to the helper function points at an opaque structure internal to the "Devel::MAT::Dumper"
module. Helper functions are not expected to interact with it, except to pass it on any "DMD_DUMP_STRUCT"
calls it may make.
DMD_SET_MAGIC_HELPER
typedef int DMD_MagicHelper(pTHX_ DMDContext *ctx, const SV *sv, MAGIC *mg);
DMD_SET_MAGIC_HELPER(MGVTBL *vtbl, DMD_MagicHelper *helper);
This macro should be called from the "BOOT" section of the XS module to associate a helper function with
a given magic virtual method table. Whenever an SV with that kind of magic is encountered by the dumper,
the helper function will be called to provide extra information about it.
When invoked, the helper function is passed a pointer to the magical SV as well as the specific "MAGIC"
instance responsible for this call. It should return an integer that is the sum total of the return
values of all the calls to "DMD_ANNOTATE_SV" that it made, or 0 if it did not make any.
The ctx pointer to the helper function points at an opaque structure internal to the "Devel::MAT::Dumper"
module. Helper functions are not expected to interact with it, except to pass it on any "DMD_DUMP_STRUCT"
calls it may make.
DMD_ADD_ROOT
DMD_ADD_ROOT(SV *sv, const char *name);
This macro should be called from the "BOOT" section of the XS module to add another root SV pointer to be
added to the root SVs table. This is useful for annotating static SV pointers or other storage that can
refer to SVs or memory structures within the module, but which would not be discovered by a normal heap
walk.
The name argument is also used as the description string within the "Devel::MAT" UI. It should begin with
either a "+" or "-" character to annotate that the root contains a strong or weak reference,
respectively.
DMD_ANNOTATE_SV
DMD_ANNOTATE_SV(const SV *referrer, const SV *referrant, const char *label);
This macro should be called by a helper function, in order to provide extra information about the SV it
has encountered. The macro notes that a pointer exists from the SV given by referrer, pointing at the SV
given by referrant, described by the given string label.
Each call to this macro returns an integer, which the helper function must accumulate the total of, and
return that number to the caller.
Not that it is not necessary that either the referrer nor the referrant actually are the SV that the
helper function encountered. Arbitrary annotations between SVs are permitted. Additionally, it is
permitted that the SV addresses do not in fact point at Perl SVs, but instead point to arbitarary data
structures, which should be written about using "DMD_DUMP_STRUCT".
DMD_DUMP_STRUCT
typedef struct {
const char *name;
enum {
DMD_FIELD_PTR,
DMD_FIELD_BOOL,
DMD_FIELD_U8,
DMD_FIELD_U32,
DMD_FIELD_UINT,
} type;
void *ptr; /* for type=PTR */
bool b; /* for type=BOOL */
long n; /* for the remaining numerical types */
} DMDNamedField;
DMD_DUMP_STRUCT(DMDContext *ctx, const char *name, void *addr, size_t size,
size_t nfields, const DMDNamedField fields[]);
This macro should be called by a helper function, in order to provide extra information about a memory
structure that is not a Perl SV. By using this macro, the module can write information into the dumpfile
about the memory structure types and values that it operates on, allowing the "Devel::MAT" tooling to
operate on it - such as by following pointers and finding or identifying the contents.
The code invoked by this macro at runtime actually does two separate tasks, which are closely related.
The first time a call is made for any particular string value in name, the function will write metadata
information into the dumpfile which gives the name and type of each of the fields. Every call, including
this first one, will write the values of the fields associated with a single instance of the structure,
by reusing the information provided to the first call.
The ctx argument must be the value given to the helper function. addr gives the pointer address of the
structure itself. size should give its total size in bytes (often sizeof(*ptr) is sufficient here).
The name, nfields, and fields parameters between them are used both by the initial metadata call, and for
every structure instance. name gives a unique name to this type of structure - it should be composed of
the base name of the XS module, and a local name within the module, separated by "/". nfields gives the
number of individual field instances given in the fields array, which itself provides a label name, a
type, and an actual value.
The first two fields of the "DMDNamedField" structure give its name and type, and one subsequent field
should be set to give the value for it. Which field to use depends on the type.
Note that it is very important, once a structure name has been seen the first time, that every subsequent
call for the same must have exactly the same count of fields, and the types of each of them. The values
of the fields, as well as the size of the structure overall, are recorded for every call, but the typing
information is stored only once on that first call. It is best to ensure that the module source contains
only a single instance of this macro for a given structure name, thus ensuring the type information will
always be consistent.
HANDLING C-LEVEL STRUCTURES
For example, given a C struct definition such as:
struct MyData {
SV *buf;
int state;
AV *more_stuff;
};
A call to provide this to the dumpfile could look like:
struct MyData *dat = ...;
DMD_DUMP_STRUCT(ctx, "Module::Name/MyData", dat, sizeof(struct MyData),
3, ((const DMDNamedField []){
{"the buf SV", DMD_FIELD_PTR, .ptr = dat->buf},
{"the state", DMD_FIELD_UINT, .n = dat->state},
{"the more_stuff AV", DMD_FIELD_PTR, .ptr = dat->more_stuff},
})
);
Conventionally, names of unique fields all begin "the ...". Fields that point to other Perl SVs should
explain what kind of SV they point to, so any discrepencies can be observed in the tooling later on.
A call to this macro alone is likely not enough to fully link the information in the dumpfile, however.
It is unlikely that any pointer value that the dumper itself will encounter would point to this data
structure - if so, Perl would not know how to deal with it. It's likely that the module would use some
technique such as storing a pointer in the UV field of a blessed SCALAR SV, as a way to retain it. In
that typical example, a helper function should be attached to the package name that SV would be blessed
into. When the dumper encounters that blessed SV it will invoke the helper function, which can then call
"DMD_DUMP_STRUCT" and also use "DMD_ANNOTATE_SV" to provide a linkage between the blessed SV containing
the UV value, and this structure.
static int dumppackage_mydata(pTHX_ DMDContext *ctx, const SV *sv)
{
int ret = 0;
struct MyData *dat = NUM2PTR(struct MyData *, SvUV((SV *)sv));
DMD_DUMP_STRUCT(...);
ret += DMD_ANNOTATE_SV(sv, (SV *)dat, "the MyData structure");
return ret;
}
BOOT:
There is no ordering requirement between these two - the annotation linking the pointers can be made
before, or after, the structure itself has been written. In fact, there are no ordering constraints at
all; feel free to write the data structures and annotations in whatever order is most natural to the
dumper code,
AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
perl v5.40.1 2025-02-18 Devel::MAT::Dumper::Helper(3pm)