Skip to content

Commit 2bec447

Browse files
authored
Merge pull request github#11029 from github/redsun82/swift-filtered-debugging
Swift: add possibility to run the extractor under an env-specified tool
2 parents ec87a93 + daa4e99 commit 2bec447

File tree

14 files changed

+115
-3
lines changed

14 files changed

+115
-3
lines changed

swift/README.md

Lines changed: 30 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,30 @@ 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+
In particular for breakpoints to work you might need to setup the following remote path mapping:
80+
81+
| Remote | Local |
82+
|-------------|--------------------------------------|
83+
| `swift` | `/absolute/path/to/codeql/swift` |
84+
| `bazel-out` | `/absolute/path/to/codeql/bazel-out` |

swift/extractor/main.cpp

Lines changed: 47 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,52 @@ static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration
5153
}
5254
}
5355

56+
static bool checkRunUnderFilter(int argc, char* const* argv) {
57+
auto runUnderFilter = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER");
58+
if (runUnderFilter == nullptr) {
59+
return true;
60+
}
61+
std::string call = argv[0];
62+
for (auto i = 1; i < argc; ++i) {
63+
call += ' ';
64+
call += argv[i];
65+
}
66+
std::regex filter{runUnderFilter, std::regex_constants::basic | std::regex_constants::nosubs};
67+
return std::regex_search(call, filter);
68+
}
69+
70+
// if `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` env variable is set, and either
71+
// * `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER` is not set, or
72+
// * it is set to a regexp matching any substring of the extractor call
73+
// then the running process is substituted with the command (and possibly
74+
// options) stated in `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER`, followed by `argv`.
75+
// Before calling `exec`, `CODEQL_EXTRACTOR_SWIFT_RUN_UNDER` is unset to avoid
76+
// unpleasant loops.
77+
// An example usage is to run the extractor under `gdbserver :1234` when the
78+
// arguments match a given source file.
79+
static void checkWhetherToRunUnderTool(int argc, char* const* argv) {
80+
assert(argc > 0);
81+
82+
auto runUnder = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
83+
if (runUnder == nullptr || !checkRunUnderFilter(argc, argv)) {
84+
return;
85+
}
86+
std::vector<char*> args;
87+
// split RUN_UNDER value by spaces to get args vector
88+
for (auto word = std::strtok(runUnder, " "); word != nullptr; word = std::strtok(nullptr, " ")) {
89+
args.push_back(word);
90+
}
91+
// append process args, including extractor executable path
92+
args.insert(args.end(), argv, argv + argc);
93+
args.push_back(nullptr);
94+
// avoid looping on this function
95+
unsetenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER");
96+
execvp(args[0], args.data());
97+
}
98+
5499
int main(int argc, char** argv) {
100+
checkWhetherToRunUnderTool(argc, argv);
101+
55102
if (argc == 1) {
56103
// TODO: print usage
57104
return 1;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/extractor -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file filtered_in.swift |
2+
| run_under: $CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/extractor -sdk $CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk -c -primary-file unfiltered.swift |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import swift
2+
3+
from StringLiteralExpr s
4+
select s.getValue()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//codeql-extractor-env: CODEQL_EXTRACTOR_SWIFT_RUN_UNDER=./run_under.sh CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER=filtered_in\.swift
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//codeql-extractor-env: CODEQL_EXTRACTOR_SWIFT_RUN_UNDER=./run_under.sh CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER=filtered_in\.swift

swift/ql/test/extractor-tests/run_under/normal.swift

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
ARGS=$(echo $@ | sed 's='$CODEQL_EXTRACTOR_SWIFT_ROOT'=$CODEQL_EXTRACTOR_SWIFT_ROOT=g; s/'$CODEQL_PLATFORM'/$CODEQL_PLATFORM/g')
2+
3+
cat > $CODEQL_EXTRACTOR_SWIFT_TRAP_DIR/$$.trap << EOF
4+
string_literal_exprs(*, "run_under: $ARGS")
5+
EOF
6+
7+
"$@"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
//codeql-extractor-env: CODEQL_EXTRACTOR_SWIFT_RUN_UNDER=./run_under.sh

swift/tools/qltest.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ EXTRACTOR="$CODEQL_EXTRACTOR_SWIFT_ROOT/tools/$CODEQL_PLATFORM/extractor"
1010
SDK="$CODEQL_EXTRACTOR_SWIFT_ROOT/qltest/$CODEQL_PLATFORM/sdk"
1111

1212
for src in *.swift; do
13+
env=()
1314
opts=(-sdk "$SDK" -c -primary-file "$src")
1415
opts+=($(sed -n '1 s=//codeql-extractor-options:==p' $src))
1516
expected_status=$(sed -n 's=//codeql-extractor-expected-status:\s*==p' $src)
1617
expected_status=${expected_status:-0}
18+
env+=($(sed -n '1 s=//codeql-extractor-env:==p' $src))
1719
echo -e "calling extractor with flags: ${opts[@]}\n" >> $QLTEST_LOG
18-
"$EXTRACTOR" "${opts[@]}" >> $QLTEST_LOG 2>&1
20+
env "${env[@]}" "$EXTRACTOR" "${opts[@]}" >> $QLTEST_LOG 2>&1
1921
actual_status=$?
2022
if [[ $actual_status != $expected_status ]]; then
2123
FAILED=1

0 commit comments

Comments
 (0)