Re: Random Solaris 7 x86 issues

2000-11-13 Thread e. boasson

(I hope this doesn't get me into trouble with the wine-devel mailing
list...  My Netscape doesn't seem to understand it.)

To whomever is interested,

A couple of minutes hacking at my Solaris 8 (Sparc) machine during the
lunch break yields the attached code that seems to emulate Linux'
behaviour.  Do whatever you feel is best.

My $0.02,

Erik Boasson.

-- 

[Unclassified]

#include sys/types.h
#include sys/wait.h
#include sys/stat.h
#include sys/mman.h
#include errno.h
#include unistd.h
#include fcntl.h
#include assert.h
#include alloca.h
#include stdio.h
#include string.h
#include signal.h
#include procfs.h


static int is_mapped_test (uintptr_t vaddr, size_t size,
   const prmap_t *asmap, int n)
{
  int i = 0, j = n;

  while (i  j)
  {
int m = (i + j) / 2;
const prmap_t *o = asmap[m];

if ((uintptr_t) o-pr_vaddr = vaddr + size)
  j = m;
else if ((uintptr_t) o-pr_vaddr + o-pr_size = vaddr)
  i = m + 1;
else
  return 1;
  }

  return 0;
}


static void *safe_mmap (void *addr, size_t len, int prot, int flags,
int fildes, off_t off)
{
  if (flags  MAP_FIXED)
return mmap (addr, len, prot, flags, fildes, off);
  else
  {
int stat = 0;
pid_t pid;
int fd;
struct stat sb;
prmap_t *asmap;
void *actual_addr;

assert ((fd = open ("/proc/self/rmap", O_RDONLY)) != -1);
if ((pid = vfork ()) == -1)
{
  perror ("is_mapped: vfork");
  abort ();
}
else if (pid == 0)
{
  fstat (fd, sb);
  asmap = alloca (sb.st_size);
  read (fd, asmap, sb.st_size);
  if (is_mapped_test ((uintptr_t) addr, len, asmap,
  sb.st_size / sizeof (prmap_t)))
_exit (EADDRINUSE);
  else if ((actual_addr = mmap (addr, len, prot, flags | MAP_FIXED,
fildes, off)) == (void *) -1)
_exit (errno);
  else if (actual_addr != addr)
  {
munmap (actual_addr, len);
kill (getpid (), SIGKILL);
  }
  else
  {
_exit (0);
  }
}
else if (waitpid (pid,  stat, WNOHANG) != pid)
{
  perror ("is_mapped: waitpid");
  abort ();
}
close (fd);
if (!WIFEXITED (stat))
  return mmap (addr, len, prot, flags, fildes, off);
else if (WEXITSTATUS (stat) == 0)
  return addr;
else if (WEXITSTATUS (stat) == EADDRINUSE)
  return mmap (addr, len, prot, flags, fildes, off);
else
{
  errno = WEXITSTATUS (stat);
  return (void *) -1;
}
  }
}


/*/


#include time.h
#include stdio.h
#include stdlib.h


void try (uintptr_t vaddr, size_t size)
{
  void *a;
  a = safe_mmap ((void *) vaddr, size, PROT_READ | PROT_WRITE,
 MAP_PRIVATE | MAP_ANON, -1, 0);
  printf ("%8x .. %8x  %8p %s\n", vaddr, vaddr + size, a, strerror (errno));
  if (a != (void *) -1) munmap (a, size);
}


int main (int argc, char **argv)
{
  char buf[128];
  int i;

  sprintf (buf, "/usr/proc/bin/pmap %d", (int) getpid ());
  system (buf);

  srandom (time (0));
  
  for (i = 1; i  argc; i++)
  {
uintptr_t vaddr;
size_t size;

if (sscanf (argv[i], "%x+%x", vaddr, size) == 2)
{
  try (vaddr, size);
}
else
{
  int n = atoi (argv[i]);
  while (n--  0)
  {
do {
  vaddr = random ()  -8192;
  size = (random () % 1048576)  -8192;
} while (vaddr + size  vaddr);
  
try (vaddr, size);
  }
}
  }

  return 0;
}



RE: Random Solaris 7 x86 issues

2000-11-13 Thread Patrik Stridvall

 (I hope this doesn't get me into trouble with the wine-devel mailing
 list...  My Netscape doesn't seem to understand it.)

My Microsoft Outlook understands it perfectly.
 
 To whomever is interested,

I am. :-)
 
 A couple of minutes hacking at my Solaris 8 (Sparc) machine during the
 lunch break yields the attached code that seems to emulate Linux'
 behaviour.  Do whatever you feel is best.

Intresting. The vfork confused me at first but I guess
it is for suspending the other threads in the process.
The Solaris 2.6 man page says that it suspends the
parent process and meantions that for multithreaded
process only the thread of control is borrowed.
It doesn't explictly says that all other threads
in the parent process are suspended but I guess
they are.

Since Wine on Solaris maps Win32 processes to
Solaris processes and Win32 threads to Solaris threads
(or rather LWP:s) it might just fix the race Alexandre
and/or Ulrich was talking about. 

However I can't test your application with Solaris 2.6 (Intel)
since it lacks MAP_ANON. I think that it is possible to
do that with a temporary dummy file instead and I think
there is code somethere in Wine that actually does this.




RE: Random Solaris 7 x86 issues

2000-11-10 Thread Patrik Stridvall

 Here are various things I'm seeing.
 
 1) Running anything produces:
 
  err:dosmem:setup_dos_mem Cannot use first megabyte for 
 DOS address
  space, please report
 
 2) Solitaire seems to work fine.
 
 3) Running telnet produces:
 
  err:win32:do_relocations FATAL: Need to relocate 
 C:Ă–WINDOWSĂ–TELNET.EXE,
  but no relocation records present (stripped during 
 link). Try to run
  that file directly
 
The following patch to map_image allows telnet to start up:
[snip]

OK. mmap on Solaris has slightly different semantics than
mmap on Linux if an address is specified and/or MAP_FIXED is
specified. The other cases are the same however.

I don't remember exactly what the difference is but IIRC on
Linux if an address is specified and the address is
page aligned it maps on that adress regardless whether
MAP_FIXED is specified.

Solaris on the other hand uses the address only as a hint
regardless of whether it is page aligned or not unless
of course MAP_FIXED is specified.

So this means that your patch might indead be the correct fix.

Ulrich know more about this than I do. Ulrich?

PS. BTW does an addition of MAP_FIXED in setup_dos_mem help?




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Ulrich Weigand


Patrik Stridvall wrote:

 OK. mmap on Solaris has slightly different semantics than
 mmap on Linux if an address is specified and/or MAP_FIXED is
 specified. The other cases are the same however.
 
 I don't remember exactly what the difference is but IIRC on
 Linux if an address is specified and the address is
 page aligned it maps on that adress regardless whether
 MAP_FIXED is specified.
 
 Solaris on the other hand uses the address only as a hint
 regardless of whether it is page aligned or not unless
 of course MAP_FIXED is specified.
 
 So this means that your patch might indead be the correct fix.
 
 Ulrich know more about this than I do. Ulrich?

The problem is the following:  if you pass MAP_FIXED to mmap(), 
it *will* use this address no matter what.  Especially, if there 
are already *other* mappings in that range, they will just be zapped.  
This is same for both Linux and Solaris.

On the other hand, if you do *not* pass MAP_FIXED, the address 
passed to mmap() is only a *hint* of where to place the mapping.
Both Linux and Solaris are free to chose some other address. In
no case will old mappings be affected.  Again, the semantics is
the same for both Linux and Solaris.

However, the *implementation* is quite different:  Linux will
always try to place the mapping at exactly the address specified,
and will only chose a different address if the other is already
taken.  Solaris, however, will nearly always move the mapping
to some other address, apparently due to efficiency considerations.

This creates a problem for Wine, because be sometimes *have* to
place a mapping at a particular address, e.g. non-relocateable
executable images.  What we need here is a routine that tries 
to place the mapping at exactly the specified address, but if
this is not possible, does *not* zap any other mappings but
returns an error.

On top of the Linux mmap(), this is easily done:  just call mmap()
with the address, and without MAP_FIXED, and check the return
value:  if the system chose another address, we know that we
have failed.  On top of the Solaris mmap(), we have a problem:
we can't use MAP_FIXED as this might zap other mappings, and
we can't *not* use MAP_FIXED, because then the system nearly
never choses the address we need, even though it were possible.

One possible solution would be to perform ourselves a check
whether the target region is free from other mappings, and
if so, use mmap() with MAP_FIXED.  One way to do this would
be to scan the proc file system entry for the current process
to find out the current mappings.  (Another way would be to
check our own reprentation of the address space as list of
FILE_VIEW data structures.  We need to take care that we don't
overlook system mappings in this case ...)  There is also a not 
quite trivial problem of how to avoid race conditions here ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  [EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Ulrich Weigand


Alexandre Julliard wrote:

 Does anybody know exactly what Solaris does?  Does it simply round the
 address to some nearest boundary, or does it pick a completely random
 address?  If it's just rounding we could allocate a larger area and
 use the part that we wanted, but if the address is random this won't
 work. 

Well, a little test program shows (on Solaris 2.5.1):
1234 -- ef6f
 -- ef6c
1000 -- ef6b
 -- ef6a

and on Solaris 2.6:
1234 -- ef6f
 -- ef6d
1000 -- ef6c
 -- ef6b

and on Solaris 2.7:
1234 -- ff39
 -- ff37
1000 -- ff36
 -- ff35

all on Sparc; always 16K allocations.

So it would appear that Solaris completely ignores the passed
address, and just sorts all mmaps() nicely together ;-)

 And no, MAP_FIXED does not work since it will wipe out existing
 mappings at this address.

Yes.  Except if we check ourselves in advance ...


Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  [EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Alexandre Julliard

Patrik Stridvall [EMAIL PROTECTED] writes:

 Solaris on the other hand uses the address only as a hint
 regardless of whether it is page aligned or not unless
 of course MAP_FIXED is specified.

Does anybody know exactly what Solaris does?  Does it simply round the
address to some nearest boundary, or does it pick a completely random
address?  If it's just rounding we could allocate a larger area and
use the part that we wanted, but if the address is random this won't
work. And no, MAP_FIXED does not work since it will wipe out existing
mappings at this address.

-- 
Alexandre Julliard
[EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread John Wehle

 The problem is the following:  if you pass MAP_FIXED to mmap(), 
 it *will* use this address no matter what.  Especially, if there 
 are already *other* mappings in that range, they will just be zapped.  

Yes. :-(

 One possible solution would be to perform ourselves a check
 whether the target region is free from other mappings, and
 if so, use mmap() with MAP_FIXED.  One way to do this would
 be to scan the proc file system entry for the current process
 to find out the current mappings.  (Another way would be to
 check our own reprentation of the address space as list of
 FILE_VIEW data structures.  We need to take care that we don't
 overlook system mappings in this case ...)  There is also a not 
 quite trivial problem of how to avoid race conditions here ...

I started to code this last night using mincore to check each page
in the target region one at a time (which should be somewhat portable),
however I didn't see an easy / obvious way to ensure that all other
threads are quiescent.

-- John
-
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: [EMAIL PROTECTED]  |
|John Wehle| Fax: 1-215-540-5495  | |
-





Re: Random Solaris 7 x86 issues

2000-11-10 Thread Alexandre Julliard

Ulrich Weigand [EMAIL PROTECTED] writes:

 So it would appear that Solaris completely ignores the passed
 address, and just sorts all mmaps() nicely together ;-)

Great :-(  And what does the address space look like at startup?
Where does it allocate the main exe and the .so libraries?  Maybe we
can reserve the addresses we need like 0 and 0x0040 with a
MAP_FIXED at startup.

  And no, MAP_FIXED does not work since it will wipe out existing
  mappings at this address.
 
 Yes.  Except if we check ourselves in advance ...

You'd need to completely freeze all threads first, because you never
know if some libc function is not going to change mappings.

-- 
Alexandre Julliard
[EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Ulrich Weigand


John Wehle wrote:

 I started to code this last night using mincore to check each page
 in the target region one at a time (which should be somewhat portable),

I don't think mincore is appropriate, as we must check whether there *is*
a mapping, not just whether some of its pages are actually present in
physical memory.  Even if a mapping happens to be completely paged out
we still must not zap it.   

Scanning the list of mappings from the proc file system should work,
though.

 however I didn't see an easy / obvious way to ensure that all other
 threads are quiescent.

This is indeed the main problem here ...


Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  [EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Ulrich Weigand


  I don't think mincore is appropriate, as we must check whether there *is*
  a mapping, not just whether some of its pages are actually present in
  physical memory.
 
 Sure it is.  The question is did mincore return an *error* for the page
 being checked (in which case nothing is mapped there) or did it return
 zero (in which case something is mapped there).  

Ah, sorry.  You're right, of course.

 Using mincore should be somewhat more portable than digging around /proc.

Yes.  The /proc format changed even across Solaris versions :-/


Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  [EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread Ulrich Weigand


Alexandre Julliard wrote:

 Great :-(  And what does the address space look like at startup?
 Where does it allocate the main exe and the .so libraries?  Maybe we
 can reserve the addresses we need like 0 and 0x0040 with a
 MAP_FIXED at startup.

Well, my little test app looks like this:
7499:   ./test
0001  8K read/exec /home/inf1/weigand/test
0002  8K read/write/exec   /home/inf1/weigand/test
FF28656K read/exec /usr/lib/libc.so.1
FF332000 32K read/write/exec   /usr/lib/libc.so.1
FF33A000  8K read/write/exec [ anon ]
FF35 16K write   [ anon ]
FF36 16K write   [ anon ]
FF37 16K write   [ anon ]
FF38 16K read/exec /usr/platform/sun4u/lib/libc_psr.so.1
FF39 16K write   [ anon ]
FF3A  8K read/exec /usr/lib/libdl.so.1
FF3B128K read/exec /usr/lib/ld.so.1
FF3DE000 16K read/write/exec   /usr/lib/ld.so.1
FFBEC000 16K read/write/exec [ stack ]
 total  960K

So at least the libraries are no problem.

The executable base address is not so nice, but there we
could probably fiddle around with linker scripts ...

Note that this is on Sparc, as I don't have access to a
Solaris/x86 box.  John, does it look much different there?


   And no, MAP_FIXED does not work since it will wipe out existing
   mappings at this address.
  
  Yes.  Except if we check ourselves in advance ...
 
 You'd need to completely freeze all threads first, because you never
 know if some libc function is not going to change mappings.

Yes, that's the problem. :-/

Bye,
Ulrich


-- 
  Dr. Ulrich Weigand
  [EMAIL PROTECTED]




Re: Random Solaris 7 x86 issues

2000-11-10 Thread John Wehle

 Note that this is on Sparc, as I don't have access to a
 Solaris/x86 box.  John, does it look much different there?

14420:  ./a
08046000  8K read/write/exec [ stack ]
0805  4K read/exec /tmp/a
0806  4K read/write/exec   /tmp/a
DFB3F000552K read/exec /usr/lib/libc.so.1
DFBC9000 28K read/write/exec   /usr/lib/libc.so.1
DFBD  4K read/write/exec [ anon ]
DFBD2000108K read/exec /usr/lib/ld.so.1
DFBF8000  4K read/exec /usr/lib/libdl.so.1
DFBFA000  4K read/write/exec [ anon ]
DFBFC000 12K read/write/exec   /usr/lib/ld.so.1
 total  728K

This is on Solaris 7 x86.

-- John
-
|   Feith Systems  |   Voice: 1-215-646-8000  |  Email: [EMAIL PROTECTED]  |
|John Wehle| Fax: 1-215-540-5495  | |
-