www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Print only part of a stack trace

reply Dennis <dkorpel gmail.com> writes:
On assertion failure, the default error handler prints a stack 
trace that looks like this

[library functions]
[application functions]
[druntime start-up functions]

I'm only interested in application functions, the rest is noise.
I could easily filter unwanted lines out if I had the stack trace 
in string form, but I don't know how to obtain that. Is there a 
simple way to do this, or should I delve into Druntime internals?
Jul 01 2020
next sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2020-07-01 19:44, Dennis wrote:
 On assertion failure, the default error handler prints a stack trace 
 that looks like this
 
 [library functions]
 [application functions]
 [druntime start-up functions]
 
 I'm only interested in application functions, the rest is noise.
 I could easily filter unwanted lines out if I had the stack trace in 
 string form, but I don't know how to obtain that. Is there a simple way 
 to do this, or should I delve into Druntime internals?
Could `Runtime.traceHandler` [1] be that you're looking for? [1] https://dlang.org/phobos/core_runtime.html#.Runtime.traceHandler -- /Jacob Carlborg
Jul 01 2020
parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 1 July 2020 at 18:05:09 UTC, Jacob Carlborg wrote:
 [1] 
 https://dlang.org/phobos/core_runtime.html#.Runtime.traceHandler
Thanks, but I don't want to re-implement the default trace handler, I want to use it on a specific location and capture its output. I'll be more specific in what I want to achieve. I have a function that checks a global error constant of a C library (OpenGL) like this: ``` void assertNoOpenGLErrors() { if (glGetError() != GL_NO_ERROR) { assert(0); // stack trace points to here instead of caller } } ``` And I would like to rewrite it to this: ``` void assertNoOpenGLErrors() { if (glGetError() != GL_NO_ERROR) { print(getStackTrace().filterTrace()); exit(); } } ``` So that the stack trace immediately points to the function that raised the OpenGL error, instead of it being buried in a large trace.
Jul 01 2020
next sibling parent reply Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Wednesday, 1 July 2020 at 18:30:15 UTC, Dennis wrote:

 I have a function that checks a global error constant of a C 
 library (OpenGL) like this:
 ```
 void assertNoOpenGLErrors() {
     if (glGetError() != GL_NO_ERROR) {
         assert(0); // stack trace points to here instead of 
 caller
     }
 }
 ```

 And I would like to rewrite it to this:
 ```
 void assertNoOpenGLErrors() {
     if (glGetError() != GL_NO_ERROR) {
         print(getStackTrace().filterTrace());
         exit();
     }
 }
 ```
void assertNoOpenGLErrors(string file = __FILE__, int line = __LINE__, string func = __PRETTY_FUNCTION__) { if (glGetError() != GL_NO_ERROR) { print(file, ":", line, ":", func, ": blah"); exit(); } } :)
Jul 01 2020
parent reply Dennis <dkorpel gmail.com> writes:
On Wednesday, 1 July 2020 at 18:44:10 UTC, Stanislav Blinov wrote:
 void assertNoOpenGLErrors(string file = __FILE__, int line = 
 __LINE__, string func = __PRETTY_FUNCTION__)
 {
     if (glGetError() != GL_NO_ERROR) {
         print(file, ":", line, ":", func, ": blah");
         exit();
     }
 }

 :)
I love __FILE__ and __LINE__, but in this case they won't cut it. In my actual code there's usually one or two more functions inbetween, and amending hundreds of signatures with __FILE__ and __LINE__ for a little debugging convenience is not worth it. I'm now trying to call the defaultTraceHandler manually like this: ``` void bar() { import std.stdio; import core.runtime: defaultTraceHandler; auto res = defaultTraceHandler(null); writeln(res); } void foo() {bar();} void main() {foo();} ``` It sort of works, but it seems it does not start at the right stack frame, the top item is this: ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) int function(char[][])*).runAll().__lambda1() [0x55c19a09c1fa]
Jul 01 2020
parent Dennis <dkorpel gmail.com> writes:
On Wednesday, 1 July 2020 at 18:54:55 UTC, Dennis wrote:
 It sort of works, but it seems it does not start at the right 
 stack frame, the top item is this:

 ??:? void rt.dmain2._d_run_main2(char[][], ulong, extern (C) 
 int function(char[][])*).runAll().__lambda1() [0x55c19a09c1fa]
So dmd skips the first 5 stack frames to account for _d_traceContext, _d_createTrace etc, while ldc filters out by filename. https://github.com/ldc-developers/druntime/blob/cc97ccd00d4082221eee1d5afdbd775201d75877/src/core/runtime.d#L855 I can easily work around this, though it's unfortunate that the public API of DefaultTraceInfo has this limitation.
Jul 01 2020
prev sibling parent reply JN <666total wp.pl> writes:
On Wednesday, 1 July 2020 at 18:30:15 UTC, Dennis wrote:
 I have a function that checks a global error constant of a C 
 library (OpenGL) like this:
 ```
 void assertNoOpenGLErrors() {
     if (glGetError() != GL_NO_ERROR) {
         assert(0); // stack trace points to here instead of 
 caller
     }
 }
Bit off-topic, but if you can use them, debug contexts offer much better OpenGL error-checking experience. https://www.khronos.org/opengl/wiki/Debug_Output . Instead of checking glGetError() after each call, you can setup a C callback that will trigger whenever an error occurs. It also offers some vendor-specific performance warnings.
Jul 01 2020
parent Dennis <dkorpel gmail.com> writes:
On Wednesday, 1 July 2020 at 19:33:08 UTC, JN wrote:
 Bit off-topic, but if you can use them, debug contexts offer 
 much better OpenGL error-checking experience. 
 https://www.khronos.org/opengl/wiki/Debug_Output . Instead of 
 checking glGetError() after each call, you can setup a C 
 callback that will trigger whenever an error occurs. It also 
 offers some vendor-specific performance warnings.
I use those as well, to get a more detailed message about the error than the error code alone. While it helps describing _what_ went wrong, it doesn't tell me _where_ it went wrong. I tried doing assert(0) in the callback, but even with glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS), the stack trace looks something like this: app.d: debugCallback [0x559eda75c7e8] ??:? [0x7f4a0bffa7d7] And then it ends. It seems like it goes up into the OpenGL dll and then gets stuck, it does not trace back to the call site of the glFunction that failed.
Jul 01 2020
prev sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 1 July 2020 at 17:44:45 UTC, Dennis wrote:
 On assertion failure, the default error handler prints a stack 
 trace that looks like this
My cgi.d does something just like that. It just does `exception.toString()` then `splitLines` on that string. Element exceptionToElement(Throwable t) { auto div = Element.make("div"); div.addClass("exception-display"); div.addChild("p", t.msg); div.addChild("p", "Inner code origin: " ~ typeid(t).name ~ " " ~ t.file ~ ":" ~ to!string(t.line)); auto pre = div.addChild("pre"); string s; s = t.toString(); Element currentBox; bool on = false; foreach(line; s.splitLines) { if(!on && line.startsWith("-----")) on = true; if(!on) continue; if(line.indexOf("arsd/") != -1) { if(currentBox is null) { currentBox = pre.addChild("details"); currentBox.addChild("summary", "Framework code"); } currentBox.addChild("span", line ~ "\n"); } else { pre.addChild("span", line ~ "\n"); currentBox = null; } } return div; }
Jul 01 2020