This is looking a bit more complicated than I thought... I now
understand that I can't simply define the ARM machine in xml and
define it using virsh, as the CPU type (arm1136-r2) is rejected by
libvirt which can't test if it's valid or not.

So I think what Cole and Martin are suggesting is that I define a
dummy emulator (the wrapper script) which plays with the arguments
passed by libvirt and then calls the real emulator qemu-system-arm. I
had a quick go at this but I couldn't work out where to put the
wrapper script. I tried putting a wrapper (qemu-system-pi - written
in python) in /usr/bin, but virsh define couldn't find it.

You should put the whole path for the script in your xml. Instead of:
<emulator>/usr/libexec/qemu-kvm</emulator>
or something like the above, you should put the path to your wrapper-script.

If your system has selinux enabled, you might need to properly set
selinux context of the wrapper script so that it works.

Best regards,
Leonardo Garcia

I also get the impression that libvirt calls the wrapper during
define, to validate the arguments? So these calls also have to be
caught and passed to the real emulator.

Overall I am tempted to stick with my original method of simply
issuing the qemu-system-arm command directly from a script, but if
anyone can suggest how I can get the wrapper to be found - or point me
to an example of one - then I will keep trying. Thanks for all the
help and encouragement so far.