July 29, 2004
"Walter" <newshound@digitalmars.com> wrote in message news:cea6oh$14c3$1@digitaldaemon.com...
>
> "Regan Heath" <regan@netwin.co.nz> wrote in message news:opsbvo8cpg5a2sq9@digitalmars.com...
> > Cool. Is "access violation" == SIGSEGV
> >
> > Does it catch anything else as well? It would be cool if I could catch:
> >
> > #define SIGINT          2       /* interrupt */
> > #define SIGILL          4       /* illegal instruction - invalid
function
> > image */
> > #define SIGFPE          8       /* floating point exception */
> > #define SIGSEGV         11      /* segment violation */
> > #define SIGTERM         15      /* Software termination signal from kill
> */
> > #define SIGBREAK        21      /* Ctrl-Break sequence */
> > #define SIGABRT         22      /* abnormal termination triggered by
abort
> > call */
> >
> > (the above are just the windows signals)
>
> Yes. If you want to see how it's done, see internal\deh.c function
> _d_translate_se_to_d_exception()
>
> > or the third option, my favourite:
> >   - The compiler defines a 'char[] file' and 'uint line' which I can
> access.
> >
> > Why is that so hard to do?
>
> I always thought __FILE__ and __LINE__ are just so ugly. But when you
think
> about it, __FILE__ and __LINE__ only really make sense for macros. Using them directly is pointless, isn't it? Wouldn't it make sense to throw a string, and then grep on that string if you can't remember where it came from?

1) Sometimes the same exception message is used in multiple places, so it
can be hard to track down.
2) Sometimes you don't have the source, but still need to know the culprit
3) the message itself might be manufactured (via
localization/externalization) so wouldn't be found with a grep
4) it's very useful to place this information into a 'log' message, so you
can easily see what produced a message witthout having to scan the source.

etc.

If you're concerned about exposing the __FILE__ as a symbol, is it possible to wrap it? Perhaps as an instrinsic function (like rol/ror)?




July 29, 2004
> 1) Sometimes the same exception message is used in multiple places, so it
> can be hard to track down.
> 2) Sometimes you don't have the source, but still need to know the culprit
> 3) the message itself might be manufactured (via
> localization/externalization) so wouldn't be found with a grep
> 4) it's very useful to place this information into a 'log' message, so you
> can easily see what produced a message witthout having to scan the source.
>
> etc.

5) dmd.exe uses __FILE__ & __LINE__ itself: I just got this message from the
compiler :-)

Internal error: s2ir.c 457


July 29, 2004
"Walter" <newshound@digitalmars.com> wrote in news:cea6oh$14c3$1@digitaldaemon.com:


> You can also simply write:
>     assert(p != null);
> and not generate a seg fault.

Sure it does! (I checked with DMD 0.96)

You probably meant:
    assert(p isnot null);     // ;-)


Joking aside, exception stacktraces would be a boon to programmers.
The pain with exceptions is that in well refactored code, exceptions are
often thrown in on function, but that function is called via various code
paths.
So you know where the exception was thrown and where it was caught, but you
don't known what happened in between.
I for one, refused to use exceptions in C++ mainly for that reason. And the
one time, I did use exceptions, I actually hacked the stacktrace in my code
by hand and a little help from the preprocessor.


The __FILE__, __LINE__ and especially __FUNCTION__ (non-standard) data is very handy for writting log files.  Please, consider that log files are *very* important to some people, so they create all this information by hand if a language doesn't provide it or in Java's case cannot produce it fast enough.



Farmer.


July 29, 2004
In article <Xns9536AC639A46itsFarmer@63.105.9.61>, Farmer says...
>
>So you know where the exception was thrown and where it was caught, but you
>don't known what happened in between.
>I for one, refused to use exceptions in C++ mainly for that reason. And the
>one time, I did use exceptions, I actually hacked the stacktrace in my code
>by hand and a little help from the preprocessor.

There have been articles written by very smart people on how to (in code) generate stack traces in C++ when exceptions are thrown.  IIRC the conclusion was that it's just not possible to do very well.  I agree that it would be nice to have compiler support for stack traces when exceptions are thrown.


Sean


July 30, 2004
I have written some code that allows you to view & dump the current stack.  My thought is that many exception types should, by default, perform this stack dump when they are created.  Then, whenever they are caught, the user can implement a stack backtrace.

We need to add these functions to class Thread:


class Thread {
...
    static byte[] ViewStack() {
      Thread t = <getCurrentThread>;
      return t.ViewStack();
    }

    byte[] ViewStack() {
      // swap the array indices for STACK_GROWS_UP
      assert(this.stackBottom > Thread.getESP());
      return (cast(byte*)0)[Thread.getESP()..this.stackBottom];
    }
...
}


I created this class.  Some types of exceptions probably should not do a stack dump; others (like SegFault and AssertError) should do so. Perhaps AssertError should be a child of a class something like this:


class Error_DumpsStack : Error {
  byte[] stackDump;
  this(char[] arg) {
    super(arg);
    stackDump = Thread.ViewStack().dup;
  }
}


Finally, users (or perhaps the standard D loader function?) should do this.  This code requires that somebody write a function PrintStackBackTrace(byte[]):


int main(char[] args) {
  try {
    ...put your main code here...
  }
  catch(Error_DumpsStack e) {
    PrintStackBacktrace(e.stackDump);
  }
  catch(Error e) {
    ...whatever...
  }
}

July 30, 2004
On Thu, 29 Jul 2004 17:51:36 -0700, Russ Lewis wrote:

> I have written some code that allows you to view & dump the current stack.

50 lines of code?
What are we waiting?

oh, right, it took 1 year to get listdir on linux version.

Walter, please, this should have been there since 0.01.

Ant

July 30, 2004
On Wed, 28 Jul 2004 23:43:33 -0700, Walter <newshound@digitalmars.com> wrote:
> "Regan Heath" <regan@netwin.co.nz> wrote in message
> news:opsbvo8cpg5a2sq9@digitalmars.com...
>> Cool. Is "access violation" == SIGSEGV
>>
>> Does it catch anything else as well? It would be cool if I could catch:
>>
>> #define SIGINT          2       /* interrupt */
>> #define SIGILL          4       /* illegal instruction - invalid function
>> image */
>> #define SIGFPE          8       /* floating point exception */
>> #define SIGSEGV         11      /* segment violation */
>> #define SIGTERM         15      /* Software termination signal from kill
> */
>> #define SIGBREAK        21      /* Ctrl-Break sequence */
>> #define SIGABRT         22      /* abnormal termination triggered by abort
>> call */
>>
>> (the above are just the windows signals)
>
> Yes. If you want to see how it's done, see internal\deh.c function
> _d_translate_se_to_d_exception()
>
>> or the third option, my favourite:
>>   - The compiler defines a 'char[] file' and 'uint line' which I can
> access.
>>
>> Why is that so hard to do?
>
> I always thought __FILE__ and __LINE__ are just so ugly.

So change the names. debug.file and debug.line are fine by me.

> But when you think
> about it, __FILE__ and __LINE__ only really make sense for macros. Using
> them directly is pointless, isn't it?

No.

> Wouldn't it make sense to throw a
> string, and then grep on that string if you can't remember where it came
> from?

Then you have to make sure all your strings aren't the same, if the same problem is thrown from several locations "Out of memory" you want the same string.

> You can also simply write:
>     assert(p != null);
> and not generate a seg fault.

Yeah, as long as I remember to check for them all time, I'd rather not have to, like you said why do this when the hardware will do it for me ;)

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
July 30, 2004
Russ Lewis wrote:

> I have written some code that allows you to view & dump the current stack.  My thought is that many exception types should, by default, 

Any chance you will post it?

> perform this stack dump when they are created.  Then, whenever they are caught, the user can implement a stack backtrace.
> 
> We need to add these functions to class Thread:

Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.
July 30, 2004
parabolis wrote:
> Russ Lewis wrote:
> 
>> I have written some code that allows you to view & dump the current stack.  My thought is that many exception types should, by default, 
> 
> Any chance you will post it?

Well, what I've posted already is the distilled core of the code.  I'll post the whole program at the bottom of this message.

> Why not add char[] stackDump to Exception and fill it in in the Exception construction? You should also be able to add a function printStackTrace() to Exception and all Errors will thus have the data by default.

IMHO, you shouldn't have stack trace in every Exception because some are likely to be caught and handled...and then doing a stack trace would be wasteful.  Perhaps I am wrong, though.



Here's the complete program.  It compiles and (seems to) work on linux.

> import std.thread;
> import std.string;
>  byte[] ViewStack(Thread t) {
>   assert(t.stackBottom > Thread.getESP());
>   return (cast(byte*)0)[Thread.getESP()..t.stackBottom];
> }
>  byte[] ViewStack() {
>   return ViewStack(Thread.getAll()[0]);
> }
>  class Error_DumpsStack : Error {
>   byte[] stackDump;
>   this(char[] arg) {
>     super(arg);
>     stackDump = ViewStack().dup;
>   }
> }
>  int main() {
>   byte[] stackView = ViewStack();
>   byte[] stackCopy = stackView.dup;
>   try {
>     throw new Error_DumpsStack("test");
>   }
>   catch(Error_DumpsStack e) {
>     printf("stackView = %d/%p stackCopy=%d/%p stackDump=%d,%p\n", stackView,stackCopy,e.stackDump);
>     printf("cmp(...) = %d\n", cmp(cast(char[])stackView[stackView.length/2..stackView.length],cast(char[])e.stackDump[e.stackDump.length-stackView.length/2..e.stackDump.length]));
>   }
>    return 0;
> }

July 30, 2004
Sean Kelly wrote:
> In article <Xns9536AC639A46itsFarmer@63.105.9.61>, Farmer says...
> 
>>So you know where the exception was thrown and where it was caught, but you don't known what happened in between.
>>I for one, refused to use exceptions in C++ mainly for that reason. And the one time, I did use exceptions, I actually hacked the stacktrace in my code  by hand and a little help from the preprocessor. 
> 
> There have been articles written by very smart people on how to (in code)
> generate stack traces in C++ when exceptions are thrown.  IIRC the conclusion
> was that it's just not possible to do very well.  I agree that it would be nice
> to have compiler support for stack traces when exceptions are thrown.

It is possible to do a portable stack trace if you know the starting address and size of every function in the program.  That is something that could be provided in a portable way by the compiler.  Something like this:

struct FunctionInfo {
  char[] name;
    // name would include module name, and, for nested
    // or literal functions, the nested function name.
    // Something like:
    //    foo.bar.baz.MyFunc(int).nestedFunc1(char)
  char[] linkname;
    // this would be the C-compatible name, as it is
    // in the object file

  byte *startingAddr;
  size_t size;
  FunctionInfo[] subFunctions;
    // nested functions and literal functions go here
};

FunctionInfo[] GetAllFunctions() {...}