www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - proposal: better stack trace support could advantageously replace

--047d7bd6adfe579c9904e41fa9aa
Content-Type: text/plain; charset=ISO-8859-1

Currently a number of functions in phobos have a syntax such as:
'T enforce(T, Dg, string file = __FILE__, size_t line = __LINE__)'
so as to show informative messages when an exception is raised, etc.

There's a number of issues with this:

1) impossible to have variadic arguments with an extra file/line parameters
at the end (unless one makes those file/line as compile time parameters but
that makes template code bloat), which would be very useful for debugging

2) the context is limited to the calling function (ie top-most stack frame
only)

3) the code is more complex than needs to be, especially when we need to
forward those arguments (again, due to the stack trace being limited to
top-most frame), as every intermediate function is involved in passing
around those arguments, whereas ideally these should only occur in 1
location (eg, at the place responsible to handle an assert failure).
Furthermore, if we later want to add more information to the context (eg
__MODULE__,__FUNCTION__, __COLUMN__ or __ARGUMENTS__), we would have to
refactor a lot of code.

4) this is possibly inefficient, as we're passing around potentially more
parameters than needed.

----------------------------
What about the following instead:

A) implicit context parameters (eg: string file = __FILE__, size_t line =
__LINE__) are no longer needed

B) whenever a stack trace is requested (eg upon an assertion failure,
program crash or signal handler), call a unique getStackTrace function
(that doesn't use the GC). This allows to show full stack trace (more
depth), with potentially more info (eg showing module, function name,
stringified arguments, etc).

C) when an exception is thrown (which may be caught later), we need to save
the stack-trace as efficiently as possible (ie saving the stringified stack
trace would be wasteful). On possibility would be to store an array of
return addresses (given by C backtrace function), memoized using
std.function.memoize. Another would be using a trie data structure, with
the assumption that there's only a limited number of such execution paths
whose stacktrace will be requested; this should be very efficient

D) For a simple implementation, getStackTrace can be based on C functions
backtrace/backtrace_symbols but these are not very reliable depending on
compiler/operating system/compile options: inlining, off-by-1, missing
debug symbols, file base name but no full name, etc. There's
also __builtin_return_address and 'llvm.returnaddress' Intrinsics that
could be used.

So this could be improved with compiler support, introducing backtraceD /
backtrace_symbolsD (D's equivalent of the existing backtrace /
backtrace_symbols) that should work irrespective of OS/D
compiler/inlining/compiler flags. In particular, when the compiler inlines:
'main > funInlined> fun' to 'main > fun',
it should still be possible to keep track of the intermediate source level
function calls with proper book-keeping in the object file.

--047d7bd6adfe579c9904e41fa9aa
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Currently a number of functions in phobos have a syntax su=
ch as:<div>&#39;T enforce(T, Dg, string file =3D __FILE__, size_t line =3D =
__LINE__)&#39;<br></div><div>so as to show informative messages when an exc=
eption is raised, etc.</div>
<div><br></div><div>There&#39;s a number of issues with this:</div><div><br=
</div><div>1) impossible to have variadic arguments with an extra file/lin=

arameters but that makes template code bloat), which would be very useful f= or debugging</div> <div><br></div><div>2) the context is limited to the calling function (ie t= op-most stack frame only)</div><div><br></div><div>3) the code is more comp= lex than needs to be, especially when we need to forward those arguments (a= gain, due to the stack trace being limited to top-most frame), as every int= ermediate function is involved in passing around those arguments, whereas i= deally these should only occur in 1 location (eg, at the place responsible = to handle an assert failure). Furthermore, if we later want to add more inf= ormation to the context (eg __MODULE__,__FUNCTION__, __COLUMN__ or __ARGUME= NTS__), we would have to refactor a lot of code.=A0</div> <div><br></div><div>4) this is possibly inefficient, as we&#39;re passing a= round potentially more parameters than needed.</div><div><br></div><div>---= -------------------------</div><div>What about the following instead:</div> <div><br></div><div>A) implicit context parameters (eg: string file =3D __F= ILE__, size_t line =3D __LINE__) are no longer needed</div><div><br></div><= div>B) whenever a stack trace is requested (eg upon an assertion failure, p= rogram crash or signal handler), call a unique getStackTrace function (that= doesn&#39;t use the GC). This allows to show full stack trace (more depth)= , with potentially more info (eg showing module, function name, stringified= arguments, etc).=A0</div> <div><br></div><div>C) when an exception is thrown (which may be caught lat= er), we need to save the stack-trace as efficiently as possible (ie saving = the stringified stack trace would be wasteful). On possibility would be to = store an array of return addresses (given by C backtrace function), memoize= d using std.function.memoize. Another would be using a trie data structure,= with the assumption that there&#39;s only a limited number of such executi= on paths whose stacktrace will be requested; this should be very efficient<= /div> <div><br></div><div>D) For a simple implementation, getStackTrace can be ba= sed on C functions backtrace/backtrace_symbols but these are not very relia= ble depending on compiler/operating system/compile options: inlining, off-b= y-1, missing debug symbols, file base name but no full name, etc. There&#39= ;s also=A0__builtin_return_address and=A0&#39;llvm.returnaddress&#39; Intri= nsics that could be used.</div> <div><br></div><div>So this could be improved with compiler support, introd= ucing backtraceD / backtrace_symbolsD (D&#39;s equivalent of the existing= =A0backtrace / backtrace_symbols) that should work irrespective of OS/D com= piler/inlining/compiler flags. In particular, when the compiler inlines:</d= iv> <div>&#39;main &gt; funInlined&gt; fun&#39; to &#39;main &gt; fun&#39;,=A0<= /div><div>it should still be possible to keep track of the intermediate sou= rce level function calls with proper book-keeping in the object file.</div> <div><br></div></div> --047d7bd6adfe579c9904e41fa9aa--
Aug 17 2013