Make sure to build in debug mode by using
Dump LSP requests/responses
--record=/tmp/cquery: You can find stdin/stdout (LSP requests/responses) in
Alternatively, enable logs and pass the
--log-all-to-stderr option to the cquery executable (
bin/cquery --log-file=/tmp/cq.log --log-all-to-stderr). You can find stderr output in:
- Emacs lsp-mode:
*lsp-cquery stderr*buffer. They will also go to
(setq lsp-print-io t)
- VSCode: TODO
You can also use sysdig on Linux:
sudo sysdig -As999 --unbuffered -p '%evt.type %proc.name %evt.buffer' "proc.exe contains cquery and fd.type=pipe" | egrep -v '^Content|^$'
Stopping at the start to debug early issues
To debug individual LSP requests, you can attach your debugger after cquery has done indexing. However,
for many other issues, such as project file loading (
project.cc) and C/C++ parsing and indexing
clang_indexer.cc, you need to set an early breakpoint to be able to trace the code.
It is recommended to use LanguageClient-neovim for debugging (even if you use Emacs or VSCode) because it can be started with simple shell command.
# vimrc nn ,al :LanguageClientStart<cr>
rm -r /tmp/cquery && CQUERY_TRACEME=1 nvim a.cc +'normal ,al'
The Neovim buffer will hang there because
CQUERY_TRACEME=1 causes the bin/cquery process to SIGTSTP itself. In another shell,
gdb -p $(pgrep -fn bin/cquery)
Poor man's breakpoint
Insert an infinite loop
volatile static int z=0;while(!z); somewhere and cquery will stop there. Attach to the cquery process with
gdb -p $(pgrep -fn cquery). Set some breakpoints, use
p z=1 for continuing.
When setting breakpoints, if several threads may stop on the same breakpoint (e.g. concurrent indexer threads),
set scheduler-locking on.
Using a debugger
Cache files are deleted to avoid possible issues related to stale cache.
CQUERY_TRACEME=1 causes the cquery process to stop at the start of
main(). You may attach to the process with:
gdb -p $(pgrep -fn cquery). Invoke
signal SIGCONTif you want cquery to continue running after detaching of gdb.
lldb -p $(pgrep -fn cquery). Invoke
pro sig SIGCONTwhen the process resumes (with a
ccommand) if you want cquery to continue running after detaching.
libclang or indexer callback issues
export LIBCLANG_DISABLE_CRASH_RECOVERY=1 disables libclang crash recovery. In case of libclang or indexer callback issues, you will not see
libclang: crash detected in the log file but get a process crash. And if you attach a debugger before it crashes, you can get the stack trace.
Diagnose whether requests are handled correctly
Set breakpoints in
src/messages/* files. They are inbound message handlers.
./build/cquery --test-unit --test-index
Extension Development / In-Editor Testing
Reload Window command which makes it pretty quick to restart cquery.
"cquery.launch.autoRestart": false will prevent cquery binary from automatically restarting if it crashes.
Reflect when parsing JSON
Problem: the LSP client is not strictly conforming to the spec e.g. passing
null instead of
do-no-exist for optional objects, making
Solution: report this to the corresponding LSP client.