BE can be extended with user written "extensions". These are shared libraries with well-defined interfaces. BE can be told to load them at start-up.
Memory extensions allow BE to view and edit content in places other than in files.
This tells BE to load the file and whenever data at a memory address from address to address+filelength is accessed, to supply the data from the file.
Memory extensions may be written to provide either read-only, or read-write access to their data.
BE loads the memory extension DLL or shared library. It then passes the args and address to the memory extension, who does something of its own chosing with them. The memory extension DLL can then supply data to BE on request.
The file bememext.h documents the extension interface.
Memory extensions can of course cache the data they fetch. They might do this if it is inefficient to make request for the data, every time a new byte is requested. Often a memory extension will request data in blocks, around the specific address requested, taking advantage of the fact that subsequent requests are likely to be to nearby addresses, often in the same block.
When the user presses r (for refresh), BE simply re-requests the data, and it could come from a cache.
When the user presses R (for really refresh), BE tells memory extensions to discard any cache they could be holding, and then re-requests the data, thus ensuring a fresh view is presented.
Memory extensions which cache therefore have to support a function which makes them discard any cached data they might be holding.
When editing files, changes to the data are recorded in memory. When BE is closed down, it attempts to write back any changes back into the disk files where the data originally came from. This is referred to as flushing. BE will prompt you as to whether to save the changes back to disk.
it can make modifications immediately.
it can accumulate modifications, and 'make them good' in response to the flush request that the extension will receive when BE shuts down, if you say you would like your changes saved.
As most memory extensions provide a live view of some real-time data, they tend to opt for the first choice.
Memory extensions which don't apply updates immediately must therefore support a function which makes them flush the data from memory to whereever it should be stored.
When BE initially accesses an address, it discards address bits which are larger than the addressing mode in use (set via the -A command line argument, default is 32). eg: if we try to access address 0x0123456789abcdef and we are operating in 48 bit addressing mode, BE will truncate the address to 0x0000456789abcdef.
BE then attempts to satisfy the memory reference using this address by considering all memory sections (files and memory extensions) in turn, until one works.
If the address is greater than 0xffffffff BE will not attempt to satisfy it using a 32 bit memory extension.
When asked to access data at a given address, sophisticated memory extensions can call back into BE to access data at other address(es). They do this by providing a 'memory access' function, which BE calls at initialisation time to tell the extension the addresses of the callback functions.
The address does not go through the mappings explained in the above Addressing section again.
A memory extension which presents a shadow view of data is a simple use of this feature.
Multiple address decode is another use. Perhaps BE is being used as the data navigation part of a debugger, and the contents of a DRAM chip has been dumped. However, due to incomplete decoding of address bits, the same data appears at several places in the address map.
Summary statistics could be generated via memory extension. For example, when a memory access is made to one range of addresses, it reads another related range and counts how many bits are 1's. It then returns the count. This is an example of a memory extension providing a form of derived data.
The Mosquitto project (Really Small Messaging Broker, supporting the MQTT protocol) uses a BE memory extension to examine its post-mortem dumps. Their git includes rsmb.ini and tools/be/bersmb.cpp.
Another use is the in live-debug of running adapter cards, or other embedded devices. The memory extension can provide data bytes directly from the memory space of the adapter. args could be used to identify the slot the adapter is in. Alternatively, args could identify IO base addresses, memory window addresses, or a device driver to use to access the data. Memory extensions which do this, do exist, and they almost turn BE into a debugger (almost, because there is no run, stop, or single step). Run, stop and single step of an adapter could be driven by the options mechanism, if that were possible and/or desired. When using these, a customised initialisation file is typically also used, which understands all the structure definitions and variables used in the firmware on the adapter.
Yet another use might be providing BE with access to physical or virtual or process specific linear address spaces, perhaps via the use of a device driver. Shared memory windows might give addressibility of datastructures in other programs. A simple example of this is a memory extension which reads bytes from the /dev/kmem special device in the AIX or Linux environment. Using this, kernel device drivers may be debugged.
Perhaps bytes sent down a communications port could be made to appear as a stream of binary data.
Disassembler extensions allow BE to disassemble code in its address space.
The -C dx command line argument is a way of telling BE to load and use a disassembler extension for displaying any code in the data.
The same rules for naming and locating disassembly extensions apply, as for memory extensions.
The file bedisext.h documents the extension interface.
As the disassembler proceeds, it tests each address to see if it is within any field in definition marked with the nocode annotation. If so, it inserts the field instead, and continues disassembly afterwards. Sounds complicated, but this is a way of preventing the disassembly of data.
BEI86 exists within IBM SSD Hursley, but I have yet to secure its release. It decodes 8086/80186 opcodes.
BEARM exists within IBM SSD Hursley, but I have yet to secure its release. It decodes ARM6 opcodes.
BEPPC exists within IBM SSD Hursley. It decodes PowerPC opcodes.
BE is compiled with xlC C++, and uses the xlC C++ loadAndInit API to load the extension, named beextension, searching along the directories listed in the PATH and LIBPATH environment variables. The IBM xlC C++ compiler can be used to compile the extension. Unfortunately xlC C++ is expensive and I no longer have access to it. I have binaries for AIX 4.1.5 and AIX 4.3.
BE is compiled with xlC C++, and is capable of using loadAndInit or dlopen The IBM xlC C++ compiler can be used to compile the extension. I have no binaries for this mode.
BE is compiled with g++, and uses dlopen to load shared libraries named beextension.so, searching along the LIBPATH environment variable. g++ can be used to compile the extension. I have an AIX 5.3 binary, although I think the same source would compile fine on AIX 4.2.1 or later.
The g++ compiler can be used to compile the extension. BE uses the dlopen API to load the extension, which is named beextension.so. dlopen locates shared libraries by looking along the LD_LIBRARY_PATH, directories listed in the /etc/ld.so.cache file, and in the /usr/lib and /lib directories.
The aCC C++ compiler can be used to compile the extension. BE uses the shl_load API to load the extension, which is named beextension.sl. shl_load locates shared libraries by looking along the SHLIB_PATH. I reserve the right to switch-over-to or add-support-for using dlopen based shared library support.
The CC C++ compiler can be used to compile the extension. BE uses the dlopen API to load the extension, which is named beextension.so. dlopen locates shared libraries by looking along the LD_LIBRARY_PATH (it may also look in other places).
The gcc C++ compiler can be used to compile the extension. BE uses the dlopen API to load the extension, which is named beextension.dll.
The gcc C++ 3.3 compiler can be used to compile the extension. BE uses the dlopen API to load the extension, which is named beextension.so.
The Visual Studio 2013 can be used to compile the extension. BE uses the Win32 LoadLibrary API to load BEextension.DLL.
The IBM VisualAge C++ compiler (version 3.0, with fixpaks CTC306, CTD302 and CTU304, or later recommended) can be used to compile the extension. BE uses the OS/2 DosLoadModule API to load BEextension.DLL, which it finds by looking along the LIBPATH environment variable.
The Watcom C/C++ compiler (version 11.0b) and the CauseWay DOS extender (version 1.3 or later) can be used to compile the extension. Despite using the Watcom compiler, I still prefer NMAKE over WMAKE. BE uses the CauseWay provided LoadLibrary API to load the extension, which is named BEextension.DLL, which it seems to find by looking in the current directory or along the PATH.
The Watcom C/C++ compiler (version 11.0b) can be used to compile the extension. Despite using the Watcom compiler, I still prefer NMAKE over WMAKE. The DLL mechanism works by the DLL actually being an NLM named with a .ndl file extension. The DLL remains in memory for as long as BE needs it. The .ndl files must be on the search path so BE can find them.