/*
* Copyright (C) 2014 RoboVM AB
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>.
*/
package org.robovm.llvm;
import static org.junit.Assert.*;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.io.FileUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.robovm.llvm.binding.CodeGenFileType;
/**
* Tests {@link ObjectFile}.
*/
public class ObjectFileTest {
@Test
public void testLoadFromFile() throws Exception {
try (Context context = new Context()) {
try (TargetMachine tm = Target.getTarget("x86").createTargetMachine("i386-unknown-macosx")) {
Module module = Module.parseIR(context, "define external i32 @foo() {\n ret i32 5\n }\n", "foo.c");
File oFile = File.createTempFile(getClass().getSimpleName(), ".o");
try (FileOutputStream out = new FileOutputStream(oFile)) {
tm.emit(module, out, CodeGenFileType.ObjectFile);
}
try (ObjectFile objectFile = ObjectFile.load(oFile)) {
List<Symbol> symbols = objectFile.getSymbols();
assertEquals(1, symbols.size());
assertEquals("_foo", symbols.get(0).getName());
assertTrue(symbols.get(0).getAddress() == 0);
assertTrue(symbols.get(0).getSize() > 0);
}
}
}
}
@Test
public void testReadSections() throws Exception {
try (Context context = new Context()) {
try (TargetMachine tm = Target.getTarget("x86").createTargetMachine("i386-unknown-macosx")) {
Module module = Module.parseIR(context, "define external i32 @foo() {\n ret i32 5\n }\n", "foo.c");
File oFile = File.createTempFile(getClass().getSimpleName(), ".o");
try (FileOutputStream out = new FileOutputStream(oFile)) {
tm.emit(module, out, CodeGenFileType.ObjectFile);
}
try (ObjectFile objectFile = ObjectFile.load(oFile)) {
TreeSet<String> sections = new TreeSet<>();
for (SectionIterator it = objectFile.getSectionIterator(); it.hasNext(); it.next()) {
sections.add(it.getName());
byte[] contents = new byte[(int) it.getSize()];
assertEquals(it.getSize(), it.copyContents(contents));
long sum = 0;
for (int i = 0; i < contents.length; i++) {
sum += contents[i];
}
assertTrue(sum != 0);
}
assertTrue(sections.contains("__text"));
}
}
}
}
@Test
@Ignore
public void testMemoryLeaks() throws Exception {
// Enable this test, set -Xmx64M and watch the memory usage while it's running.
for (int i = 0; i < 100000; i++) {
testLoadFromFile();
if (i % 100 == 0) {
System.out.println(i);
}
}
}
@Test
public void testLineNumberInfo() throws Exception {
String cc = "gcc";
String symbolPrefix = "";
if (System.getProperty("os.name").toLowerCase().contains("mac")) {
cc = "clang";
symbolPrefix = "_";
}
File cFile = File.createTempFile(getClass().getSimpleName(), ".c");
FileUtils.writeStringToFile(cFile,
"int main() {\n"
+ " return 0;\n"
+ "}\n");
DefaultExecutor executor = new DefaultExecutor();
executor.setWorkingDirectory(cFile.getParentFile());
executor.execute(new CommandLine(cc)
.addArgument("-g")
.addArgument("-c")
.addArgument(cFile.getAbsolutePath()));
List<LineInfo> mainLineInfos = null;
File oFile = new File(cFile.getParentFile(), cFile.getName().substring(0, cFile.getName().lastIndexOf('.')) + ".o");
try (ObjectFile objectFile = ObjectFile.load(oFile)) {
for (Symbol symbol : objectFile.getSymbols()) {
if (symbol.getSize() > 0) {
List<LineInfo> lineInfos = objectFile.getLineInfos(symbol);
if (!lineInfos.isEmpty() && symbol.getName().equals(symbolPrefix + "main")) {
mainLineInfos = lineInfos;
break;
}
}
}
}
assertNotNull(mainLineInfos);
// Assert that the info for main() contains lines 1 and 2 and possibly 3
Set<Integer> lineNumbers = new HashSet<>();
for (LineInfo lineInfo : mainLineInfos) {
lineNumbers.add(lineInfo.getLineNumber());
}
assertTrue(lineNumbers.size() >= 2 && lineNumbers.size() <= 3);
assertTrue(lineNumbers.contains(1));
assertTrue(lineNumbers.contains(2));
if (lineNumbers.size() == 3) {
assertTrue(lineNumbers.contains(3));
}
}
}