| /******************************************************************************* |
| * Copyright (c) 2017 Ericsson |
| * |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Mikael Ferland - Initial API and implementation |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.tracecompass.internal.tmf.core.callstack; |
| |
| import java.util.Comparator; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.NavigableMap; |
| import java.util.Objects; |
| import java.util.TreeMap; |
| |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.tracecompass.tmf.core.symbols.IMappingFile; |
| import org.eclipse.tracecompass.tmf.core.symbols.TmfResolvedSymbol; |
| |
| /** |
| * This class maps addresses to their symbol text. The mappings may contain |
| * several areas of addresses. Each area should end with a symbol with suffix |
| * 'END__', so that if the requested symbol is not an exact match to one of the |
| * mapped symbol, it will return the closest symbol that is lesser than the |
| * requested address, unless that symbol has the end suffix, it is out of the |
| * area of this mapping. |
| * |
| * @author Mikael Ferland |
| */ |
| public final class MappingFile implements IMappingFile { |
| |
| private static final String DEFAULT_END_SUFFIX = "END__"; //$NON-NLS-1$ |
| private static Comparator<@NonNull Long> MAP_COMPARATOR = Long::compareUnsigned; |
| |
| private final String fFullPath; |
| private final boolean fIsBinaryFile; |
| private final NavigableMap<Long, TmfResolvedSymbol> fSymbolMapping; |
| private final int fPid; |
| |
| /** |
| * Create a new {@link MappingFile} |
| * |
| * @param path |
| * Path leading to the mapping file |
| * @param isBinaryFile |
| * Type of the mapping file |
| * @param results |
| * Resolved symbols for the given mapping file |
| * @param pid |
| * The ID of the process this mapping applies to. A negative value |
| * means it applies to all processes |
| */ |
| public MappingFile(String path, boolean isBinaryFile, Map<Long, TmfResolvedSymbol> results, int pid) { |
| fFullPath = path; |
| fIsBinaryFile = isBinaryFile; |
| fSymbolMapping = new TreeMap<>(MAP_COMPARATOR); |
| fSymbolMapping.putAll(results); |
| fPid = pid; |
| } |
| |
| @Override |
| public String getFullPath() { |
| return fFullPath; |
| } |
| |
| @Override |
| public boolean isBinaryFile() { |
| return fIsBinaryFile; |
| } |
| |
| private long getLastAddress() { |
| return fSymbolMapping.lastKey(); |
| } |
| |
| @Override |
| public @Nullable TmfResolvedSymbol getSymbolEntry(long address) { |
| Entry<Long, TmfResolvedSymbol> floorEntry = fSymbolMapping.floorEntry(address); |
| if (floorEntry == null) { |
| return null; |
| } |
| // See if the symbol returned is the end of a block or the last symbol. In this |
| // case, don't use the floor unless it hits the exact address |
| TmfResolvedSymbol symbol = Objects.requireNonNull(floorEntry.getValue()); |
| long floorValue = symbol.getBaseAddress(); |
| return ((symbol.getSymbolName().endsWith(getEndSuffix()) || floorValue == getLastAddress()) |
| && floorValue != address) ? null : symbol; |
| } |
| |
| /** |
| * Get the suffix for symbols that mark the end of address blocks in the file |
| * |
| * @return The suffix for symbols that end blocks of mapping addresses |
| */ |
| private static String getEndSuffix() { |
| return DEFAULT_END_SUFFIX; |
| } |
| |
| @Override |
| public int getPid() { |
| return fPid; |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(fFullPath, fIsBinaryFile, fSymbolMapping); |
| } |
| |
| @Override |
| public boolean equals(@Nullable Object obj) { |
| if (this == obj) { |
| return true; |
| } |
| if (obj == null) { |
| return false; |
| } |
| if (getClass() != obj.getClass()) { |
| return false; |
| } |
| |
| MappingFile other = (MappingFile) obj; |
| return (fFullPath.equals(other.fFullPath)) && (fIsBinaryFile == other.fIsBinaryFile) && (fSymbolMapping.equals(other.fSymbolMapping)); |
| } |
| } |