[comp.sys.amiga.programmer] Problem with SetFunction

davids@ucscf.UCSC.EDU (Dave Schreiber) (03/18/91)

I've been trying to patch AllocMem() as an experiment, and haven't been
able to get it to work.  I manage to patch it correctly with SetFunction(),
but when I try to print a carriage return using printf, the machine crashes
with a 8000 0006 error (CHK instruction).  Here's the code:

#include <exec/types.h>
#include <exec/exec.h>
#include <clib/exec_protos.h>

struct ExecBase *ExecBase;

APTR __regargs (*oldAllocMem)();
APTR __regargs newAllocMem(ULONG size,ULONG types);

#define NEG_AM_OFFSET 0xff3a

main()
{
   APTR temp;

   ExecBase=(struct ExecBase *)OpenLibrary("exec.library",0L);

   Forbid();      /*Stop multitasking*/

             /*Patch AllocMem()*/
   oldAllocMem=SetFunction(ExecBase,NEG_AM_OFFSET,newAllocMem);

   temp=(APTR)AllocMem(1000,0L); /*Goes to my routine & allocates*/
                                 /*the memory without a problem*/

   printf("%x ",temp);  /*Crashes here if there's a \n in that line*/
		  /*Otherwise, it just continues on fine*/

	       /*Undo patch*/
   printf("%x\n",SetFunction(ExecBase,NEG_AM_OFFSET,oldAllocMem));

   Permit();

   if(temp!=0L)
      FreeMem(temp,1000);  /*Again, doesn't crash*/

   CloseLibrary(ExecBase); /*Exits without a hitch*/
}

APTR __regargs newAllocMem(ULONG size,ULONG types)
{
   return(oldAllocMem(size,types));
}

If I change newAllocMem() so that it just returns NULL, the call to
AllocMem() in main() returns NULL; i.e. I know that calls to AllocMem() are
being routed to my module.  newAllocMem() as it is above also works without
a hitch.  But when I printf() an '\n' (or when I Permit() without undoing the
patch), it crashes.  Any suggestions?  BTW, I'm using a 3000 under 2.02
(under 1.3 it crashes as well, but it gives a 8000 0003 error).

Thanks in advance.

-- 
Dave Schreiber                               E-mail:  davids@ucscf.ucsc.edu
"It was fun learning about logic, but I don't see where or when I will ever
use it again."                               Disclaimer:

bairds@eecs.cs.pdx.edu (Shawn L. Baird) (03/18/91)

davids@ucscf.UCSC.EDU (Dave Schreiber) writes:



>I've been trying to patch AllocMem() as an experiment, and haven't been
>able to get it to work.  I manage to patch it correctly with SetFunction(),
>but when I try to print a carriage return using printf, the machine crashes
>with a 8000 0006 error (CHK instruction).  Here's the code:

[ stuff deleted ]

>   Forbid();      /*Stop multitasking*/

>             /*Patch AllocMem()*/
>   oldAllocMem=SetFunction(ExecBase,NEG_AM_OFFSET,newAllocMem);

>   temp=(APTR)AllocMem(1000,0L); /*Goes to my routine & allocates*/
>                                 /*the memory without a problem*/

>   printf("%x ",temp);  /*Crashes here if there's a \n in that line*/
>		  /*Otherwise, it just continues on fine*/

>	       /*Undo patch*/
>   printf("%x\n",SetFunction(ExecBase,NEG_AM_OFFSET,oldAllocMem));

>   Permit();

[ more stuff deleted ]

Here's my $0.02. Since you've stopped multi-tasking the console device,
which is another task, cannot run. Thus the crash. Since stdout doesn't
flush until it gets a newline... Try this instead:

   Forbid();      /*Stop multitasking*/

             /*Patch AllocMem()*/
   oldAllocMem=SetFunction(ExecBase,NEG_AM_OFFSET,newAllocMem);

   Permit();

   temp=(APTR)AllocMem(1000,0L); /*Goes to my routine & allocates*/
                                 /*the memory without a problem*/

   printf("%x\n",temp);  /*Crashes here if there's a \n in that line*/
		  /*Otherwise, it just continues on fine*/

   Forbid();

	       /*Undo patch*/
   tmpfunc=SetFunction(ExecBase,NEG_AM_OFFSET,oldAllocMem));

   Permit();

   printf("%x\n",tmpfunc); /* print out the address of the old routine */
   /* if tmpfunc != newAllocMem then somebody else probably also did a
      SetFunction() while we were running I guess */

| Shawn L. Baird                        | Or via US Snail:                  |
| bairds@eecs.ee.pdx.edu                | 17650 SE Cason Rd.                |
| ...uunet!tektronix!psueea!eecs!bairds | Gladstone, OR  97027              |

bairds@eecs.cs.pdx.edu (Shawn L. Baird) (03/18/91)

Kludge fix mode:

   It crashes if you Permit() after the SetFunction()? Hmmm... Not sure why
that would be the case. Try something fun like doing a SetFunction() and
then exiting, freeing up the memory that newAllocMem() was at. That ought to
create a few special effects. ;)

| Shawn L. Baird                        | Or via US Snail:                  |
| bairds@eecs.ee.pdx.edu                | 17650 SE Cason Rd.                |
| ...uunet!tektronix!psueea!eecs!bairds | Gladstone, OR  97027              |

rosenber@ra.abo.fi (Robin Rosenberg INF) (03/19/91)

In article <13531@darkstar.ucsc.edu> davids@ucscf.UCSC.EDU (Dave Schreiber) writes:

>I've been trying to patch AllocMem() as an experiment, and haven't been
>able to get it to work.  I manage to patch it correctly with SetFunction(),
>but when I try to print a carriage return using printf, the machine crashes
>with a 8000 0006 error (CHK instruction).  Here's the code:

1. Stack checking off

2. Make sure your global as accessible, either
compile for absoulute addressing or declare your patch function using
__saveds to get A4 right.

3. AllocMem has THREE parameters: size(d0),types(d1) and execbase(a6).
Declared them properly when writing the patch. Something like. Declare
the pointer to the old function the same way.

void * (* __asm __saveds oldallocmem)(
register __d0 ULONG size,
register __d1 ULONG types,
register __a6 struct ExecBase *SysBase);

void *__asm __saveds myallocmem(
	register __d0 ULONG size,
	register __d1 ULONG types,
	register __a6 struct ExecBase *SysBase)
{
	return (*oldallocmem)(size,types,SysBase);
}

-----
	Robin

forgeas@swinjm.UUCP (Jean-Michel Forgeas) (03/19/91)

In article <13531@darkstar.ucsc.edu>, Dave Schreiber writes:

> APTR __regargs newAllocMem(ULONG size,ULONG types);
> [...]
>    oldAllocMem=SetFunction(ExecBase,NEG_AM_OFFSET,newAllocMem);
> [...]
> APTR __regargs newAllocMem(ULONG size,ULONG types)
> {
>    return(oldAllocMem(size,types));
> }

Just an idea: when it sees __regargs, the compiler assigns registers
to parameters, and in your case should use D0/D1. But did you verify
it with a small disassembly of newAllocMem() ?

> temp=(APTR)AllocMem(1000,0L); /*Goes to my routine & allocates*/
>                               /*the memory without a problem*/

How are you sure that 'temp' is something valid ?

> If I change newAllocMem() so that it just returns NULL, the call to
> AllocMem() in main() returns NULL; i.e. I know that calls to AllocMem() are
> being routed to my module.  newAllocMem() as it is above also works without
> a hitch.  But when I printf() an '\n' (or when I Permit() without undoing the
> patch), it crashes.  Any suggestions?  BTW, I'm using a 3000 under 2.02
> (under 1.3 it crashes as well, but it gives a 8000 0003 error).

Seems that it crashes every time newAllocMem() calls oldAllocMem().
1 - Either you call oldAllocMem with bad values into registers,
    don't forget that the a6 register must stay with ExecBase value.
2 - Either you don't call oldAllocMem() at all but jump into
    the 5th dimension.

Best regards,
    Jean-Michel
--
                                     \___/
Jean-Michel Forgeas                   \-/
cbmvax!cbmehq!cbmfra!swinjm!forgeas    |    The Software Winery
                                      -^-
                           And, where is the universe ?