aboutsummaryrefslogtreecommitdiff
path: root/runtime/doc/dev_tools.txt
blob: efc6ce277a28e9d70917d2ba05d672213c262b23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
*dev_tools.txt*          Nvim


                            NVIM REFERENCE MANUAL


Tools and techniques for developing Nvim                        *dev-tools*

The following advice is helpful when working on or debugging issues with Nvim
itself.

TODO: merge |debug.txt| into here.

                                  Type |gO| to see the table of contents.

==============================================================================
Backtraces                                            *dev-tools-backtrace*

LINUX

Core dumps are disabled by default on Ubuntu, CentOS and others.
To enable core dumps:
>bash
    ulimit -c unlimited
<
On systemd-based systems getting a backtrace is as easy as:
>bash
    coredumpctl -1 gdb
<
`coredumpctl` is an optional tool, so you may need to install it:
>bash
    sudo apt install systemd-coredump
<

The full backtrace is most useful; please send us the `backtrace.txt` file
when reporting a bug related to a crash:
>bash
    2>&1 coredumpctl -1 gdb | tee -a backtrace.txt
    (gdb) thread apply all bt full
<

On systems without `coredumpctl`, you may find a `core` dump file appearing
in the current directory or in other locations. On Linux systems where
`apport` is installed (such as Ubuntu), the directory where core dump files
are saved can be `/var/lib/apport/coredump` or elsewhere, depending on the
system configuration (see `/proc/sys/kernel/core_pattern`). See also:
https://stackoverflow.com/a/18368068

To get a backtrace from the `./core` dump file:
>bash
    gdb build/bin/nvim ./core 2>&1 | tee backtrace.txt
    (gdb) thread apply all bt full
<

MACOS

If `nvim` crashes, you can see the backtrace in `Console.app` (under "Crash
Reports" or "User Diagnostic Reports" for older macOS versions).
>bash
    open -a Console
<
You may also want to enable core dumps on macOS. To do this, first make sure
the `/cores/` directory exists and is writable:
>bash
    sudo mkdir /cores
    sudo chown root:admin /cores
    sudo chmod 1775 /cores
<
Then set the core size limit to `unlimited`:
>bash
    ulimit -c unlimited
<
Note that this is done per shell process. If you want to make this the default
for all shells, add the above line to your shell's init file (e.g. `~/.bashrc`
or similar).

You can then open the core file in `lldb`:
>bash
    lldb -c /cores/core.12345
<
Apple's documentation archive has some other useful information
https://developer.apple.com/library/archive/technotes/tn2124/_index.html#//apple_ref/doc/uid/DTS10003391-CH1-SECCOREDUMPS,
but note that some of the things on this page are out of date (such as enabling
core dumps with `/etc/launchd.conf`).

==============================================================================
Gdb                                                          *dev-tools-gdb*

USING GDB TO STEP THROUGH FUNCTIONAL TESTS

Use `TEST_TAG` to run tests matching busted tags (of the form `#foo` e.g.
`it("test #foo ...", ...)`):
>bash
    GDB=1 TEST_TAG=foo make functionaltest
<
Then, in another terminal:
>bash
    gdb build/bin/nvim
    (gdb) target remote localhost:7777

-- See `nvim_argv` in https://github.com/neovim/neovim/blob/master/test/functional/testnvim.lua.

USING LLDB TO STEP THROUGH UNIT TESTS

>
    lldb .deps/usr/bin/luajit -- .deps/usr/bin/busted --lpath="./build/?.lua" test/unit/
<
USING GDB

To attach to a running `nvim` process with a pid of 1234 (Tip: the pid of a
running Nvim instance can be obtained by calling |getpid()|), for instance:
>bash
    gdb -tui -p 1234 build/bin/nvim
<
The `gdb` interactive prompt will appear. At any time you can:

- `break foo` to set a breakpoint on the `foo()` function
- `n` to step over the next statement
    - `<Enter>` to repeat the last command
- `s` to step into the next statement
- `c` to continue
- `finish` to step out of the current function
- `p zub` to print the value of `zub`
- `bt` to see a backtrace (callstack) from the current location
- `CTRL-x CTRL-a` or `tui enable` to show a TUI view of the source file in the
  current debugging context. This can be extremely useful as it avoids the
  need for a gdb "frontend".
- `<up>` and `<down>` to scroll the source file view

GDB REVERSE DEBUGGING

- `set record full insn-number-max unlimited`
- `continue` for a bit (at least until `main()` is executed
- `record`
- provoke the bug, then use `revert-next`, `reverse-step`, etc. to rewind the
  debugger

USING GDBSERVER

You may want to connect multiple `gdb` clients to the same running `nvim`
process, or you may want to connect to a remote `nvim` process with a local
`gdb`. Using `gdbserver`, you can attach to a single process and control it
from multiple `gdb` clients.

Open a terminal and start `gdbserver` attached to `nvim` like this:
>bash
    gdbserver :6666 build/bin/nvim 2> gdbserver.log
<
`gdbserver` is now listening on port 6666. You then need to attach to this
debugging session in another terminal:
>bash
    gdb build/bin/nvim
<
Once you've entered `gdb`, you need to attach to the remote session:
>
    (gdb) target remote localhost:6666
<
In case gdbserver puts the TUI as a background process, the TUI can become
unable to read input from pty (and receives SIGTTIN signal) and/or output data
(SIGTTOU signal). To force the TUI as the foreground process, you can add
>c
    signal (SIGTTOU, SIG_IGN);
    if (!tcsetpgrp(data->input.in_fd, getpid())) {
        perror("tcsetpgrp failed");
    }
<
to `tui.c:terminfo_start`.

USING GDBSERVER IN TMUX

Consider using a custom makefile
https://github.com/neovim/neovim/blob/master/BUILD.md#custom-makefile to
quickly start debugging sessions using the `gdbserver` method mentioned above.
This example `local.mk` will create the debugging session when you type `make
debug`.
>make
    .PHONY: dbg-start dbg-attach debug build

    build:
        @$(MAKE) nvim

    dbg-start: build
        @tmux new-window -n 'dbg-neovim' 'gdbserver :6666 ./build/bin/nvim -D'

    dbg-attach:
        @tmux new-window -n 'dbg-cgdb' 'cgdb -x gdb_start.sh ./build/bin/nvim'

    debug: dbg-start dbg-attach
<
Here `gdb_start.sh` includes `gdb` commands to be called when the debugger
starts. It needs to attach to the server started by the `dbg-start` rule. For
example:
>
    (gdb) target remote localhost:6666
    (gdb) br main
<

vim:tw=78:ts=8:et:ft=help:norl: