#!/usr/bin/env dub
/+ dub.sdl:
name "android-research-elf-loader"
platforms "linux"
targetPath "build"
+/
/**
* Read an actual ELF's PT_INTERP without executing it.
* Evidence for ../index.md#canonical-store-and-elf-abi.
* Defaults to this executable; pass a Linux or Android ELF as the argument.
*/
module (module) elf_loaderRead an actual ELF's PT_INTERP without executing it.
Evidence for ../index.md#canonical-store-and-elf-abi.
Defaults to this executable; pass a Linux or Android ELF as the argument.
elf_loader;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias template) elf_loader.read = std.file.read(R)(R name, size_t upTo = size_t.max) if (isSomeFiniteCharInputRange!R && !isConvertibleToString!R)Read entire contents of file name and returns it as an untyped
array. If the file size is larger than upTo, only upTo
bytes are read.
read;
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) elf_loader.writeln = std.stdio.writeln(T...)(T args)Equivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln;
import (package) stdstd.(module) std.exceptionThis module defines functions related to exceptions and general error
handling. It also defines functions intended to aid in unit testing.
Category Functions Assumptions assertNotThrown assertThrown assumeUnique assumeWontThrow mayPointTo Enforce doesPointTo enforce errnoEnforce Handlers collectException collectExceptionMsg ifThrown handle Other basicExceptionCtors emptyExceptionMsg ErrnoException RangePrimitive
Source
std/exception.d
Examples
Synopis
import core.stdc.stdlib : malloc, free;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map, splitter;
import std.algorithm.searching : endsWith;
import std.conv : ConvException, to;
import std.range : front, retro;
// use enforce like assert
int a = 3;
enforce(a > 2, "a needs to be higher than 2.");
// enforce can throw a custom exception
enforce!ConvException(a > 2, "a needs to be higher than 2.");
// enforce will return it's input
enum size = 42;
auto memory = enforce(malloc(size), "malloc failed")[0 .. size];
scope(exit) free(memory.ptr);
// collectException can be used to test for exceptions
Exception e = collectException("abc".to!int);
assert(e.file.endsWith("conv.d"));
// and just for the exception message
string msg = collectExceptionMsg("abc".to!int);
assert(msg == "Unexpected 'a' when converting from type string to type int");
// assertThrown can be used to assert that an exception is thrown
assertThrown!ConvException("abc".to!int);
// ifThrown can be used to provide a default value if an exception is thrown
assert("x".to!int().ifThrown(0) == 0);
// handle is a more advanced version of ifThrown for ranges
auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a));
auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
assert(h.equal([12, 0, 54]));
assertThrown!ConvException(h.retro.equal([54, 0, 12]));
// basicExceptionCtors avoids the boilerplate when creating custom exceptions
static class MeaCulpa : Exception
{
mixin basicExceptionCtors;
}
e = collectException((){throw new MeaCulpa("diagnostic message");}());
assert(e.msg == "diagnostic message");
assert(e.file == __FILE__);
assert(e.line == __LINE__ - 3);
// assumeWontThrow can be used to cast throwing code into `nothrow`
void exceptionFreeCode() nothrow
{
// auto-decoding only throws if an invalid UTF char is given
assumeWontThrow("abc".front);
}
// assumeUnique can be used to cast mutable instance to an `immutable` one
// use with care
char[] str = " mutable".dup;
str[0 .. 2] = "im";
immutable res = assumeUnique(str);
assert(res == "immutable");
exception : (alias template) elf_loader.enforce = std.exception.enforce(E : Throwable = Exception) if (is(typeof(new E("", string.init, size_t.init)) : Throwable) || is(typeof(new E(string.init, size_t.init)) : Throwable))Enforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce;
ulong ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number(const(ubyte)[] (parameter) const(ubyte)[] bytesbytes, (alias) object.size_t = ulongsize_t (parameter) ulong offsetoffset, (alias) object.size_t = ulongsize_t (parameter) ulong countcount, bool (parameter) bool littlelittle)
{
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((parameter) ulong offsetoffset <= (parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength && (parameter) ulong countcount <= (parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength - (parameter) ulong offsetoffset, "truncated ELF");
ulong (local variable) ulong resultresult;
foreach ((local variable) ulong ii; 0 .. (parameter) ulong countcount)
(local variable) ulong resultresult |= cast(ulong) (parameter) const(ubyte)[] bytesbytes[(parameter) ulong offsetoffset + (local variable) ulong ii] << (8 * ((parameter) bool littlelittle ? (local variable) ulong ii : (parameter) ulong countcount - (local variable) ulong ii - 1));
return (local variable) ulong resultresult;
}
(alias) object.string = stringstring string elf_loader.interpreter(const(ubyte)[] bytes)interpreter(const(ubyte)[] (parameter) const(ubyte)[] bytesbytes)
{
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength >= 52 && (parameter) const(ubyte)[] bytesbytes[0 .. 4] == [0x7f, 'E', 'L', 'F'], "not an ELF");
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((parameter) const(ubyte)[] bytesbytes[4] == 1 || (parameter) const(ubyte)[] bytesbytes[4] == 2, "unsupported ELF class");
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((parameter) const(ubyte)[] bytesbytes[5] == 1 || (parameter) const(ubyte)[] bytesbytes[5] == 2, "unsupported ELF byte order");
const (local variable) const(bool) widewide = (parameter) const(ubyte)[] bytesbytes[4] == 2;
const (local variable) const(bool) littlelittle = (parameter) const(ubyte)[] bytesbytes[5] == 1;
const (local variable) const(ulong) tabletable = ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(bool) widewide ? 32 : 28, (local variable) const(bool) widewide ? 8 : 4, (local variable) const(bool) littlelittle);
const (local variable) const(ulong) stridestride = ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(bool) widewide ? 54 : 42, 2, (local variable) const(bool) littlelittle);
const (local variable) const(ulong) countcount = ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(bool) widewide ? 56 : 44, 2, (local variable) const(bool) littlelittle);
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((local variable) const(ulong) stridestride >= ((local variable) const(bool) widewide ? 56 : 32), "invalid ELF program header stride");
foreach ((local variable) ulong ii; 0 .. (local variable) const(ulong) countcount)
{
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((local variable) const(ulong) tabletable <= (parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength && (local variable) ulong ii <= ((parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength - (local variable) const(ulong) tabletable) / (local variable) const(ulong) stridestride, "truncated program headers");
const (local variable) const(ulong) entryentry = cast((alias) object.size_t = ulongsize_t) ((local variable) const(ulong) tabletable + (local variable) ulong ii * (local variable) const(ulong) stridestride);
if (ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(ulong) entryentry, 4, (local variable) const(bool) littlelittle) != 3) // PT_INTERP
continue;
const (local variable) const(ulong) offsetoffset = ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(ulong) entryentry + ((local variable) const(bool) widewide ? 8 : 4), (local variable) const(bool) widewide ? 8 : 4, (local variable) const(bool) littlelittle);
const (local variable) const(ulong) lengthlength = ulong elf_loader.number(const(ubyte)[] bytes, ulong offset, ulong count, bool little)number((parameter) const(ubyte)[] bytesbytes, (local variable) const(ulong) entryentry + ((local variable) const(bool) widewide ? 32 : 16), (local variable) const(bool) widewide ? 8 : 4, (local variable) const(bool) littlelittle);
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((local variable) const(ulong) offsetoffset <= (parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength && (local variable) const(ulong) lengthlength <= (parameter) const(ubyte)[] bytesbytes.(field) ulong const(ubyte)[].lengthlength - (local variable) const(ulong) offsetoffset && (local variable) const(ulong) lengthlength > 0,
"truncated ELF interpreter");
const (local variable) const(ubyte[]) valuevalue = (parameter) const(ubyte)[] bytesbytes[cast((alias) object.size_t = ulongsize_t) (local variable) const(ulong) offsetoffset .. cast((alias) object.size_t = ulongsize_t) ((local variable) const(ulong) offsetoffset + (local variable) const(ulong) lengthlength)];
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safeEnforces that the given value is true.
If the given value is false, an exception is thrown.
The
msg - error message as a string
dg - custom delegate that return a string and is only called if an exception occurred
ex - custom exception to be thrown. It is lazy and is only created if an exception occurred
enforce((local variable) const(ubyte[]) valuevalue[$ - 1] == 0, "unterminated ELF interpreter");
return cast((alias) object.string = stringstring) (local variable) const(ubyte[]) valuevalue[0 .. $ - 1].immutable(ubyte)[] object.idup!(const(ubyte))(const(ubyte)[] a) pure nothrow @property @safeProvide the .idup array property, which creates an immutable duplicate.
idup;
}
return null;
}
void void D main(string[] args)main((alias) object.string = stringstring[] (parameter) string[] argsargs)
{
const (local variable) const(string) pathpath = (parameter) string[] argsargs.(field) ulong string[].lengthlength > 1 ? (parameter) string[] argsargs[1] : "/proc/self/exe";
const (local variable) const(string) loaderloader = string elf_loader.interpreter(const(ubyte)[] bytes)interpreter(cast(ubyte[]) void[] std.file.read!string(string name, ulong upTo = 18446744073709551615LU) @safeRead entire contents of file name and returns it as an untyped
array. If the file size is larger than upTo, only upTo
bytes are read.
Examples
import std.utf : byChar;
scope(exit)
{
assert(exists(deleteme));
remove(deleteme);
}
std.file.write(deleteme, "1234"); // deleteme is the name of a temporary file
assert(read(deleteme, 2) == "12");
assert(read(deleteme.byChar) == "1234");
assert((cast(const(ubyte)[])read(deleteme)).length == 4);
read((local variable) const(string) pathpath));
void std.stdio.writeln!(string, string)(string __param_0, string __param_1) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("ELF: ", (local variable) const(string) pathpath);
void std.stdio.writeln!(string, string)(string __param_0, string __param_1) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("PT_INTERP: ", (local variable) const(string) loaderloader.(field) ulong const(string).lengthlength ? (local variable) const(string) loaderloader : "none (no dynamic interpreter)");
void std.stdio.writeln!string(string __param_0) @safeEquivalent to write(args, '\n'). Calling writeln without
arguments is valid and just prints a newline to the standard
output.
Example
Reads stdin and writes it to stdout with an argument
counter.
import std.stdio;
void main()
{
string line;
for (size_t count = 0; (line = readln) !is null; count++)
{
writeln("Input ", count, ": ", line);
}
}
writeln("An ELF's directory does not change its embedded interpreter path.");
}