Re: [Lazarus] Making fpdebug more cross-platform friendly
Martin Frb via lazarus schrieb am Do., 16. Dez. 2021, 23:27: > Only, question is, if we need the ABI? > - Do win64 and linux64 share the same ABI? (or win32 <> linux32)? >Afaik SEH is win specific (and probably would be best of in the ABI?). >But there could still be a base class that is shared between Win/Linux. > Yes, SEH is Windows specific. The ABI is mostly CPU specific however. E.g. all the i386 calling conventions can be used on all OSes. On the x86_64 systems one usually uses either the SysV or the Win64 ABI, but both FPC and Clang allow the use of the other calling convention as well. On the other hand the register usage on m68k for example differs between Amiga and non-Amiga (the stack pointer is a different register and the stack alignment is 2 instead of 4 Byte) and this can't be changed. So in my opinion the design should allow for as much code sharing/reuse as possible, e.g. with a general x86_64 ABI with OS specifics (e.g. SEH) on top. Regards, Sven > -- ___ lazarus mailing list lazarus@lists.lazarus-ide.org https://lists.lazarus-ide.org/listinfo/lazarus
Re: [Lazarus] Making fpdebug more cross-platform friendly
Ok, for now limiting this to a smaller audience, to get some brainstorming done. => Original mail at the bottom. Some initial thoughts. *** First, I would suggest, that all calls go to T[Foo]DbgProccess *** T[Foo]DbgProccess can then forward them. Outside classes should not have knowledge, nor access to the delegates. (Better start restricted, so we have more flexibility for future changes) -- I can currently see the following areas, that could be separated as needed. API: Calls to the OS => start/stop/mem-access/register/access ABI: Conventions about register usage, and stack layout (registers are known by either name or dwarf-index) CPU: Identifying specific asm instructions (Breakpoint / ret / call ) IHMO: - API remains hardcoded in T[Foo]DbgProccess. - The others are private delegate classes. - Your idea about WOW64_CONTEXT / _ARM64_NT_CONTEXT is imho API. It can not be CPU or ABI. If it were, we would need to subclass them for each API. - Identifying breakpoint is CPU (not necessarily the current asm class / could be a new class) - unwinding stack => could be either. (there may be an API of the OS, otherwise ABI, maybe with help of CPU) Only, question is, if we need the ABI? - Do win64 and linux64 share the same ABI? (or win32 <> linux32)? Afaik SEH is win specific (and probably would be best of in the ABI?). But there could still be a base class that is shared between Win/Linux. Similar about ABI vs CPU. Only here we definitely have a shared base class for inter 32/64bit (currently it's only one class / no subclasses for the bitness). So IMHO there is a point in splitting them. --- Mind that, FPC specific units could provide specialized sub-classes of any of the delegate classes. E.g. dealing with $fin$MyProcedure subroutines. (Win-SEH) For some purposes, finally blocks need to look like they are part of the main-procedure, not sub-routines of their own. --- With the above some of the issues can be solved by combining different subclasses of each. And then we would end up with combinations like this: (I am not sure, if the ABI for Win and Linux are actually different..., but there would be win-seh) TDbgWinProcess with: x64-win ABI / x64 CPU TDbgWinProcess with: i386-win-ABI / x32 CPU TDbgWinProcess with: arm-ABI / arm CPU TDbgLinuxProcess with: x64-linux-ABI / x64 CPU TDbgLinuxProcess with: i386-linux-ABI / x32 CPU ... There is potential for some re-usable code there. Since all access would be through T[Foo]DbgProccess code can be moved gradually. --- However, setting Breakpoints for example may be a bit more complex. For example: - if there is a limit to the amount, or only certain locations can be set. - If breakpoints are not set to memory, but like watchpoints on intel. In those cases, it needs to be decided how much power to give to the CPU class. Should the CPU class be able to make calls to read/write mem and/or change registers? (That is the point, where it would be a separate class from the asm class, which at most reads mem) Even, if the CPU class can handle it all by itself, it may still end up needing support in the main class (T[Foo]DbgProccess). - There can be errors due to restrictions (user watch points have been set to the register needed for the breakpoint). - There may be different requirement on the relative timing of those actions and other actions outside the CPU class. Those timings are not known by the CPU class. So we end up with a tighter coupling than desired. -- Comments? Ideas? On 16/12/2021 12:10, Christo Crause via lazarus wrote: Currently there are a few instances where x86 specific assumptions/code are used [1] in what I consider as the target agnostic level of fpdebug. My proposal is to move these instances to a hardware target specific unit so that these target specific handling is clearly separated. One location for the target specific code is perhaps the fpdbgdisas* units, since it already provides a number of hardware specific concepts such as identifying call & return instructions and some stack frame analysis. Adding for example IsSoftwareBreakInstruction seems like a logical addition. These changes are hindering some functionality on AVR and Xtensa targets, e.g. some instructions are incorrectly disassembled because they start with $CC, which is incorrectly interpreted as a software break. Also the StepOut functionality currently assumes the x86 ABI to locate the return address, which obviously fails for other targets. While these methods could in principle be hidden by new target specific overrides, it is not aligned with proper OOP principles. I will start with some concepts to address these soon. Similarly, but possibly a bit more tricky, is to separate the OS code from the OS view of the hardware. This would imply for example that the register handling in fpdbglinuxclasses needs to be
Re: [Lazarus] Making fpdebug more cross-platform friendly
On 16/12/2021 12:10, Christo Crause via lazarus wrote: One location for the target specific code is perhaps the fpdbgdisas* units, since it already provides a number of hardware specific concepts such as identifying call & return instructions and some stack frame analysis. Adding for example IsSoftwareBreakInstruction seems like a logical addition. The current Frame-analysis is not really in good shape. It is more likely that the central entry point for hardware and/or OS specifics will be the subclassed TDbgProcess (or potentially in some cases the subclassed Thread, but I can't think of a case for that). The process class can then decide to use the asm class, or have other means... Dividing this between hardware and OS will be a story of its own. These changes are hindering some functionality on AVR and Xtensa targets, e.g. some instructions are incorrectly disassembled because they start with $CC, which is incorrectly interpreted as a software break. So that needs to be controlled by the process class then. Also the StepOut functionality currently assumes the x86 ABI to locate the return address, which obviously fails for other targets. While these methods could in principle be hidden by new target specific overrides, it is not aligned with proper OOP principles. I will start with some concepts to address these soon. Probably there will be some need for delegate classes Btw, this is a big one, and I have some todo on this too. Currently the entire handling of win SEH is in LazDebuggerFp => that should move. But it needs exactly the above ability of having target specific functions. Even one step further: => those are not even default for win, because they assume fpc generated code [1]. So they need to be added, similar like the fpc additions for dwarf (separate unit, with detection of compiler) So it's likely they will undergo a big rework. [1] They should be fixed to be generic. Similarly, but possibly a bit more tricky, is to separate the OS code from the OS view of the hardware. This would imply for example that the register handling in fpdbglinuxclasses needs to be separated from the rest of the code so that one could re-use the Linux layer, but swap out the hardware specific layer x86_Linux. Similarly for Windows, the WOW64_CONTEXT could be part of an x86_Windows unit, so that it is possible to also define and use _ARM64_NT_CONTEXT for Windows on ARM64. [1] Examples of x86 specific code not in a x86 specific unit fpdbgclasses.pas: checking for int3 and its x86 encoding in TDbgProcess, TDbgThread and TBreakLocationMap The above will probably best go into a delegation class. But the extend needs to be evaluated. The first 2 actually should allow to override (so that is not the desired solution)... fpdbgcontroller.pas: TDbgControllerCallRoutineCmd uses x86 call specific encoding in InsertCallInstructionCode and RestoreInstructionPointer, StoreRoutineResult using x86 register specific assumptions, TDbgControllerStepOutCmd.SetReturnAdressBreakpoint assumes return address is stored according to x86 stack frame layout. As I said, there will have to be a big rework. Until then, quickfix it by overriding it in the backend (like LazDebuggerFp does). More later -- ___ lazarus mailing list lazarus@lists.lazarus-ide.org https://lists.lazarus-ide.org/listinfo/lazarus
[Lazarus] Making fpdebug more cross-platform friendly
Currently there are a few instances where x86 specific assumptions/code are used [1] in what I consider as the target agnostic level of fpdebug. My proposal is to move these instances to a hardware target specific unit so that these target specific handling is clearly separated. One location for the target specific code is perhaps the fpdbgdisas* units, since it already provides a number of hardware specific concepts such as identifying call & return instructions and some stack frame analysis. Adding for example IsSoftwareBreakInstruction seems like a logical addition. These changes are hindering some functionality on AVR and Xtensa targets, e.g. some instructions are incorrectly disassembled because they start with $CC, which is incorrectly interpreted as a software break. Also the StepOut functionality currently assumes the x86 ABI to locate the return address, which obviously fails for other targets. While these methods could in principle be hidden by new target specific overrides, it is not aligned with proper OOP principles. I will start with some concepts to address these soon. Similarly, but possibly a bit more tricky, is to separate the OS code from the OS view of the hardware. This would imply for example that the register handling in fpdbglinuxclasses needs to be separated from the rest of the code so that one could re-use the Linux layer, but swap out the hardware specific layer x86_Linux. Similarly for Windows, the WOW64_CONTEXT could be part of an x86_Windows unit, so that it is possible to also define and use _ARM64_NT_CONTEXT for Windows on ARM64. Any thoughts, critique or suggestions are welcome. Best wishes, Christo [1] Examples of x86 specific code not in a x86 specific unit fpdbgclasses.pas: checking for int3 and its x86 encoding in TDbgProcess, TDbgThread and TBreakLocationMap fpdbgcontroller.pas: TDbgControllerCallRoutineCmd uses x86 call specific encoding in InsertCallInstructionCode and RestoreInstructionPointer, StoreRoutineResult using x86 register specific assumptions, TDbgControllerStepOutCmd.SetReturnAdressBreakpoint assumes return address is stored according to x86 stack frame layout. -- ___ lazarus mailing list lazarus@lists.lazarus-ide.org https://lists.lazarus-ide.org/listinfo/lazarus