2019-02-25 10:08:43 +01:00
|
|
|
package de.orb.wiiu.rpxparser;
|
|
|
|
|
|
|
|
import java.io.File;
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2019-02-28 16:41:31 +01:00
|
|
|
import java.util.NoSuchElementException;
|
2019-02-25 10:08:43 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
public class RPXFile {
|
|
|
|
final ElfReader elf_reader;
|
|
|
|
public static int MAX_FUNCTION_LENGTH_TO_COPY = 0;
|
|
|
|
|
|
|
|
private static final int MIN_SYMBOLS = 10;
|
|
|
|
|
|
|
|
public RPXFile(File f) throws IOException {
|
|
|
|
this(Files.readAllBytes(f.toPath()));
|
|
|
|
}
|
|
|
|
|
|
|
|
public RPXFile(byte[] data) throws IOException {
|
|
|
|
this(ByteBuffer.wrap(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
public RPXFile(ByteBuffer buf) throws IOException {
|
|
|
|
buf.position(0);
|
|
|
|
elf_reader = new ElfReader(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<ElfExport> getExports() {
|
|
|
|
return elf_reader.sections() //
|
|
|
|
.filter(section -> section instanceof ElfExportsTable) //
|
|
|
|
.flatMap(m -> ((ElfExportsTable) m).stream()) //
|
2019-02-28 16:41:31 +01:00
|
|
|
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
|
2019-02-25 10:08:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public Map<String, List<RPLImport>> getImports() {
|
|
|
|
return elf_reader.sections() //
|
|
|
|
.filter(section -> section instanceof ElfRelocationTable) // We want to check ElfRelocationTable sections
|
|
|
|
.flatMap(section -> ((ElfRelocationTable) section).stream()) // Get all relocations
|
2019-02-28 16:41:31 +01:00
|
|
|
.flatMap(r -> {
|
|
|
|
ElfSymbol t = r.symbol().get();
|
|
|
|
if (t != null) {
|
|
|
|
return Stream.of(t);
|
|
|
|
}
|
|
|
|
return Stream.empty();
|
|
|
|
}) // Get symbols of relocations if existing
|
2019-02-25 10:08:43 +01:00
|
|
|
.filter(symbol -> symbol.section().filter(s -> (s instanceof ElfImportsTable)).isPresent()) // Only keep symbols of ElfImportsTable section
|
2019-02-28 16:41:31 +01:00
|
|
|
.map(symbol -> new RPLImport(symbol.name().orElseThrow(() -> new NoSuchElementException()),
|
|
|
|
((ElfImportsTable) symbol.section().get()).rplname())) // Map to RPLImport
|
2019-02-25 10:08:43 +01:00
|
|
|
.distinct() //
|
|
|
|
.collect(Collectors.collectingAndThen( //
|
|
|
|
Collectors.groupingBy(RPLImport::getRplName, Collectors.toList()), // Group by RPLName
|
|
|
|
Collections::unmodifiableMap));
|
2019-02-25 12:12:57 +01:00
|
|
|
}
|
2019-02-25 10:08:43 +01:00
|
|
|
|
|
|
|
public Optional<byte[]> getFunctionData(ElfSymbol symbol) {
|
|
|
|
return symbol.section().flatMap(section -> getFunctionData(section, symbol.value() - section.address(), (int) symbol.size()));
|
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<byte[]> getFunctionData(ElfSection section, long _offset, int length) {
|
|
|
|
if (_offset < section.address() || _offset > section.address() + section.size()) {
|
|
|
|
return Optional.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
long offsetInSection = _offset - section.address();
|
|
|
|
ByteBuffer buf = section.getSectionBuffer();
|
|
|
|
|
|
|
|
buf.position((int) offsetInSection);
|
|
|
|
|
|
|
|
byte[] data = new byte[(int) length];
|
|
|
|
buf.get(data, 0, (int) length);
|
|
|
|
|
|
|
|
return Optional.of(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<ElfSymbolTable> getSymbolTable() {
|
|
|
|
return elf_reader.section(".symtab").map(section -> (ElfSymbolTable) section);
|
|
|
|
}
|
|
|
|
|
|
|
|
public Optional<ElfSection> getTextSection() {
|
|
|
|
return elf_reader.section(".text");
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean hasSymbols() {
|
|
|
|
return getFunctionSymbolsTextStream().limit(MIN_SYMBOLS).count() == MIN_SYMBOLS;
|
|
|
|
}
|
|
|
|
|
|
|
|
public Stream<ElfSymbol> getSymbols() {
|
|
|
|
return getSymbolTable().map(st -> st.stream()).orElse(Stream.empty());
|
|
|
|
}
|
|
|
|
|
|
|
|
public Stream<ElfSymbol> getFunctionSymbolsTextStream() {
|
|
|
|
return getSymbols().filter(s -> s.type() == ElfSymbol.STT_FUNC) // We are only interested in functions
|
2019-02-28 16:41:31 +01:00
|
|
|
.filter(s -> s.name().map(name -> name).filter(name -> !name.isEmpty()).isPresent()) // Not interested in functions with an empty name
|
2019-02-25 10:08:43 +01:00
|
|
|
.filter(s -> s.section().filter(m -> ".text".equals(m.name())).isPresent()); //
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<ElfSymbol> getFunctionSymbolsText() {
|
2019-02-28 16:41:31 +01:00
|
|
|
return getFunctionSymbolsTextStream().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
|
2019-02-25 10:08:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|