This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Committed: fix two simulator lseek syscall bugs (sim/cris and generic)
- From: Hans-Peter Nilsson <hans-peter dot nilsson at axis dot com>
- To: gdb-patches at sourceware dot org
- Date: Thu, 7 Oct 2010 02:13:43 +0200
- Subject: Committed: fix two simulator lseek syscall bugs (sim/cris and generic)
These were noticed while investigating
<http://gcc.gnu.org/PR45841>, a libstdc++ testsuite regression,
in which my autotester using the simulator flagged a regression,
a proper libstdc++ bug, but somewhat serendipitously for the
wrong reason; these bugs.
The lseek syscall is a gotcha. That bug might be there for
other ports (and I wouldn't be surprised if in other
simulators). The src/sim API to the host (struct cb_syscall)
uses "long" for syscall parameters. The cris-*-* target is
ILP32, and target syscall parameters, generally being unsigned
32-bit numbers and addresses are handled in the port as "USI"
(uint32_t). But, the lseek position parameter needs to be
sign-extended rather than zero-extended when on a LP64 host, or
you'll end up with 4G files (thankfully sparse) for writable
files, and wrong positions or errors for other files. I
couldn't think of any other syscall parameter requiring
sign-extension for this target.
Speaking of lseek errors, the callback for lseek didn't handle
them. Just a matter of wrapping it using the correct idiom,
like for other nearby I/O calls.
Regression-tested for cris-elf, committed.
sim/testsuite:
* sim/cris/c/seek3.c, sim/cris/c/seek4.c: New tests.
sim/cris:
* traps.c (cris_break_13_handler): Pass lseek
offset parameter as sign-extended.
sim/common:
* callback.c (os_lseek): Call wrap on lseek result.
Index: sim/cris/traps.c
===================================================================
RCS file: /cvs/src/src/sim/cris/traps.c,v
retrieving revision 1.22
diff -u -p -r1.22 traps.c
--- sim/cris/traps.c 14 Jan 2009 10:53:06 -0000 1.22
+++ sim/cris/traps.c 6 Oct 2010 05:06:01 -0000
@@ -1477,6 +1477,14 @@ cris_break_13_handler (SIM_CPU *current_
s.arg2 = arg2;
s.arg3 = arg3;
+ /* The type of s.arg2 is long, so for hosts with 64-bit longs, we need
+ to sign-extend the lseek offset to be passed as a signed number,
+ else we'll truncate it to something > 2GB on hosts where sizeof
+ long > sizeof USI. We avoid doing it for all syscalls, as arg2 is
+ e.g. an address for some syscalls. */
+ if (callnum == TARGET_SYS_lseek)
+ s.arg2 = (SI) arg2;
+
if (callnum == TARGET_SYS_exit_group
|| (callnum == TARGET_SYS_exit && current_cpu->m1threads == 0))
{
Index: sim/common/callback.c
===================================================================
RCS file: /cvs/src/src/sim/common/callback.c,v
retrieving revision 1.25
diff -u -p -r1.25 callback.c
--- sim/common/callback.c 14 Jan 2009 10:53:05 -0000 1.25
+++ sim/common/callback.c 6 Oct 2010 05:06:01 -0000
@@ -278,7 +278,7 @@ os_lseek (p, fd, off, way)
result = fdbad (p, fd);
if (result)
return result;
- result = lseek (fdmap (p, fd), off, way);
+ result = wrap (p, lseek (fdmap (p, fd), off, way));
return result;
}
--- /dev/null Tue Oct 29 15:57:07 2002
+++ sim/testsuite/sim/cris/c/seek3.c Wed Oct 6 00:53:22 2010
@@ -0,0 +1,49 @@
+/* Check for a sim bug, whereby the position was always unsigned
+ (truncation instead of sign-extension for 64-bit hosts). */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+ FILE *f;
+ const char fname[] = "sk1test.dat";
+ const char tsttxt[]
+ = "A random line of text, used to test correct read, write and seek.\n";
+ char buf[sizeof tsttxt] = "";
+ const char correct[] = "correct";
+ char buf2[sizeof correct] = {0};
+ int fd;
+
+ f = fopen (fname, "wb");
+ if (f == NULL
+ || fwrite (tsttxt, 1, strlen (tsttxt), f) != strlen (tsttxt)
+ || fclose (f) != 0)
+ {
+ printf ("fail\n");
+ exit (1);
+ }
+
+ /* We have to use file-descriptor calls instead of stream calls to
+ provoke the bug (for stream calls, the lseek call is canonicalized
+ to use SEEK_SET). */
+ fd = open (fname, O_RDONLY);
+ if (fd < 0
+ || read (fd, buf, strlen (tsttxt)) != strlen (tsttxt)
+ || strcmp (buf, tsttxt) != 0
+ || lseek (fd, -30L, SEEK_CUR) != 36
+ || read (fd, buf2, strlen (correct)) != strlen (correct)
+ || strcmp (buf2, correct) != 0)
+ {
+ printf ("fail\n");
+ exit (1);
+ }
+
+ printf ("pass\n");
+ exit (0);
+}
--- /dev/null Tue Oct 29 15:57:07 2002
+++ sim/testsuite/sim/cris/c/seek4.c Wed Oct 6 00:56:53 2010
@@ -0,0 +1,44 @@
+/* Check for a sim bug, whereby an invalid seek (to a negative offset)
+ did not return an error. */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+int
+main (void)
+{
+ FILE *f;
+ const char fname[] = "sk1test.dat";
+ const char tsttxt[]
+ = "A random line of text, used to test correct read, write and seek.\n";
+ char buf[sizeof tsttxt] = "";
+ int fd;
+
+ f = fopen (fname, "wb");
+ if (f == NULL
+ || fwrite (tsttxt, 1, strlen (tsttxt), f) != strlen (tsttxt)
+ || fclose (f) != 0)
+ {
+ printf ("fail\n");
+ exit (1);
+ }
+
+ fd = open (fname, O_RDONLY);
+ if (fd < 0
+ || lseek (fd, -1L, SEEK_CUR) != -1
+ || errno != EINVAL
+ || read (fd, buf, strlen (tsttxt)) != strlen (tsttxt)
+ || strcmp (buf, tsttxt) != 0)
+ {
+ printf ("fail\n");
+ exit (1);
+ }
+
+ printf ("pass\n");
+ exit (0);
+}
brgds, H-P