Skip to content

Commit 8fa99e9

Browse files
Add new expansion policies.
This commit add two new expansion policies: - system: keep includes from system headers, such as stdio.h, stdlib.h, and other libraries that may be installed in the system. - compiler: keep compiler-specific includes, such as stdatomic.h, stddef.h, and other includes that may expand into compiler-specific code. Use `-DCE_KEEP_INCLUDES=<policy>` to use them. Signed-off-by: Giuliano Belinassi <gbelinassi@suse.de>
1 parent 8655255 commit 8fa99e9

File tree

6 files changed

+113
-18
lines changed

6 files changed

+113
-18
lines changed

README.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,17 @@ Notice how *any reference to unused_function is removed* and *all headers has be
9393
$ clang out.c -O2 -o a
9494
```
9595
If you desire to keep the includes, see `-DCE_KEEP_INCLUDES` options and the _Supported options_ chapter.
96+
The following expansion policies are supported:
97+
- `nothing`: Do not expand any header.
98+
- `everything`: Expand all headers. Has the same semantic effect of not passing `-DCE_KEEP_INCLUDES`, but forces clang-extract to pass it through its header expansion logics (slow and very likely buggy!).
99+
- `kernel`: Special policy used by the kernel livepatching developers.
100+
- `system`: Keep all system headers installed in `/usr/include`, etc.
101+
- `compiler`: Keep all compiler-specific headers, such as `stdatomic.h`. Useful if you want to expand everything but still want to ensure compatibility with other compilers.
102+
103+
You may want to use `clang-tidy` to cleanup the generated file afterwards to remove duplicated includes:
104+
```
105+
$ clang-tidy -checks='-*,readability-duplicate-include,misc-include-cleaner' -fix <out.c>
106+
```
96107

97108
### Symbol Externalization
98109

@@ -192,7 +203,7 @@ Clang-extract support many options which controls the output code:
192203
- `-DCE_NO_EXTERNALIZATION` Disable symbol externalization.
193204
- `-DCE_DUMP_PASSES` Dump the results of each transformation pass into files. Files will be dumped at the same path of the input files. Additional files are also generated on `/tmp/` folder.
194205
- `-DCE_KEEP_INCLUDES` Keep all possible `#include<file>` directives.
195-
- `-DCE_KEEP_INCLUDES=<policy>` Keep all possible `#include<file>` directives, but using the specified include expansion <policy>. Valid values are nothing, everything and kernel.
206+
- `-DCE_KEEP_INCLUDES=<policy>` Keep all possible `#include<file>` directives, but using the specified include expansion <policy>. Valid values are `nothing`, `everything`, `kernel`, `system` and `compiler`.
196207
- `-DCE_EXPAND_INCLUDES=<args>` Force expansion of the headers provided in <args>.
197208
- `-DCE_RENAME_SYMBOLS` Allow renaming of extracted symbols.
198209
- `-DCE_DEBUGINFO_PATH=<arg>` Path to the compiled (ELF) object of the desired program to extract. This is used to decide if externalization is necessary or not for given symbol.

libcextract/ArgvParser.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ void ArgvParser::Print_Usage_Message(void)
157157
" -DCE_KEEP_INCLUDES=<policy>\n"
158158
" Keep all possible #include<file> directives, but using the\n"
159159
" specified include expansion <policy>. Valid values are\n"
160-
" nothing, everything and kernel.\n"
160+
" nothing, everything, kernel, system and compiler.\n"
161161
" -DCE_EXPAND_INCLUDES=<args>\n"
162162
" Force expansion of the headers provided in <args>.\n"
163163
" -DCE_RENAME_SYMBOLS Allow renaming of extracted symbols.\n"

libcextract/ExpansionPolicy.cpp

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -39,25 +39,40 @@ bool KernelExpansionPolicy::Must_Expand(const StringRef &absolute_path,
3939
return true;
4040
}
4141

42-
IncludeExpansionPolicy *IncludeExpansionPolicy::Get_Expansion_Policy(
43-
IncludeExpansionPolicy::Policy p)
42+
bool SystemExpansionPolicy::Must_Expand(const StringRef &absolute_path,
43+
const StringRef &relative_path)
4444
{
45-
switch (p) {
46-
case Policy::NOTHING:
47-
return new NoIncludeExpansionPolicy();
48-
break;
49-
50-
case Policy::EVERYTHING:
51-
return new ExpandEverythingExpansionPolicy();
52-
break;
45+
const char *absolute_path_c = absolute_path.data();
46+
47+
/* Look for system headers by looking to specific prefixes. */
48+
const char *include_paths[] = { "/usr/include/", "/usr/lib64/",
49+
"/usr/lib/", "/usr/local/include/", };
50+
for (unsigned i = 0; i < ARRAY_LENGTH(include_paths); i++) {
51+
if (prefix(include_paths[i], absolute_path_c)) {
52+
return false; // Do not expand.
53+
}
54+
}
5355

54-
case Policy::KERNEL:
55-
return new KernelExpansionPolicy();
56-
break;
56+
/* Expand anything that doesn't match this. */
57+
return true;
58+
}
5759

58-
default:
59-
assert(false && "Invalid policy");
60+
bool CompilerExpansionPolicy::Must_Expand(const StringRef &absolute_path,
61+
const StringRef &relative_path)
62+
{
63+
const char *absolute_path_c = absolute_path.data();
64+
65+
/* Look for clang compiler headers by looking to specific prefixes. */
66+
const char *include_paths[] = { "/usr/lib64/clang/", "/usr/lib/clang/",
67+
"/usr/local/lib64/clang/", "/usr/local/lib64/clang/", };
68+
for (unsigned i = 0; i < ARRAY_LENGTH(include_paths); i++) {
69+
if (prefix(include_paths[i], absolute_path_c)) {
70+
return false; // Do not expand.
71+
}
6072
}
73+
74+
/* Expand anything that doesn't match this. */
75+
return true;
6176
}
6277

6378
std::unique_ptr<IncludeExpansionPolicy> IncludeExpansionPolicy::Get_Expansion_Policy_Unique(
@@ -79,6 +94,16 @@ std::unique_ptr<IncludeExpansionPolicy> IncludeExpansionPolicy::Get_Expansion_Po
7994
KernelExpansionPolicy());
8095
break;
8196

97+
case Policy::SYSTEM:
98+
return std::make_unique<SystemExpansionPolicy>(
99+
SystemExpansionPolicy());
100+
break;
101+
102+
case Policy::COMPILER:
103+
return std::make_unique<CompilerExpansionPolicy>(
104+
CompilerExpansionPolicy());
105+
break;
106+
82107
default:
83108
assert(false && "Invalid policy");
84109
}
@@ -96,7 +121,9 @@ IncludeExpansionPolicy::Policy IncludeExpansionPolicy::Get_From_String(const cha
96121
} policies[] = {
97122
{ "nothing", IncludeExpansionPolicy::NOTHING },
98123
{ "everything", IncludeExpansionPolicy::EVERYTHING },
99-
{ "kernel", IncludeExpansionPolicy::KERNEL }
124+
{ "kernel", IncludeExpansionPolicy::KERNEL },
125+
{ "system", IncludeExpansionPolicy::SYSTEM },
126+
{ "compiler", IncludeExpansionPolicy::COMPILER },
100127
};
101128

102129
for (unsigned long i = 0; i < ARRAY_LENGTH(policies); i++) {

libcextract/ExpansionPolicy.hh

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class IncludeExpansionPolicy
3232
NOTHING,
3333
EVERYTHING,
3434
KERNEL,
35+
SYSTEM,
36+
COMPILER,
3537
};
3638

3739
static IncludeExpansionPolicy *Get_Expansion_Policy(Policy policy);
@@ -75,8 +77,23 @@ class ExpandEverythingExpansionPolicy : public IncludeExpansionPolicy
7577
}
7678
};
7779

80+
/** Expand any header according to kernel livepatching rules. */
7881
class KernelExpansionPolicy : public IncludeExpansionPolicy
7982
{
8083
public:
8184
virtual bool Must_Expand(const StringRef &absolute_path, const StringRef &relative_path);
8285
};
86+
87+
/** Expand any header that is not installed in the system. */
88+
class SystemExpansionPolicy : public IncludeExpansionPolicy
89+
{
90+
public:
91+
virtual bool Must_Expand(const StringRef &absolute_path, const StringRef &relative_path);
92+
};
93+
94+
/** Expand any header that is not compiler-specific. */
95+
class CompilerExpansionPolicy : public IncludeExpansionPolicy
96+
{
97+
public:
98+
virtual bool Must_Expand(const StringRef &absolute_path, const StringRef &relative_path);
99+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/* { dg-options "-DCE_EXTRACT_FUNCTIONS=fn_c -DCE_NO_EXTERNALIZATION -DCE_KEEP_INCLUDES=compiler" }*/
2+
3+
#include <stdio.h>
4+
#include <stdatomic.h>
5+
#include <pthread.h>
6+
7+
atomic_int cnt_atomic;
8+
9+
void* fn_c(void *thr_data) {
10+
(void)thr_data;
11+
for (int i = 0; i < 40000; i++) {
12+
atomic_fetch_add(&cnt_atomic, 1);
13+
}
14+
return NULL;
15+
}
16+
17+
/* { dg-final { scan-tree-dump-not "#include <stdio.h>" } } */
18+
/* { dg-final { scan-tree-dump "#include <stdatomic.h>" } } */
19+
/* { dg-final { scan-tree-dump "#include <stddef.h>" } } */
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/* { dg-options "-DCE_EXTRACT_FUNCTIONS=fn_c -DCE_NO_EXTERNALIZATION -DCE_KEEP_INCLUDES=system" }*/
2+
3+
#include <stdio.h>
4+
#include <stdatomic.h>
5+
#include <pthread.h>
6+
#include "header-1.h"
7+
8+
atomic_int cnt_atomic;
9+
10+
void* fn_c(void *thr_data) {
11+
(void)thr_data;
12+
for (int i = 0; i < 40000; i++) {
13+
atomic_fetch_add(&cnt_atomic, 1);
14+
}
15+
return NULL;
16+
}
17+
18+
/* { dg-final { scan-tree-dump "#include <stdio.h>" } } */
19+
/* { dg-final { scan-tree-dump "#include <stdatomic.h>" } } */
20+
/* { dg-final { scan-tree-dump "#include <pthread.h>" } } */
21+
/* { dg-final { scan-tree-dump-not "#include \"header-1.h\"" } } */

0 commit comments

Comments
 (0)