I don't see why we can't just add more error codes. There are only about 132 error codes at the moment, and return values are 32 bit.
A high bit mask with more detailed information would suffice, so you get the traditional error code in the low 8 bits, then information about the error location in the kernel in other bits. The kernel could export a map of more detailed information, so you could match up (and document) the reasons.
Obviously this is a breaking change, so your binary might have to set some flag to get the extended bits from the kernel.