/*
* Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Red Hat Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.oracle.objectfile.elf.dwarf;
import com.oracle.objectfile.LayoutDecision;
import com.oracle.objectfile.LayoutDecisionMap;
import com.oracle.objectfile.ObjectFile;
import com.oracle.objectfile.debugentry.ClassEntry;
import com.oracle.objectfile.debugentry.PrimaryEntry;
import com.oracle.objectfile.debugentry.Range;
import org.graalvm.compiler.debug.DebugContext;
import java.util.LinkedList;
import java.util.Map;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_ARANGES_SECTION_NAME;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_INFO_SECTION_NAME;
import static com.oracle.objectfile.elf.dwarf.DwarfDebugInfo.DW_VERSION_2;
Section generator for debug_aranges section.
/**
* Section generator for debug_aranges section.
*/
public class DwarfARangesSectionImpl extends DwarfSectionImpl {
private static final int DW_AR_HEADER_SIZE = 12;
private static final int DW_AR_HEADER_PAD_SIZE = 4; // align up to 2 * address size
public DwarfARangesSectionImpl(DwarfDebugInfo dwarfSections) {
super(dwarfSections);
}
@Override
public String getSectionName() {
return DW_ARANGES_SECTION_NAME;
}
@Override
public void createContent() {
int pos = 0;
/*
* We need an entry for each compilation unit.
*
* <ul>
*
* <li><code>uint32 length ............ in bytes (not counting these 4 bytes)</code>
*
* <li><code>uint16 dwarf_version ..... always 2</code>
*
* <li><code>uint32 info_offset ....... offset of compilation unit on debug_info</code>
*
* <li><code>uint8 address_size ....... always 8</code>
*
* <li><code>uint8 segment_desc_size .. ???</code>
*
* </ul>
*
* That is 12 bytes followed by padding aligning up to 2 * address size.
*
* <ul>
*
* <li><code>uint8 pad[4]</code>
*
* </ul>
*
* Followed by N + 1 times:
*
* <ul> <li><code>uint64 lo ................ lo address of range</code>
*
* <li><code>uint64 length ............ number of bytes in range</code>
*
* </ul>
*
* Where N is the number of ranges belonging to the compilation unit and the last range
* contains two zeroes.
*/
for (ClassEntry classEntry : getPrimaryClasses()) {
pos += DW_AR_HEADER_SIZE;
/*
* Align to 2 * address size.
*/
pos += DW_AR_HEADER_PAD_SIZE;
LinkedList<PrimaryEntry> classPrimaryEntries = classEntry.getPrimaryEntries();
if (classEntry.includesDeoptTarget()) {
/* Deopt targets are in a higher address range so delay emit for them. */
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
if (!classPrimaryEntry.getPrimary().isDeoptTarget()) {
pos += 2 * 8;
}
}
} else {
pos += classPrimaryEntries.size() * 2 * 8;
}
pos += 2 * 8;
}
/* Now allow for deopt target ranges. */
for (ClassEntry classEntry : getPrimaryClasses()) {
if (classEntry.includesDeoptTarget()) {
pos += DW_AR_HEADER_SIZE;
/*
* Align to 2 * address size.
*/
pos += DW_AR_HEADER_PAD_SIZE;
LinkedList<PrimaryEntry> classPrimaryEntries = classEntry.getPrimaryEntries();
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
if (classPrimaryEntry.getPrimary().isDeoptTarget()) {
pos += 2 * 8;
}
}
pos += 2 * 8;
}
}
byte[] buffer = new byte[pos];
super.setContent(buffer);
}
@Override
public byte[] getOrDecideContent(Map<ObjectFile.Element, LayoutDecisionMap> alreadyDecided, byte[] contentHint) {
ObjectFile.Element textElement = getElement().getOwner().elementForName(".text");
LayoutDecisionMap decisionMap = alreadyDecided.get(textElement);
if (decisionMap != null) {
Object valueObj = decisionMap.getDecidedValue(LayoutDecision.Kind.VADDR);
if (valueObj != null && valueObj instanceof Number) {
/*
* This may not be the final vaddr for the text segment but it will be close enough
* to make debug easier i.e. to within a 4k page or two.
*/
debugTextBase = ((Number) valueObj).longValue();
}
}
return super.getOrDecideContent(alreadyDecided, contentHint);
}
@Override
public void writeContent(DebugContext context) {
byte[] buffer = getContent();
int size = buffer.length;
int pos = 0;
enableLog(context, pos);
log(context, " [0x%08x] DEBUG_ARANGES", pos);
for (ClassEntry classEntry : getPrimaryClasses()) {
int lastpos = pos;
int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4;
int cuIndex = classEntry.getCUIndex();
LinkedList<PrimaryEntry> classPrimaryEntries = classEntry.getPrimaryEntries();
/*
* Count only real methods, omitting deopt targets.
*/
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
Range primary = classPrimaryEntry.getPrimary();
if (!primary.isDeoptTarget()) {
length += 2 * 8;
}
}
/*
* Add room for a final null entry.
*/
length += 2 * 8;
log(context, " [0x%08x] %s CU %d length 0x%x", pos, classEntry.getFileName(), cuIndex, length);
pos = putInt(length, buffer, pos);
/* DWARF version is always 2. */
pos = putShort(DW_VERSION_2, buffer, pos);
pos = putInt(cuIndex, buffer, pos);
/* Address size is always 8. */
pos = putByte((byte) 8, buffer, pos);
/* Segment size is always 0. */
pos = putByte((byte) 0, buffer, pos);
assert (pos - lastpos) == DW_AR_HEADER_SIZE;
/*
* Align to 2 * address size.
*/
for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) {
pos = putByte((byte) 0, buffer, pos);
}
log(context, " [0x%08x] Address Length Name", pos);
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
Range primary = classPrimaryEntry.getPrimary();
/*
* Emit only real methods, omitting linkage stubs.
*/
if (!primary.isDeoptTarget()) {
log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName());
pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos);
pos = putLong(primary.getHi() - primary.getLo(), buffer, pos);
}
}
pos = putLong(0, buffer, pos);
pos = putLong(0, buffer, pos);
}
/* now write ranges for deopt targets */
for (ClassEntry classEntry : getPrimaryClasses()) {
if (classEntry.includesDeoptTarget()) {
int lastpos = pos;
int length = DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4;
int cuIndex = classEntry.getDeoptCUIndex();
LinkedList<PrimaryEntry> classPrimaryEntries = classEntry.getPrimaryEntries();
/*
* Count only linkage stubs.
*/
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
Range primary = classPrimaryEntry.getPrimary();
if (primary.isDeoptTarget()) {
length += 2 * 8;
}
}
/* we must have seen at least one stub */
assert length > DW_AR_HEADER_SIZE + DW_AR_HEADER_PAD_SIZE - 4;
/*
* Add room for a final null entry.
*/
length += 2 * 8;
log(context, " [0x%08x] %s CU linkage stubs %d length 0x%x", pos, classEntry.getFileName(), cuIndex, length);
pos = putInt(length, buffer, pos);
/* DWARF version is always 2. */
pos = putShort(DW_VERSION_2, buffer, pos);
pos = putInt(cuIndex, buffer, pos);
/* Address size is always 8. */
pos = putByte((byte) 8, buffer, pos);
/* Segment size is always 0. */
pos = putByte((byte) 0, buffer, pos);
assert (pos - lastpos) == DW_AR_HEADER_SIZE;
/*
* Align to 2 * address size.
*/
for (int i = 0; i < DW_AR_HEADER_PAD_SIZE; i++) {
pos = putByte((byte) 0, buffer, pos);
}
log(context, " [0x%08x] Address Length Name", pos);
for (PrimaryEntry classPrimaryEntry : classPrimaryEntries) {
Range primary = classPrimaryEntry.getPrimary();
/*
* Emit only linkage stubs.
*/
if (primary.isDeoptTarget()) {
log(context, " [0x%08x] %016x %016x %s", pos, debugTextBase + primary.getLo(), primary.getHi() - primary.getLo(), primary.getFullMethodName());
pos = putRelocatableCodeOffset(primary.getLo(), buffer, pos);
pos = putLong(primary.getHi() - primary.getLo(), buffer, pos);
}
}
pos = putLong(0, buffer, pos);
pos = putLong(0, buffer, pos);
}
}
assert pos == size;
}
/*
* The debug_aranges section content depends on debug_info section content and offset.
*/
private static final String TARGET_SECTION_NAME = DW_INFO_SECTION_NAME;
@Override
public String targetSectionName() {
return TARGET_SECTION_NAME;
}
private final LayoutDecision.Kind[] targetSectionKinds = {
LayoutDecision.Kind.CONTENT,
LayoutDecision.Kind.OFFSET
};
@Override
public LayoutDecision.Kind[] targetSectionKinds() {
return targetSectionKinds;
}
}