Documentation/internal/portnotes.md
Code that isn't tested doesn't work, we like to run CI on all supported platforms. Currently our CI is done on an instance of TeamCity cloud provided by JetBrains, with the exception of the FreeBSD port, which is tested by Cirrus-CI.
TeamCity settings are in .teamcity/settings.kts which in turn runs one of _scripts/test_linux.sh, _scripts/test_mac.sh or _scripts/test_windows.ps1.
All test scripts eventually end up calling into our main test program _scripts/make.go, which makes the appropriate go test calls.
If you plan to port Delve to a new platform you should first figure out how we are going to add your port to our CI, there are three possible solutions:
Exception to this requirement can be discussed in special cases.
An introduction to the architecture of Delve can be found in the 2018 Gophercon Iceland talk: slides, video.
cmd/dlv/... implements the command line programpkg/terminal/... implements the command line user interfaceservice/... with the exception of service/test, implements our API as well as DAPpkg/dwarf/... with the exception of pkg/dwarf/regnum, implements DWARF features not covered by the standard librarypkg that isn't inside pkg/procpkg/proc is the symbolic layer of Delve, its job is to bridge the distance between the API and low level Operating System and CPU features. Almost all features of Delve are implemented here, except for the interaction with the OS/CPU, which is provided by one of three backends: pkg/proc/native, pkg/proc/core or pkg/proc/gdbserial.
This package also contains the main test suite for Delve's backends in pkg/proc/proc_test.go. The tests for reading variables, however, are inside service/test for historical reasons.
When porting Delve to a new CPU a new instance of the proc.Arch structure should be filled, see pkg/proc/arch.go and pkg/proc/amd64_arch.go as an example. To do this you will have to:
pkg/dwarf/regnum (see pkg/dwarf/regnum/amd64.go as an example). This mapping is not arbitrary it needs to be described in some standard document which should be linked to in the documentation of pkg/dwarf/regnum, for example the mapping for amd64 is described by the System V ABI AMD64 Architecture Processor Supplement v. 1.0 on page 61 figure 3.36.proc.Arch.fixFrameUnwindContext or porc.Arch.switchStack should do leave them emptyproc.Arch.prologues field needs to be filled by looking at the relevant parts of the Go linker (cmd/link), the code is somewhere inside $GOROOT/src/cmd/internal/obj, usually the function is called stacksplit.If your target OS uses an executable file format other than ELF, Mach-O or PE you will also have to change pkg/proc/bininfo.go .
See also the note on build tags.
This implements GDB remote serial protocol, it is used as the main backend on macOS as well as connecting to rr.
Unless you are making a macOS port you shouldn't worry about this.
This implements code for reading core files. You don't need to support this for the port platform, see the note on skippable features. If you decide to do it anyway see the note on build tags.
This is the interface between Delve and the OS/CPU, you will definitely want to work on this and it will be the bulk of the port job. The tests for this code however are not in this directory, they are in pkg/proc and service/test.
pkg/proc/native/support_sentinel.go to disable it in the port platformproc.Arch struct for target architecture if it isn't supported alreadypkg/proc
go test -vservice/test
go test -vgo run _scripts/make.go testDelve has the ability to read cross-platform core files: you can read a core file of any supported platform with Delve running on any other supported platform.
For example, a core file produced by linux/arm64 can be read using Delve running under windows/amd64.
This feature has far reaching consequences, for example the stack unwinding code in pkg/proc/stack.go could be asked to unwind a stack for an architecture different from the one its running under.
What this means in practice is that, in general, using build tags (like _amd64.go) or checking runtime.GOOS and runtime.GOARCH is forbidden throughout Delve's source tree, with two important exceptions:
pkg/proc/native is allowed to check runtime.GOOS/runtime.GOARCH as well as using build tagsOther exceptions can be considered, but in general code outside of pkg/proc/native should:
proc.BinaryInfo.GOOS instead of runtime.GOOSproc.BinaryInfo.Arch.Name instead of runtime.GOARCHproc.BinaryInfo.Arch.PtrSize() instead of determining the pointer size with unsafe.Sizeofuint64 wherever an address-sized integer is needed, instead of uintptramd64_filename.go instead of the build tag version, filename_amd64.goDelve offers many features, however not all of them are necessary for a useful port of Delve. The following features are optional to implement for a port:
pkg/proc/core)pkg/proc/native/dump_*.go)(*nativeThread).writeHardwareBreakpoint etc)proc.Arch.switchStack)pkg/proc/internal/ebpf)pkg/proc/fncall.go -- it is probably not supported on the port architecture anyway)For all these features it is acceptable (and possibly advisable) to either leave the implementation empty or to write a stub that always returns an "not implemented" error. Tests relative to these features can be skipped, proc_test.go has a skipOn utility function that can be called to skip a specific test on some architectures.
Other tests should pass reliably, it is acceptable to skip some of them as long as most of them will pass. The following tests should not be skipped even if you will be tempted to:
proc.TestNextConcurrentproc.TestNextConcurrentVariant2proc.TestBreakpointCounts (enable proc.TestBreakpointCountsWithDetection if you have problems with this)proc.TestStepConcurrentDirectproc.TestStepConcurrentPtrDelve was initially written for amd64 and assumed 64bit and little endianness everywhere. The assumption on pointer size has been removed throughout the codebase, the assumption about endianness hasn't. Both pkg/dwarf/loclist and pkg/dwarf/frame incorrectly assume little endian encoding. Other parts of the code might do the same.
When resuming a thread stopped at a breakpoint Delve will:
Step 2 is implemented using the hardware single step feature that many CPUs have and that is exposed via PTRACE_SINGLESTEP or similar features. ARM32 and MIPS do not have a hardware single step implemented, this means that it has to be implemented in software. The linux kernel used to have a software implementation of PTRACE_SINGLESTEP but those have been removed because they were too burdensome to maintain and delegated the feature to userspace debuggers entirely.
A software singlestep implementation would work like this:
Delve does not currently have any infrastructure to help implement this, which means that porting to architectures without hardware singlestep is even more complicated.