dmd/compiler/test/dshell/dwarf.d
2022-07-09 18:53:07 +02:00

177 lines
4.6 KiB
D
Executable file

import dshell;
import std.algorithm;
import std.file;
import std.process;
import std.regex;
import std.conv;
int main()
{
version(DigitalMars) { }
else
{
writeln("Skipping dwarf.d for non-DMD compilers.");
return DISABLED;
}
version(Windows)
{
writeln("Skipping dwarf.d for Windows.");
return DISABLED;
}
version(OSX)
{
writeln("Skipping dwarf.d for MacOS X.");
return DISABLED;
}
version(Windows)
immutable slash = "\\";
else
immutable slash = "/";
// If the Unix system doesn't have objdump, disable the tests
auto sysObjdump = executeShell("objdump --version");
if (sysObjdump.status)
return DISABLED;
double objdumpVersion;
try
{
// output examples :
// GNU objdump 2.15
// GNU objdump 2.17.50 [FreeBSD] 2007-07-03
// GNU objdump (GNU Binutils) 2.36.1
string strVer = sysObjdump.output.split("\n")[0];
writeln("Objdump version of the machine : ", strVer);
auto cap = matchFirst(strVer, `[0-9]+\.[0-9]+`);
assert(cap);
objdumpVersion = cap.hit.to!double;
}
catch (ConvException ce)
{
// The conversion failed
return DISABLED;
}
writeln("Parsed objdump version of the machine : ", objdumpVersion);
// DWARF 3 (and 4) support has been implemented in version 2.20 (2.20.51.0.1)
if(objdumpVersion < 2.20)
return DISABLED;
immutable extra_dwarf_dir = EXTRA_FILES ~ slash ~ "dwarf" ~ slash;
bool failed;
// test them all
foreach (string path; dirEntries(extra_dwarf_dir, SpanMode.shallow))
{
if (!isFile(path) || extension(path) != ".d")
continue;
// retrieve the filename without the extension
auto filename = baseName(stripExtension(path));
string[string] requirements = getRequirements(path);
try
{
if (objdumpVersion < requirements["MIN_OBJDUMP_VERSION"].to!double)
{
writeln("Warning: test " ~ path ~ " skipped.");
continue ;
}
}
catch(Exception e) { }
string exe = OUTPUT_BASE ~ slash ~ filename;
run("$DMD -m$MODEL -of" ~ exe ~ "$EXE -conf= -fPIE -g " ~ requirements["EXTRA_ARGS"]
~ " -I" ~ extra_dwarf_dir ~ " " ~ path);
// Write objdump result to a file
auto objdump = exe ~ ".objdump";
auto objdump_file = File(objdump, "w");
run("objdump -W " ~ exe, objdump_file);
objdump_file.close();
auto llvmDwarfdump = executeShell("llvm-dwarfdump --version");
try {
if (!llvmDwarfdump.status && requirements["DWARF_VERIFY"].to!bool)
run("llvm-dwarfdump --verify " ~ exe);
} catch (ConvException e) { }
// Objdump excepted results
string excepted_results_file = extra_dwarf_dir ~ "excepted_results"
~ slash ~ filename ~ ".txt";
if (!exists(excepted_results_file))
assert(0, "DWARF tests must have a .txt file in the `excepted_results`"
~ " folder which contains the DWARF dump info");
// Read file result as a string
auto result = cast(string)readText(objdump);
string failmsg;
foreach (line; File(excepted_results_file).byLine)
{
if (!canFind(result, line))
{
failmsg ~= filename ~ ": Couln't find `" ~ line
~ "` in the DWARF dump info.\n";
failed = true;
}
}
if (failmsg)
{
// Writes the result into stdout for the CI machines.
writeln(result);
write(failmsg);
}
}
return failed;
}
string[string] getRequirements(string dfile)
{
string[string] result;
// Initialize to an empty string to prevent RangeViolation exceptions.
foreach (req; ["EXTRA_ARGS", "MIN_OBJDUMP_VERSION"])
result[req] = "";
result["DWARF_VERIFY"] = "true";
bool begin;
auto f = File(dfile, "r");
foreach (line; f.byLine)
{
if (line.length < 2)
continue;
if (line.startsWith("/*"))
{
begin = true;
}
if (begin)
{
string[] args = line.split(":").to!(string[]);
if (args.length == 2)
{
result[args[0]] = args[1].strip();
}
if (line.indexOf("*/") != -1)
{
break;
}
}
}
f.close();
return result;
}