First of all, use a Debug
build. It is compiled with
-O0 -g
while the default Release
build is -O3
.
Logs
Enable logging and verbose mode when starting the server.
-log-file=/tmp/ccls.log -v=1
To figure out the compiler command line used to parse your source files:
- Find the line below
indexer* ... parse
. This is used be the indexer. - Find the line below
preamble ... create session for
. This is used for completion/diagnostics.
If there is some diagnostics problem, change the first argument to clang
, append -fsyntax-only
and run the command in a shell to reproduce.
stderr
You can find stderr output in:
- LanguageClient-neovim:
/tmp/LanguageServer.log
(default) - Emacs lsp-mode:
*lsp-ccls stderr*
buffer. They will also go to*message*
buffer if(setq lsp-log-io t)
- VSCode: TODO
Indexer issues
export CCLS_CRASH_RECOVERY=0
disables clang crash recovery. In case of
clangIndex issues, you will not see clang crashed
in the log file but get a
process crash. And if you attach a debugger before it crashes, you can get the
stack trace.
gdb --args /path/to/ccls -index=/path/to/project
Dump LSP requests/responses
On Linux:
# sysdig
sudo sysdig -As999 --unbuffered -p '%evt.type %proc.name %evt.buffer' "proc.exe contains ccls and fd.type=pipe" | egrep -v '^Content|^$'
# strace
strace -s999 -e read,write -fp $(pgrep -fn ccls)
To intercept early requests/responses, you can use a shell script wrapper
#!/bin/sh
exec strace -s999 -e read,write -o /tmp/strace.log -f path/to/ccls "$@"
Stopping at the start to debug early issues
To debug individual LSP requests, you can attach your debugger after ccls has
done indexing. However, for many other issues, such as project file loading
(project.cc
) and C/C++ parsing and indexing indexer.cc
, you need to set an
early breakpoint to be able to trace the code.
Export the environment variable CCLS_TRACEME=1
or CCLS_TRACEME=s
before starting ccls.
Consider using a shell script wrapper.
CCLS_TRACEME=1
or s
causes the ccls
process to SIGTSTP/SIGSTOP itself.
In another shell, gdb -p $(pgrep -fn ccls)
Poor man's breakpoint
Insert an infinite loop volatile static int z=0;while(!z);
somewhere and
ccls will stop there. Attach to the ccls process with gdb -p $(pgrep -fn ccls)
. Set some breakpoints, use print
commands, and execute p z=1
for
continuing.
When setting breakpoints, if several threads may stop on the same breakpoint
(e.g. concurrent indexer threads), execute set scheduler-locking on
.
Using a debugger
Cache files are deleted to avoid possible issues related to stale
cache. CCLS_TRACEME=1
causes the ccls process to stop at the start of
main()
. You may attach to the process with:
Use CCLS_TRACEME=s
to raise(SIGSTOP)
, if SIGTSTP
does not work.
gdb -p $(pgrep -fn ccls)
. Invokesignal SIGCONT
if you want ccls to continue running after detaching of gdb.lldb -p $(pgrep -fn ccls)
. Invokepro sig SIGCONT
when the process resumes (with ac
command) if you want ccls to continue running after detaching.
Developing
Diagnose whether requests are handled correctly
Set breakpoints in src/messages/*
files. They are inbound message handlers.