/*
 * UnresolvedSymbol.java - This file is part of the Jakstab project.
 * Copyright 2007-2015 Johannes Kinder <jk@jakstab.org>
 *
 * 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.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */
package org.jakstab.loader;

import org.jakstab.asm.AbsoluteAddress;
import org.jakstab.util.Logger;

public class UnresolvedSymbol {

	private static final Logger logger = Logger.getLogger(UnresolvedSymbol.class);
	
	private final ExecutableImage module;
	private final String fromLibrary;
	private final String name;
	private final int fp;
	public enum AddressingType { ABSOLUTE, PC_RELATIVE }
	private final AddressingType addressingType;
	
	
	public UnresolvedSymbol(ExecutableImage module, String fromLibrary, 
			String name, int filepointer, AddressingType addressingType) {
		this.fromLibrary = fromLibrary;
		this.module = module;
		this.name = name;
		this.fp = filepointer;
		this.addressingType = addressingType;
	}
	
	public UnresolvedSymbol(ExecutableImage module, String name, int filepointer, AddressingType addressingType) {
		this(module, null, name, filepointer, addressingType);
	}	

	public void resolve(AbsoluteAddress virtualAddress) {
		byte[] data = module.getByteArray();
		long address = Integer.MIN_VALUE;
		if (addressingType == AddressingType.ABSOLUTE) {
			address = virtualAddress.getValue();
		} else if (addressingType == AddressingType.PC_RELATIVE) {
			// offset = absolute address - PC value (PC holds address of _next_ instruction, which is 4 bytes (address size) from file pointer)
			address = virtualAddress.getValue() - module.getVirtualAddress(fp + 4).getValue();
		}
		logger.debug("Patching bytes at VA " + module.getVirtualAddress(fp) + ", offset 0x" + Integer.toHexString(fp) + " in byte array, " +
				"which were " + Integer.toHexString(data[fp]) + " " + Integer.toHexString(data[fp+1]) + " " + Integer.toHexString(data[fp+2]) + " " + Integer.toHexString(data[fp+3])); 
		data[fp]     = (byte)( address        & 0xFFL);  
		data[fp + 1] = (byte)((address >>  8) & 0xFFL);  
		data[fp + 2] = (byte)((address >> 16) & 0xFFL);  
		data[fp + 3] = (byte)((address >> 24) & 0xFFL);
	}

	public String getName() {
		return name;
	}

	public String getFromLibrary() {
		return fromLibrary;
	}

	@Override
	public String toString() {
		return name + "(0x" + Long.toHexString(fp) + ")";
	}

	public ExecutableImage getModule() {
		return module;
	}
	
}
