mirror of
https://github.com/autc04/Retro68.git
synced 2024-12-04 16:50:57 +00:00
360 lines
9.0 KiB
Java
360 lines
9.0 KiB
Java
/* MemoryMap.java -- Maps address ranges to their data.
|
|
Copyright (C) 2007 Free Software Foundation
|
|
|
|
This file is part of libgcj.
|
|
|
|
This software is copyrighted work licensed under the terms of the
|
|
Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
|
|
details. */
|
|
|
|
package gnu.gcj.tools.gc_analyze;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.EOFException;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.io.RandomAccessFile;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.channels.FileChannel;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.SortedSet;
|
|
import java.util.TreeSet;
|
|
|
|
/**
|
|
* Reads /proc/self/maps output from dump file.
|
|
* Creates map of <filename> to Range.
|
|
*
|
|
* Returns filename given address.
|
|
* Returns offset given address.
|
|
* Returns BytePtr given address.
|
|
*
|
|
*/
|
|
class MemoryMap
|
|
{
|
|
static class RangeComparator implements Comparator<Range>
|
|
{
|
|
public int compare(Range r1, Range r2)
|
|
{
|
|
if (r2.end == 0 && r1.end != 0)
|
|
return -compare(r2, r1);
|
|
|
|
if (r1.begin < r2.begin)
|
|
return -1;
|
|
else if (r1.begin >= r2.end)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static class Range
|
|
{
|
|
long begin;
|
|
long end;
|
|
|
|
long offset;
|
|
String filename;
|
|
Range()
|
|
{
|
|
}
|
|
|
|
Range(long b, long e, String s, long o)
|
|
{
|
|
begin = b;
|
|
end = e;
|
|
filename = s;
|
|
offset = o;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parse the string as an unsigned hexadecimal number. This is
|
|
* similar to Long.parseInt(s,16), but without the restriction that
|
|
* values that have the sign bit set not being allowed.
|
|
*
|
|
* @param s the number as a String.
|
|
* @return the number.
|
|
*/
|
|
static long parseHexLong(String s)
|
|
{
|
|
if (s.length() > 16)
|
|
throw new NumberFormatException();
|
|
long r = 0;
|
|
for (int i = 0; i < s.length(); i++)
|
|
{
|
|
int digit = 0;
|
|
char c = s.charAt(i);
|
|
switch (c)
|
|
{
|
|
case '0':
|
|
case '1':
|
|
case '2':
|
|
case '3':
|
|
case '4':
|
|
case '5':
|
|
case '6':
|
|
case '7':
|
|
case '8':
|
|
case '9':
|
|
digit = c - '0';
|
|
break;
|
|
case 'a':
|
|
case 'b':
|
|
case 'c':
|
|
case 'd':
|
|
case 'e':
|
|
case 'f':
|
|
digit = 10 + c - 'a';
|
|
break;
|
|
case 'A':
|
|
case 'B':
|
|
case 'C':
|
|
case 'D':
|
|
case 'E':
|
|
case 'F':
|
|
digit = 10 + c - 'A';
|
|
break;
|
|
default:
|
|
throw new NumberFormatException();
|
|
}
|
|
r = (r << 4) + digit;
|
|
}
|
|
return r;
|
|
}
|
|
|
|
// String filename -> Range
|
|
TreeSet<Range> map = new TreeSet<Range>(new RangeComparator());
|
|
HashMap<String, SymbolTable> symbolTables =
|
|
new HashMap<String, SymbolTable>();
|
|
ByteOrder byteOrder;
|
|
int wordSize;
|
|
|
|
public MemoryMap(BufferedReader reader,
|
|
String rawFileName) throws IOException
|
|
{
|
|
FileChannel raw = (new RandomAccessFile(rawFileName, "r")).getChannel();
|
|
ByteBuffer buf = ByteBuffer.allocate(8);
|
|
raw.read(buf);
|
|
if (buf.hasRemaining())
|
|
{
|
|
raw.close();
|
|
throw new EOFException();
|
|
}
|
|
buf.flip();
|
|
wordSize = buf.get();
|
|
|
|
if (wordSize == 8 || wordSize == 4)
|
|
byteOrder = ByteOrder.LITTLE_ENDIAN;
|
|
else
|
|
{
|
|
byteOrder = ByteOrder.BIG_ENDIAN;
|
|
buf.rewind();
|
|
wordSize = buf.getInt();
|
|
if (0 == wordSize)
|
|
wordSize = buf.getInt();
|
|
}
|
|
switch (wordSize)
|
|
{
|
|
case 4:
|
|
case 8:
|
|
break;
|
|
default:
|
|
throw new IOException("Bad .bytes file header");
|
|
}
|
|
buf = ByteBuffer.allocate(3 * wordSize);
|
|
buf.order(byteOrder);
|
|
raw.position(0L);
|
|
|
|
for(;;)
|
|
{
|
|
// Read the block header.
|
|
buf.clear();
|
|
if (-1 == raw.read(buf))
|
|
{
|
|
//EOF
|
|
raw.close();
|
|
break;
|
|
}
|
|
if (buf.hasRemaining())
|
|
{
|
|
raw.close();
|
|
throw new EOFException();
|
|
}
|
|
buf.flip();
|
|
long dummy
|
|
= (wordSize == 4) ? (buf.getInt() & 0xffffffffL) : buf.getLong();
|
|
if (dummy != wordSize)
|
|
throw new IOException("Bad .bytes file header");
|
|
long start
|
|
= wordSize == 4 ? (buf.getInt() & 0xffffffffL) : buf.getLong();
|
|
long length
|
|
= wordSize == 4 ? (buf.getInt() & 0xffffffffL) : buf.getLong();
|
|
if (length < 0L)
|
|
throw new IOException("Bad .bytes file header");
|
|
|
|
long currentPos = raw.position();
|
|
raw.position(currentPos + length);
|
|
|
|
Range range = new Range(start, start + length,
|
|
rawFileName, currentPos);
|
|
map.add(range);
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
String s = reader.readLine();
|
|
if (s == null)
|
|
break;
|
|
if (s.indexOf("Begin address map") >= 0)
|
|
{
|
|
for (;;)
|
|
{
|
|
s = reader.readLine();
|
|
if (s.indexOf("End address map") >= 0)
|
|
{
|
|
dump();
|
|
return;
|
|
}
|
|
int endOfAddress = s.indexOf('-');
|
|
long address = parseHexLong(s.substring(0, endOfAddress));
|
|
int endOfAddress2 = s.indexOf(' ', endOfAddress + 1);
|
|
long address2 = parseHexLong(s.substring(endOfAddress + 1,
|
|
endOfAddress2));
|
|
int endOfOffset = s.indexOf(' ', endOfAddress2 + 6);
|
|
long offset;
|
|
try
|
|
{
|
|
offset = parseHexLong(s.substring(endOfAddress2 + 6,
|
|
endOfOffset));
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
offset = 0;
|
|
}
|
|
int end = s.indexOf('/');
|
|
|
|
if (end > 0)
|
|
{
|
|
String file = s.substring(end);
|
|
if (file.startsWith("/dev/"))
|
|
continue;
|
|
|
|
Range r = new Range(address, address2, file, offset);
|
|
if (offset == 0)
|
|
{
|
|
// Read the file's symbol table
|
|
try
|
|
{
|
|
File f = ToolPrefix.fileForName(file);
|
|
if (f != null)
|
|
{
|
|
SymbolTable st = new SymbolTable(f.getPath());
|
|
if (st.loadAddr != address)
|
|
st.relocation = address - st.loadAddr;
|
|
symbolTables.put(file, st);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ex.printStackTrace();
|
|
}
|
|
}
|
|
map.add(r);
|
|
}
|
|
} // inner loop
|
|
} // started inner loop
|
|
} // outer loop - finding begin
|
|
} // memoryMap
|
|
|
|
|
|
public void dump()
|
|
{
|
|
System.out.println("MemoryMap:");
|
|
for (Range r : map)
|
|
{
|
|
System.out.println(Long.toHexString(r.begin) + "-"
|
|
+ Long.toHexString(r.end) + " -> "
|
|
+ r.filename + " offset "
|
|
+ Long.toHexString(r.offset));
|
|
}
|
|
}
|
|
|
|
Range getRange(long addr)
|
|
{
|
|
Range r = new Range();
|
|
r.begin = addr;
|
|
SortedSet<Range> t = map.tailSet(r);
|
|
if (t.isEmpty())
|
|
return null;
|
|
Range c = t.first();
|
|
if (c.begin <= addr && addr < c.end)
|
|
return c;
|
|
return null;
|
|
}
|
|
|
|
String getFile(long addr)
|
|
{
|
|
Range r = getRange(addr);
|
|
if (null != r)
|
|
return r.filename;
|
|
return null;
|
|
}
|
|
|
|
long getOffset(long addr)
|
|
{
|
|
Range r = getRange(addr);
|
|
if (null != r)
|
|
return r.offset;
|
|
return 0L;
|
|
}
|
|
|
|
/**
|
|
* @return BytePtr which includes given address.
|
|
*/
|
|
BytePtr getBytePtr(long addr, int length) throws IOException
|
|
{
|
|
Range r = getRange(addr);
|
|
|
|
if (null == r)
|
|
return null;
|
|
|
|
File f = ToolPrefix.fileForName(r.filename);
|
|
if (null == f)
|
|
return null;
|
|
|
|
if (addr + length > r.end)
|
|
length = (int)(r.end - addr);
|
|
|
|
ByteBuffer b = ByteBuffer.allocate(length);
|
|
b.order(byteOrder);
|
|
|
|
FileChannel fc = (new RandomAccessFile(f, "r")).getChannel();
|
|
fc.position(r.offset + addr - r.begin);
|
|
int nr = fc.read(b);
|
|
fc.close();
|
|
if (nr != length)
|
|
return null;
|
|
b.flip();
|
|
return new BytePtr(b, wordSize);
|
|
}
|
|
|
|
public String getSymbol(long addr)
|
|
{
|
|
Range r = getRange(addr);
|
|
|
|
if (r == null)
|
|
return null;
|
|
|
|
SymbolTable st = symbolTables.get(r.filename);
|
|
if (st == null)
|
|
return null;
|
|
|
|
// Apply relocation
|
|
addr -= st.relocation;
|
|
|
|
return st.getSymbol(addr);
|
|
}
|
|
}
|