Difference between revisions of "FpDebug/ru"

From Lazarus wiki
Jump to navigationJump to search
(Added template)
Line 81: Line 81:
 
Аналогичным образом FPC обрабатывает ShortStrings внутри как запись и кодирует их как есть. Опять же, различие заключается в деталях реализации.
 
Аналогичным образом FPC обрабатывает ShortStrings внутри как запись и кодирует их как есть. Опять же, различие заключается в деталях реализации.
  
== Modifying managed types ==
+
== Изменение управляемых типов ==
  
This applies to any debugger that can set new values to a watch (modify variable in the debugged exe).
+
Это применимо к любому отладчику, который может устанавливать новые значения для списка слежения (изменяет переменную в отлаживаемом exe).  
  
Managed types can not be correctly modified.
+
Управляемые типы не могут быть изменены корректно.
  
To modify managed types the debugger would need to know about:
+
Для изменения управляемых типов отладчику необходимо знать:  
* the ref count
+
* счетчик ссылок
* copy on write behaviour
+
* копирование при записи
* how to allocate/free memory / or better how to call the inc/dec_ref methods for each types, so they will do the work correctly
+
* как выделить/освободить память / или лучше как вызвать методы inc/dec_ref для каждого типа, чтобы они выполняли работу правильно
  
None of that info is available.
+
Ничего из этого не доступно.
  
If you assign a new value to a string or dynamic array, then the ref count of the old and new value must be adjusted. If needed memory must be allocated or freed.
+
Если вы присваиваете новое значение строке или динамическому массиву, то необходимо скорректировать счетчик ссылок старого и нового значения. При необходимости память должна быть выделена или освобождена.
If that is not done correctly it will at least cause a memory leak. But it can also cause crashes or random other buggy behaviour when the debugged exe continues.
+
Если это сделать неправильно, это, по крайней мере, вызовет утечку памяти. Но это также может вызвать сбои или другие случайные ошибки, когда отлаженный exe продолжает работу.
  
In an array it is possible to change a single element. "SomeArray[5] := 7;". If the array is referenced from several variables, this will affect all of them. The same happens if you execute this statement in your app.
+
В массиве можно изменить один элемент. "SomeArray[5] := 7;". Если на массив ссылаются несколько переменных, это повлияет на их всех. То же самое произойдет, если вы выполните этот оператор в своем приложении.
  
String (AnsiString) have copy-on-write. If you do "SomeString[4] := 'a'" then the variable from which you accessed the string gets a new copy, and other variables (that share the memory) should not be affected. The debugger does not have that info. Nor does it have access to the refcount and memory alloc/de-alloc (or internal string procs).  
+
У строки (AnsiString) использует механизм копирование при записи (copy-on-write). Если вы сделаете "SomeString[4] := 'a'", тогда переменная, из которой вы получили доступ к строке, получит новую копию, и другие переменные (которые совместно используют память) не должны быть затронуты. У отладчика этой информации нет. Также у него нет доступа к счетчику ссылок и распределению/освобождению памяти (или внутренним строковым процессам).
  
 
== Calling function with managed types as param or result ==
 
== Calling function with managed types as param or result ==

Revision as of 21:58, 31 December 2020

English (en) русский (ru)

О пакете

FpDebug - это отладчик, написанный языке Паскаль для использования в Pascal.

Подробнее:

  • FpDebug написан на Паскале
  • FpDebug использует формат отладочной информации DWARF
    • Текущая реализация является подмножеством DWARF с поддержкой DWARF версий 2 и 3. Однако «подмножество» - это просто состояние реализации. Цель состоит в том, чтобы расширить его, дабы реализовать как можно больше стандартных возможностей.
    • Текущая реализация охватывает подмножество, которое используется FPC
    • FpDebug имеет специальные реализации для работы с конкретным использованием DWARF для FPC (ошибки, отсутствующая информация, подробности реализации)

Что подразумевается под «FpDebug»

FpDebug может ссылаться на

Пакет "FpDebug"

Это движок отладчика. Это не относится к IDE. Пакет используется несколькими бэкэндами IDE:

  • Отладчик LLDB (с fpdebug): этот отладчик использует LLDB в качестве бэкэнда. Чтобы отображать результаты в стиле Паскаля, он использует движок «fpdebug» для отображения locals/watches.
  • Отладчик GNU (с fpdebug): для пошаговой отладки(stepping)/точек останова(breakpoints)/... используется GDB, а FpDebug - для списка слежения (watches).
  • Внутренний отладчик Dwarf FpDebug: "чистый" FpDebug. Пошаговая отладка(Stepping), Запуск(Running), Точки останова(Breakpoint), Список слежения (Watches), Локальные переменные (Locals), Стэк (Stack)....

FpDebug как ссылка на серверную часть IDE LazDebuggerFp

Фактическое имя серверной части IDE - LazDebuggerFp. Это имя пакета, который необходимо установить для использования отладчика. Однако, как видно выше, ни в каком техническом контексте (например, в заголовках в среде IDE) это не упоминается как «FpDebug ...»

Другие проекты FpDebug

Имя используется для другого проекта с той же целью.

Устанровка в IDE

Установите пакет LazDebuggerFp

Общие проблемы отладки

Эти проблемы не могут быть исправлены одним отладчиком. Им тоже нужны изменения в FPC. На некоторых может также повлиять отсутствие поддержки в DWARF.

Эти проблемы относятся ко всем серверным модулям отладчика.

Свойства

Свойства - одна из наиболее востребованных функций (любого) отладчика(ов). Вот почему они еще не могут быть проверены, и почему до этого пройдет еще немало времени.

Прежде, чем вдаваться в подробности: для «Свойства без getter-функции» (т.е. «с прямым доступом к полю») FPC (как средство решения проблемы) в настоящее время добавляет запись для переменной с именем свойства. Это означает, что такие свойства могут отображаться. Они также могут быть записаны отладчиком (если отладчик поддерживает изменение данных), и если они записаны, это делается в обход любой процедуры Setter, поскольку отладчик не знает, есть ли даже сеттер.

Есть несколько недостающих частей, позволяющих отладчику показывать (и, возможно, изменять) свойства.

  • Отладчику нужна поддержка для вызова функций.
  • FPC нужен способ добавить информацию о «свойствах» к отладочной информации.

Что касается вызова функции. Это просто может отсутствовать реализация в отладчике. Это еще не было исследовано более глубоко. Может потребоваться или не потребоваться дополнительная информация в DWARF, созданном FPC.

Что касается добавления «свойств» к отладочной информации: DWARF (по крайней мере версии 2 и 3 / не проверено 4 или 5) фактически не имеет возможности кодировать эту информацию. Следовательно, FPC в настоящее время также не добавляет его.

В случае, если DWARF не добавит это вовремя, DWARF позволит использовать данные от производителя (afaik). До сих пор ни один отладчик не знал бы о каких-либо «частных данных fpc», поэтому в этом не было никакого смысла. В будущем такие данные могут быть согласованы между FPC и FpDebug. Но до этого еще далеко. FpDebug еще даже не выполняет вызов функций.

Strings (vs PChar и Array of Char)

Первоначально в DWARF не было концепции кодирования строк. Это было добавлено в DWARF 4 (требуется проверка), но еще не исследовано на предмет удобства использования с FPC. Также в FPC в настоящее время реализованы только DWARF 2 и 3 (с первыми шагами к версии 4).

Остается только 2 способа кодирования строки в DWARF.

  • Как указатель на char
  • Как массив char

Какой из них используется, зависит от версии FPC и от того, используется ли DWARF 2 или 3.

Если это «указатель на char», то это делает его неотличимым от реального PChar. По этой причине все отладчики в Lazarus иногда для таких отслеживаемых выражений, как SomeString[4], показывают результат «PChar: 'a'; String: 'b'». Поскольку PChar начинается с нуля, а строка - с единицы, индекс «4» может означать 4-й или 5-й символ.

Недавние FPC используют «массив символов», когда они генерируются DWARF 3. В том, что у них (в настоящее время) есть различия в деталях реализации между тем, как они кодируют строки и реальный массив символов. (Например, пропуск необязательного/избыточного бита информации. В данном случае: DW_AT_byte_stride). Эти детали не имеют смысла с точки зрения любого другого отладчика, но FpDebug может их обнаружить, поскольку знает об этих деталях реализации. Конечно, это очень ненадежно, следующая версия FPC всегда может это изменить.

Аналогичным образом FPC обрабатывает ShortStrings внутри как запись и кодирует их как есть. Опять же, различие заключается в деталях реализации.

Изменение управляемых типов

Это применимо к любому отладчику, который может устанавливать новые значения для списка слежения (изменяет переменную в отлаживаемом exe).

Управляемые типы не могут быть изменены корректно.

Для изменения управляемых типов отладчику необходимо знать:

  • счетчик ссылок
  • копирование при записи
  • как выделить/освободить память / или лучше как вызвать методы inc/dec_ref для каждого типа, чтобы они выполняли работу правильно

Ничего из этого не доступно.

Если вы присваиваете новое значение строке или динамическому массиву, то необходимо скорректировать счетчик ссылок старого и нового значения. При необходимости память должна быть выделена или освобождена. Если это сделать неправильно, это, по крайней мере, вызовет утечку памяти. Но это также может вызвать сбои или другие случайные ошибки, когда отлаженный exe продолжает работу.

В массиве можно изменить один элемент. "SomeArray[5] := 7;". Если на массив ссылаются несколько переменных, это повлияет на их всех. То же самое произойдет, если вы выполните этот оператор в своем приложении.

У строки (AnsiString) использует механизм копирование при записи (copy-on-write). Если вы сделаете "SomeString[4] := 'a'", тогда переменная, из которой вы получили доступ к строке, получит новую копию, и другие переменные (которые совместно используют память) не должны быть затронуты. У отладчика этой информации нет. Также у него нет доступа к счетчику ссылок и распределению/освобождению памяти (или внутренним строковым процессам).

Calling function with managed types as param or result

Assuming function calling was implemented in general....

For the same reason as in "Modifying managed types" the debugger could not create strings or arrays in order to call functions that expect them as param.

Result values could be accepted, but would cause a memory leak.

Scope / Variable search order

There are various issues where FPC does not put enough information into the DWARF info so that a debugger could compute the correct scope for all variables. In same cases this may be due to DWARF not offering this, or not offering it at the time where it was implemented or last updated in FPC. Some of it may be fixable, if FPC would change the way it encodes the info.

Nested Procedures

var SomeVar: Integer; // global var

procedure Outer(NumText: string);
var 
  SomeVar: Integer; // local var, declared above "Nested"

  procedure Nested;
  var 
    I: Integer;
  begin
    WriteLn(OuterVarInScope);  
  end;

//var 
//  SomeVar: Integer; // local var, declared below "Nested"
begin
  Nested;
end;

The local var "SomeVar" hides the global var of the same name, if you are in the procedure "Outer". The local var is also visible (and hides the global) if you are in "Nested".

But if you comment the local var "declared above Nested" and uncomment the local var "declared below Nested", then the local var is no longer in the scope of "Nested". "Nested" would now see the global var. ("Outer" still sees the local).

The DWARF info currently only tells the debugger that "SomeVar" is declared as local var in "Outer". And that "Nested" is inside "Outer". But the DWARF info does not include if "SomeVar" is declared above or below "Nested". So the debugger can not tell the difference. The debugger will in both cases show the local "SomeVar" when paused in "Nested"


Global vars from other units

The DWARF info contains a section for each unit. All Symbols of a unit are listed in the correct section. However there is no info, which unit is in the "uses" clause of which other unit. And evidently even less, in which order they are used.

If there are several global variables of the same name, one in each of several units, then FPC uses the order of the uses clause (right to left) to find the variable that will be seen from code in the current unit.

If there is code in a unit FooBar that access a variable named NotInFooBar (that is not declared in unit FooBar), then this variable must be from one of the other units. If there are several variables named NotInFooBar in different units, then the debugger has no information which one FPC did use. The debugger is currently showing the first it finds. (Which is kind of random)

FPC Issues

This affects all debuggers

  • resourcestring

Currently not implemented https://bugs.freepascal.org/view.php?id=35571

  • const Foo = unicodestring('abc')

No debug info implemented https://bugs.freepascal.org/view.php?id=35569

  • type Foo = object (Dwarf 3) - Fixed in 3.3.3

Incorrectly encoded as class-instance https://bugs.freepascal.org/view.php?id=36017
The debugger can not display the data.

  • Dynamic array when cross compiling

https://bugs.freepascal.org/view.php?id=35567
The debugger may calculate the length wrong.

  • Wrong stride for bitpacked array - Fixed in 3.3.3

https://bugs.freepascal.org/view.php?id=36144
FpDebug currently has a workaround

Status

FpDebug supports Linux, Windows and MacOs.

Any functionality regarding execution control (stepping/pausing...) is only tested for Linux and Windows. Support for this on Mac is incomplete/fragile.

Light bulb  Примечание: For Windows/Linux please see Debugger Status

For Mac support is currently considered "Alpha" Data evaluation can be used on Mac via the "LLDB+FpDebug" backend

The information is indicative and subject to updates / subject to further testing

Notes

Stepping out

"Stepping out" relies on finding the caller address. The location of which depends on whether a function has a "stackframe" (use the BasePointer register) and has the frame already/still set-up. Detection of this is limited to a few standard situations. (Especially in none FPC code, or optimized code this will not be detectable).

Within un-optimized FPC code this feature works.

Hardware Watchpoints (aka Data Breakpoints)

Partly implemented for most data types (subset of the types supported by the hardware), including Conditions and other properties.

All watchpoints will have global scope. Watching a local var will alert you the next time the variable's memory is overwritten (e.g. if another variable takes the memory).

"Write only" watchpoints act as "read/write"

Watchpoints also trigger if they are overwritten with the value they already have.

Watchpoints do not show the before/after dialog.

Watchpoints that are not aligned to an address that is a multiply of their size, may be triggered by neighbouring values. E.g., a Word starting at an odd address, can be triggered by the byte before or after it. A 64 bit pointer must be aligned to an 8 byte boundary, or can be triggered by neighbours.

Thread and Stack

See "Stepping out". Relies on the same frame detection.

Watches / Locals / Inspect

Implemented

  • Any missing types need to be discovered (i.e. not aware of any type that does not display, if not listed under "fpc issues"
  • currency types may not display the decimal dot (they will show value * 1000)
  • Not all setting from the watch properties are implemented (most are not)
  • Expressions:
    • The debugger accepts expressions that it will calculate. Not all Pascal operators have been implemented.
    • Expressions are calculated without range checks
      • simple terms (just an identifier)
        • Includes the value identifier "self" (if in a method), and the constants nil, true, false
      • typecasts
      • @ and ^ (address of and deref)
      • "^TFoo(x)" typecast x, as pointer to TFoo
      • () bracketed expression "a*(b+c)"
      • [] index for arrays, pointers, and pchar
      • . Foo.Bar access of members
      • constant numbers in decimal, hex ($), oct (&), bin (%)
      • constant string (ansistring)
      • +-*/ for int and float
      • mod for int
      • + for string
      • +- for pointer+int
      • div for int
      • = <> < > <= >= for int, float, string
      • not and or xor: for int and boolean

Modify variables (not implemented)

Not Done

Console Output

On Windows console is opened by OS. On Linux the output goes to the debugger window "Console output"

Cross bit-ness Debugging (32/64 bit)

FpDebug has no cross debugging between different platforms.

However, if your IDE has a different bitness that your project FpDebug may be able to debug it.

Windows

A 64 bit IDE
can debug both 64bit and 32bit applications
A 32 bit IDE
can only debug 32bit applications

Linux

Cross debugging has not yet been tested, but may be possible.

Not implemented yet

  • Modify watches
  • Changing Location of execution (while paused) / Resume execution from different line
  • Properties
  • Function calls
  • ...