/*
* PERWAPI - An API for Reading and Writing PE Files
*
* Copyright (c) Diane Corney, Queensland University of Technology, 2004.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the PERWAPI Copyright as included with this
* distribution in the file PERWAPIcopyright.rtf.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY as is explained in the copyright notice.
*
* The author may be contacted at d.corney@qut.edu.au
*
* Version Date: 26/01/07
*/
using System;
using System.Collections;
using System.Text;
namespace QUT.PERWAPI
{
/**************************************************************************/
public abstract class CodeBlock
{
private static readonly int maxCodeSize = 255;
protected CILLabel start, end;
protected bool small = true;
/*-------------------- Constructors ---------------------------------*/
public CodeBlock(CILLabel start, CILLabel end)
{
this.start = start;
this.end = end;
}
///
/// The label that marks the start of this code block
///
public CILLabel Start { get { return start; } }
///
/// The label that marks the end of this code block
///
public CILLabel End { get { return end; } }
internal virtual bool isFat()
{
// Console.WriteLine("block start = " + start.GetLabelOffset() +
// " block end = " + end.GetLabelOffset());
return (end.GetLabelOffset() - start.GetLabelOffset()) > maxCodeSize;
}
internal virtual void Write(PEWriter output, bool fatFormat)
{
if (fatFormat) output.Write(start.GetLabelOffset());
else output.Write((short)start.GetLabelOffset());
uint len = end.GetLabelOffset() - start.GetLabelOffset();
if (Diag.DiagOn) Console.WriteLine("block start = " + start.GetLabelOffset() + " len = " + len);
if (fatFormat) output.Write(len);
else output.Write((byte)len);
}
}
/**************************************************************************/
///
/// The descriptor for a guarded block (.try)
///
public class TryBlock : CodeBlock
{
protected bool fatFormat = false;
protected ushort flags = 0;
ArrayList handlers = new ArrayList();
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new try block
///
/// start label for the try block
/// end label for the try block
public TryBlock(CILLabel start, CILLabel end) : base(start, end) { }
///
/// Add a handler to this try block
///
/// a handler to be added to the try block
public void AddHandler(HandlerBlock handler)
{
//flags = handler.GetFlag();
handlers.Add(handler);
}
///
/// Get an array containing all the handlers.
///
/// The list of handlers.
public HandlerBlock[] GetHandlers()
{
return (HandlerBlock[])handlers.ToArray(typeof(HandlerBlock));
}
internal void SetSize()
{
fatFormat = base.isFat();
if (fatFormat) return;
for (int i = 0; i < handlers.Count; i++)
{
HandlerBlock handler = (HandlerBlock)handlers[i];
if (handler.isFat())
{
fatFormat = true;
return;
}
}
}
internal int NumHandlers()
{
return handlers.Count;
}
internal override bool isFat()
{
return fatFormat;
}
internal void BuildTables(MetaDataOut md)
{
for (int i = 0; i < handlers.Count; i++)
{
((HandlerBlock)handlers[i]).BuildTables(md);
}
}
internal void BuildCILInfo(CILWriter output)
{
for (int i = 0; i < handlers.Count; i++)
{
((HandlerBlock)handlers[i]).BuildCILInfo(output);
}
}
internal override void Write(PEWriter output, bool fatFormat)
{
if (Diag.DiagOn) Console.WriteLine("writing exception details");
for (int i = 0; i < handlers.Count; i++)
{
if (Diag.DiagOn) Console.WriteLine("Except block " + i);
HandlerBlock handler = (HandlerBlock)handlers[i];
flags = handler.GetFlag();
if (Diag.DiagOn) Console.WriteLine("flags = " + flags);
if (fatFormat) output.Write((uint)flags);
else output.Write(flags);
base.Write(output, fatFormat);
handler.Write(output, fatFormat);
}
}
}
/**************************************************************************/
public abstract class HandlerBlock : CodeBlock
{
protected static readonly ushort ExceptionFlag = 0;
protected static readonly ushort FilterFlag = 0x01;
protected static readonly ushort FinallyFlag = 0x02;
protected static readonly ushort FaultFlag = 0x04;
/*-------------------- Constructors ---------------------------------*/
public HandlerBlock(CILLabel start, CILLabel end) : base(start, end) { }
internal virtual ushort GetFlag()
{
if (Diag.DiagOn) Console.WriteLine("Catch Block");
return ExceptionFlag;
}
internal virtual void BuildTables(MetaDataOut md) { }
internal virtual void BuildCILInfo(CILWriter output) { }
internal override void Write(PEWriter output, bool fatFormat)
{
base.Write(output, fatFormat);
}
}
/**************************************************************************/
///
/// The descriptor for a catch clause (.catch)
///
public class Catch : HandlerBlock
{
Class exceptType;
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new catch clause
///
/// the exception to be caught
/// start of the handler code
/// end of the handler code
public Catch(Class except, CILLabel handlerStart, CILLabel handlerEnd)
: base(handlerStart, handlerEnd)
{
exceptType = except;
}
internal override void BuildTables(MetaDataOut md)
{
if (!(exceptType is ClassDef)) exceptType.BuildMDTables(md);
}
internal override void BuildCILInfo(CILWriter output)
{
if (!(exceptType is ClassDef)) exceptType.BuildCILInfo(output);
}
internal override void Write(PEWriter output, bool fatFormat)
{
base.Write(output, fatFormat);
output.Write(exceptType.Token());
}
}
/**************************************************************************/
///
/// The descriptor for a filter clause (.filter)
///
public class Filter : HandlerBlock
{
CILLabel filterLabel;
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new filter clause
///
/// the label where the filter code starts
/// the start of the handler code
/// the end of the handler code
public Filter(CILLabel filterLabel, CILLabel handlerStart,
CILLabel handlerEnd)
: base(handlerStart, handlerEnd)
{
this.filterLabel = filterLabel;
}
internal override ushort GetFlag()
{
if (Diag.DiagOn) Console.WriteLine("Filter Block");
return FilterFlag;
}
internal override void Write(PEWriter output, bool fatFormat)
{
base.Write(output, fatFormat);
output.Write(filterLabel.GetLabelOffset());
}
}
/**************************************************************************/
///
/// Descriptor for a finally block (.finally)
///
public class Finally : HandlerBlock
{
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new finally clause
///
/// start of finally code
/// end of finally code
public Finally(CILLabel finallyStart, CILLabel finallyEnd)
: base(finallyStart, finallyEnd) { }
internal override ushort GetFlag()
{
if (Diag.DiagOn) Console.WriteLine("Finally Block");
return FinallyFlag;
}
internal override void Write(PEWriter output, bool fatFormat)
{
base.Write(output, fatFormat);
output.Write((int)0);
}
}
/**************************************************************************/
///
/// Descriptor for a fault block (.fault)
///
public class Fault : HandlerBlock
{
/*-------------------- Constructors ---------------------------------*/
///
/// Create a new fault clause
///
/// start of the fault code
/// end of the fault code
public Fault(CILLabel faultStart, CILLabel faultEnd)
: base(faultStart, faultEnd) { }
internal override ushort GetFlag()
{
if (Diag.DiagOn) Console.WriteLine("Fault Block");
return FaultFlag;
}
internal override void Write(PEWriter output, bool fatFormat)
{
base.Write(output, fatFormat);
output.Write((int)0);
}
}
}