[net.arch] Where to do stack checking, etc.

jer@peora.UUCP (J. Eric Roskos) (09/09/85)

> The MMU is the answer.

I disagree with this.  Unless you design your microprocessor architecture
from the beginning to require an MMU.

I was thinking about this question this weekend while trying to debug two
very frustrating errors in a C program I was writing on my IBM PC (a UUCP-
interfacing mailer).  There were two things badly needed.

1) The ability to trap when JUST ONE particular address was generated as a
data reference.  There was this pointer, somewhere in this 80K program,
which was overwriting part of an error message, so that a garbage character
showed up whenever the error message came out.  Apparently it was just
using the byte in the error message as the location for a variable, instead
of the byte it was supposed to use, because the program ran perfectly -- it
just had this strange character in the middle of the error message.  Now,
if I could just have had the machine trap when that character was written
to, I could have found out immediately where the error was.  As it was, I
still don't know where the error is... and probably will have to spend
several hours hunting for it.  This isn't such a major addition to the
microprocessor; and the problem it solves is not that uncommon, and is one
of the most difficult to debug.

2) Checking for stack integrity.  In this same program, a return address on
the stack was getting overwritten, causing the program to branch off into
the data when some subroutine returned.  Finding this required putting in
some "I'm returning now...now I'm back" messages in a number of routines to
discover which one actually was doing it.  This one is a little harder to
implement, but certainly would help.*


The reason I say I disagree with the "in the MMU" approach is that
currently most people treat MMUs as optional devices.  This means that any
application in which you use a microprocessor but don't use an MMU won't
have access to such facilities; and I think that for microprocessors, the
non-MMU applications probably far exceed the ones that use MMUs (I'm
referring here to the use of microprocessors in controllers, etc.).

----------

*I'm sure at least someone is wondering what the cause of this error was...
Well, it turns out that with this particular C compiler, if you give
certain invalid values to the "mode" parameter of the creat() system call,
it overwrites the stack... don't ask me why...
-- 
Shyy-Anzr:  J. Eric Roskos
UUCP:       ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer
US Mail:    MS 795; Perkin-Elmer SDC;
	    2486 Sand Lake Road, Orlando, FL 32809-7642

res@ihlpl.UUCP (Rich Strebendt @ AT&T Information Systems - Indian Hill West; formerly) (09/11/85)

> > The MMU is the answer.
> 
> I disagree with this.  Unless you design your microprocessor architecture
> from the beginning to require an MMU.
> 
> I was thinking about this question this weekend while trying to debug two
> very frustrating errors in a C program I was writing on my IBM PC (a UUCP-
> interfacing mailer).  There were two things badly needed.
> 
> 1) The ability to trap when JUST ONE particular address was generated as a
> data reference.  

I agree with the usefulness of this ability -- though I would not limit it to
JUST ONE of anything.  I prefer the trap setting ability I had years ago
working with IBM TSS.  There were three types of traps that I found very useful
in debugging a large program:

	a) Trap on a data store into any location in a specified range.
	Trapping on stores to locations in the range 0-256 often caught stores
	through null or nearly null pointers.

	b) Trap on an instruction fetch from any location in a range of
	addresses.  Very handy for catching a wild branch.

	c) Trap on any change to a specified register.  Handy to monitor
	returns from subroutines (R13 changed, I think -- it has been a while!)
	to find out whither they were returning -- or when the return address
	was being clobbered.

> The reason I say I disagree with the "in the MMU" approach is that
> currently most people treat MMUs as optional devices.  This means that any
> application in which you use a microprocessor but don't use an MMU won't
> have access to such facilities; and I think that for microprocessors, the
> non-MMU applications probably far exceed the ones that use MMUs (I'm
> referring here to the use of microprocessors in controllers, etc.).

I strongly agree.  I am developing firmware (board resident software) for a
controller.  All addressing is done on-board without an MMU.  The
stack-overflow exception has helped catch and make known a couple of bugs.  The
trap facilities above would have made finding a couple of others a good bit
easier.

					Rich Strebendt
					...!ihnp4!iwsl6!res

dougp@ISM780.UUCP (09/11/85)

It's these kinds of problems which have led me to conclude that the *only*
reasonable debugging tool for micros is an in-circuit emulator.  Once you've
had the pleasure of being able to trap on exactly these conditions (specific
addresses being used to reference data, a particular data byte being written
somewhere, etc) you get really spoiled.

For an IBM PC, you might try the ATRON PC PROBE.  Atron is in the San Jose,
CA area, somewhere.  They have a real nice board which does reasonable
emulation and costs less than $2K.  The only catch is that you have to
start it from MS/PC-DOS (you can then re-invoke the bootstrap in the ROM,
however...).

Doug Pintar at Interactive Systems Corp.

jer@peora.UUCP (J. Eric Roskos) (09/16/85)

> For an IBM PC, you might try the ATRON PC PROBE.  Atron is in the San Jose,
> CA area, somewhere.  They have a real nice board which does reasonable
> emulation and costs less than $2K.

Yes, I've used ICEs before (I like the "logic analyzer" type that clip on
to the microprocessor, rather than an emulator, though, since those
emulators sometimes have strange timing properties).

But my point was, you shouldn't have to spend $2000... I mean, I certainly
am not going to for my personal IBM PC when I can just spend a few hours
(worth much less than $2000) and find it by hand.  If it's built into the
microprocessor, though, then that's a big improvement...
-- 
Shyy-Anzr:  J. Eric Roskos
UUCP: Ofc:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer
     Home:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jerpc!jer
  US Mail:  MS 795; Perkin-Elmer SDC;
	    2486 Sand Lake Road, Orlando, FL 32809-7642

mac@uvacs.UUCP (Alex Colvin) (09/16/85)

> > 1) The ability to trap when JUST ONE particular address was generated as a
> > data reference.  

The Honeywell (formerly GE) mainframes also have this ability, much like
the IBM machines cited above (335@ihlpl).  It does come in handy for
debugging the kernel, but since the address is absolute, it's not much use
to time-sharing users.

I'm still looking for a machine that will trap references to uninitialized
data.

res@ihlpl.UUCP (Rich Strebendt @ AT&T Information Systems - Indian Hill West; formerly) (09/19/85)

> > > 1) The ability to trap when JUST ONE particular address was generated as a
> > > data reference.  
> 
> The Honeywell (formerly GE) mainframes also have this ability, much like
> the IBM machines cited above (335@ihlpl).  It does come in handy for
> debugging the kernel, but since the address is absolute, it's not much use
> to time-sharing users.

Just a quick clarification on the IBM TSS/370 traps: those traps that
worked on addresses worked on virtual addresses.  Thus, they were of
great value to a time-sharing program developer.

					Rich Strebendt
					...!ihnp4!iwsl6!res

cdshaw@watmum.UUCP (Chris Shaw) (09/19/85)

In article <1599@peora.UUCP> jer@peora.UUCP (J. Eric Roskos) writes:
>1) The ability to trap when JUST ONE particular address was generated as a
>data reference.  

I've used a marvelous tool for this problem.. It's called a logic analyzer.
Unfortunately, they are expensive, and on systems which do a lot of
address translation, figuring out what address you REALLY want might be
a problem. For reasonably ordinary (micro) systems, however they're great.
I remember testing some 1802 code one time, using the most primitive debugging
method in existence: "It doesn't work, now figure out why !". A logic analyzer
killed my bug in no time.


Chris Shaw    watmath!watmum!cdshaw  or  cdshaw@watmath
University of Waterloo
A doze by any other name would be a sleep.
		- Shakesfeare

jer@peora.UUCP (J. Eric Roskos) (09/19/85)

> I'm still looking for a machine that will trap references to uninitialized
> data.

This is a hard problem.  My dissertation advisor (R. I. Winner) did a good
bit of research on this problem; see, for example, Winner, R. I.,
"Unassigned Objects," ACM TOPLAS, October, 1984.  The problem is that either
you have to have a unique bit pattern representing unassigned data (which
means there's one value that has a special meaning), or you have to have a
tag bit denoting "unassigned".

Various interesting models of memory are possible if you generalize the
unassigned object.
-- 
Shyy-Anzr:  J. Eric Roskos
UUCP: Ofc:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer
     Home:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jerpc!jer
  US Mail:  MS 795; Perkin-Elmer SDC;
	    2486 Sand Lake Road, Orlando, FL 32809-7642

tom@hcrvx1.UUCP (Tom Kelly) (09/19/85)

In article <2384@uvacs.UUCP> mac@uvacs.UUCP (Alex Colvin) writes:
>
>I'm still looking for a machine that will trap references to uninitialized
>data.

The Burroughs B7700 and its relatives (B6700, etc.) can do this.  All
memory locations have a three bit "tag" that indicates what kind of
data is stored in the memory location (code, operand, pointer, ...).

One of the tags (6) is "reserved for software control".  The hardware
considers it an unitialized operand.  Reference to it for the purpose
of computation causes a fault.  (There is a special code sequence
that can be used to get at the contents, but the compilers don't
use that code when using it as a normal operand).  A normal store
operation would overwrite the tag 6.

The Pascal compiler I worked on initialized all scalar local variables
to have tag 6.  If you used them without initializing them, you'd
get an abort with the message "Invalid Operand".  The Tasmania
Pascal compiler for the B6700 also put a tag 6 into the control variable
of a for loop at loop exit, since the value is supposed to be indeterminate.

I found this to be very helpful in debugging programs.

Tom Kelly  (416) 922-1937
{utzoo, ihnp4, decvax}!hcr!hcrvx1!tom

jans@orca.UUCP (Jan Steinman) (09/19/85)

In article <2384@uvacs.UUCP> mac@uvacs.UUCP (Alex Colvin) writes:
>>> 1) The ability to trap when JUST ONE particular address was generated as a
>>> data reference.  
>
>The Honeywell... mainframes also have this ability, ... but since the
>address is absolute, it's not much use to time-sharing users.
>
>I'm still looking for a machine that will trap references to uninitialized
>data.

(I still stand by my statement that such things belong in the (either on or
off chip) MMU.)

The NS32000 MMU has two registers for reference breakpointing.  These can be
set up for either data or program, initialized or not, as either physical or
virtual addresses.  I used them heavily for debugging a reference counting
garbage collector.  (Alright!  Who set that reference count to -1!)
Unfortunately, the reference breakpoints are broken on the latest mask.
8
-- 
:::::: Artificial   Intelligence   Machines   ---   Smalltalk   Project ::::::
:::::: Jan Steinman		Box 1000, MS 61-405	(w)503/685-2956 ::::::
:::::: tektronix!tekecs!jans	Wilsonville, OR 97070	(h)503/657-7703 ::::::

thoth@tellab2.UUCP (Marcus Hall) (09/21/85)

In article <2384@uvacs.UUCP> mac@uvacs.UUCP (Alex Colvin) writes:
>
>I'm still looking for a machine that will trap references to uninitialized
>data.

Hasn't this been implemented in some system by faking a parity error on all
uninitialized data.  After trapping on the parity error, if what's there is
the same as the bit "special" pattern, it's a pretty good guess that it's
uninitialized (as distinguished from a real live parity error).

I'm fairly sure that I have seen this somewhere, but I'm not quite sure where
it was.  It requires being able to write a word with bad parity (not too
hard, I guess) and is essentially very kludgy, but it doesn't cost an extra
bit just to tell if the area is uninitialized.

marcus hall
..!ihnp4!tellab1!tellab2!thoth

joe@petsd.UUCP (Joe Orost) (09/25/85)

In article <3563@tellab2.UUCP> thoth@tellab2.UUCP (Marcus Hall) writes:
>In article <2384@uvacs.UUCP> mac@uvacs.UUCP (Alex Colvin) writes:
>>I'm still looking for a machine that will trap references to uninitialized
>>data.
>
>Hasn't this been implemented in some system by faking a parity error on all
>uninitialized data.  After trapping on the parity error, if what's there is
>the same as the bit "special" pattern, it's a pretty good guess that it's
>uninitialized (as distinguished from a real live parity error).
>
>I'm fairly sure that I have seen this somewhere, but I'm not quite sure where
>it was.  It requires being able to write a word with bad parity (not too
>hard, I guess) and is essentially very kludgy, but it doesn't cost an extra
>bit just to tell if the area is uninitialized.

What happens on a machine with virtual memory, or even swapping?  How do you
swap out/in a parity error?  Do you have to lock in all pages that have
parity errors anywhere jammed in them?

What about an uninitialized array of bytes.  Say you want to set the first
byte = 0.  So, you execute a store byte instruction.  Now, most processors
that I know of do a store byte by doing a load fullword, inserting the byte,
and doing a store fullword.  BANGO!  a parity error!

No wonder Ada doesn't require unitialized variable checking!

				regards,
				joe

--

 ........        .........	Full-Name:  Joseph M. Orost
 .       .       .		UUCP:       ihnp4!vax135!petsd!joe
 . ......   ...  ........	ARPA:	    vax135!petsd!joe@BERKELEY
 .               .		Phone:      (201) 758-7284
 .               .........	Location:   40 19'49" N / 74 04'37" W
				US Mail:    MS 313; Perkin-Elmer; 106 Apple St
					    Tinton Falls, NJ 07724

jer@peora.UUCP (J. Eric Roskos) (09/27/85)

Joe Orost writes:
> What about an uninitialized array of bytes.  Say you want to set the first
> byte = 0.  So, you execute a store byte instruction.  Now, most processors
> that I know of do a store byte by doing a load fullword, inserting the byte,
> and doing a store fullword.  BANGO!*  a parity error!
>
> No wonder Ada doesn't require unitialized variable checking!

There's another problem related to arrays, also.  Suppose you have an
array, some of whose elements are uninitialized.  Then should the whole
array be treated as uninitialized, or not?  Either way you can find cases
where you need it to be the other way.  The above example relates to a more
general problem of implementing tagged architectures, viz., do you put
tags on bytes, or words, or what?  If you put the tags on bytes, then when
you have a data type that is, say, a word, you have that problem with
how to handle arrays with some uninitialized and some initialized elements,
again... (if you allow someone to access the word as bytes sometimes too,
at least).
-- 
Shyy-Anzr:  J. Eric Roskos
UUCP: Ofc:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jer
     Home:  ..!{decvax,ucbvax,ihnp4}!vax135!petsd!peora!jerpc!jer
  US Mail:  MS 795; Perkin-Elmer SDC;
	    2486 Sand Lake Road, Orlando, FL 32809-7642

       *"But, I want one what goes `WANGO'!"
				-- From a 1950s Pogo comic strip

atbowler@watmath.UUCP (Alan T. Bowler [SDG]) (10/11/85)

In article <2384@uvacs.UUCP> mac@uvacs.UUCP (Alex Colvin) writes:
>> > 1) The ability to trap when JUST ONE particular address was generated as a
>> > data reference.  
>
>The Honeywell (formerly GE) mainframes also have this ability, much like
>the IBM machines cited above (335@ihlpl).  It does come in handy for
>debugging the kernel, but since the address is absolute, it's not much use
>to time-sharing users.
>
>I'm still looking for a machine that will trap references to uninitialized
>data.

The timesharing user has the debugger which allows you to stop execution
on a reference to or an attempt to change any address or range of addresses