Swift: add possibility to run the extractor under an env-specified tool

if `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` env variable is set, and either
* `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER` is not set, or
* it is set to a regexp matching any substring of the extractor call
then the extractor process is substituted with the command (and possibly
options) stated in `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER`, followed by the
system arguments of the extractor itself (which should include the
extractor program itself at the start).

Before calling `exec`, `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` is unset to
avoid unpleasant loops.

An example usage is to run the extractor under `gdbserver :1234` when
the arguments match a given source file.
This commit is contained in:
Paolo Tranquilli
2022-10-28 10:53:30 +02:00
parent ca279f4073
commit 3dcdc739de
2 changed files with 72 additions and 1 deletions

View File

@@ -24,7 +24,9 @@ Notice you can run `bazel run :create-extractor-pack` if you already are in the
Using `codeql ... --search-path=swift/extractor-pack` will then pick up the Swift extractor. You can also use
`--search-path=.`, as the extractor pack is mentioned in the root `codeql-workspace.yml`. Alternatively, you can
set up the search path in [the per-user CodeQL configuration file](https://codeql.github.com/docs/codeql-cli/specifying-command-options-in-a-codeql-configuration-file/#using-a-codeql-configuration-file).
set up the search path
in [the per-user CodeQL configuration file](https://codeql.github.com/docs/codeql-cli/specifying-command-options-in-a-codeql-configuration-file/#using-a-codeql-configuration-file)
.
## Code generation
@@ -53,3 +55,26 @@ options. This is known to have issues on non-Linux platforms.
The `CMakeLists.txt` file allows to load the Swift extractor as a CMake project, which allows integration into a wider
variety of IDEs. Building with CMake also creates a `compile_commands.json` compilation database that can be picked up
by even more IDEs. In particular, opening the `swift` directory in VSCode should work.
### Debugging codeql database creation
If you want to debug a specific run of the extractor within an integration test or a complex `codeql database create`
invocation, you can do so using [`gdbserver`][gdbserver] or [`lldb-server`][lldb-server].
[gdbserver]: https://sourceware.org/gdb/onlinedocs/gdb/gdbserver-man.html
[lldb-server]: https://lldb.llvm.org/man/lldb-server.html
For example with `gdbserver`, you can
```bash
export CODEQL_EXTRACTOR_SWIFT_RUN_UNDER="gdbserver :1234"
export CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER="SomeSwiftSource\.swift" # can be any regex matching extractor args
```
before starting the database extraction, and when that source is encountered the extractor will be run under
a `gdbserver` instance listening on port 1234. You can then attach to the running debugging server from `gdb` or your
IDE. Please refer to your IDE's instructions for how to set up remote debugging.
*Note for CLion users*: there is an issue for which breakpoints will not work in this mode if you are opening the
workspace using the Intellij Bazel plugin. For the time being the workaround is to use the CMake project instead.

View File

@@ -5,6 +5,8 @@
#include <vector>
#include <string>
#include <iostream>
#include <regex>
#include <unistd.h>
#include <swift/Basic/LLVMInitialize.h>
#include <swift/FrontendTool/FrontendTool.h>
@@ -51,7 +53,51 @@ static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration
}
}
// if `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` env variable is set, and either
// * `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER` is not set, or
// * it is set to a regexp matching any substring of the extractor call
// then the running process is substituted with the command (and possibly
// options) stated in `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER`, followed by `argv`.
// Before calling `exec`, `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` is unset to avoid
// unpleasant loops.
// An example usage is to run the extractor under `gdbserver :1234` when the
// arguments match a given source file.
void checkToRunUnderTool(int argc, char* const* argv) {
auto runUnder = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
if (runUnder == nullptr) {
return;
}
auto runUnderFilter = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER");
if (runUnderFilter != nullptr) {
assert(argc > 0);
std::string call = argv[0];
for (auto i = 0; i < argc; ++i) {
call += ' ';
call += argv[i];
}
std::regex filter{runUnderFilter, std::regex_constants::basic | std::regex_constants::nosubs};
if (!std::regex_search(call, filter)) {
return;
}
}
std::vector<char*> args;
for (auto word = std::strtok(runUnder, " "); word != nullptr; word = std::strtok(nullptr, " ")) {
args.push_back(word);
}
if (args.empty()) {
return;
}
for (auto i = 0; i < argc; ++i) {
args.push_back(argv[i]);
}
args.push_back(nullptr);
unsetenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
execvp(args[0], args.data());
}
int main(int argc, char** argv) {
checkToRunUnderTool(argc, argv);
if (argc == 1) {
// TODO: print usage
return 1;