Technologies and systems come and go but error messages stay. Of course, this is because errors are (or were, before exceptions) signified by integer error codes and libraries maintain, among other things, dictionaries of human-readable messages to go with such codes. Most system programmers, or any other programmers which still dwell on C instead of using something less close to the metal, can remember a subset of those codes simply because they've seen them often enough. I first started using "real" computers with DOS, and I still remember that error code 2 is "File not found". But there are other, more interesting ones. Executables and dynamically linked libraries often have those dictionaries embedded which are then only a strings away from plain view.
Left-over error messages from the olden days can tell us a lot about the way technology progressed, its current - and even still present - limitations and quirks.
The early days - WTF are we running on?
By inspecting a set of executables built for modern Windows systems, with a modern Microsoft C/C++ compiler, we can find gems like these:
- R6002 - floating point support not loaded
- R6019 - unable to open console device
Yes, there was a time where it was uncertain if the CPU the application is running on could operate on floating point values and a text-mode "console" (or a similar emulated device) was mandatory.
- While accessing a floppy disk, an ID address mark was not found.
- While accessing a floppy disk, the track address from the sector ID field was found to be different than the track address maintained by the controller.
- The floppy disk controller reported an error that is not recognized by the floppy disk driver.
- While accessing a floppy-disk, the controller returned inconsistent results via its registers.
but also once in a not quite expected one:
- The paging file cannot be created on a floppy diskette
... which is a good advice in any case, as swapping to a floppy disk would be - let's say - mildly insane.
Once again, something in it thinks it may have to do without an FPU:
- A real-mode application issued a floating-point instruction and floating-point hardware is not present
The question of bitness
NTDLL also references 16-bit Windows applications in several places, and other computer architectures such as PowerPC, ARM and MIPS but that is to be expected. More interestingly, a string in DBGENG.DLL mentions "Presentation manager (16-bit)", the first Windows "shell", the precursor to the Program Manager, the Start menu, the desktop and the Metro interfaces.
Somewhere along the line some function in INPUT.DLL apparently allows something to happen in 32-bit mode only, judging from the following message:
- %s is available only on 32 bit processes
This is not very surprising, as newer versions of Windows also locked down what applications could and could not do, in the name of security.
Executables of systems past
The MSVCR80.DLL recognizes executables by their extensions in some contexts, and those are of course: ".com, .bat, .cmd and .exe". .COM files are a very early form of executables, predating even MS-DOS. They are basically streams of x86 CPU instructions without any headers, setup, tables, or relocations, with only a rudimentary implied environment state (such as the address where they are loaded) and can only be executed in the "real mode" of such CPUs.
All this reflects the fact that the most popular combination of a system architecture and the operating system in the world is ridiculously backwards-compatible, being able to execute executables more than 30 years old. Thus the NTDLL contains the following error message:
- A virtual DOS machine (VDM) is loading, unloading, or moving an MS-DOS or Win16 program segment image
The Unix world has its own obsolete-yet-present executable format, the a.out, which supported a limited set of features, and while it had proper headers and support for complex program structure, in its various incarnations, it was not extensible and so was easily obsoleted. The default executable filename of this format (and what gave it its name) was a.out, and even today modern compilers and linkers, unless instructed otherwise, will generate an executable file named "a.out" by default.
Memory of whom?
A modern, 32-bit Windows executable contains the following messages:
- Obtained XMS handle %u
- Freed XMS handle %u
- Write to XMS failed
- Read from XMS failed
- Obtained EMS handle %u
- Freed EMS handle %u
- Write to EMS failed
- Read from EMS failed
Believe it or not, there came a time when 640 KiB was not enough, and people started working on ways to get around it. EMS and XMS were two ways in which MS-DOS applications could use more memory. EMS was the older and quirkier one, effectively working as a "in-memory swap space". Applications could reserve EMS memory in pages, work with this memory, and when they needed more, they would tell the EMS memory manager to swap out the memory they just used for some other pages. The memory manager would do so, and the old, real-mode x86 application would access the same memory addresses as before, but with new contents. XMS was the "real deal", using brand new CPU's support (on 286 and 386) to allow applications to really, natively use whatever they needed.
We'll only ever run this code in the US, right?
Localization and internationalization issues are a big topic in themselves. MSVCR80.DLL could, in certain circumstances, show the user the following error:
- Filename cannot be displayed on Win9x
The reason behind this is that in those olden days, Windows 95, 98 and their derivatives were "ASCII-mostly". They did support Unicode but they also still had the concept of "code pages" and most of the strings used in the system and third party applications were single-byte. The file system (VFAT) supported a 16-bit encoding of Unicode and it was possible to have files created either on another Win9x system using a different code page or on a Windows NT system with more pervasive Unicode support, whose names simply could not be represented in the currently running system.
Security? What security?
Microsoft has been notorious in its past as paying little to no attention to the challenges of maintaining a secure system in the Internet age. The remnants of old, insecure technologies are still present in NTDLL:
- The Windows password is too complex to be converted to a LAN Manager password. The LAN Manager password returned is a NULL string.
- You specified an incorrect password to a LAN Manager 2.x or MS-NET server.
The LAN Manager is Microsoft's earliest attempt on having a user-friendly system of shared folders and files, horribly insecure by today's standard. Until recently, Windows stored any user passwords both in a (slightly) more modern hash format, and in the old, easily breakable LM HASH format, allowing for trivial brute-forcing of logins.
Among other things, cmdial32.dll contains an error message which simply sounds fishy, without knowing the details:
- GetEapUserId - We are at winlogon or the credentials passed are of username/password type. So, simply returning.
netjoin.dll also seems a bit laid back about the whole password topic:
- NetpUpgradePreNT5JoinInfo: netlogon did not establish secure channel, machine password not updated. This is not a fatal error. netlogon will retry updating the password later.
Browsing through strings in the system32 folder is also highly entertaining. Among other things, you can find embedded XML, SQL queries, help messages, and even several variants of interpreted programming languages. Of course, if that is your thing :)
Doing a similar analysis on Unix-like systems, primarily Linux, is practically futile, because it is very rare to have old code laying around in actively used libraries. Executables are recompiled very often, at least for each new release of the system / distribution, and static old executables are hard to find. On top of that, Unix was sort of designed better from the start and there are less kludges present. The errno mechanism encodes only abstract system errors mostly decoupled from low-level details. The most exciting errors you can receive in this way are "Device not configured" or "Protocol not available."
Know of some more revealing, obsolete error messages? Post them in the comments section!