Skip to content

Commit dd0d602

Browse files
author
Daniel Kroening
authored
Merge pull request diffblue#2030 from tautschnig/goto-cc-linux-kernel
Goto-cc extensions to build (and link) recent Linux kernels
2 parents 42e58d4 + 177c8c1 commit dd0d602

File tree

5 files changed

+159
-128
lines changed

5 files changed

+159
-128
lines changed

src/goto-cc/compile.cpp

+131-119
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Date: June 2006
1313

1414
#include "compile.h"
1515

16+
#include <cstring>
1617
#include <fstream>
1718
#include <sstream>
1819
#include <iostream>
@@ -135,56 +136,114 @@ bool compilet::doit()
135136
warnings_before;
136137
}
137138

138-
/// puts input file names into a list and does preprocessing for libraries.
139-
/// \return false on success, true on error.
140-
bool compilet::add_input_file(const std::string &file_name)
139+
enum class file_typet
140+
{
141+
FAILED_TO_OPEN_FILE,
142+
UNKNOWN,
143+
SOURCE_FILE,
144+
NORMAL_ARCHIVE,
145+
THIN_ARCHIVE,
146+
GOTO_BINARY,
147+
ELF_OBJECT
148+
};
149+
150+
static file_typet detect_file_type(const std::string &file_name)
141151
{
142152
// first of all, try to open the file
143-
{
144-
std::ifstream in(file_name);
145-
if(!in)
146-
{
147-
warning() << "failed to open file `" << file_name << "'" << eom;
148-
return warning_is_fatal; // generously ignore unless -Werror
149-
}
150-
}
153+
std::ifstream in(file_name);
154+
if(!in)
155+
return file_typet::FAILED_TO_OPEN_FILE;
156+
157+
const std::string::size_type r = file_name.rfind('.');
151158

152-
size_t r=file_name.rfind('.', file_name.length()-1);
159+
const std::string ext =
160+
r == std::string::npos ? "" : file_name.substr(r + 1, file_name.length());
153161

154-
if(r==std::string::npos)
162+
if(
163+
ext == "c" || ext == "cc" || ext == "cp" || ext == "cpp" || ext == "CPP" ||
164+
ext == "c++" || ext == "C" || ext == "i" || ext == "ii" || ext == "class" ||
165+
ext == "jar" || ext == "jsil")
155166
{
156-
// a file without extension; will ignore
157-
warning() << "input file `" << file_name
158-
<< "' has no extension, not considered" << eom;
159-
return warning_is_fatal;
167+
return file_typet::SOURCE_FILE;
160168
}
161169

162-
std::string ext = file_name.substr(r+1, file_name.length());
163-
164-
if(ext=="c" ||
165-
ext=="cc" ||
166-
ext=="cp" ||
167-
ext=="cpp" ||
168-
ext=="CPP" ||
169-
ext=="c++" ||
170-
ext=="C" ||
171-
ext=="i" ||
172-
ext=="ii" ||
173-
ext=="class" ||
174-
ext=="jar" ||
175-
ext=="jsil")
170+
char hdr[8];
171+
in.get(hdr, 8);
172+
if((ext == "a" || ext == "o") && strncmp(hdr, "!<thin>", 8) == 0)
173+
return file_typet::THIN_ARCHIVE;
174+
175+
if(ext == "a")
176+
return file_typet::NORMAL_ARCHIVE;
177+
178+
if(is_goto_binary(file_name))
179+
return file_typet::GOTO_BINARY;
180+
181+
if(hdr[0] == 0x7f && memcmp(hdr + 1, "ELF", 3) == 0)
182+
return file_typet::ELF_OBJECT;
183+
184+
return file_typet::UNKNOWN;
185+
}
186+
187+
/// puts input file names into a list and does preprocessing for libraries.
188+
/// \return false on success, true on error.
189+
bool compilet::add_input_file(const std::string &file_name)
190+
{
191+
switch(detect_file_type(file_name))
176192
{
193+
case file_typet::FAILED_TO_OPEN_FILE:
194+
warning() << "failed to open file `" << file_name
195+
<< "': " << std::strerror(errno) << eom;
196+
return warning_is_fatal; // generously ignore unless -Werror
197+
198+
case file_typet::UNKNOWN:
199+
// unknown extension, not a goto binary, will silently ignore
200+
debug() << "unknown file type in `" << file_name << "'" << eom;
201+
return false;
202+
203+
case file_typet::ELF_OBJECT:
204+
// ELF file without goto-cc section, silently ignore
205+
debug() << "ELF object without goto-cc section: `" << file_name << "'"
206+
<< eom;
207+
return false;
208+
209+
case file_typet::SOURCE_FILE:
177210
source_files.push_back(file_name);
211+
return false;
212+
213+
case file_typet::NORMAL_ARCHIVE:
214+
return add_files_from_archive(file_name, false);
215+
216+
case file_typet::THIN_ARCHIVE:
217+
return add_files_from_archive(file_name, true);
218+
219+
case file_typet::GOTO_BINARY:
220+
object_files.push_back(file_name);
221+
return false;
178222
}
179-
else if(ext=="a")
180-
{
181-
#ifdef _WIN32
182-
char td[MAX_PATH+1];
183-
#else
184-
char td[] = "goto-cc.XXXXXX";
185-
#endif
186223

187-
std::string tstr=get_temporary_directory(td);
224+
UNREACHABLE;
225+
}
226+
227+
/// extracts goto binaries from AR archive and add them as input files.
228+
/// \return false on success, true on error.
229+
bool compilet::add_files_from_archive(
230+
const std::string &file_name,
231+
bool thin_archive)
232+
{
233+
#ifdef _WIN32
234+
char td[MAX_PATH + 1];
235+
#else
236+
char td[] = "goto-cc.XXXXXX";
237+
#endif
238+
239+
std::stringstream cmd;
240+
FILE *stream;
241+
242+
std::string tstr = working_directory;
243+
244+
if(!thin_archive)
245+
{
246+
tstr = get_temporary_directory(td);
188247

189248
if(tstr=="")
190249
{
@@ -193,7 +252,6 @@ bool compilet::add_input_file(const std::string &file_name)
193252
}
194253

195254
tmp_dirs.push_back(tstr);
196-
std::stringstream cmd("");
197255
if(chdir(tmp_dirs.back().c_str())!=0)
198256
{
199257
error() << "Cannot switch to temporary directory" << eom;
@@ -203,76 +261,47 @@ bool compilet::add_input_file(const std::string &file_name)
203261
// unpack now
204262
cmd << "ar x " << concat_dir_file(working_directory, file_name);
205263

206-
FILE *stream;
207-
208264
stream=popen(cmd.str().c_str(), "r");
209265
pclose(stream);
210266

211267
cmd.clear();
212268
cmd.str("");
269+
}
213270

214-
// add the files from "ar t"
215-
#ifdef _WIN32
216-
if(file_name[0]!='/' && file_name[1]!=':') // NOLINT(readability/braces)
217-
#else
218-
if(file_name[0]!='/') // NOLINT(readability/braces)
219-
#endif
220-
{
221-
cmd << "ar t " <<
222-
#ifdef _WIN32
223-
working_directory << "\\" << file_name;
224-
#else
225-
working_directory << "/" << file_name;
226-
#endif
227-
}
228-
else
229-
{
230-
cmd << "ar t " << file_name;
231-
}
271+
// add the files from "ar t"
272+
cmd << "ar t " << concat_dir_file(working_directory, file_name);
232273

233-
stream=popen(cmd.str().c_str(), "r");
274+
stream = popen(cmd.str().c_str(), "r");
234275

235-
if(stream!=nullptr)
276+
if(stream != nullptr)
277+
{
278+
std::string line;
279+
int ch; // fgetc returns an int, not char
280+
while((ch = fgetc(stream)) != EOF)
236281
{
237-
std::string line;
238-
int ch; // fgetc returns an int, not char
239-
while((ch=fgetc(stream))!=EOF)
282+
if(ch != '\n')
240283
{
241-
if(ch!='\n')
242-
{
243-
line+=static_cast<char>(ch);
244-
}
245-
else
246-
{
247-
std::string t;
248-
#ifdef _WIN32
249-
t = tmp_dirs.back() + '\\' + line;
250-
#else
251-
t = tmp_dirs.back() + '/' + line;
252-
#endif
253-
254-
if(is_goto_binary(t))
255-
object_files.push_back(t);
256-
257-
line = "";
258-
}
284+
line += static_cast<char>(ch);
259285
}
286+
else
287+
{
288+
std::string t = concat_dir_file(tstr, line);
260289

261-
pclose(stream);
262-
}
290+
if(is_goto_binary(t))
291+
object_files.push_back(t);
292+
else
293+
debug() << "Object file is not a goto binary: " << line << eom;
263294

264-
cmd.str("");
295+
line = "";
296+
}
297+
}
265298

266-
if(chdir(working_directory.c_str())!=0)
267-
error() << "Could not change back to working directory" << eom;
268-
}
269-
else if(is_goto_binary(file_name))
270-
object_files.push_back(file_name);
271-
else
272-
{
273-
// unknown extension, not a goto binary, will silently ignore
299+
pclose(stream);
274300
}
275301

302+
if(!thin_archive && chdir(working_directory.c_str()) != 0)
303+
error() << "Could not change back to working directory" << eom;
304+
276305
return false;
277306
}
278307

@@ -302,41 +331,24 @@ bool compilet::find_library(const std::string &name)
302331
{
303332
std::string libname=tmp+name+".so";
304333

305-
if(is_goto_binary(libname))
306-
return !add_input_file(libname);
307-
else if(is_elf_file(libname))
334+
switch(detect_file_type(libname))
308335
{
336+
case file_typet::GOTO_BINARY:
337+
return !add_input_file(libname);
338+
339+
case file_typet::ELF_OBJECT:
309340
warning() << "Warning: Cannot read ELF library " << libname << eom;
310341
return warning_is_fatal;
342+
343+
default:
344+
break;
311345
}
312346
}
313347
}
314348

315349
return false;
316350
}
317351

318-
/// checking if we can load an object file
319-
/// \par parameters: file name
320-
/// \return true if the given file name exists and is an ELF file, false
321-
/// otherwise
322-
bool compilet::is_elf_file(const std::string &file_name)
323-
{
324-
std::fstream in;
325-
326-
in.open(file_name, std::ios::in);
327-
if(in.is_open())
328-
{
329-
char buf[4];
330-
for(std::size_t i=0; i<4; i++)
331-
buf[i]=static_cast<char>(in.get());
332-
if(buf[0]==0x7f && buf[1]=='E' &&
333-
buf[2]=='L' && buf[3]=='F')
334-
return true;
335-
}
336-
337-
return false;
338-
}
339-
340352
/// parses object files and links them
341353
/// \return true on error, false otherwise
342354
bool compilet::link()

src/goto-cc/compile.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class compilet:public language_uit
5353

5454
bool add_input_file(const std::string &);
5555
bool find_library(const std::string &);
56-
bool is_elf_file(const std::string &);
56+
bool add_files_from_archive(const std::string &file_name, bool thin_archive);
5757

5858
bool parse(const std::string &filename);
5959
bool parse_stdin();

src/goto-cc/gcc_cmdline.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ Author: CM Wintersteiger, 2006
1818

1919
#include <util/prefix.h>
2020

21-
/// parses the command line options into a cmdlinet
22-
/// \par parameters: argument count, argument strings
23-
/// \return none
21+
// clang-format off
2422
// non-gcc options
2523
const char *goto_cc_options_with_separated_argument[]=
2624
{
@@ -163,6 +161,8 @@ const char *gcc_options_without_argument[]=
163161
"-print-multi-directory",
164162
"-print-multi-lib",
165163
"-print-search-dirs",
164+
"-print-sysroot",
165+
"-print-sysroot-headers-suffix",
166166
"-Q",
167167
"-Qn",
168168
"-Qy",
@@ -211,7 +211,11 @@ const char *gcc_options_without_argument[]=
211211
"-fast", // Apple only
212212
nullptr
213213
};
214+
// clang-format on
214215

216+
/// parses the command line options into a cmdlinet
217+
/// \par parameters: argument count, argument strings
218+
/// \return none
215219
bool gcc_cmdlinet::parse(int argc, const char **argv)
216220
{
217221
assert(argc>0);

src/goto-cc/gcc_mode.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,24 @@ int gcc_modet::doit()
380380
return EX_OK; // Exit!
381381
}
382382

383-
if(cmdline.isset("dumpversion"))
383+
if(
384+
cmdline.isset("dumpmachine") || cmdline.isset("dumpspecs") ||
385+
cmdline.isset("dumpversion") || cmdline.isset("print-sysroot") ||
386+
cmdline.isset("print-sysroot-headers-suffix"))
384387
{
385388
if(produce_hybrid_binary)
386389
return run_gcc(compiler);
387390

388-
std::cout << "3.4.4\n";
391+
// GCC will only print one of these, even when multiple arguments are
392+
// passed, so we do the same
393+
if(cmdline.isset("dumpmachine"))
394+
std::cout << config.this_architecture() << '\n';
395+
else if(cmdline.isset("dumpversion"))
396+
std::cout << "3.4.4\n";
397+
398+
// we don't have any meaningful output for the other options, and GCC
399+
// doesn't necessarily produce non-empty output either
400+
389401
return EX_OK;
390402
}
391403

0 commit comments

Comments
 (0)