/**
* ****************************************************************************
* Copyright (c) 2010-2016 by Min Cai (min.cai.china@gmail.com).
* <p>
* This file is part of the Archimulator multicore architectural simulator.
* <p>
* Archimulator 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 3 of the License, or
* (at your option) any later version.
* <p>
* Archimulator 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.
* <p>
* You should have received a copy of the GNU General Public License
* along with Archimulator. If not, see <http://www.gnu.org/licenses/>.
* ****************************************************************************
*/
package archimulator.os;
import archimulator.analysis.BasicBlock;
import archimulator.analysis.ElfAnalyzer;
import archimulator.analysis.Function;
import archimulator.analysis.Instruction;
import archimulator.common.*;
import archimulator.isa.*;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Process.
*
* @author Min Cai
*/
public abstract class Process
extends BasicSimulationObject<CPUExperiment, Simulation>
implements SimulationObject<CPUExperiment, Simulation>, Serializable {
private List<String> environments;
private int standardInFileDescriptor;
private int standardOutFileDescriptor;
private int stackBase;
private int stackSize;
private int textSize;
private int environmentBase;
private int heapTop;
private int dataTop;
private int programEntry;
private boolean littleEndian;
private Memory memory;
private int id;
private ContextMapping contextMapping;
/**
* Create a process.
*
* @param kernel the kernel
* @param contextMapping the context mapping
*/
public Process(Kernel kernel, ContextMapping contextMapping) {
super(kernel);
this.contextMapping = contextMapping;
this.id = getExperiment().currentProcessId++;
kernel.getProcesses().add(this);
this.standardInFileDescriptor = 0;
this.standardOutFileDescriptor = 1;
this.environments = new ArrayList<>();
this.littleEndian = false;
this.memory = new Memory(kernel, this.littleEndian, this.id);
try {
this.loadProgram(kernel, contextMapping);
} catch (Exception e) {
e.printStackTrace();
System.exit(-1);
}
}
/**
* Load the program.
* @param kernel the kernel
* @param contextMapping the context mapping
*/
protected abstract void loadProgram(Kernel kernel, ContextMapping contextMapping);
/**
* Translate the specified file descriptor number.
*
* @param fileDescriptor the file descriptor number
* @return the translated file descriptor number
*/
public int translateFileDescriptor(int fileDescriptor) {
if (fileDescriptor == 1 || fileDescriptor == 2) {
return this.standardOutFileDescriptor;
} else if (fileDescriptor == 0) {
return this.standardInFileDescriptor;
} else {
return fileDescriptor;
}
}
/**
* Close the program.
*/
public void closeProgram() {
if (this.standardInFileDescriptor != 0) {
NativeSystemCalls.LIBC.close(this.standardInFileDescriptor);
}
if (this.standardOutFileDescriptor > 2) {
NativeSystemCalls.LIBC.close(this.standardOutFileDescriptor);
}
}
/**
* Decode the specified machine instruction.
*
* @param machineInstruction the machine instruction
* @return the decoded static instruction
*/
protected StaticInstruction decode(int machineInstruction) {
for (Mnemonic mnemonic : StaticInstruction.MNEMONICS) {
BitField extraBitField = mnemonic.getExtraBitField();
if ((machineInstruction & mnemonic.getMask()) == mnemonic.getBits() && (extraBitField == null || extraBitField.valueOf(machineInstruction) == mnemonic.getExtraBitFieldValue())) {
return new StaticInstruction(mnemonic, machineInstruction);
}
}
throw new IllegalArgumentException();
}
/**
* Get the static instruction at the specified program counter (PC).
*
* @param pc the program counter (PC)
* @return the static instruction at the specified program counter (PC)
*/
public abstract StaticInstruction getStaticInstruction(int pc);
/**
* Get the ID of the process.
*
* @return the ID of the process
*/
public int getId() {
return id;
}
/**
* Get the standard in file descriptor.
*
* @return the standard in file descriptor
*/
public int getStandardInFileDescriptor() {
return standardInFileDescriptor;
}
/**
* Get the standard out file descriptor.
*
* @return the standard out file descriptor
*/
public int getStandardOutFileDescriptor() {
return standardOutFileDescriptor;
}
/**
* Get the list of environment variables.
*
* @return the list of environment variables
*/
public List<String> getEnvironments() {
return environments;
}
/**
* Get the stack base.
*
* @return the stack base
*/
public int getStackBase() {
return stackBase;
}
/**
* Set the stack base.
*
* @param stackBase the stack base
*/
public void setStackBase(int stackBase) {
this.stackBase = stackBase;
}
/**
* Get the stack size.
*
* @return the stack size
*/
public int getStackSize() {
return stackSize;
}
/**
* Set the stack size.
*
* @param stackSize the stack size
*/
public void setStackSize(int stackSize) {
this.stackSize = stackSize;
}
/**
* Get the text size.
*
* @return the text size
*/
public int getTextSize() {
return textSize;
}
/**
* Set the text size.
*
* @param textSize the text size
*/
public void setTextSize(int textSize) {
this.textSize = textSize;
}
/**
* Get the environment base.
*
* @return the environment base
*/
public int getEnvironmentBase() {
return environmentBase;
}
/**
* Set the environment base.
*
* @param environmentBase the environment base
*/
public void setEnvironmentBase(int environmentBase) {
this.environmentBase = environmentBase;
}
/**
* Get the heap top.
*
* @return the heap top
*/
public int getHeapTop() {
return heapTop;
}
/**
* Set the heap top.
*
* @param heapTop the heap top
*/
public void setHeapTop(int heapTop) {
this.heapTop = heapTop;
}
/**
* Get the data top.
*
* @return the data top
*/
public int getDataTop() {
return dataTop;
}
/**
* Set the data top.
*
* @param dataTop the data top
*/
public void setDataTop(int dataTop) {
this.dataTop = dataTop;
}
/**
* Get the program entry.
*
* @return the program entry
*/
public int getProgramEntry() {
return programEntry;
}
/**
* Set the program entry.
*
* @param programEntry the program entry
*/
public void setProgramEntry(int programEntry) {
this.programEntry = programEntry;
}
/**
* Get a value indicating whether the process is little endian or not.
*
* @return a value indicating whether the process is little endian or not
*/
public boolean isLittleEndian() {
return littleEndian;
}
/**
* Get the memory.
*
* @return the memory
*/
public Memory getMemory() {
return memory;
}
/**
* Get the context mapping.
*
* @return the context mapping
*/
public ContextMapping getContextMapping() {
return contextMapping;
}
/**
* Get the name of the process.
*
* @return the name of the process
*/
@Override
public String getName() {
return "ctx" + getContextMapping().getThreadId() + "/process";
}
/**
* Text base.
*/
public static final int TEXT_BASE = 0x00400000;
/**
* Data base.
*/
public static final int DATA_BASE = 0x10000000;
/**
* Stack base.
*/
public static final int STACK_BASE = 0x7fffc000;
/**
* Stack size.
*/
public static final int STACK_SIZE = 1024 * 1024;
/**
* Maximum environment.
*/
public static final int MAX_ENVIRON = 16 * 1024;
/**
* Round up.
*
* @param n the number
* @param alignment th alignment
* @return the result
*/
protected static int roundUp(int n, int alignment) {
return (n + alignment - 1) & ~(alignment - 1);
}
/**
* Get the current directory.
*
* @return the current directory
*/
private static String getCurrentDirectory() {
try {
return new File(".").getCanonicalPath();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Get the ELF file analyzer.
*
* @return the ELF file analyzer
*/
public abstract ElfAnalyzer getElfAnalyzer();
/**
* Get the function name from the process by PC.
*
* @param pc the program counter (PC) value
* @return the function name from the process if any exists; otherwise null
*/
public abstract String getFunctionNameFromPc(int pc);
/**
* Get the list of hotspot functions in the current process.
*
* @return the list of hotspot functions in the current process
*/
public List<Function> getHotspotFunctions() {
return this.getElfAnalyzer().getProgram().getFunctions().stream().filter(this::isHotspotFunction).collect(Collectors.toList());
}
/**
* Get a value indicating whether the specified function is a hotspot function or not.
*
* @param function the function
* @return a value indicating whether the specified function is a hotspot function or not
*/
public boolean isHotspotFunction(Function function) {
for (BasicBlock basicBlock : function.getBasicBlocks()) {
for (Instruction instruction : basicBlock.getInstructions()) {
PseudoCall pseudoCall = StaticInstruction.getPseudoCall(instruction.getStaticInstruction().getMachineInstruction());
if (pseudoCall != null && pseudoCall.getImm() == PseudoCall.PSEUDOCALL_HOTSPOT_FUNCTION_BEGIN) {
return true;
}
}
}
return false;
}
}