Display of bitpacked arrays in the debugger lazarus / 12-Debugger ---------------------------------------------------------------------- 440bx · 2021-06-04 10:12 Hello, What the debugger shows for a bitpacked array of boolean isn't what I'm expecting and, I'm wondering if I am missing/misinterpreting something. The debugger's DRIVEMAP shows true(205), false, false, true(2), true(2), etc. I cannot figure out what the "205" and the "2"s mean. Also, I expected the DRIVEMAP to show: true, false, true, true... etc (see the black screenshot output) but the debugger shows an extra "false" between the first two instances of true.  Am I missing something or is there something wrong in what is displayed by the debugger ? The program that produces those results is : (hover over the "ProcessDeviceMapData" parameter after the call to the Nt... function - parameter line is highlighted.)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 {$APPTYPE    CONSOLE} {$TYPEDADDRESS ON} program _QueryInformationProcess;  uses  Windows,  sysutils  ; {$ifdef VER90}type  DWORD = longint;  PDWORD = ^DWORD;{$endif} type  NTSTATUS = DWORD;  const   { 17   23 } ProcessDeviceMap = 23;  { PROCESS_DEVICEMAP_INFORMATION        }                                     { PROCESS_DEVICEMAP_INFORMATION_EX     }   ntdll = 'ntdll';   PROCESS_ALL_ACCESS        = STANDARD_RIGHTS_REQUIRED or SYNCHRONIZE or $FFFF;   STATUS_SUCCESS            = 0;  function NtQueryInformationProcess(ProcessHandle            : THANDLE;                                 ProcessInformationClass  : DWORD;                                 ProcessInformation       : pointer;                                 ProcessInformationLength : DWORD;                                 ReturnLength             : PDWORD)         : NTSTATUS; stdcall; external ntdll;  function IsDebuggerPresent {$ifdef FPC} () {$endif}       : BOOL; stdcall external kernel32;  function _itoa             (              { _in_  } In32bitInteger  : integer;              { _out_ } OutAsciizString : pchar;              { _in_  } InRadix         : DWORD             )         : pchar; cdecl external ntdll;                            { !! CDECL }  type  { _PROCESS_DEVICEMAP_INFORMATION                                          }   PPROCESS_DEVICEMAP_INFORMATION = ^TPROCESS_DEVICEMAP_INFORMATION;  TPROCESS_DEVICEMAP_INFORMATION = record    case integer of      {$ifdef WIN64}      0 : (           { record size must be a multiple of 16 in 64bit                    }          ForceSize                 : packed array[0..5] of pointer;        );      {$endif}       1 : (           SetMap                    : record             DirectoryHandle             : THANDLE;           end;          );       2 : (           QueryMap                  : record             DriveMap                    : DWORD;             DriveType                   : packed array[0..31] of byte;           end;          );      {$ifdef FPC}      3 : (           BitMap                  : record             DriveMap                    : bitpacked array[0..31] of boolean;             DriveType                 : packed array[0..31]    of byte;           end;          );      {$endif}  end; var  ProcessHandle                   : THANDLE;   ProcessDeviceMapData            : TPROCESS_DEVICEMAP_INFORMATION;    BufferSize    : DWORD;   ReturnLength  : DWORD;   Status        : NTSTATUS;    itoa_buf      : packed array[0..127] of char;  begin  writeln;   // since we are dealing with our own process we can specify PROCESS_ALL_ACCESS   ProcessHandle := OpenProcess(PROCESS_ALL_ACCESS,                               FALSE,                               GetCurrentProcessId());   if ProcessHandle = 0 then Halt(1);     writeln;    writeln;    writeln('  ProcessDeviceMap : ', ord(ProcessDeviceMap), ' (d) ',               IntToHex(ord(ProcessDeviceMap), 0), ' (h)');     BufferSize   := sizeof(ProcessDeviceMapData);    ReturnLength := 0;     writeln;    writeln;    writeln('  Buffer size : ', BufferSize);     ZeroMemory(@ProcessDeviceMapData, sizeof(ProcessDeviceMapData));     if IsDebuggerPresent then DebugBreak();    Status := NtQueryInformationProcess(ProcessHandle,                                      ProcessDeviceMap,                                       @ProcessDeviceMapData,                                        BufferSize,                                       @ReturnLength);     if IsDebuggerPresent then DebugBreak();    if Status <> STATUS_SUCCESS then    begin      writeln;      writeln;      writeln('  NtQueryInformationProcess failed.  NTSTATUS : ',                 IntToHex(Status, 0));    end;      writeln;    writeln;     writeln('  ', _itoa(ProcessDeviceMapData.QueryMap.DriveMap, itoa_buf, 2));    writeln;    writeln('  returned length : ', ReturnLength);   writeln;  writeln('Press / to end this program.');  readln;end.  Thank you for your help. ---------------------------------------------------------------------- Martin_fr · 2021-06-04 10:26 Which Debugger? Last time I tested, GDB had issues with packed data. That needs to be fixed in gdb (not yet tested gdb 10, but that has other issues) FpDebug: not sure about 2.0.x But in trunk it works.  Though for the hint, it shortens the embedded arrays. Code: [Select]ForceSize: ($03030300020227DE, $0005020202020003, $0000030000000300, $0000030000000000, nil, nil) SetMap: {record} (217020505612494814) QueryMap: {record} (33695710;  (0, 3, 3, {29 more elements})) BitMap: {record} ((False, True, True, {29 more elements});  (0, 3, 3, {29 more elements})) A watch on ProcessDeviceMapData.BitMap Code: [Select]DriveMap: (False, True, True, True, True, False, True, True, True, True, {22 more elements}) DriveType: (0, 3, 3, 3, 3, 0, 2, 2, 2, 2, {22 more elements}) And if you enter ProcessDeviceMapData.BitMap.DriveMap you see the data. You can open ProcessDeviceMapData in "inspect dialog" (afaik Alt F5), then click through the path, and (in latest trunk) hit the "add watch" button. --- I did recently notice that packed sets do not yet work in FpDebug. ---------------------------------------------------------------------- Martin_fr · 2021-06-04 10:30 Note that it may not be entirely gdb's fault (though I think it happens with fpc trunk and gdb too) https://bugs.freepascal.org/view.php?id=36144 (and maybe others) Not sure in which version that was fixed. However, IIRC FpDebug works around that. So FpDebug should work with older fpc too. ---------------------------------------------------------------------- MarkMLl · 2021-06-04 10:33 What's generating the Boolean? If it's C then it might be assuming that non-zero is universally recognised as true, and the debugger's alerting you to the fact. Some of my own code has arrays or bytebools (?), and yesterday I noticed that the numeric value was either 0 or 255. MarkMLl ---------------------------------------------------------------------- 440bx · 2021-06-04 10:44 Quote from: Martin_fr on June 04, 2021, 12:26:30 pmWhich Debugger? sorry, I forgot to mention the debugger version, it is v7.2 (old version but, it usually works well for what I do) Quote from: Martin_fr on June 04, 2021, 12:26:30 pmLast time I tested, GDB had issues with packed data. That needs to be fixed in gdb (not yet tested gdb 10, but that has other issues)I've experienced a few issues with GDB and bitpacked data but, this one was different than the ones I've seen in the past.  Thought I'd ask just in case. I really have to check out FpDebug sometime and, a newer version of Lazarus than the one I'm using.  The output you showed looked enticing Quote from: MarkMLl on June 04, 2021, 12:33:11 pmWhat's generating the Boolean? If it's C then it might be assuming that non-zero is universally recognised as true, and the debugger's alerting you to the fact.It's C but, it is a bitmap returned in a DWORD.  It's the same DWORD returned by GetLogicalDrives (GetLogicalDrives calls that NT function get the DWORD it returns.)  It's not an array of bytebool it's definitely a bit array (as _itoa showed.) ---------------------------------------------------------------------- Martin_fr · 2021-06-04 10:45 Quote from: MarkMLl on June 04, 2021, 12:33:11 pmWhat's generating the Boolean? If it's C then it might be assuming that non-zero is universally recognised as true, and the debugger's alerting you to the fact. Some of my own code has arrays or bytebools (?), and yesterday I noticed that the numeric value was either 0 or 255. "packed array of boolean" has only a single bit. So there is on 255. But - fpc did write incorrect bit access info - afaik gdb does not use that info correct (even after the fpc fix) / but that needs double checking So gdb interprets this as an "array of bytebool" => and that yield diff results. ------------- On that note / IIRC a: Boolean;  // 0 or 1 => 255 will be accepted but is out of range b: LongBool; // 0 or any other However, the debug info has no diff for those 2 types. So even fpdebug will show the (xxx) for any none 0 or 1 value. ---------------------------------------------------------------------- Martin_fr · 2021-06-04 10:58 Quote from: 440bx on June 04, 2021, 12:44:42 pmI really have to check out FpDebug sometime and, a newer version of Lazarus than the one I'm using.  The output you showed looked enticing There is an overview, what works in which debugger. https://wiki.lazarus.freepascal.org/Debugger_Status Though it does not go into the level of individual data types. ---------------------------------------------------------------------- 440bx · 2021-06-04 11:06 Quote from: Martin_fr on June 04, 2021, 12:58:03 pmThere is an overview, what works in which debugger. https://wiki.lazarus.freepascal.org/Debugger_Status Though it does not go into the level of individual data types. I just checked it out (the page only) and, I have to say, you guys seem to be making really good progress.  It's looking good.