Skip to content

Commit 3dcdc73

Browse files
committed
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.
1 parent ca279f4 commit 3dcdc73

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

swift/README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ Notice you can run `bazel run :create-extractor-pack` if you already are in the
2424

2525
Using `codeql ... --search-path=swift/extractor-pack` will then pick up the Swift extractor. You can also use
2626
`--search-path=.`, as the extractor pack is mentioned in the root `codeql-workspace.yml`. Alternatively, you can
27-
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).
27+
set up the search path
28+
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)
29+
.
2830

2931
## Code generation
3032

@@ -53,3 +55,26 @@ options. This is known to have issues on non-Linux platforms.
5355
The `CMakeLists.txt` file allows to load the Swift extractor as a CMake project, which allows integration into a wider
5456
variety of IDEs. Building with CMake also creates a `compile_commands.json` compilation database that can be picked up
5557
by even more IDEs. In particular, opening the `swift` directory in VSCode should work.
58+
59+
### Debugging codeql database creation
60+
61+
If you want to debug a specific run of the extractor within an integration test or a complex `codeql database create`
62+
invocation, you can do so using [`gdbserver`][gdbserver] or [`lldb-server`][lldb-server].
63+
64+
[gdbserver]: https://sourceware.org/gdb/onlinedocs/gdb/gdbserver-man.html
65+
66+
[lldb-server]: https://lldb.llvm.org/man/lldb-server.html
67+
68+
For example with `gdbserver`, you can
69+
70+
```bash
71+
export CODEQL_EXTRACTOR_SWIFT_RUN_UNDER="gdbserver :1234"
72+
export CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER="SomeSwiftSource\.swift" # can be any regex matching extractor args
73+
```
74+
75+
before starting the database extraction, and when that source is encountered the extractor will be run under
76+
a `gdbserver` instance listening on port 1234. You can then attach to the running debugging server from `gdb` or your
77+
IDE. Please refer to your IDE's instructions for how to set up remote debugging.
78+
79+
*Note for CLion users*: there is an issue for which breakpoints will not work in this mode if you are opening the
80+
workspace using the Intellij Bazel plugin. For the time being the workaround is to use the CMake project instead.

swift/extractor/main.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <vector>
66
#include <string>
77
#include <iostream>
8+
#include <regex>
9+
#include <unistd.h>
810

911
#include <swift/Basic/LLVMInitialize.h>
1012
#include <swift/FrontendTool/FrontendTool.h>
@@ -51,7 +53,51 @@ static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration
5153
}
5254
}
5355

56+
// if `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` env variable is set, and either
57+
// * `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER` is not set, or
58+
// * it is set to a regexp matching any substring of the extractor call
59+
// then the running process is substituted with the command (and possibly
60+
// options) stated in `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER`, followed by `argv`.
61+
// Before calling `exec`, `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` is unset to avoid
62+
// unpleasant loops.
63+
// An example usage is to run the extractor under `gdbserver :1234` when the
64+
// arguments match a given source file.
65+
void checkToRunUnderTool(int argc, char* const* argv) {
66+
auto runUnder = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
67+
if (runUnder == nullptr) {
68+
return;
69+
}
70+
auto runUnderFilter = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER");
71+
if (runUnderFilter != nullptr) {
72+
assert(argc > 0);
73+
std::string call = argv[0];
74+
for (auto i = 0; i < argc; ++i) {
75+
call += ' ';
76+
call += argv[i];
77+
}
78+
std::regex filter{runUnderFilter, std::regex_constants::basic | std::regex_constants::nosubs};
79+
if (!std::regex_search(call, filter)) {
80+
return;
81+
}
82+
}
83+
std::vector<char*> args;
84+
for (auto word = std::strtok(runUnder, " "); word != nullptr; word = std::strtok(nullptr, " ")) {
85+
args.push_back(word);
86+
}
87+
if (args.empty()) {
88+
return;
89+
}
90+
for (auto i = 0; i < argc; ++i) {
91+
args.push_back(argv[i]);
92+
}
93+
args.push_back(nullptr);
94+
unsetenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
95+
execvp(args[0], args.data());
96+
}
97+
5498
int main(int argc, char** argv) {
99+
checkToRunUnderTool(argc, argv);
100+
55101
if (argc == 1) {
56102
// TODO: print usage
57103
return 1;

0 commit comments

Comments
 (0)