I used the AVR Dragon to extract the contents of the flash memory (
avrdude -P usb -c dragon_jtag -p atmega1284p -U flash:r:flash.img:r) and compared it against the saved raw image file using the linux
cmpcommands. Sure enough, three pages of flash memory were set to
0xFF, probably from some erroneous page clear operation. Brown-out detection was disabled by the fuse settings to save power. Big mistake! What I think happened was as the voltage dipped below its valid range the microcontroller started executing random commands, including 3 SPM page clears, one of which was the first page of flash which holds the interrupt vector table. Valid execution was doomed.
What I should have done was to enable brown-out detection in the fuses, 2.7V seems the most appropriate setting for an 8MHz clock and 3.3V operation. To save power during sleeping the brown-out detection can be disabled with a call to
sleep_bod_disable(). Lesson learned!