aboutsummaryrefslogtreecommitdiffstats
path: root/tools/syz-declextract
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-04-14 08:03:20 +0200
committerDmitry Vyukov <dvyukov@google.com>2025-04-15 08:30:57 +0000
commiteb2144e822c56abb85860646d22d7ce4656fcdb1 (patch)
tree7f1d897ee854cb0c5025121e2a8646ea0c72b48d /tools/syz-declextract
parent851253229c4963cf9144bc2c74b5001693172559 (diff)
tools/syz-declextract: extract ioctls declared with enums
Some ioctls are declared inconsistently using enums rather than macros. Extract these as well.
Diffstat (limited to 'tools/syz-declextract')
-rw-r--r--tools/syz-declextract/clangtool/declextract.cpp65
-rw-r--r--tools/syz-declextract/testdata/file_operations.c7
-rw-r--r--tools/syz-declextract/testdata/file_operations.c.info13
-rw-r--r--tools/syz-declextract/testdata/file_operations.c.json76
-rw-r--r--tools/syz-declextract/testdata/file_operations.c.txt5
-rw-r--r--tools/syz-declextract/testdata/include/uapi/file_operations.h5
6 files changed, 109 insertions, 62 deletions
diff --git a/tools/syz-declextract/clangtool/declextract.cpp b/tools/syz-declextract/clangtool/declextract.cpp
index 4be87b501..3b9769069 100644
--- a/tools/syz-declextract/clangtool/declextract.cpp
+++ b/tools/syz-declextract/clangtool/declextract.cpp
@@ -52,7 +52,8 @@ struct MacroDef {
};
using MacroMap = std::unordered_map<std::string, MacroDef>;
-struct MacroDesc {
+// ConstDesc describes a macro or an enum value.
+struct ConstDesc {
std::string Name;
std::string Value;
SourceRange SourceRange;
@@ -140,8 +141,9 @@ private:
std::optional<QualType> getSizeofType(const Expr* E);
int sizeofType(const Type* T);
int alignofType(const Type* T);
- void extractIoctl(const Expr* Cmd, const MacroDesc& Macro);
- std::optional<MacroDesc> isMacroRef(const Expr* E);
+ void extractIoctl(const Expr* Cmd, const ConstDesc& Const);
+ std::optional<ConstDesc> isMacroOrEnum(const Expr* E);
+ ConstDesc constDesc(const Expr* E, const std::string& Str, const std::string& Value, const SourceRange& SourceRange);
};
// PPCallbacksTracker records all macro definitions (name/value/source location).
@@ -174,6 +176,18 @@ private:
}
};
+const Expr* removeCasts(const Expr* E) {
+ for (;;) {
+ if (auto* P = dyn_cast<ParenExpr>(E))
+ E = P->getSubExpr();
+ else if (auto* C = dyn_cast<CastExpr>(E))
+ E = C->getSubExpr();
+ else
+ break;
+ }
+ return E;
+}
+
bool Extractor::handleBeginSource(CompilerInstance& CI) {
Preprocessor& PP = CI.getPreprocessor();
PP.addPPCallbacks(std::make_unique<PPCallbacksTracker>(PP, Macros));
@@ -357,20 +371,27 @@ std::string Extractor::getDeclFileID(const Decl* Decl) {
return file;
}
-std::optional<MacroDesc> Extractor::isMacroRef(const Expr* E) {
+std::optional<ConstDesc> Extractor::isMacroOrEnum(const Expr* E) {
if (!E)
return {};
+ if (auto* Enum = removeCasts(E)->getEnumConstantDecl())
+ return constDesc(E, Enum->getNameAsString(), "", Enum->getSourceRange());
auto Range = Lexer::getAsCharRange(E->getSourceRange(), *SourceManager, Context->getLangOpts());
const std::string& Str = Lexer::getSourceText(Range, *SourceManager, Context->getLangOpts()).str();
auto MacroDef = Macros.find(Str);
if (MacroDef == Macros.end())
return {};
+ return constDesc(E, Str, MacroDef->second.Value, MacroDef->second.SourceRange);
+}
+
+ConstDesc Extractor::constDesc(const Expr* E, const std::string& Str, const std::string& Value,
+ const SourceRange& SourceRange) {
int64_t Val = evaluate(E);
- emitConst(Str, Val, MacroDef->second.SourceRange.getBegin());
- return MacroDesc{
+ emitConst(Str, Val, SourceRange.getBegin());
+ return ConstDesc{
.Name = Str,
- .Value = MacroDef->second.Value,
- .SourceRange = MacroDef->second.SourceRange,
+ .Value = Value,
+ .SourceRange = SourceRange,
.IntValue = Val,
};
}
@@ -597,18 +618,6 @@ std::string Extractor::getUniqueDeclName(const NamedDecl* Decl) {
return Decl->getNameAsString() + "_" + getDeclFileID(Decl);
}
-const Expr* removeCasts(const Expr* E) {
- for (;;) {
- if (auto* P = dyn_cast<ParenExpr>(E))
- E = P->getSubExpr();
- else if (auto* C = dyn_cast<CastExpr>(E))
- E = C->getSubExpr();
- else
- break;
- }
- return E;
-}
-
bool isInterestingCall(const CallExpr* Call) {
auto* CalleeDecl = Call->getDirectCallee();
// We don't handle indirect calls yet.
@@ -677,8 +686,8 @@ struct FunctionAnalyzer : RecursiveASTVisitor<FunctionAnalyzer> {
auto* Case = dyn_cast<CaseStmt>(C);
if (!Case)
continue;
- auto LMacro = Extractor->isMacroRef(Case->getLHS());
- auto RMacro = Extractor->isMacroRef(Case->getRHS());
+ auto LMacro = Extractor->isMacroOrEnum(Case->getLHS());
+ auto RMacro = Extractor->isMacroOrEnum(Case->getRHS());
if (LMacro || RMacro) {
IsInteresting = true;
break;
@@ -711,7 +720,7 @@ struct FunctionAnalyzer : RecursiveASTVisitor<FunctionAnalyzer> {
// Otherwise it's a default case, for which we don't add any values.
if (auto* Case = dyn_cast<CaseStmt>(C)) {
int64_t LVal = Extractor->evaluate(Case->getLHS());
- auto LMacro = Extractor->isMacroRef(Case->getLHS());
+ auto LMacro = Extractor->isMacroOrEnum(Case->getLHS());
if (LMacro) {
Current->Values.push_back(LMacro->Name);
Extractor->extractIoctl(Case->getLHS(), *LMacro);
@@ -723,7 +732,7 @@ struct FunctionAnalyzer : RecursiveASTVisitor<FunctionAnalyzer> {
// case FOO ... BAR:
// Add all values in the range.
int64_t RVal = Extractor->evaluate(Case->getRHS());
- auto RMacro = Extractor->isMacroRef(Case->getRHS());
+ auto RMacro = Extractor->isMacroOrEnum(Case->getRHS());
for (int64_t V = LVal + 1; V <= RVal - (RMacro ? 1 : 0); V++)
Current->Values.push_back(std::to_string(V));
if (RMacro)
@@ -937,13 +946,13 @@ void Extractor::matchFileOps() {
});
}
-void Extractor::extractIoctl(const Expr* Cmd, const MacroDesc& Macro) {
+void Extractor::extractIoctl(const Expr* Cmd, const ConstDesc& Const) {
// This is old style ioctl defined directly via a number.
// We can't infer anything about it.
- if (Macro.Value.find("_IO") != 0)
+ if (Const.Value.find("_IO") != 0)
return;
FieldType Type;
- auto Dir = _IOC_DIR(Macro.IntValue);
+ auto Dir = _IOC_DIR(Const.IntValue);
if (Dir == _IOC_NONE) {
Type = IntType{.ByteSize = 1, .IsConst = true};
} else if (std::optional<QualType> Arg = getSizeofType(Cmd)) {
@@ -957,7 +966,7 @@ void Extractor::extractIoctl(const Expr* Cmd, const MacroDesc& Macro) {
return;
}
Output.emit(Ioctl{
- .Name = Macro.Name,
+ .Name = Const.Name,
.Type = std::move(Type),
});
}
diff --git a/tools/syz-declextract/testdata/file_operations.c b/tools/syz-declextract/testdata/file_operations.c
index 136e608dd..0e62a6f16 100644
--- a/tools/syz-declextract/testdata/file_operations.c
+++ b/tools/syz-declextract/testdata/file_operations.c
@@ -5,6 +5,10 @@
#include "include/uapi/file_operations.h"
#include "include/uapi/unused_ioctl.h"
+enum {
+ FOO_IOCTL12 = _IOR('c', 12, int),
+};
+
static void foo_open() {}
static void foo_read() {}
static void foo_write() {}
@@ -25,6 +29,9 @@ static void foo_ioctl(void* file, unsigned int cmd, unsigned long arg) {
case FOO_IOCTL3:
case FOO_IOCTL4:
case FOO_IOCTL5:
+ case FOO_IOCTL10:
+ case FOO_IOCTL11:
+ case FOO_IOCTL12:
}
foo_ioctl2(cmd, arg);
}
diff --git a/tools/syz-declextract/testdata/file_operations.c.info b/tools/syz-declextract/testdata/file_operations.c.info
index a6ad4f27b..d0adb11d8 100644
--- a/tools/syz-declextract/testdata/file_operations.c.info
+++ b/tools/syz-declextract/testdata/file_operations.c.info
@@ -4,11 +4,14 @@ FILEOP foo_write func:foo_write loc:0 coverage:0 access:unknown manual_desc:unkn
FILEOP proc_open func:proc_open loc:0 coverage:0 access:unknown manual_desc:unknown auto_desc:false file:file_operations.c subsystem:kernel
FILEOP proc_read func:proc_read loc:0 coverage:0 access:unknown manual_desc:unknown auto_desc:false file:file_operations.c subsystem:kernel
FILEOP proc_write func:proc_write loc:0 coverage:0 access:unknown manual_desc:unknown auto_desc:false file:file_operations.c subsystem:kernel
-IOCTL FOO_IOCTL1 func:foo_ioctl loc:10 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
-IOCTL FOO_IOCTL2 func:foo_ioctl loc:10 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
-IOCTL FOO_IOCTL3 func:foo_ioctl loc:10 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
-IOCTL FOO_IOCTL4 func:foo_ioctl loc:10 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
-IOCTL FOO_IOCTL5 func:foo_ioctl loc:10 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL1 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL10 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL11 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL12 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL2 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL3 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL4 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
+IOCTL FOO_IOCTL5 func:foo_ioctl loc:13 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
IOCTL FOO_IOCTL6 func:foo_ioctl loc:8 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
IOCTL FOO_IOCTL7 func:foo_ioctl loc:8 coverage:0 access:unknown manual_desc:false auto_desc:true file:file_operations.c subsystem:kernel
IOCTL UNUSED_IOCTL1 func:unused_ioctl loc:4 coverage:0 access:unknown manual_desc:false auto_desc:false file:file_operations.c subsystem:kernel
diff --git a/tools/syz-declextract/testdata/file_operations.c.json b/tools/syz-declextract/testdata/file_operations.c.json
index 734840160..0c1706767 100644
--- a/tools/syz-declextract/testdata/file_operations.c.json
+++ b/tools/syz-declextract/testdata/file_operations.c.json
@@ -27,8 +27,8 @@
{
"name": "foo_ioctl",
"file": "file_operations.c",
- "start_line": 21,
- "end_line": 30,
+ "start_line": 25,
+ "end_line": 37,
"is_static": true,
"scopes": [
{
@@ -74,18 +74,21 @@
"FOO_IOCTL2",
"FOO_IOCTL3",
"FOO_IOCTL4",
- "FOO_IOCTL5"
+ "FOO_IOCTL5",
+ "FOO_IOCTL10",
+ "FOO_IOCTL11",
+ "FOO_IOCTL12"
],
- "start_line": 23,
- "end_line": 28
+ "start_line": 27,
+ "end_line": 35
}
]
},
{
"name": "foo_ioctl2",
"file": "file_operations.c",
- "start_line": 13,
- "end_line": 19,
+ "start_line": 17,
+ "end_line": 23,
"is_static": true,
"scopes": [
{
@@ -97,16 +100,16 @@
"FOO_IOCTL6",
"FOO_IOCTL7"
],
- "start_line": 15,
- "end_line": 18
+ "start_line": 19,
+ "end_line": 22
}
]
},
{
"name": "foo_mmap",
"file": "file_operations.c",
- "start_line": 11,
- "end_line": 11,
+ "start_line": 15,
+ "end_line": 15,
"is_static": true,
"scopes": [
{
@@ -117,8 +120,8 @@
{
"name": "foo_open",
"file": "file_operations.c",
- "start_line": 8,
- "end_line": 8,
+ "start_line": 12,
+ "end_line": 12,
"is_static": true,
"scopes": [
{
@@ -129,8 +132,8 @@
{
"name": "foo_read",
"file": "file_operations.c",
- "start_line": 9,
- "end_line": 9,
+ "start_line": 13,
+ "end_line": 13,
"is_static": true,
"scopes": [
{
@@ -141,8 +144,8 @@
{
"name": "foo_write",
"file": "file_operations.c",
- "start_line": 10,
- "end_line": 10,
+ "start_line": 14,
+ "end_line": 14,
"is_static": true,
"scopes": [
{
@@ -165,8 +168,8 @@
{
"name": "proc_ioctl",
"file": "file_operations.c",
- "start_line": 43,
- "end_line": 43,
+ "start_line": 50,
+ "end_line": 50,
"is_static": true,
"scopes": [
{
@@ -177,8 +180,8 @@
{
"name": "proc_open",
"file": "file_operations.c",
- "start_line": 40,
- "end_line": 40,
+ "start_line": 47,
+ "end_line": 47,
"is_static": true,
"scopes": [
{
@@ -189,8 +192,8 @@
{
"name": "proc_read",
"file": "file_operations.c",
- "start_line": 41,
- "end_line": 41,
+ "start_line": 48,
+ "end_line": 48,
"is_static": true,
"scopes": [
{
@@ -201,8 +204,8 @@
{
"name": "proc_write",
"file": "file_operations.c",
- "start_line": 42,
- "end_line": 42,
+ "start_line": 49,
+ "end_line": 49,
"is_static": true,
"scopes": [
{
@@ -213,8 +216,8 @@
{
"name": "unused_ioctl",
"file": "file_operations.c",
- "start_line": 59,
- "end_line": 64,
+ "start_line": 66,
+ "end_line": 71,
"is_static": true,
"scopes": [
{
@@ -226,8 +229,8 @@
"UNUSED_IOCTL1",
"UNUSED_IOCTL2"
],
- "start_line": 61,
- "end_line": 63
+ "start_line": 68,
+ "end_line": 70
}
]
}
@@ -239,6 +242,21 @@
"value": 25345
},
{
+ "name": "FOO_IOCTL10",
+ "filename": "include/uapi/file_operations.h",
+ "value": 2147771146
+ },
+ {
+ "name": "FOO_IOCTL11",
+ "filename": "include/uapi/file_operations.h",
+ "value": 2147771147
+ },
+ {
+ "name": "FOO_IOCTL12",
+ "filename": "file_operations.c",
+ "value": 2147771148
+ },
+ {
"name": "FOO_IOCTL2",
"filename": "include/uapi/file_operations.h",
"value": 2147771138
diff --git a/tools/syz-declextract/testdata/file_operations.c.txt b/tools/syz-declextract/testdata/file_operations.c.txt
index f37a386db..30743ffb9 100644
--- a/tools/syz-declextract/testdata/file_operations.c.txt
+++ b/tools/syz-declextract/testdata/file_operations.c.txt
@@ -15,6 +15,9 @@ read$auto_foo_file_operations(fd fd_foo_file_operations, buf ptr[out, array[int8
write$auto_foo_file_operations(fd fd_foo_file_operations, buf ptr[in, array[int8]], len bytesize[buf])
mmap$auto_foo_file_operations(addr vma, len len[addr], prot flags[mmap_prot], flags flags[mmap_flags], fd fd_foo_file_operations, offset fileoff)
ioctl$auto_FOO_IOCTL1(fd fd_foo_file_operations, cmd const[FOO_IOCTL1], arg const[0])
+ioctl$auto_FOO_IOCTL10(fd fd_foo_file_operations, cmd const[FOO_IOCTL10], arg ptr[in, array[int8]])
+ioctl$auto_FOO_IOCTL11(fd fd_foo_file_operations, cmd const[FOO_IOCTL11], arg ptr[in, array[int8]])
+ioctl$auto_FOO_IOCTL12(fd fd_foo_file_operations, cmd const[FOO_IOCTL12], arg ptr[in, array[int8]])
ioctl$auto_FOO_IOCTL2(fd fd_foo_file_operations, cmd const[FOO_IOCTL2], arg ptr[in, int32])
ioctl$auto_FOO_IOCTL3(fd fd_foo_file_operations, cmd const[FOO_IOCTL3], arg ptr[in, foo_ioctl_arg$auto])
ioctl$auto_FOO_IOCTL4(fd fd_foo_file_operations, cmd const[FOO_IOCTL4], arg ptr[inout, foo_ioctl_arg$auto])
@@ -26,3 +29,5 @@ foo_ioctl_arg$auto {
a int32
b int32
}
+
+define FOO_IOCTL12 2147771148
diff --git a/tools/syz-declextract/testdata/include/uapi/file_operations.h b/tools/syz-declextract/testdata/include/uapi/file_operations.h
index f81d6886d..a4fa3a21e 100644
--- a/tools/syz-declextract/testdata/include/uapi/file_operations.h
+++ b/tools/syz-declextract/testdata/include/uapi/file_operations.h
@@ -13,6 +13,11 @@
#define FOO_IOCTL8 _IO('c', 8)
#define FOO_IOCTL9 _IO('c', 9)
+enum {
+ FOO_IOCTL10 = _IOR('c', 10, int),
+ FOO_IOCTL11 = _IOR('c', 11, int),
+};
+
struct foo_ioctl_arg {
int a, b;
};