[CLOSED] Need an example to debug a TStringList with FpDebug on Linux 64bits lazarus / 12-Debugger ---------------------------------------------------------------------- devEric69 · 2020-01-07 11:29 edit: problem with this configuration: Linux 64 bits (Ubuntu), Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3. --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . --- . Hello, I'm on FpDebug, and I'm trying to retrieve string-items from the chained list. On Gdb, I was using (Cf. the screenshot)..: TStringItem(^TStringItemList(oStrLst.FList)[0]) ...but I can't do this, with FpDebug. Sorry to be boring, but it might help the "newbies" with FPC + Laz. 1°) I understood that, as under Gdb, you only have direct access to the only fields of an object in the heap. 2°) knowing this, with FpDebug I would like an example to debug a TStringList. 3°) with a created object named oStrLst, I can quickly access, at most, only oStrLst.FList. FList being also an object in the heap, encapsulated by oStrLst.  4°) globally, I know that @(oObject) returns the address where is the location of the first byte in the heap, of oObject. 5°) if I apply 4° to oStrLst.FList, then @oStrLst.FList returns two informations: - the address where is the location of the first byte of oStrLst.FList. - and besides, since the @ ***of the debugger*** is typed, it knows on which type it's pointing on the heap, ie @ equals ^TTypeInHeap. ==> so, @oStrLst.FList returns the location in the heap, where @oStrLst.FList is in the heap, and @oStrLst.FList is the same as PStringItemList(@oStrLst.FList). 6°) I understood that the use of @ in FpDebug, when it returns the location of a chained list of structure \ record, allows to retrieve each structure \ record by incrementing it by +1, +2, +3 to retrieve the structure \ record [+1], the structure \ record [+2], the structure \ record [+3]. So, by deduction there is +0 which can retrieve the structure \ record[+0]. 7°) I think I may have understood that the use of @ in FpDebug, when it returns the location of a chained list of structure \ record, makes it possible to retrieve every structure \ record, by incrementing it by +1, +2, +3 to retrieve the structure \ record [+1], the structure \ record [+2], the structure \ record [+3]. Thus, by deduction there is also an implicit +0, which can retrieve the structure \ record[+0]. So, in the debugger (FpDebug), I read: (@oStrLst.FList) == Pointer to PStringItemList ==> here, the only thing I should know for sure, is that having a pointer on a pointer, I'll have to derefer it twice, to get into the pointer on a pointer record structure. No? ==> I've tested, but it failed: TStringItem((@oStrLst.FList)^^).FString, TStringItem((@oStrLst.FList+1)^^).FString, etc TStringItem(^TStringItemList(@oStrLst.FList+1)^)^.FString, etc How do I do it, please? Regards. ---------------------------------------------------------------------- Martin_fr · 2020-01-07 14:41 First of all you are using 2.1 (svn)? What Fpc version? Dwarf 2 or 3) Your watch    TStringItem(^TStringItemList(StrList.FList)[0]) works for me. In fpdebug. (Tested on Win, 3.0.4, Dwarf 3, but watches should not make to much of a diff...>) Not sure why it fails for you. What is the error? This also works: StrList.FList^[0] Assuming StrList is declared as TStringList (rather than TStrings, which may need a typecast) The issue with properties, is not just GDB or FpDebug. 1) Dwarf (at least in the versions used, not sure about dwarf 5)) does not have a definition for "property that can be a field or a function". 2) Consequently FPC does not write debug info for properties.    Except if it points to a field without gettre, then fpc writes an entry for a class field (pretending it was one) 3) If both of the above are solved, it is a matter of calling function in the debugged app. (That is something that fpdebug will solve in future) Dwarf has an option for proprietary entries. So maybe fpc one day will write info explicitly for fpdebug, if no other way exists..... But that has not yet been discussed... Quote- and besides, since the @ ***of the degogger*** is typed, it knows on which type it's pointing on the heap, ie @ equals ^TTypeInHeap.While this should work in fpDebug too, and does for me (with your example), it is not always needed. FpDebug is much better of detecting types. The @ returns a typed pointer. But if your object was declared TStrings, then @ return ^TStrings. In that case you need a typecast. In FpDebug you can however choose ^TStringList(@MyStrings)^   is the same as  TStringList(MyStrings) GDB becomes confused with the internal pointer in Pascal classes. FpDebug should deal with this. You can use the "Debug Inspector" (alt F5), and double click the field you want to follow. If you set "use instance type", then "Debug Inspector" will build the correct watch. (Though it does not check for the simplest solution). Quotey incrementing it by +1, +2, +3 to retrieve the structure \ record [+1], the structure \ record [+2], the structure \ record [+3].FpDebug (and I thing GDB too) does correct pointer Math.    (MyItemPtr + 1)^ should be the same as MyItemPtr[1] That is increase by 1 time the size of TMyItem. (But see below, what type the item is in your case....) Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringItem((@oStrLst.FList)^^).FStringworks for me Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringItem((@oStrLst.FList+1)^^).FStringFails However, it should fail....? I read it as    @oStrLst.FList    Take the Address of the field FList. That is one pointer more than you want.               FList is PStringItemList, so we have a pointer to that pointer    @oStrLst.FList+1   Points to the mem location SizeOf(Pointer) behind FList.                That is, it expects a 2nd FList in the fields of TStringList. IMHO it should be    (^TStringItem(  oStrLst.FList  ) + 1)^ And that works. This does not add a further pointer level, but just changes the type of the pointer, because - FList is NOT a pointer to a TStringItem. - FList is a pointer to a static array of TStringItem FpDebug does know that. (As would fpc (I believe), if you tried to compile your expression) Therefore FList + 1 => Increments by the size of the entire static array!!!! Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringItem(^TStringItemList(@StrList.FList+1)^)^.FStringAgain TStringItemList => static array TypedPointer + 1 => increase by size of type ^TStringItemList + 1 => increase by size of the entire static array. Afaik the same that fpc would do, if you compiled this. (If fpc does something else (other than throw an error), then let me know) ---------------------------------------------------------------------- devEric69 · 2020-01-08 17:48 QuoteFirst of all you are using 2.1 (svn)? What Fpc version? Dwarf 2 or 3) use: Linux \ Ubuntu 18.04 (64 bits), Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3. QuoteYour watch    TStringItem(^TStringItemList(StrList.FList)[0]) works for me. (Also works for me on Win7, 32bits.) In the window: debug>Evaluate/Modify, TStringItem(^TStringItemList(oStrLst.FList)[0]) displays Range check error (it displays nothing in the Debug Inspector), and this output in the Terminal\console: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TApplication.HandleException: ERangeErrorRange check error  Stack trace:  $000000000136A417 line 4263 of fpdbgdwarfdataclasses.pas  $000000000135EBDD line 2574 of fpdbgdwarfdataclasses.pas  $0000000001316052 line 3286 of fpdbgdwarf.pas  $0000000001342BD1 line 1293 of fpdbginfo.pas  $0000000001316079 line 3289 of fpdbgdwarf.pas  $0000000001327455 line 653 of fppascalparser.pas  $000000000132A027 line 1088 of fppascalparser.pas  $000000000132E0D5 line 1850 of fppascalparser.pas  $000000000132B072 line 1308 of fppascalparser.pas  $000000000132E0D5 line 1850 of fppascalparser.pas  $000000000132D126 line 1739 of fppascalparser.pas  $000000000149C3D9 line 1352 of fpdebugdebugger.pas  $000000000149EA9A line 1906 of fpdebugdebugger.pas  $0000000000B8CA52 line 6158 of dbgintfdebuggerbase.pp  $0000000000B8C070 line 6033 of dbgintfdebuggerbase.pp  $0000000000B5CEC6 line 2926 of debugmanager.pas  $0000000001262F06 line 201 of ../debugger/evaluatedlg.pp QuoteThis also works: oStrLst.FList^[0] (Also works for me on Win7, 32bits.) oStrLst.FList^[0] displays Range check error in Evaluate\modify (it displays nothing in the Debug Inspector), and this output in the Terminal\console: Code: Text  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Range check error  Stack trace:  $000000000136A417 line 4263 of fpdbgdwarfdataclasses.pas  $000000000135EBDD line 2574 of fpdbgdwarfdataclasses.pas  $0000000001316052 line 3286 of fpdbgdwarf.pas  $0000000001342BD1 line 1293 of fpdbginfo.pas  $0000000001316079 line 3289 of fpdbgdwarf.pas  $000000000130F498 line 2024 of fpdbgdwarf.pas  $0000000001330DA0 line 2416 of fppascalparser.pas  $000000000132E0D5 line 1850 of fppascalparser.pas  $0000000001329AF5 line 1035 of fppascalparser.pas  $000000000132E0D5 line 1850 of fppascalparser.pas  $000000000132D126 line 1739 of fppascalparser.pas  $000000000149C3D9 line 1352 of fpdebugdebugger.pas  $000000000149EA9A line 1906 of fpdebugdebugger.pas  $0000000000B8CA52 line 6158 of dbgintfdebuggerbase.pp  $0000000000B8C070 line 6033 of dbgintfdebuggerbase.pp  $0000000000B5CEC6 line 2926 of debugmanager.pas  $0000000001262F06 line 201 of ../debugger/evaluatedlg.pp QuoteAssuming StrList is declared as TStringList (rather than TStrings, which may need a typecast) Yes, it is. Quote1) Dwarf (at least in the versions used, not sure about dwarf 5)) does not have a definition for "property that can be a field or a function". Okay, that's what I've understood. [/quote] Quote    - and besides, since the @ ***of the debugger*** is typed, it knows on which type it's pointing on the heap, ie @ equals ^TTypeInHeap.While this should work in fpDebug too, and does for me (with your example), it is not always needed. [/quote] Forget that sentence: having mostly used Delphi, I had falsely assumed that @ was doing an untyped return . QuoteYou can use the "Debug Inspector" (alt F5), and double click the field you want to follow. If you set "use instance type", then "Debug Inspector" will build the correct watch. (Though it does not check for the simplest solution). Ok: I'll rather report back to the forum by saying what I see in the Debug Inspector window (but it's the Evaluate Modify window that writes the anomalies to the terminal console instead. So, I'll continued to test in that one, too.). Quote(MyItemPtr + 1)^ should be the same as MyItemPtr[1]. Okay: I had falsely believed that MyItemPtr[1] was only valid in Gdb. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i TStringItem((@oStrLst.FList)^^).FString Always the same massage: Range check error in Evaluate\modify (and nothing in the Debug Inspector). Quote@oStrLst.FList+1   Points to the mem location SizeOf(Pointer) behind FList. That is, it expects a 2nd FList in the fields of TStringList. All right, I've understood and revised. I had to, like a " newbie " (Cf. screenshot: an *attempt* to generalize the "how" to create an expression for the bug inspector). Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  (^TStringItem(  oStrLst.FList  ) + 1)^ ➔ I'm not "stuck" under Linux \ Ubuntu with that expression. Thanks a lot! ---------------------------------------------------------------------- Martin_fr · 2020-01-08 18:11 FpDebug in Lazarus 2.1 has tons of fixes over 2.0.x. That includes several range check errors, and a few cases of no result in debug inspector. This also includes addition of watching some types that 2.1 did not display (like bitpacked types). There are also fixes to other aspects (not watch related), like stepping. Quote I had falsely assumed that @ was doing an untyped returnThat may become an option at some point (setting in debugger properties) QuoteOkay: I had falsely believed that MyItemPtr[1] was only valid in Gdb.This is valid in fpc. Fpc compiles any typed pointer with array access. Note, that this can be very confusing if you have (Delphi like) auto deref. That is if you can write "MyPointerToRecord.Field", and fpc inserts the omitted "^". In this case the result may first auto deref, and then access the array.... And IIRC somehow it differs from What-Delphi-does. There is a report somewhere. FpDebug does not do auto-deref. Well there is a IFDEF that you can define to get basic auto deref. Again something that will eventually be an option in the config. QuoteAll right, I've understood and revised. I had to, like a " newbie " (Cf. screenshot: an *attempt* to generalize the "how" to create an expression for the bug inspector). FpDebug should take exactly the same input as fpc. If it does not, then please report. Compile your expression with fpc, and use debugln, to print the result to console. GDB has problems with pointers[1]. Partly this is because classes are internally pointers, and gdb does not always know the diff between an actual (user defined) pointer (to the variable holding the internal class pointer) and the internal pointer. GDB also seems to get upset, if there are pointers to structures within other structures. So for gdb you need to at a lot of typecasts. GDB also has issues with   PStringItemList = ^TStringItemList;   TStringItemList = array[0..MaxListSize] of TStringItem; Even if you try to access just one item inside TStringItemList, gdb (or many versions of gdb) attempt to alloc memory for the entire array. And that fails as the array is way to big. That is why in GDB the trick is to use ^TStringItem => so GDB does not see the array. [1] => This may also be down to how FPC encodes those pointers. Don't know who is to blame. ---------------------------------------------------------------------- valdir.marcos · 2020-01-09 04:14 Quote from: Martin_fr on January 08, 2020, 07:11:13 pmFpDebug in Lazarus 2.1 has tons of fixes over 2.0.x. That includes several range check errors, and a few cases of no result in debug inspector. This also includes addition of watching some types that 2.1 did not display (like bitpacked types). There are also fixes to other aspects (not watch related), like stepping. Quote I had falsely assumed that @ was doing an untyped returnThat may become an option at some point (setting in debugger properties) QuoteOkay: I had falsely believed that MyItemPtr[1] was only valid in Gdb.This is valid in fpc. Fpc compiles any typed pointer with array access. Note, that this can be very confusing if you have (Delphi like) auto deref. That is if you can write "MyPointerToRecord.Field", and fpc inserts the omitted "^". In this case the result may first auto deref, and then access the array.... And IIRC somehow it differs from What-Delphi-does. There is a report somewhere. FpDebug does not do auto-deref. Well there is a IFDEF that you can define to get basic auto deref. Again something that will eventually be an option in the config. QuoteAll right, I've understood and revised. I had to, like a " newbie " (Cf. screenshot: an *attempt* to generalize the "how" to create an expression for the bug inspector). FpDebug should take exactly the same input as fpc. If it does not, then please report. Compile your expression with fpc, and use debugln, to print the result to console. GDB has problems with pointers[1]. Partly this is because classes are internally pointers, and gdb does not always know the diff between an actual (user defined) pointer (to the variable holding the internal class pointer) and the internal pointer. GDB also seems to get upset, if there are pointers to structures within other structures. So for gdb you need to at a lot of typecasts. GDB also has issues with   PStringItemList = ^TStringItemList;   TStringItemList = array[0..MaxListSize] of TStringItem; Even if you try to access just one item inside TStringItemList, gdb (or many versions of gdb) attempt to alloc memory for the entire array. And that fails as the array is way to big. That is why in GDB the trick is to use ^TStringItem => so GDB does not see the array. [1] => This may also be down to how FPC encodes those pointers. Don't know who is to blame.I know the matter is not all that simple, but if it works on fpDebug and not on GDB, then it's GDB's fault. However, if it doesn't even work properly on fpDebug that is been specially designed to debug FPC, then FPC should be blamed... ---------------------------------------------------------------------- devEric69 · 2020-01-09 10:15 QuoteFpDebug in Lazarus 2.1 has tons of fixes over 2.0.x. That includes several range check errors, and a few cases of no result in debug inspector. This also includes addition of watching some types that 2.1 did not display (like bitpacked types). There are also fixes to other aspects (not watch related), like stepping. All right. But I'm staying with my setup (Linux (64 bits), Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3.): Lazarus 2.1 has bugs too unstable for me (nothing to do with FpDebug; as https://bugs.freepascal.org/view.php?id=35721), and will involve fixes in jvcllaz packages too. So, I'm waiting for the next "even" version of Lazarus. ==> I'm closing this thread, for Linux configuration (64 bits), Lazarus version: 2.0.4 (svn revision: 62502M) compiled with fpc 3.0.4 - fpDebug \ Dwarf3. ---------------------------------------------------------------------- Martin_fr · 2020-01-09 10:59 Quote from: valdir.marcos on January 09, 2020, 05:14:42 amI know the matter is not all that simple, but if it works on fpDebug and not on GDB, then it's GDB's fault. However, if it doesn't even work properly on fpDebug that is been specially designed to debug FPC, then FPC should be blamed... No that depends only if the info produced by FPC matches the dwarf specs. ---------------------------------------------------------------------- valdir.marcos · 2020-01-09 11:14 Quote from: Martin_fr on January 09, 2020, 11:59:41 amQuote from: valdir.marcos on January 09, 2020, 05:14:42 amI know the matter is not all that simple, but if it works on fpDebug and not on GDB, then it's GDB's fault. However, if it doesn't even work properly on fpDebug that is been specially designed to debug FPC, then FPC should be blamed... No that depends only if the info produced by FPC matches the dwarf specs.Does that mean FPC needs to improve its generated DWARF information, or that fpDebug needs to improve its DWARF information reading, or both? https://en.wikipedia.org/wiki/DWARF ---------------------------------------------------------------------- Martin_fr · 2020-01-09 11:51 Quote from: valdir.marcos on January 09, 2020, 12:14:58 pmQuote from: Martin_fr on January 09, 2020, 11:59:41 amQuote from: valdir.marcos on January 09, 2020, 05:14:42 amI know the matter is not all that simple, but if it works on fpDebug and not on GDB, then it's GDB's fault. However, if it doesn't even work properly on fpDebug that is been specially designed to debug FPC, then FPC should be blamed... No that depends only if the info produced by FPC matches the dwarf specs.Does that mean FPC needs to improve its generated DWARF information, or that fpDebug needs to improve its DWARF information reading, or both? https://en.wikipedia.org/wiki/DWARF There are some reported bugs with FPC written dwarf. Some/Most already fixed in upcoming fpc. Otherwise FPC's "watches related" dwarf info did look good as far as I can tell. But that is no guarantee. Some gdb issues are with watches of which I believe the encoding is correct. GDB is written to match what c compilers produce... FPC has added --godwarfcpp   (do not use this with fpdebug) FpDebug is not complete either, it covers 99% of what fpc produces (the only thing I know to be missing is "file of sometype" / which anyway has not much useful data) Afaik GDB is also not complete..... Here is an example what upsets gdb. In dwarf there is no exact match for pascal "interface". This is basically a structure. However the way things are, the best that can be done (and what fpc does) is declare a structure with no members at all. The dwarf spec does not require members. But gdb has an assertion, and fails. Then again I never tested fpdebug with gcc. It *should* work... But who knows. You can search mantis for dwarf And for gdb: https://wiki.lazarus.freepascal.org/GDB_Debugger_Tips#Bugs_in_GDB ---------------------------------------------------------------------- valdir.marcos · 2020-01-10 03:46 Quote from: Martin_fr on January 09, 2020, 12:51:38 pmQuote from: valdir.marcos on January 09, 2020, 12:14:58 pmQuote from: Martin_fr on January 09, 2020, 11:59:41 amQuote from: valdir.marcos on January 09, 2020, 05:14:42 amI know the matter is not all that simple, but if it works on fpDebug and not on GDB, then it's GDB's fault. However, if it doesn't even work properly on fpDebug that is been specially designed to debug FPC, then FPC should be blamed... No that depends only if the info produced by FPC matches the dwarf specs.Does that mean FPC needs to improve its generated DWARF information, or that fpDebug needs to improve its DWARF information reading, or both? https://en.wikipedia.org/wiki/DWARFThere are some reported bugs with FPC written dwarf. Some/Most already fixed in upcoming fpc. Otherwise FPC's "watches related" dwarf info did look good as far as I can tell. But that is no guarantee. Some gdb issues are with watches of which I believe the encoding is correct. GDB is written to match what c compilers produce... FPC has added --godwarfcpp   (do not use this with fpdebug) FpDebug is not complete either, it covers 99% of what fpc produces (the only thing I know to be missing is "file of sometype" / which anyway has not much useful data) Afaik GDB is also not complete..... Here is an example what upsets gdb. In dwarf there is no exact match for pascal "interface". This is basically a structure. However the way things are, the best that can be done (and what fpc does) is declare a structure with no members at all. The dwarf spec does not require members. But gdb has an assertion, and fails. Then again I never tested fpdebug with gcc. It *should* work... But who knows. You can search mantis for dwarf And for gdb: https://wiki.lazarus.freepascal.org/GDB_Debugger_Tips#Bug s_in_GDBThanks for all information and patience. I am trying to understand a bit deeper: Books and Articles on building a debugger https://forum.lazarus.freepascal.org/index.php/topic,48075.0.html