FreePascalのコンソールアプリでメモリダンプ

FreePascalのコンソールアプリで、デバッグするときにメモリダンプするユーティリティがほしかったので、ChatGPTにざっくり書いてもらって少し手直しして使っている。

コード

memory_dump.pp:

program memory_dump;

uses
  SysUtils;

procedure DumpMemory(addr: Pointer; size: Integer);
var
  i, j: Integer;
  p: PByte;
  asciiLine: string;
begin
  p := PByte(addr);
  for i := 0 to (size div 16) - 1 do
  begin
    // 16バイトずつ表示
    Write(Format('%p ', [Pointer(p)])); // メモリアドレスを表示

    asciiLine := ''; // ASCII表現の行

    // 16バイト分のデータを表示
    for j := 0 to 15 do
    begin
      Write(Format('%02x ', [p^])); // 16進数で表示
      if (p^ >= 32) and (p^ <= 126) then
        asciiLine := asciiLine + Chr(p^) // 表示可能なASCII文字を保存
      else
        asciiLine := asciiLine + '.'; // 表示できない文字は '.' に置換

      Inc(p);
    end;

    // ASCII表現を表示
    WriteLn(' ', asciiLine);
  end;

  // 残りのバイトがある場合
  if (size mod 16) <> 0 then
  begin
    Write(Format('%p ', [Pointer(p)])); // メモリアドレスを表示
    asciiLine := ''; // ASCII表現の行

    // 残りのバイトを表示
    for j := 0 to (size mod 16) - 1 do
    begin
      Write(Format('%02x ', [p^]));
      if (p^ >= 32) and (p^ <= 126) then
        asciiLine := asciiLine + Chr(p^)
      else
        asciiLine := asciiLine + '.';

      Inc(p);
    end;

    // 残り部分の整列
    for j := (size mod 16) to 15 do
      Write('   ');

    // ASCII表現を表示
    WriteLn(' ', asciiLine);
  end;
end;

var
  testData: array[0..31] of Byte;
  i: Integer;
begin
  // ダミーデータの初期化
  for i := 0 to High(testData) do
    testData[i] := i + 32;

  // メモリダンプの実行
  DumpMemory(@testData, SizeOf(testData));
end.

コンパイル

$ fpc memory_dump.pp

実行結果

$ ./memory_dump
000000000047D530 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F   !"#$%&'()*+,-./
000000000047D540 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F  0123456789:;<=>?

メモリアドレスの表示とascii出力があるので、ポインタのアドレス探しつつ... みたいなデバッグで役に立ちました。 このprocedure自体は、そのままDelphiでも使えそう。