|
From: <sv...@va...> - 2005-11-13 16:52:58
|
Author: tom
Date: 2005-11-13 16:52:56 +0000 (Sun, 13 Nov 2005)
New Revision: 5116
Log:
Make the address space manager use fstat64 when it is available. There
are two reasons for this:
- It can cope with manjor and minor device numbers outside the
traditional 0-255 range.
- It returns correct results for x86 binaries on amd64 systems
where fstat returns uninitialised rubbish in the top 16 bits
of the device number.
We also make the /proc/self/maps reading code encode device numbers in
the new style to cope with manjor and minor device numbers outside the
traditional 0-255 range.
Modified:
trunk/coregrind/m_aspacemgr/aspacemgr.c
Modified: trunk/coregrind/m_aspacemgr/aspacemgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/m_aspacemgr/aspacemgr.c 2005-11-13 16:41:15 UTC (rev =
5115)
+++ trunk/coregrind/m_aspacemgr/aspacemgr.c 2005-11-13 16:52:56 UTC (rev =
5116)
@@ -508,6 +508,14 @@
return res.isError ? (-1) : 0;
}
=20
+#ifdef __NR_fstat64
+static Int aspacem_fstat64( Int fd, struct vki_stat64* buf )
+{
+ SysRes res =3D VG_(do_syscall2)(__NR_fstat64, fd, (UWord)buf);
+ return res.isError ? (-1) : 0;
+}
+#endif
+
static void aspacem_exit( Int status )
{
(void)VG_(do_syscall1)(__NR_exit_group, status );
@@ -545,8 +553,22 @@
/*OUT*/UWord* ino, /*OUT*/UInt* mode )
{
struct vki_stat buf;
- Int r =3D aspacem_fstat(fd, &buf);
+ Int r;
+#ifdef __NR_fstat64
+ struct vki_stat64 buf64;
+ /* Try fstat64 first as it can cope with minor and major device
+ numbers outside the 0-255 range and it works properly for x86
+ binaries on amd64 systems where fstat seems to be broken. */
+ r =3D aspacem_fstat64(fd, &buf64);
if (r =3D=3D 0) {
+ *dev =3D buf64.st_dev;
+ *ino =3D buf64.st_ino;
+ *mode =3D buf64.st_mode;
+ return True;
+ }
+#endif
+ r =3D aspacem_fstat(fd, &buf);
+ if (r =3D=3D 0) {
*dev =3D buf.st_dev;
*ino =3D buf.st_ino;
*mode =3D buf.st_mode;
@@ -3200,7 +3222,7 @@
UChar* filename;
UChar rr, ww, xx, pp, ch, tmp;
UInt ino, prot;
- UWord maj, min;
+ UWord maj, min, dev;
ULong foffset;
=20
read_procselfmaps_into_buf();
@@ -3311,11 +3333,32 @@
if (ww =3D=3D 'w') prot |=3D VKI_PROT_WRITE;
if (xx =3D=3D 'x') prot |=3D VKI_PROT_EXEC;
=20
+ /* Linux has two ways to encode a device number when it
+ is exposed to user space (via fstat etc). The old way
+ is the traditional unix scheme that produces a 16 bit
+ device number with the top 8 being the major number and
+ the bottom 8 the minor number.
+ =20
+ The new scheme allows for a 12 bit major number and
+ a 20 bit minor number by using a 32 bit device number
+ and putting the top 12 bits of the minor number into
+ the top 12 bits of the device number thus leaving an
+ extra 4 bits for the major number.
+ =20
+ If the minor and major number are both single byte
+ values then both schemes give the same result so we
+ use the new scheme here in case either number is
+ outside the 0-255 range and then use fstat64 when
+ available (or fstat on 64 bit systems) so that we
+ should always have a new style device number and
+ everything should match. */
+ dev =3D (min & 0xff) | (maj << 8) | ((min & ~0xff) << 12);
+
if (record_gap && gapStart < start)
(*record_gap) ( gapStart, start-gapStart );
=20
(*record_mapping) ( start, endPlusOne-start,=20
- prot, maj * 256 + min, ino,
+ prot, dev, ino,
foffset, filename );
=20
if ('\0' !=3D tmp) {
|