0

I'm trying to obtain line numbers to create a debug log, hoping to more easily plot a path through code function calls etc

However if I am using StackTrace correctly it is not giving the response I needed:

Private Sub FormAnalyser_Load(sender As Object, e As EventArgs) Handles MyBase.Load
...
If isDebug Then LogDebugCall("analyser.vb", "_queryBuilder.Load()")
_queryBuilder.Load()
...
End Sub

In Debugger.vb class.

Public Shared Sub LogDebugCall(docName As String, callStatement As String)
Debug.Indent()
Debug.Indent()
Debug.Indent()

Dim st As New StackTrace(True)
Dim sf As StackFrame = st.GetFrame(st.FrameCount - 1)
Dim line As String
line = "Line: " & CStr(sf.GetFileLineNumber())

Dim tmp As String 
tmp = sf.GetMethod().Name

Debug.WriteLine(callStatement & Space(50 - Len(callStatement)) & "(Call: " & callStatement & " " & docName & " " & line & ")")
...
End sub

So I always get LineNUmber of 0 although the FrameCount might be 58 or whatever depending at what point it is called. INspection of sf gives - sf {ThreadStart at offset 68 in file:line:column :0:0 } System.Diagnostics.StackFrame and there is an OFFSET_UNKNOWN flag -1 There is a thread here that shows setting of debug_info which I have not done, but cant find this setting in VS community 2013. Is this the cause of my woes or am I just using it wrongly?

As this is still not giving me anything usefull and having read here. I simplified the structure just for test puposes that the method suggested there but moved it to my form class directly.

Public Sub PrintCurrentLine(ByVal ex As Exception)
    Dim st As StackTrace = New StackTrace(ex)
    Dim sf As StackFrame = st.GetFrame(st.FrameCount - 1)
    Console.WriteLine("Line " & sf.GetFileLineNumber())
End Sub

Exception wasnt suitable as I want it when there is no exception so

Public Sub PrintCurrentLine()
    Dim st As StackTrace = New StackTrace(true)
    Dim sf As StackFrame = st.GetFrame(st.FrameCount - 1)
    Console.WriteLine("Line " & sf.GetFileLineNumber())
End Sub

Not working! Value returned in both instances -1 So I declared st,sf directly in the calling method whose line number I want to catch and sf.GetFileLineNumber() still returns -1 So if anybody else has anything else to throw at me I would appreciate it!

Thanks guys!

Community
  • 1
  • 1
Andrew Seabrook
  • 397
  • 2
  • 17
  • Are you building in Release mode instead of Debug? Or do you want to provide line numbers in a Release build? – Cᴏʀʏ Jun 29 '15 at 12:28
  • Can you not make your logging functions make use of the [Caller Information features](https://msdn.microsoft.com/en-us/library/hh534540(v=vs.110).aspx)? – Damien_The_Unbeliever Jun 29 '15 at 12:29
  • No its debug mode! as regards Caller Information features - I have not come across that before will try it out. But still would like to know whats causing the StackTrace issue. – Andrew Seabrook Jun 29 '15 at 12:35
  • Actually it seems that the Caller Informatin features are only going to work on .Net 4.5 (correct?) but I am stuck with 4.0 for the time being! – Andrew Seabrook Jun 29 '15 at 13:35

2 Answers2

2

although the FrameCount might be 58

The further you are removed from your own code, and you're likely to be a mile away from it when the frame count is 58 and you're looking at the bottom, the lower the odds that the CLR can find a proper PDB file that contains the required line number info. It will not have line number info for any .NET Framework methods for example.

Furthermore, your compiler will by default generate a "stripped" PDB file for the Release build. It is missing line number info. Which is in general a sensible thing to do, companies tend to not like expose implementation details to prying eyes and line numbers are in general not useful in the Release build because the jitter optimizer moves code around.

So, this is by and large entirely normal. If you are sure that it should show your own code's line numbers then pay attention to Project > Properties > Compile tab > Advanced > Generate debug info setting. You want "Full" for the Release configuration, not the default "pdb-only". And pay attention to your deployment procedure, you have to copy the PDBs along with the executable files. And don't take the displayed numbers too seriously.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • This is for Debug Mode only. Missed the Advanced button, unfortunatly I find that Full is already set. I wonder if I am not understanding something correctly about StackTrace use however, as the Call Stack window has access to this information! I am looking to visualise a complete path through code subsequent to a given event. Wanting to know what has called what from where - Currently I have a ham-fisted manual approach for the classes, events, calls, and method entry, but line numbers would really help - particularly in the case of the method calls. Thanks. – Andrew Seabrook Jun 29 '15 at 14:01
  • The only thing I can look at is the snippet you posted. You will not get line number info for that, the stack frame is way at the bottom and always belongs to a method in the .NET Framework assembly. – Hans Passant Jun 29 '15 at 14:07
  • I dont know if it says anything but after the mentioned code I added Dim tmp As String tmp = sf.GetMethod().Name , and tmp is assigned "ThreadStart" in my example case, the method calling the method in which the StackTrace snippet is implemented is named: FormAnalyser_Load() and the method in which StackTrace is called is LogDebugCall – Andrew Seabrook Jun 29 '15 at 14:35
  • Well, of course, every thread starts with ThreadStart. The Load event handler will be another frame, less than 58, you'll have to iterate all of them to see it. Starting to sound impractical yet? It is. – Hans Passant Jun 29 '15 at 14:42
  • Well No. I am obviously not understanding something. Surely the highest numbered frame represents the method that the trace is currently in. So surely current number -1 represents the calling method. Why do I need to loop through all the earlier frames. I only want the line number from which the call to the debugging method in which StackTrace is implemented. – Andrew Seabrook Jun 29 '15 at 14:58
  • Well, you found out that this is not true. Start at 1. – Hans Passant Jun 29 '15 at 15:03
  • Well I have foundout nothing clear edited the original to comment on looping through the frames. – Andrew Seabrook Jun 30 '15 at 07:52
  • 1
    Yikes. If you get the same method over and over again you know you got a bug. Use `st.GetFrame(i)` instead. – Hans Passant Jun 30 '15 at 07:54
  • Yes I realized just after I posted - iBad I see what you mean when seeing the output from the trace. – Andrew Seabrook Jul 01 '15 at 12:12
0

Ok SO I got to the answer and obtaining the linenumbers were not so difficult in the end. I am implementing a call to my debugger class in each method: debugger.MethodIn() the frame sf represents that method with the debugger call, and sfCaller represents the the method that called that method.

Dim st As New StackTrace(True)
Dim sf As StackFrame
Dim sfCaller As StackFrame
sf = st.GetFrame(1)
sfCaller = st.GetFrame(2)
col = sfCaller.GetFileLineNumber 
ln = sfCaller.GetFileColumnNumber
Andrew Seabrook
  • 397
  • 2
  • 17