From: jqb AT netcom DOT com (Jim Balter) Subject: strerror that reports win32 errnos (was Re: Windows API calls that don't work?) 24 Mar 1997 21:51:38 -0800 Approved: cygnus DOT gnu-win32 AT cygnus DOT com Distribution: cygnus Message-ID: <3336FAD7.6AB9.cygnus.gnu-win32@netcom.com> References: <199703241434 DOT HAA06803 AT nz1 DOT netzone DOT com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit X-Mailer: Mozilla 3.01Gold (WinNT; I) Original-To: Mikey Original-CC: Colin Peters , cygnus Original-Sender: owner-gnu-win32 AT cygnus DOT com Mikey wrote: > > In answer to your last question, ld -s (strips) an executable incorrectly, > and from what I understand makes it unusable on NT, you keep getting not > owner errors, And the reason that it's "not owner" is that cygwin.dll defaults to EPERM when GetLastError() returns something it doesn't understand. To get something better: The following modified version of seterrno from syscalls.cc sets errno to 32000000 + the win32 errno instead of to EPERM, and fixes two bugs: ANDing GetLastError() with too small a mask, and running off the end of the errmap (I guess it just happens to be followed by a zero for the old code to work): /* Set `errno' based on GetLastError (). */ void seterrno (const char *file, int line) { // The oldcode used 0xFF, which is wrong. // Even the 0xFFFF probably isn't needed. int win32err = GetLastError () & 0xFFFF; for (int i = 0; i < sizeof errmap / sizeof errmap[0]; i++) if (win32err == errmap[i].w) { syscall_printf ("%s:%d %s -> errno %d\n", file, line, errmap[i].s, errmap[i].e); set_errno (errmap[i].e); return; } syscall_printf ("%s:%d seterrno: unknown win32 error %d!!\n", file, line, win32err); set_errno (32000000 + win32err); } Here's a rewrite of strerror.cc that returns a message that includes the errno when the errno is unknown, instead of returning the previous message returned, possibly NULL (clearly not intended but the result of a careless #if 0) and to use sys_err and sys_nerr instead of its own switch: // ANSI C pedantry: The standard says that strerror must act as though // no libc routine calls it, which includes perror. By calling an // internal routine and passing in a buffer, we avoid perror sharing the // one used by strerror. // XXX perror in newlib still calls strerror, not __error_string #define ERRHEAD "Error" #define STRERROR_BUFSIZE sizeof ERRHEAD + 12 extern char * sys_errlist[]; extern int sys_nerr; extern "C" char * __error_string (int errnum, char *buf) { if (0 <= errnum && errnum < sys_nerr) return sys_errlist[errnum]; __small_sprintf (buf, ERRHEAD " %d", errnum); return buf; } char * strerror (int errnum) { static char buf[STRERROR_BUFSIZE]; return __error_string (errnum, buf); } To make that work, add libcerr.o to DLL_OFILES in Makefile.in (formerly it only went into libcygwin.a, but now strerror in cygwin.dll needs it). And finally, fix libcerr.cc by adding the missing entry for errno 0: /* 0 */ "No error", The upshot of this is that, when I run a stripped executable from bash, it now says bash: ./foo: Error 32000193 and I can look up 193 in WINERROR.H or Windows32/Errors.h and see it is ERROR_BAD_EXEC_FORMAT. Something else one can do, if they don't mind the bloat, is to add a table or switch to strerror.cc to actually print out the win32 error message string. Or it could at least notice that the errno is 32...... and generate "win32 error ..." instead (I didn't bother, but would for something of product quality). -- - For help on using this list, send a message to "gnu-win32-request AT cygnus DOT com" with one line of text: "help".