Created
December 15, 2021 23:37
-
-
Save apangin/53dfa51bb894580122ceb0814ab1a779 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sun.misc.Unsafe; | |
import java.io.IOException; | |
import java.lang.reflect.Field; | |
import java.nio.ByteBuffer; | |
import java.nio.ByteOrder; | |
import java.nio.channels.FileChannel; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
import java.util.ArrayList; | |
import java.util.List; | |
import java.util.NoSuchElementException; | |
public class SymbolReader { | |
final ByteBuffer buf; | |
final long baseAddress; | |
final int symtab; | |
final int strings; | |
SymbolReader(String libName) throws IOException { | |
List<String> maps = Files.readAllLines(Paths.get("/proc/self/maps")); | |
String map = maps.stream().filter(s -> s.endsWith(libName)).findFirst().get(); | |
try (FileChannel ch = FileChannel.open(Paths.get(map.substring(map.indexOf('/'))))) { | |
this.buf = ch.map(FileChannel.MapMode.READ_ONLY, 0, ch.size()).order(ByteOrder.nativeOrder()); | |
} | |
this.baseAddress = Long.parseUnsignedLong(map.substring(0, map.indexOf('-')), 16); | |
this.symtab = findSection(2); | |
this.strings = buf.getInt(section(buf.getInt(symtab + 40)) + 24); | |
} | |
int section(int n) { | |
return buf.getInt(40) + (buf.getShort(58) & 0xffff) * n; | |
} | |
int findSection(int type) { | |
int sections = buf.getShort(60) & 0xffff; | |
for (int i = 0; i < sections; i++) { | |
int section = section(i); | |
if (buf.getInt(section + 4) == type) { | |
return section; | |
} | |
} | |
throw new NoSuchElementException("Section not found: " + type); | |
} | |
long findSymbol(String symbolName) { | |
int symbols = buf.getInt(symtab + 24); | |
int symbolsEnd = symbols + buf.getInt(symtab + 32); | |
int entrySize = buf.getInt(symtab + 56); | |
for (; symbols < symbolsEnd; symbols += entrySize) { | |
int name = buf.getInt(symbols); | |
long value = buf.getLong(symbols + 8); | |
if (name != 0 && value != 0 && strcmp(strings + name, symbolName)) { | |
return baseAddress + value; | |
} | |
} | |
throw new NoSuchElementException("Symbol not found: " + symbolName); | |
} | |
boolean strcmp(int pos, String str) { | |
int length = str.length(); | |
for (int i = 0; i < length; i++) { | |
if (buf.get(pos++) != str.charAt(i)) { | |
return false; | |
} | |
} | |
return buf.get(pos) == 0; | |
} | |
static Unsafe getUnsafe() throws ReflectiveOperationException { | |
Field f = Unsafe.class.getDeclaredField("theUnsafe"); | |
f.setAccessible(true); | |
return (Unsafe) f.get(null); | |
} | |
static void eatAllMemory() { | |
ArrayList<Object> list = new ArrayList(); | |
try { | |
while (true) { | |
list.add(new byte[1024 * 1024]); | |
} | |
} catch (OutOfMemoryError e) { | |
list = null; | |
} | |
} | |
public static void main(String[] args) throws Exception { | |
Unsafe unsafe = getUnsafe(); | |
long addr = new SymbolReader("/libjvm.so") | |
.findSymbol("_ZZ25report_java_out_of_memoryPKcE22out_of_memory_reported"); | |
System.out.println("OOM reported = " + unsafe.getInt(addr)); | |
eatAllMemory(); | |
System.out.println("OOM reported = " + unsafe.getInt(addr)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment